[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] VT-d: pci code cleanup
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1245397520 -3600 # Node ID 2f1fa2215e60a325aabc14e22187761c13987f20 # Parent e2625f2359408ed47bc6e65278c79b3cddafebd3 VT-d: pci code cleanup This patch moves the pci code from iommu.c to pci.c. Instead of setup pci hierarchy in array bus2bridge in iommu_context_mapping, use scan_pci_devices once to add all existed PCI devices in system to alldevs_list and setup pci hierarchy in array bus2bridge. In addition, implement find_upstream_bridge to find the upstream PCIe-to-PCI/PCIX bridge or PCI legacy bridge for a PCI device, therefore it's cleanly to handle context map/unmap for PCI device, even for source-id setting. Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx> --- xen/drivers/passthrough/pci.c | 153 +++++++++++++++++++++++++++ xen/drivers/passthrough/vtd/iommu.c | 203 +++++++++--------------------------- xen/include/xen/pci.h | 11 + 3 files changed, 215 insertions(+), 152 deletions(-) diff -r e2625f235940 -r 2f1fa2215e60 xen/drivers/passthrough/pci.c --- a/xen/drivers/passthrough/pci.c Fri Jun 19 08:44:33 2009 +0100 +++ b/xen/drivers/passthrough/pci.c Fri Jun 19 08:45:20 2009 +0100 @@ -30,6 +30,16 @@ LIST_HEAD(alldevs_list); LIST_HEAD(alldevs_list); spinlock_t pcidevs_lock = SPIN_LOCK_UNLOCKED; +#define MAX_BUSES 256 +static struct { + u8 map; + u8 bus; + u8 devfn; +} bus2bridge[MAX_BUSES]; + +/* bus2bridge_lock protects bus2bridge array */ +static DEFINE_SPINLOCK(bus2bridge_lock); + struct pci_dev *alloc_pdev(u8 bus, u8 devfn) { struct pci_dev *pdev; @@ -240,6 +250,149 @@ void pci_release_devices(struct domain * spin_unlock(&pcidevs_lock); } +#define PCI_CLASS_BRIDGE_PCI 0x0604 + +int pdev_type(u8 bus, u8 devfn) +{ + u16 class_device; + u16 status, creg; + int pos; + u8 d = PCI_SLOT(devfn), f = PCI_FUNC(devfn); + + class_device = pci_conf_read16(bus, d, f, PCI_CLASS_DEVICE); + if ( class_device == PCI_CLASS_BRIDGE_PCI ) + { + pos = pci_find_next_cap(bus, devfn, + PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP); + if ( !pos ) + return DEV_TYPE_LEGACY_PCI_BRIDGE; + creg = pci_conf_read16(bus, d, f, pos + PCI_EXP_FLAGS); + return ((creg & PCI_EXP_FLAGS_TYPE) >> 4) == PCI_EXP_TYPE_PCI_BRIDGE ? + DEV_TYPE_PCIe2PCI_BRIDGE : DEV_TYPE_PCIe_BRIDGE; + } + + status = pci_conf_read16(bus, d, f, PCI_STATUS); + if ( !(status & PCI_STATUS_CAP_LIST) ) + return DEV_TYPE_PCI; + + if ( pci_find_next_cap(bus, devfn, PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP) ) + return DEV_TYPE_PCIe_ENDPOINT; + + return DEV_TYPE_PCI; +} + +/* + * find the upstream PCIe-to-PCI/PCIX bridge or PCI legacy bridge + * return 0: the device is integrated PCI device or PCIe + * return 1: find PCIe-to-PCI/PCIX bridge or PCI legacy bridge + * return -1: fail + */ +int find_upstream_bridge(u8 *bus, u8 *devfn, u8 *secbus) +{ + int ret = 0; + int cnt = 0; + + if ( *bus == 0 ) + return 0; + + if ( !bus2bridge[*bus].map ) + return 0; + + ret = 1; + spin_lock(&bus2bridge_lock); + while ( bus2bridge[*bus].map ) + { + *secbus = *bus; + *devfn = bus2bridge[*bus].devfn; + *bus = bus2bridge[*bus].bus; + if ( cnt++ >= MAX_BUSES ) + { + ret = -1; + goto out; + } + } + +out: + spin_unlock(&bus2bridge_lock); + return ret; +} + +/* + * scan pci devices to add all existed PCI devices to alldevs_list, + * and setup pci hierarchy in array bus2bridge. This function is only + * called in VT-d hardware setup + */ +int __init scan_pci_devices(void) +{ + struct pci_dev *pdev; + int bus, dev, func; + u8 sec_bus, sub_bus; + int type; + u32 l; + + spin_lock(&pcidevs_lock); + for ( bus = 0; bus < 256; bus++ ) + { + for ( dev = 0; dev < 32; dev++ ) + { + for ( func = 0; func < 8; func++ ) + { + l = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID); + /* some broken boards return 0 or ~0 if a slot is empty: */ + if ( (l == 0xffffffff) || (l == 0x00000000) || + (l == 0x0000ffff) || (l == 0xffff0000) ) + continue; + + pdev = alloc_pdev(bus, PCI_DEVFN(dev, func)); + if ( !pdev ) + { + printk("%s: alloc_pdev failed.\n", __func__); + spin_unlock(&pcidevs_lock); + return -ENOMEM; + } + + /* build bus2bridge */ + type = pdev_type(bus, PCI_DEVFN(dev, func)); + switch ( type ) + { + case DEV_TYPE_PCIe_BRIDGE: + break; + + case DEV_TYPE_PCIe2PCI_BRIDGE: + case DEV_TYPE_LEGACY_PCI_BRIDGE: + sec_bus = pci_conf_read8(bus, dev, func, + PCI_SECONDARY_BUS); + sub_bus = pci_conf_read8(bus, dev, func, + PCI_SUBORDINATE_BUS); + + spin_lock(&bus2bridge_lock); + for ( sub_bus &= 0xff; sec_bus <= sub_bus; sec_bus++ ) + { + bus2bridge[sec_bus].map = 1; + bus2bridge[sec_bus].bus = bus; + bus2bridge[sec_bus].devfn = PCI_DEVFN(dev, func); + } + spin_unlock(&bus2bridge_lock); + break; + + case DEV_TYPE_PCIe_ENDPOINT: + case DEV_TYPE_PCI: + break; + + default: + printk("%s: unknown type: bdf = %x:%x.%x\n", + __func__, bus, dev, func); + spin_unlock(&pcidevs_lock); + return -EINVAL; + } + } + } + } + + spin_unlock(&pcidevs_lock); + return 0; +} + #ifdef SUPPORT_MSI_REMAPPING static void dump_pci_devices(unsigned char ch) { diff -r e2625f235940 -r 2f1fa2215e60 xen/drivers/passthrough/vtd/iommu.c --- a/xen/drivers/passthrough/vtd/iommu.c Fri Jun 19 08:44:33 2009 +0100 +++ b/xen/drivers/passthrough/vtd/iommu.c Fri Jun 19 08:45:20 2009 +0100 @@ -1066,92 +1066,12 @@ static int domain_context_mapping_one( return 0; } -#define PCI_BASE_CLASS_BRIDGE 0x06 -#define PCI_CLASS_BRIDGE_PCI 0x0604 - -enum { - DEV_TYPE_PCIe_ENDPOINT, - DEV_TYPE_PCIe_BRIDGE, // PCIe root port, switch - DEV_TYPE_PCI_BRIDGE, // PCIe-to-PCI/PCIx bridge, PCI-to-PCI bridge - DEV_TYPE_PCI, -}; - -int pdev_type(u8 bus, u8 devfn) -{ - u16 class_device; - u16 status, creg; - int pos; - u8 d = PCI_SLOT(devfn), f = PCI_FUNC(devfn); - - class_device = pci_conf_read16(bus, d, f, PCI_CLASS_DEVICE); - if ( class_device == PCI_CLASS_BRIDGE_PCI ) - { - pos = pci_find_next_cap(bus, devfn, - PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP); - if ( !pos ) - return DEV_TYPE_PCI_BRIDGE; - creg = pci_conf_read16(bus, d, f, pos + PCI_EXP_FLAGS); - return ((creg & PCI_EXP_FLAGS_TYPE) >> 4) == PCI_EXP_TYPE_PCI_BRIDGE ? - DEV_TYPE_PCI_BRIDGE : DEV_TYPE_PCIe_BRIDGE; - } - - status = pci_conf_read16(bus, d, f, PCI_STATUS); - if ( !(status & PCI_STATUS_CAP_LIST) ) - return DEV_TYPE_PCI; - - if ( pci_find_next_cap(bus, devfn, PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP) ) - return DEV_TYPE_PCIe_ENDPOINT; - - return DEV_TYPE_PCI; -} - -#define MAX_BUSES 256 -static DEFINE_SPINLOCK(bus2bridge_lock); -static struct { u8 map, bus, devfn; } bus2bridge[MAX_BUSES]; - -static int _find_pcie_endpoint(u8 *bus, u8 *devfn, u8 *secbus) -{ - int cnt = 0; - *secbus = *bus; - - ASSERT(spin_is_locked(&bus2bridge_lock)); - if ( !bus2bridge[*bus].map ) - return 0; - - while ( bus2bridge[*bus].map ) - { - *secbus = *bus; - *devfn = bus2bridge[*bus].devfn; - *bus = bus2bridge[*bus].bus; - if ( cnt++ >= MAX_BUSES ) - return 0; - } - - return 1; -} - -static int find_pcie_endpoint(u8 *bus, u8 *devfn, u8 *secbus) -{ - int ret = 0; - - if ( *bus == 0 ) - /* assume integrated PCI devices in RC have valid requester-id */ - return 1; - - spin_lock(&bus2bridge_lock); - ret = _find_pcie_endpoint(bus, devfn, secbus); - spin_unlock(&bus2bridge_lock); - - return ret; -} - static int domain_context_mapping(struct domain *domain, u8 bus, u8 devfn) { struct acpi_drhd_unit *drhd; int ret = 0; - u16 sec_bus, sub_bus; u32 type; - u8 secbus, secdevfn; + u8 secbus; struct pci_dev *pdev = pci_get_pdev(bus, devfn); if ( pdev == NULL ) @@ -1179,22 +1099,8 @@ static int domain_context_mapping(struct switch ( type ) { case DEV_TYPE_PCIe_BRIDGE: - break; - - case DEV_TYPE_PCI_BRIDGE: - sec_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), - PCI_SECONDARY_BUS); - sub_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), - PCI_SUBORDINATE_BUS); - - spin_lock(&bus2bridge_lock); - for ( sub_bus &= 0xff; sec_bus <= sub_bus; sec_bus++ ) - { - bus2bridge[sec_bus].map = 1; - bus2bridge[sec_bus].bus = bus; - bus2bridge[sec_bus].devfn = devfn; - } - spin_unlock(&bus2bridge_lock); + case DEV_TYPE_PCIe2PCI_BRIDGE: + case DEV_TYPE_LEGACY_PCI_BRIDGE: break; case DEV_TYPE_PCIe_ENDPOINT: @@ -1211,31 +1117,29 @@ static int domain_context_mapping(struct ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn); if ( ret ) - break; - - secbus = bus; - secdevfn = devfn; - /* dependent devices mapping */ - while ( bus2bridge[bus].map ) - { - secbus = bus; - secdevfn = devfn; - devfn = bus2bridge[bus].devfn; - bus = bus2bridge[bus].bus; + break; + + if ( find_upstream_bridge(&bus, &devfn, &secbus) < 1 ) + break; + + /* PCIe to PCI/PCIx bridge */ + if ( pdev_type(bus, devfn) == DEV_TYPE_PCIe2PCI_BRIDGE ) + { ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn); if ( ret ) return ret; - } - - if ( (secbus != bus) && (secdevfn != 0) ) + /* - * The source-id for transactions on non-PCIe buses seem - * to originate from devfn=0 on the secondary bus behind - * the bridge. Map that id as well. The id to use in - * these scanarios is not particularly well documented - * anywhere. + * Devices behind PCIe-to-PCI/PCIx bridge may generate + * different requester-id. It may originate from devfn=0 + * on the secondary bus behind the bridge. Map that id + * as well. */ ret = domain_context_mapping_one(domain, drhd->iommu, secbus, 0); + } + else /* Legacy PCI bridge */ + ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn); + break; default: @@ -1296,7 +1200,7 @@ static int domain_context_unmap(struct d struct acpi_drhd_unit *drhd; int ret = 0; u32 type; - u8 secbus, secdevfn; + u8 secbus; struct pci_dev *pdev = pci_get_pdev(bus, devfn); BUG_ON(!pdev); @@ -1309,7 +1213,8 @@ static int domain_context_unmap(struct d switch ( type ) { case DEV_TYPE_PCIe_BRIDGE: - case DEV_TYPE_PCI_BRIDGE: + case DEV_TYPE_PCIe2PCI_BRIDGE: + case DEV_TYPE_LEGACY_PCI_BRIDGE: break; case DEV_TYPE_PCIe_ENDPOINT: @@ -1327,22 +1232,21 @@ static int domain_context_unmap(struct d if ( ret ) break; - secbus = bus; - secdevfn = devfn; - /* dependent devices unmapping */ - while ( bus2bridge[bus].map ) - { - secbus = bus; - secdevfn = devfn; - devfn = bus2bridge[bus].devfn; - bus = bus2bridge[bus].bus; + if ( find_upstream_bridge(&bus, &devfn, &secbus) < 1 ) + break; + + /* PCIe to PCI/PCIx bridge */ + if ( pdev_type(bus, devfn) == DEV_TYPE_PCIe2PCI_BRIDGE ) + { ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn); if ( ret ) return ret; - } - - if ( (secbus != bus) && (secdevfn != 0) ) + ret = domain_context_unmap_one(domain, drhd->iommu, secbus, 0); + } + else /* Legacy PCI bridge */ + ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn); + break; default: @@ -1584,31 +1488,24 @@ static void setup_dom0_devices(struct do { struct hvm_iommu *hd; struct pci_dev *pdev; - int bus, dev, func; - u32 l; + int bus, devfn; hd = domain_hvm_iommu(d); spin_lock(&pcidevs_lock); for ( bus = 0; bus < 256; bus++ ) { - for ( dev = 0; dev < 32; dev++ ) - { - for ( func = 0; func < 8; func++ ) - { - l = pci_conf_read32(bus, dev, func, PCI_VENDOR_ID); - /* some broken boards return 0 or ~0 if a slot is empty: */ - if ( (l == 0xffffffff) || (l == 0x00000000) || - (l == 0x0000ffff) || (l == 0xffff0000) ) - continue; - - pdev = alloc_pdev(bus, PCI_DEVFN(dev, func)); - pdev->domain = d; - list_add(&pdev->domain_list, &d->arch.pdev_list); - domain_context_mapping(d, pdev->bus, pdev->devfn); - if ( ats_device(0, pdev->bus, pdev->devfn) ) - enable_ats_device(0, pdev->bus, pdev->devfn); - } + for ( devfn = 0; devfn < 256; devfn++ ) + { + pdev = pci_get_pdev(bus, devfn); + if ( !pdev ) + continue; + + pdev->domain = d; + list_add(&pdev->domain_list, &d->arch.pdev_list); + domain_context_mapping(d, pdev->bus, pdev->devfn); + if ( ats_device(0, pdev->bus, pdev->devfn) ) + enable_ats_device(0, pdev->bus, pdev->devfn); } } spin_unlock(&pcidevs_lock); @@ -1809,6 +1706,8 @@ int intel_vtd_setup(void) memset(domid_bitmap, 0, domid_bitmap_size / 8); set_bit(0, domid_bitmap); + scan_pci_devices(); + if ( init_vtd_hw() ) goto error; @@ -1902,10 +1801,10 @@ static int intel_iommu_group_id(u8 bus, static int intel_iommu_group_id(u8 bus, u8 devfn) { u8 secbus; - if ( !bus2bridge[bus].map || find_pcie_endpoint(&bus, &devfn, &secbus) ) + if ( find_upstream_bridge(&bus, &devfn, &secbus) < 0 ) + return -1; + else return PCI_BDF2(bus, devfn); - else - return -1; } static u32 iommu_state[MAX_IOMMUS][MAX_IOMMU_REGS]; diff -r e2625f235940 -r 2f1fa2215e60 xen/include/xen/pci.h --- a/xen/include/xen/pci.h Fri Jun 19 08:44:33 2009 +0100 +++ b/xen/include/xen/pci.h Fri Jun 19 08:45:20 2009 +0100 @@ -66,6 +66,17 @@ struct pci_dev { extern spinlock_t pcidevs_lock; +enum { + DEV_TYPE_PCIe_ENDPOINT, + DEV_TYPE_PCIe_BRIDGE, // PCIe root port, switch + DEV_TYPE_PCIe2PCI_BRIDGE, // PCIe-to-PCI/PCIx bridge + DEV_TYPE_LEGACY_PCI_BRIDGE, // Legacy PCI bridge + DEV_TYPE_PCI, +}; + +int scan_pci_devices(void); +int pdev_type(u8 bus, u8 devfn); +int find_upstream_bridge(u8 *bus, u8 *devfn, u8 *secbus); struct pci_dev *alloc_pdev(u8 bus, u8 devfn); void free_pdev(struct pci_dev *pdev); struct pci_dev *pci_lock_pdev(int bus, int devfn); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |