diff -r 05e36e506c09 tools/ioemu/hw/pass-through.c --- a/tools/ioemu/hw/pass-through.c Wed Jan 23 18:12:37 2008 +0000 +++ b/tools/ioemu/hw/pass-through.c Thu Jan 24 09:04:10 2008 +0800 @@ -56,56 +56,6 @@ static int next_bdf(char **str, int *seg 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) @@ -273,7 +223,7 @@ static int pt_register_regions(struct pt 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] ) { @@ -358,9 +308,6 @@ struct pt_dev * register_real_device(PCI assigned_device->pci_dev = pci_dev; - /* Issue PCIe FLR */ - pdev_flr(pci_dev); - /* Assign device */ machine_bdf.reg = 0; machine_bdf.bus = r_bus; diff -r 05e36e506c09 xen/arch/x86/hvm/vmx/vtd/extern.h --- a/xen/arch/x86/hvm/vmx/vtd/extern.h Wed Jan 23 18:12:37 2008 +0000 +++ b/xen/arch/x86/hvm/vmx/vtd/extern.h Thu Jan 24 09:13:16 2008 +0800 @@ -34,6 +34,7 @@ void print_iommu_regs(struct acpi_drhd_u void print_iommu_regs(struct acpi_drhd_unit *drhd); void print_vtd_entries(struct domain *d, struct iommu *iommu, int bus, int devfn, unsigned long gmfn); +void pdev_flr(u8 bus, u8 devfn); int qinval_setup(struct iommu *iommu); int queue_invalidate_context(struct iommu *iommu, diff -r 05e36e506c09 xen/arch/x86/hvm/vmx/vtd/intel-iommu.c --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Wed Jan 23 18:12:37 2008 +0000 +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Thu Jan 24 09:04:10 2008 +0800 @@ -1481,6 +1481,7 @@ void return_devices_to_dom0(struct domai 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); } @@ -1929,6 +1930,7 @@ int assign_device(struct domain *d, u8 b "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 */ diff -r 05e36e506c09 xen/arch/x86/hvm/vmx/vtd/utils.c --- a/xen/arch/x86/hvm/vmx/vtd/utils.c Wed Jan 23 18:12:37 2008 +0000 +++ b/xen/arch/x86/hvm/vmx/vtd/utils.c Thu Jan 24 09:14:38 2008 +0800 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include "dmar.h" @@ -93,6 +93,101 @@ void disable_pmr(struct iommu *iommu) "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) {