# HG changeset patch # User Yu Zhao # Date 1237366099 14400 # Node ID cdf29bb6c74d5e075099855e9ddffb27e633079a # Parent 9fc957e63f8dc0fdb2400eb424da4c1122b7ac65 Xen: use proper device ID to search VT-d unit for ARI and SR-IOV device PCIe Alternative Routing-ID Interpretation (ARI) ECN defines the Extended Function -- a function whose function number is greater than 7 within an ARI Device. Intel VT-d spec 1.2 section 8.3.2 specifies that the Extended Function is under the scope of the same remapping unit as the traditional function. The hypervisor needs to know if a function is Extended Function so it can find proper DMAR for it. And section 8.3.3 specifies that the SR-IOV Virtual Function is under the scope of the same remapping unit as the Physical Function. The hypervisor also needs to know if a function is the Virtual Function and which Physical Function it's associated with for same reason. diff -r 9fc957e63f8d -r cdf29bb6c74d xen/arch/ia64/xen/hypercall.c --- a/xen/arch/ia64/xen/hypercall.c Tue Mar 17 15:40:25 2009 +0000 +++ b/xen/arch/ia64/xen/hypercall.c Wed Mar 18 04:48:19 2009 -0400 @@ -650,6 +650,7 @@ case PHYSDEVOP_manage_pci_add: { struct physdev_manage_pci manage_pci; + struct pci_dev dev; ret = -EPERM; if ( !IS_PRIV(current->domain) ) break; @@ -657,7 +658,13 @@ if ( copy_from_guest(&manage_pci, arg, 1) != 0 ) break; - ret = pci_add_device(manage_pci.bus, manage_pci.devfn); + dev.bus = manage_pci.bus; + dev.devfn = manage_pci.devfn; + dev.is_extfn = manage_pci.is_extfn; + dev.is_virtfn = manage_pci.is_virtfn; + dev.physfn.bus = manage_pci.physfn.bus; + dev.physfn.devfn = manage_pci.physfn.devfn; + ret = pci_add_device(&dev); break; } diff -r 9fc957e63f8d -r cdf29bb6c74d xen/arch/x86/physdev.c --- a/xen/arch/x86/physdev.c Tue Mar 17 15:40:25 2009 +0000 +++ b/xen/arch/x86/physdev.c Wed Mar 18 04:48:19 2009 -0400 @@ -397,6 +397,7 @@ case PHYSDEVOP_manage_pci_add: { struct physdev_manage_pci manage_pci; + struct pci_dev dev; ret = -EPERM; if ( !IS_PRIV(v->domain) ) break; @@ -404,7 +405,13 @@ if ( copy_from_guest(&manage_pci, arg, 1) != 0 ) break; - ret = pci_add_device(manage_pci.bus, manage_pci.devfn); + dev.bus = manage_pci.bus; + dev.devfn = manage_pci.devfn; + dev.is_extfn = manage_pci.is_extfn; + dev.is_virtfn = manage_pci.is_virtfn; + dev.physfn.bus = manage_pci.physfn.bus; + dev.physfn.devfn = manage_pci.physfn.devfn; + ret = pci_add_device(&dev); break; } diff -r 9fc957e63f8d -r cdf29bb6c74d xen/drivers/passthrough/pci.c --- a/xen/drivers/passthrough/pci.c Tue Mar 17 15:40:25 2009 +0000 +++ b/xen/drivers/passthrough/pci.c Wed Mar 18 04:48:19 2009 -0400 @@ -43,8 +43,8 @@ return NULL; memset(pdev, 0, sizeof(struct pci_dev)); - *((u8*) &pdev->bus) = bus; - *((u8*) &pdev->devfn) = devfn; + pdev->bus = bus; + pdev->devfn = devfn; pdev->domain = NULL; INIT_LIST_HEAD(&pdev->msi_list); list_add(&pdev->alldevs_list, &alldevs_list); @@ -92,15 +92,20 @@ return NULL; } -int pci_add_device(u8 bus, u8 devfn) +int pci_add_device(struct pci_dev *dev) { struct pci_dev *pdev; int ret = -ENOMEM; spin_lock(&pcidevs_lock); - pdev = alloc_pdev(bus, devfn); + pdev = alloc_pdev(dev->bus, dev->devfn); if ( !pdev ) goto out; + + pdev->is_extfn = dev->is_extfn; + pdev->is_virtfn = dev->is_virtfn; + pdev->physfn.bus = dev->physfn.bus; + pdev->physfn.devfn = dev->physfn.devfn; ret = 0; if ( !pdev->domain ) @@ -115,8 +120,8 @@ out: spin_unlock(&pcidevs_lock); - printk(XENLOG_DEBUG "PCI add device %02x:%02x.%x\n", bus, - PCI_SLOT(devfn), PCI_FUNC(devfn)); + printk(XENLOG_DEBUG "PCI add device %02x:%02x.%x\n", dev->bus, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); return ret; } diff -r 9fc957e63f8d -r cdf29bb6c74d xen/drivers/passthrough/vtd/dmar.c --- a/xen/drivers/passthrough/vtd/dmar.c Tue Mar 17 15:40:25 2009 +0000 +++ b/xen/drivers/passthrough/vtd/dmar.c Wed Mar 18 04:48:19 2009 -0400 @@ -157,6 +157,17 @@ struct acpi_drhd_unit *drhd; struct acpi_drhd_unit *found = NULL, *include_all = NULL; int i; + struct pci_dev *dev; + + dev = pci_get_pdev(bus, devfn); + BUG_ON(!dev); + + if (dev->is_extfn) { + devfn = 0; + } else if (dev->is_virtfn) { + bus = dev->physfn.bus; + devfn = PCI_SLOT(dev->physfn.devfn) ? 0 : dev->physfn.devfn; + } list_for_each_entry ( drhd, &acpi_drhd_units, list ) { diff -r 9fc957e63f8d -r cdf29bb6c74d xen/include/public/physdev.h --- a/xen/include/public/physdev.h Tue Mar 17 15:40:25 2009 +0000 +++ b/xen/include/public/physdev.h Wed Mar 18 04:48:19 2009 -0400 @@ -178,6 +178,12 @@ /* IN */ uint8_t bus; uint8_t devfn; + unsigned is_extfn:1; + unsigned is_virtfn:1; + struct { + uint8_t bus; + uint8_t devfn; + } physfn; }; typedef struct physdev_manage_pci physdev_manage_pci_t; diff -r 9fc957e63f8d -r cdf29bb6c74d xen/include/xen/pci.h --- a/xen/include/xen/pci.h Tue Mar 17 15:40:25 2009 +0000 +++ b/xen/include/xen/pci.h Wed Mar 18 04:48:19 2009 -0400 @@ -41,8 +41,14 @@ spinlock_t msix_table_lock; struct domain *domain; - const u8 bus; - const u8 devfn; + u8 bus; + u8 devfn; + unsigned is_extfn:1; + unsigned is_virtfn:1; + struct { + u8 bus; + u8 devfn; + } physfn; }; #define for_each_pdev(domain, pdev) \ @@ -62,7 +68,7 @@ struct pci_dev *pci_lock_domain_pdev(struct domain *d, int bus, int devfn); void pci_release_devices(struct domain *d); -int pci_add_device(u8 bus, u8 devfn); +int pci_add_device(struct pci_dev *dev); int pci_remove_device(u8 bus, u8 devfn); struct pci_dev *pci_get_pdev(int bus, int devfn); struct pci_dev *pci_get_pdev_by_domain(struct domain *d, int bus, int devfn);