return 1;
}
-uint8_t find_cap_offset(struct pci_dev *pci_dev, uint8_t cap)
-{
- int id;
- int max_cap = 48;
- int pos = PCI_CAPABILITY_LIST;
- int status;
-
- status = pci_read_byte(pci_dev, PCI_STATUS);
- if ( (status & PCI_STATUS_CAP_LIST) == 0 )
- return 0;
-
- while ( max_cap-- )
- {
- pos = pci_read_byte(pci_dev, pos);
- if ( pos < 0x40 )
- break;
-
- pos &= ~3;
- id = pci_read_byte(pci_dev, pos + PCI_CAP_LIST_ID);
-
- if ( id == 0xff )
- break;
- if ( id == cap )
- return pos;
-
- pos += PCI_CAP_LIST_NEXT;
- }
- return 0;
-}
-
-void pdev_flr(struct pci_dev *pci_dev)
-{
- int pos;
- int dev_cap;
- int dev_status;
-
- pos = find_cap_offset(pci_dev, PCI_CAP_ID_EXP);
- if ( pos )
- {
- dev_cap = pci_read_long(pci_dev, pos + PCI_EXP_DEVCAP);
- if ( dev_cap & PCI_EXP_DEVCAP_FLR )
- {
- pci_write_word(pci_dev, pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);
- do {
- dev_status = pci_read_long(pci_dev, pos + PCI_EXP_DEVSTA);
- } while (dev_status & PCI_EXP_DEVSTA_TRPND);
- }
- }
-}
-
/* Being called each time a mmio region has been updated */
void pt_iomem_map(PCIDevice *d, int i, uint32_t e_phys, uint32_t e_size,
int type)
PCIDevice *d = &assigned_device->dev;
/* Register PIO/MMIO BARs */
- for ( i=0; i < PCI_BAR_ENTRIES; i++ )
+ for ( i = 0; i < PCI_BAR_ENTRIES; i++ )
{
if ( pci_dev->base_addr[i] )
{
assigned_device->pci_dev = pci_dev;
- /* Issue PCIe FLR */
- pdev_flr(pci_dev);
-
/* Assign device */
machine_bdf.reg = 0;
machine_bdf.bus = r_bus;
extern void print_vtd_entries(struct domain *d, int bus, int devfn,
unsigned long gmfn);
+void pdev_flr(u8 bus, u8 devfn);
+
static spinlock_t domid_bitmap_lock; /* protect domain id bitmap */
static int domid_bitmap_size; /* domain id bitmap size in bit */
static void *domid_bitmap; /* iommu domain id bitmap */
dprintk(XENLOG_INFO VTDPREFIX,
"return_devices_to_dom0: bdf = %x:%x:%x\n",
pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+ pdev_flr(pdev->bus, pdev->devfn);
reassign_device_ownership(d, dom0, pdev->bus, pdev->devfn);
}
"assign_device: bus = %x dev = %x func = %x\n",
bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ pdev_flr(bus, devfn);
reassign_device_ownership(dom0, d, bus, devfn);
/* Setup rmrr identify mapping */
#include <xen/irq.h>
#include <xen/spinlock.h>
#include <xen/sched.h>
-#include <asm/delay.h>
+#include <xen/delay.h>
#include <asm/iommu.h>
#include <asm/hvm/vmx/intel-iommu.h>
#include "dmar.h"
"Disabled protected memory registers\n");
}
+static u8 find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap)
+{
+ u8 id;
+ int max_cap = 48;
+ u8 pos = PCI_CAPABILITY_LIST;
+ u16 status;
+
+ status = read_pci_config_16(bus, dev, func, PCI_STATUS);
+ if ( (status & PCI_STATUS_CAP_LIST) == 0 )
+ return 0;
+
+ while ( max_cap-- )
+ {
+ pos = read_pci_config_byte(bus, dev, func, pos);
+ if ( pos < 0x40 )
+ break;
+
+ pos &= ~3;
+ id = read_pci_config_byte(bus, dev, func, pos + PCI_CAP_LIST_ID);
+
+ if ( id == 0xff )
+ break;
+ else if ( id == cap )
+ return pos;
+
+ pos += PCI_CAP_LIST_NEXT;
+ }
+
+ return 0;
+}
+
+#define PCI_D3hot (3)
+#define PCI_CONFIG_DWORD_SIZE (64)
+#define PCI_EXP_DEVCAP_FLR (1 << 28)
+#define PCI_EXP_DEVCTL_FLR (1 << 15)
+
+void pdev_flr(u8 bus, u8 devfn)
+{
+ u8 pos;
+ u32 dev_cap, dev_status, pm_ctl;
+ int flr = 0;
+ u8 dev = PCI_SLOT(devfn);
+ u8 func = PCI_FUNC(devfn);
+
+ pos = find_cap_offset(bus, dev, func, PCI_CAP_ID_EXP);
+ if ( pos != 0 )
+ {
+ dev_cap = read_pci_config(bus, dev, func, pos + PCI_EXP_DEVCAP);
+ if ( dev_cap & PCI_EXP_DEVCAP_FLR )
+ {
+ write_pci_config(bus, dev, func,
+ pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR);
+ do {
+ dev_status = read_pci_config(bus, dev, func,
+ pos + PCI_EXP_DEVSTA);
+ } while ( dev_status & PCI_EXP_DEVSTA_TRPND );
+
+ flr = 1;
+ }
+ }
+
+ /* If this device doesn't support function level reset,
+ * program device from D0 t0 D3hot, and then return to D0
+ * to implement function level reset
+ */
+ if ( flr == 0 )
+ {
+ pos = find_cap_offset(bus, dev, func, PCI_CAP_ID_PM);
+ if ( pos != 0 )
+ {
+ int i;
+ u32 config[PCI_CONFIG_DWORD_SIZE];
+ for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )
+ config[i] = read_pci_config(bus, dev, func, i*4);
+
+ /* Enter D3hot without soft reset */
+ pm_ctl = read_pci_config(bus, dev, func, pos + PCI_PM_CTRL);
+ pm_ctl |= PCI_PM_CTRL_NO_SOFT_RESET;
+ pm_ctl &= ~PCI_PM_CTRL_STATE_MASK;
+ pm_ctl |= PCI_D3hot;
+ write_pci_config(bus, dev, func, pos + PCI_PM_CTRL, pm_ctl);
+ mdelay(10);
+
+ /* From D3hot to D0 */
+ write_pci_config(bus, dev, func, pos + PCI_PM_CTRL, 0);
+ mdelay(10);
+
+ /* Write saved configurations to device */
+ for ( i = 0; i < PCI_CONFIG_DWORD_SIZE; i++ )
+ write_pci_config(bus, dev, func, i*4, config[i]);
+
+ flr = 1;
+ }
+ }
+}
void print_iommu_regs(struct acpi_drhd_unit *drhd)
{