Jan Beulich
2011-Sep-20 15:19 UTC
[Xen-devel] [PATCH 6/7] PCI multi-seg: Pass-through adjustments
Signed-off-by: Jan Beulich <jbeulich@suse.com> --- 2011-09-20.orig/xen/drivers/passthrough/amd/pci_amd_iommu.c 2011-09-20 16:06:32.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/amd/pci_amd_iommu.c 2011-09-20 16:06:38.000000000 +0200 @@ -123,35 +123,17 @@ static void amd_iommu_setup_domain_devic spin_unlock_irqrestore(&iommu->lock, flags); } -static void __init amd_iommu_setup_dom0_devices(struct domain *d) +static void __init amd_iommu_setup_dom0_device(struct pci_dev *pdev) { - struct amd_iommu *iommu; - struct pci_dev *pdev; - int bus, devfn, bdf; + int bdf = (pdev->bus << 8) | pdev->devfn; + struct amd_iommu *iommu = find_iommu_for_device(pdev->seg, bdf); - spin_lock(&pcidevs_lock); - for ( bus = 0; bus < 256; bus++ ) - { - for ( devfn = 0; devfn < 256; devfn++ ) - { - pdev = pci_get_pdev(0, bus, devfn); - if ( !pdev ) - continue; - - pdev->domain = d; - list_add(&pdev->domain_list, &d->arch.pdev_list); - - bdf = (bus << 8) | devfn; - iommu = find_iommu_for_device(pdev->seg, bdf); - - if ( likely(iommu != NULL) ) - amd_iommu_setup_domain_device(d, iommu, bdf); - else - AMD_IOMMU_DEBUG("No iommu for device %02x:%02x.%x\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - } - } - spin_unlock(&pcidevs_lock); + if ( likely(iommu != NULL) ) + amd_iommu_setup_domain_device(pdev->domain, iommu, bdf); + else + AMD_IOMMU_DEBUG("No iommu for device %04x:%02x:%02x.%u\n", + pdev->seg, pdev->bus, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); } int __init amd_iov_detect(void) @@ -279,7 +261,7 @@ static void __init amd_iommu_dom0_init(s } } - amd_iommu_setup_dom0_devices(d); + setup_dom0_pci_devices(d, amd_iommu_setup_dom0_device); } static void amd_iommu_disable_domain_device( --- 2011-09-20.orig/xen/drivers/passthrough/pci.c 2011-08-25 15:06:40.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/pci.c 2011-08-25 15:12:12.000000000 +0200 @@ -202,9 +202,7 @@ struct pci_dev *pci_get_pdev_by_domain( void pci_enable_acs(struct pci_dev *pdev) { int pos; - u16 cap; - u16 ctrl; - + u16 cap, ctrl, seg = pdev->seg; u8 bus = pdev->bus; u8 dev = PCI_SLOT(pdev->devfn); u8 func = PCI_FUNC(pdev->devfn); @@ -212,7 +210,7 @@ void pci_enable_acs(struct pci_dev *pdev if ( !iommu_enabled ) return; - pos = pci_find_ext_capability(0, bus, pdev->devfn, PCI_EXT_CAP_ID_ACS); + pos = pci_find_ext_capability(seg, bus, pdev->devfn, PCI_EXT_CAP_ID_ACS); if (!pos) return; @@ -453,7 +451,7 @@ void pci_release_devices(struct domain * #define PCI_CLASS_BRIDGE_PCI 0x0604 -int pdev_type(u8 bus, u8 devfn) +int pdev_type(u16 seg, u8 bus, u8 devfn) { u16 class_device; u16 status, creg; @@ -488,9 +486,9 @@ int pdev_type(u8 bus, u8 devfn) * 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 find_upstream_bridge(u16 seg, u8 *bus, u8 *devfn, u8 *secbus) { - struct pci_seg *pseg = get_pseg(0); + struct pci_seg *pseg = get_pseg(seg); int ret = 0; int cnt = 0; @@ -525,7 +523,7 @@ out: /* * detect pci device, return 0 if it exists, or return 0 */ -int __init pci_device_detect(u8 bus, u8 dev, u8 func) +int __init pci_device_detect(u16 seg, u8 bus, u8 dev, u8 func) { u32 vendor; @@ -554,7 +552,7 @@ static int __init _scan_pci_devices(stru { for ( func = 0; func < 8; func++ ) { - if ( pci_device_detect(bus, dev, func) == 0 ) + if ( pci_device_detect(pseg->nr, bus, dev, func) == 0 ) continue; pdev = alloc_pdev(pseg, bus, PCI_DEVFN(dev, func)); @@ -565,7 +563,7 @@ static int __init _scan_pci_devices(stru } /* build bus2bridge */ - type = pdev_type(bus, PCI_DEVFN(dev, func)); + type = pdev_type(pseg->nr, bus, PCI_DEVFN(dev, func)); switch ( type ) { case DEV_TYPE_PCIe_BRIDGE: @@ -594,8 +592,8 @@ static int __init _scan_pci_devices(stru break; default: - printk("%s: unknown type: bdf = %x:%x.%x\n", - __func__, bus, dev, func); + printk("%s: unknown type: %04x:%02x:%02x.%u\n", + __func__, pseg->nr, bus, dev, func); return -EINVAL; } @@ -620,6 +618,44 @@ int __init scan_pci_devices(void) return ret; } +struct setup_dom0 { + struct domain *d; + void (*handler)(struct pci_dev *); +}; + +static int __init _setup_dom0_pci_devices(struct pci_seg *pseg, void *arg) +{ + struct setup_dom0 *ctxt = arg; + int bus, devfn; + + for ( bus = 0; bus < 256; bus++ ) + { + for ( devfn = 0; devfn < 256; devfn++ ) + { + struct pci_dev *pdev = pci_get_pdev(pseg->nr, bus, devfn); + + if ( !pdev ) + continue; + + pdev->domain = ctxt->d; + list_add(&pdev->domain_list, &ctxt->d->arch.pdev_list); + ctxt->handler(pdev); + } + } + + return 0; +} + +void __init setup_dom0_pci_devices( + struct domain *d, void (*handler)(struct pci_dev *)) +{ + struct setup_dom0 ctxt = { .d = d, .handler = handler }; + + spin_lock(&pcidevs_lock); + pci_segments_iterate(_setup_dom0_pci_devices, &ctxt); + spin_unlock(&pcidevs_lock); +} + /* Disconnect all PCI devices from the PCI buses. From the PCI spec: * "When a 0 is written to [the COMMAND] register, the device is * logically disconnected from the PCI bus for all accesses except @@ -654,8 +690,9 @@ static int _dump_pci_devices(struct pci_ list_for_each_entry ( pdev, &pseg->alldevs_list, alldevs_list ) { - printk("%02x:%02x.%x - dom %-3d - MSIs < ", - pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), + printk("%04x:%02x:%02x.%u - dom %-3d - MSIs < ", + pseg->nr, pdev->bus, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->domain ? pdev->domain->domain_id : -1); list_for_each_entry ( msi, &pdev->msi_list, list ) printk("%d ", msi->irq); --- 2011-09-20.orig/xen/drivers/passthrough/vtd/dmar.c 2011-08-25 15:06:43.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/vtd/dmar.c 2011-08-25 15:12:12.000000000 +0200 @@ -457,11 +457,11 @@ acpi_parse_one_drhd(struct acpi_dmar_ent d = PCI_SLOT(dmaru->scope.devices[i]); f = PCI_FUNC(dmaru->scope.devices[i]); - if ( pci_device_detect(b, d, f) == 0 ) + if ( pci_device_detect(drhd->segment, b, d, f) == 0 ) { dprintk(XENLOG_WARNING VTDPREFIX, - " Non-existent device (%x:%x.%x) is reported " - "in this DRHD''s scope!\n", b, d, f); + " Non-existent device (%04x:%02x:%02x.%u) is reported" + " in this DRHD''s scope!\n", drhd->segment, b, d, f); invalid_cnt++; } } @@ -556,12 +556,13 @@ acpi_parse_one_rmrr(struct acpi_dmar_ent d = PCI_SLOT(rmrru->scope.devices[i]); f = PCI_FUNC(rmrru->scope.devices[i]); - if ( pci_device_detect(b, d, f) == 0 ) + if ( pci_device_detect(rmrr->segment, b, d, f) == 0 ) { dprintk(XENLOG_WARNING VTDPREFIX, - " Non-existent device (%x:%x.%x) is reported " - "in RMRR (%"PRIx64", %"PRIx64")''s scope!\n", - b, d, f, rmrru->base_address, rmrru->end_address); + " Non-existent device (%04x:%02x:%02x.%u) is reported" + " in RMRR (%"PRIx64", %"PRIx64")''s scope!\n", + rmrr->segment, b, d, f, + rmrru->base_address, rmrru->end_address); ignore = 1; } else --- 2011-09-20.orig/xen/drivers/passthrough/vtd/intremap.c 2011-08-19 17:08:35.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/vtd/intremap.c 2011-08-25 15:12:12.000000000 +0200 @@ -448,15 +448,17 @@ void io_apic_write_remap_rte( static void set_msi_source_id(struct pci_dev *pdev, struct iremap_entry *ire) { int type; + u16 seg; u8 bus, devfn, secbus; int ret; if ( !pdev || !ire ) return; + seg = pdev->seg; bus = pdev->bus; devfn = pdev->devfn; - type = pdev_type(bus, devfn); + type = pdev_type(seg, bus, devfn); switch ( type ) { case DEV_TYPE_PCIe_BRIDGE: @@ -469,7 +471,7 @@ static void set_msi_source_id(struct pci break; case DEV_TYPE_PCI: - ret = find_upstream_bridge(&bus, &devfn, &secbus); + ret = find_upstream_bridge(seg, &bus, &devfn, &secbus); if ( ret == 0 ) /* integrated PCI device */ { set_ire_sid(ire, SVT_VERIFY_SID_SQ, SQ_ALL_16, @@ -477,19 +479,20 @@ static void set_msi_source_id(struct pci } else if ( ret == 1 ) /* find upstream bridge */ { - if ( pdev_type(bus, devfn) == DEV_TYPE_PCIe2PCI_BRIDGE ) + if ( pdev_type(seg, bus, devfn) == DEV_TYPE_PCIe2PCI_BRIDGE ) set_ire_sid(ire, SVT_VERIFY_BUS, SQ_ALL_16, (bus << 8) | pdev->bus); - else if ( pdev_type(bus, devfn) == DEV_TYPE_LEGACY_PCI_BRIDGE ) + else if ( pdev_type(seg, bus, devfn) == DEV_TYPE_LEGACY_PCI_BRIDGE ) set_ire_sid(ire, SVT_VERIFY_BUS, SQ_ALL_16, PCI_BDF2(bus, devfn)); } break; default: - dprintk(XENLOG_WARNING VTDPREFIX, "d%d: unknown(%u): bdf = %x:%x.%x\n", + dprintk(XENLOG_WARNING VTDPREFIX, + "d%d: unknown(%u): %04x:%02x:%02x.%u\n", pdev->domain->domain_id, type, - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); break; } } --- 2011-09-20.orig/xen/drivers/passthrough/vtd/iommu.c 2011-09-20 16:06:24.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/vtd/iommu.c 2011-09-20 16:06:42.000000000 +0200 @@ -50,7 +50,7 @@ bool_t __read_mostly untrusted_msi; int nr_iommus; -static void setup_dom0_devices(struct domain *d); +static void setup_dom0_device(struct pci_dev *); static void setup_dom0_rmrr(struct domain *d); static int domain_iommu_domid(struct domain *d, @@ -1240,7 +1240,7 @@ static void __init intel_iommu_dom0_init iommu_set_dom0_mapping(d); } - setup_dom0_devices(d); + setup_dom0_pci_devices(d, setup_dom0_device); setup_dom0_rmrr(d); iommu_flush_all(); @@ -1408,7 +1408,7 @@ static int domain_context_mapping( ASSERT(spin_is_locked(&pcidevs_lock)); - type = pdev_type(bus, devfn); + type = pdev_type(seg, bus, devfn); switch ( type ) { case DEV_TYPE_PCIe_BRIDGE: @@ -1437,7 +1437,7 @@ static int domain_context_mapping( if ( ret ) break; - if ( find_upstream_bridge(&bus, &devfn, &secbus) < 1 ) + if ( find_upstream_bridge(seg, &bus, &devfn, &secbus) < 1 ) break; ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn); @@ -1447,7 +1447,7 @@ static int domain_context_mapping( * requester-id. It may originate from devfn=0 on the secondary bus * behind the bridge. Map that id as well if we didn''t already. */ - if ( !ret && pdev_type(bus, devfn) == DEV_TYPE_PCIe2PCI_BRIDGE && + if ( !ret && pdev_type(seg, bus, devfn) == DEV_TYPE_PCIe2PCI_BRIDGE && (secbus != pdev->bus || pdev->devfn != 0) ) ret = domain_context_mapping_one(domain, drhd->iommu, secbus, 0); @@ -1539,7 +1539,7 @@ static int domain_context_unmap( return -ENODEV; iommu = drhd->iommu; - type = pdev_type(bus, devfn); + type = pdev_type(seg, bus, devfn); switch ( type ) { case DEV_TYPE_PCIe_BRIDGE: @@ -1568,11 +1568,11 @@ static int domain_context_unmap( tmp_bus = bus; tmp_devfn = devfn; - if ( find_upstream_bridge(&tmp_bus, &tmp_devfn, &secbus) < 1 ) + if ( find_upstream_bridge(seg, &tmp_bus, &tmp_devfn, &secbus) < 1 ) break; /* PCIe to PCI/PCIx bridge */ - if ( pdev_type(tmp_bus, tmp_devfn) == DEV_TYPE_PCIe2PCI_BRIDGE ) + if ( pdev_type(seg, tmp_bus, tmp_devfn) == DEV_TYPE_PCIe2PCI_BRIDGE ) { ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn); if ( ret ) @@ -1945,28 +1945,11 @@ static int intel_iommu_remove_device(str pdev->devfn); } -static void __init setup_dom0_devices(struct domain *d) +static void __init setup_dom0_device(struct pci_dev *pdev) { - struct pci_dev *pdev; - int bus, devfn; - - spin_lock(&pcidevs_lock); - for ( bus = 0; bus < 256; bus++ ) - { - for ( devfn = 0; devfn < 256; devfn++ ) - { - pdev = pci_get_pdev(0, bus, devfn); - if ( !pdev ) - continue; - - pdev->domain = d; - list_add(&pdev->domain_list, &d->arch.pdev_list); - domain_context_mapping(d, pdev->seg, pdev->bus, pdev->devfn); - pci_enable_acs(pdev); - pci_vtd_quirk(pdev); - } - } - spin_unlock(&pcidevs_lock); + domain_context_mapping(pdev->domain, pdev->seg, pdev->bus, pdev->devfn); + pci_enable_acs(pdev); + pci_vtd_quirk(pdev); } void clear_fault_bits(struct iommu *iommu) @@ -2240,7 +2223,7 @@ done: static int intel_iommu_group_id(u16 seg, u8 bus, u8 devfn) { u8 secbus; - if ( find_upstream_bridge(&bus, &devfn, &secbus) < 0 ) + if ( find_upstream_bridge(seg, &bus, &devfn, &secbus) < 0 ) return -1; else return PCI_BDF2(bus, devfn); --- 2011-09-20.orig/xen/include/xen/pci.h 2011-08-25 15:06:35.000000000 +0200 +++ 2011-09-20/xen/include/xen/pci.h 2011-08-25 15:12:12.000000000 +0200 @@ -82,13 +82,15 @@ enum { DEV_TYPE_PCI, }; -int pci_device_detect(u8 bus, u8 dev, u8 func); +int pci_device_detect(u16 seg, u8 bus, u8 dev, u8 func); 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 *pci_lock_pdev(int bus, int devfn); -struct pci_dev *pci_lock_domain_pdev(struct domain *d, int bus, int devfn); +int pdev_type(u16 seg, u8 bus, u8 devfn); +int find_upstream_bridge(u16 seg, u8 *bus, u8 *devfn, u8 *secbus); +struct pci_dev *pci_lock_pdev(int seg, int bus, int devfn); +struct pci_dev *pci_lock_domain_pdev( + struct domain *, int seg, int bus, int devfn); +void setup_dom0_pci_devices(struct domain *, void (*)(struct pci_dev *)); void pci_release_devices(struct domain *d); int pci_add_segment(u16 seg); int pci_add_device(u16 seg, u8 bus, u8 devfn, const struct pci_dev_info *); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel