Jan Beulich
2011-Aug-25 14:57 UTC
[Xen-devel] [PATCH, RFC 4/7] PCI multi-seg: VT-d specific adjustments
Signed-off-by: Jan Beulich <jbeulich@novell.com> --- 2011-08-25.orig/xen/drivers/passthrough/vtd/dmar.c 2011-08-16 08:15:46.000000000 +0200 +++ 2011-08-25/xen/drivers/passthrough/vtd/dmar.c 2011-08-25 15:06:43.000000000 +0200 @@ -188,6 +188,9 @@ struct acpi_drhd_unit * acpi_find_matche list_for_each_entry ( drhd, &acpi_drhd_units, list ) { + if ( drhd->segment != pdev->seg ) + continue; + for (i = 0; i < drhd->scope.devices_cnt; i++) if ( drhd->scope.devices[i] == PCI_BDF2(bus, devfn) ) return drhd; @@ -201,13 +204,16 @@ struct acpi_drhd_unit * acpi_find_matche return include_all; } -struct acpi_atsr_unit * acpi_find_matched_atsr_unit(u8 bus, u8 devfn) +struct acpi_atsr_unit * acpi_find_matched_atsr_unit(u16 seg, u8 bus, u8 devfn) { struct acpi_atsr_unit *atsr; struct acpi_atsr_unit *all_ports = NULL; list_for_each_entry ( atsr, &acpi_atsr_units, list ) { + if ( atsr->segment != seg ) + continue; + if ( test_bit(bus, atsr->scope.buses) ) return atsr; @@ -269,8 +275,8 @@ static int scope_device_count(void *star } -static int __init acpi_parse_dev_scope(void *start, void *end, - void *acpi_entry, int type) +static int __init acpi_parse_dev_scope( + void *start, void *end, void *acpi_entry, int type, u16 seg) { struct dmar_scope *scope = acpi_entry; struct acpi_ioapic_unit *acpi_ioapic_unit; @@ -314,8 +320,8 @@ static int __init acpi_parse_dev_scope(v bus, path->dev, path->fn, PCI_SUBORDINATE_BUS); if ( iommu_verbose ) dprintk(VTDPREFIX, - " bridge: %x:%x.%x start = %x sec = %x sub = %x\n", - bus, path->dev, path->fn, + " bridge: %04x:%02x:%02x.%u start=%x sec=%x sub=%x\n", + seg, bus, path->dev, path->fn, acpi_scope->start_bus, sec_bus, sub_bus); dmar_scope_add_buses(scope, sec_bus, sub_bus); @@ -323,20 +329,21 @@ static int __init acpi_parse_dev_scope(v case ACPI_DEV_MSI_HPET: if ( iommu_verbose ) - dprintk(VTDPREFIX, " MSI HPET: %x:%x.%x\n", - bus, path->dev, path->fn); + dprintk(VTDPREFIX, " MSI HPET: %04x:%02x:%02x.%u\n", + seg, bus, path->dev, path->fn); break; case ACPI_DEV_ENDPOINT: if ( iommu_verbose ) - dprintk(VTDPREFIX, " endpoint: %x:%x.%x\n", - bus, path->dev, path->fn); + dprintk(VTDPREFIX, " endpoint: %04x:%02x:%02x.%u\n", + seg, bus, path->dev, path->fn); if ( type == DMAR_TYPE ) { struct acpi_drhd_unit *drhd = acpi_entry; - if ( (bus == 0) && (path->dev == 2) && (path->fn == 0) ) + if ( (seg == 0) && (bus == 0) && (path->dev == 2) && + (path->fn == 0) ) igd_drhd_address = drhd->address; } @@ -344,8 +351,8 @@ static int __init acpi_parse_dev_scope(v case ACPI_DEV_IOAPIC: if ( iommu_verbose ) - dprintk(VTDPREFIX, " IOAPIC: %x:%x.%x\n", - bus, path->dev, path->fn); + dprintk(VTDPREFIX, " IOAPIC: %04x:%02x:%02x.%u\n", + seg, bus, path->dev, path->fn); if ( type == DMAR_TYPE ) { @@ -398,6 +405,7 @@ acpi_parse_one_drhd(struct acpi_dmar_ent memset(dmaru, 0, sizeof(struct acpi_drhd_unit)); dmaru->address = drhd->address; + dmaru->segment = drhd->segment; dmaru->include_all = drhd->flags & 1; /* BIT0: INCLUDE_ALL */ INIT_LIST_HEAD(&dmaru->ioapic_list); if ( iommu_verbose ) @@ -411,7 +419,7 @@ acpi_parse_one_drhd(struct acpi_dmar_ent dev_scope_start = (void *)(drhd + 1); dev_scope_end = ((void *)drhd) + header->length; ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end, - dmaru, DMAR_TYPE); + dmaru, DMAR_TYPE, drhd->segment); if ( dmaru->include_all ) { @@ -528,11 +536,12 @@ acpi_parse_one_rmrr(struct acpi_dmar_ent rmrru->base_address = base_addr; rmrru->end_address = end_addr; + rmrru->segment = rmrr->segment; dev_scope_start = (void *)(rmrr + 1); dev_scope_end = ((void *)rmrr) + header->length; ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end, - rmrru, RMRR_TYPE); + rmrru, RMRR_TYPE, rmrr->segment); if ( ret || (rmrru->scope.devices_cnt == 0) ) xfree(rmrru); @@ -609,6 +618,7 @@ acpi_parse_one_atsr(struct acpi_dmar_ent return -ENOMEM; memset(atsru, 0, sizeof(struct acpi_atsr_unit)); + atsru->segment = atsr->segment; atsru->all_ports = atsr->flags & 1; /* BIT0: ALL_PORTS */ if ( iommu_verbose ) dprintk(VTDPREFIX, @@ -618,7 +628,7 @@ acpi_parse_one_atsr(struct acpi_dmar_ent dev_scope_start = (void *)(atsr + 1); dev_scope_end = ((void *)atsr) + header->length; ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end, - atsru, ATSR_TYPE); + atsru, ATSR_TYPE, atsr->segment); } else { --- 2011-08-25.orig/xen/drivers/passthrough/vtd/dmar.h 2011-06-20 08:41:50.000000000 +0200 +++ 2011-08-25/xen/drivers/passthrough/vtd/dmar.h 2011-08-25 15:06:43.000000000 +0200 @@ -49,6 +49,7 @@ struct acpi_drhd_unit { struct dmar_scope scope; /* must be first member of struct */ struct list_head list; u64 address; /* register base address of the unit */ + u16 segment; u8 include_all:1; struct iommu *iommu; struct list_head ioapic_list; @@ -59,12 +60,14 @@ struct acpi_rmrr_unit { struct list_head list; u64 base_address; u64 end_address; + u16 segment; u8 allow_all:1; }; struct acpi_atsr_unit { struct dmar_scope scope; /* must be first member of struct */ struct list_head list; + u16 segment; u8 all_ports:1; }; @@ -84,7 +87,7 @@ struct acpi_rhsa_unit { idx < rmrr->scope.devices_cnt; idx++) struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *pdev); -struct acpi_atsr_unit * acpi_find_matched_atsr_unit(u8 bus, u8 devfn); +struct acpi_atsr_unit * acpi_find_matched_atsr_unit(u16 seg, u8 bus, u8 devfn); #define DMAR_TYPE 1 #define RMRR_TYPE 2 @@ -114,7 +117,7 @@ void *map_to_nocache_virt(int nr_iommus, int vtd_hw_check(void); void disable_pmr(struct iommu *iommu); -int is_usb_device(u8 bus, u8 devfn); +int is_usb_device(u16 seg, u8 bus, u8 devfn); int is_igd_drhd(struct acpi_drhd_unit *drhd); #endif /* _DMAR_H_ */ --- 2011-08-25.orig/xen/drivers/passthrough/vtd/iommu.c 2011-08-25 15:06:40.000000000 +0200 +++ 2011-08-25/xen/drivers/passthrough/vtd/iommu.c 2011-08-25 15:06:43.000000000 +0200 @@ -814,16 +814,17 @@ static int iommu_page_fault_do_one(struc { const char *reason; int fault_type; + u16 seg = iommu->intel->drhd->segment; reason = iommu_get_fault_reason(fault_reason, &fault_type); if ( fault_type == DMA_REMAP ) { INTEL_IOMMU_DEBUG( - "DMAR:[%s] Request device [%02x:%02x.%d] " + "DMAR:[%s] Request device [%04x:%02x:%02x.%u] " "fault addr %"PRIx64", iommu reg = %p\n" "DMAR:[fault reason %02xh] %s\n", (type ? "DMA Read" : "DMA Write"), - (source_id >> 8), PCI_SLOT(source_id & 0xFF), + seg, (source_id >> 8), PCI_SLOT(source_id & 0xFF), PCI_FUNC(source_id & 0xFF), addr, iommu->reg, fault_reason, reason); #ifndef __i386__ /* map_domain_page() cannot be used in this context */ @@ -834,10 +835,10 @@ static int iommu_page_fault_do_one(struc } else INTEL_IOMMU_DEBUG( - "INTR-REMAP: Request device [%02x:%02x.%d] " + "INTR-REMAP: Request device [%04x:%02x:%02x.%u] " "fault index %"PRIx64", iommu reg = %p\n" "INTR-REMAP:[fault reason %02xh] %s\n", - (source_id >> 8), PCI_SLOT(source_id & 0xFF), + seg, (source_id >> 8), PCI_SLOT(source_id & 0xFF), PCI_FUNC(source_id & 0xFF), addr >> 48, iommu->reg, fault_reason, reason); return 0; @@ -1238,6 +1239,7 @@ int domain_context_mapping_one( struct context_entry *context, *context_entries; u64 maddr, pgd_maddr; struct pci_dev *pdev = NULL; + u16 seg = iommu->intel->drhd->segment; int agaw; ASSERT(spin_is_locked(&pcidevs_lock)); @@ -1250,7 +1252,7 @@ int domain_context_mapping_one( { int res = 0; - pdev = pci_get_pdev(0, bus, devfn); + pdev = pci_get_pdev(seg, bus, devfn); if (!pdev) res = -ENODEV; else if (pdev->domain != domain) @@ -1332,18 +1334,20 @@ int domain_context_mapping_one( unmap_vtd_domain_page(context_entries); - me_wifi_quirk(domain, bus, devfn, MAP_ME_PHANTOM_FUNC); + if ( !seg ) + me_wifi_quirk(domain, bus, devfn, MAP_ME_PHANTOM_FUNC); return 0; } -static int domain_context_mapping(struct domain *domain, u8 bus, u8 devfn) +static int domain_context_mapping( + struct domain *domain, u16 seg, u8 bus, u8 devfn) { struct acpi_drhd_unit *drhd; int ret = 0; u32 type; u8 secbus; - struct pci_dev *pdev = pci_get_pdev(0, bus, devfn); + struct pci_dev *pdev = pci_get_pdev(seg, bus, devfn); drhd = acpi_find_matched_drhd_unit(pdev); if ( !drhd ) @@ -1361,18 +1365,20 @@ static int domain_context_mapping(struct case DEV_TYPE_PCIe_ENDPOINT: if ( iommu_verbose ) - dprintk(VTDPREFIX, "d%d:PCIe: map bdf = %x:%x.%x\n", - domain->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + dprintk(VTDPREFIX, "d%d:PCIe: map %04x:%02x:%02x.%u\n", + domain->domain_id, seg, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn)); ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn); - if ( !ret && ats_device(0, bus, devfn) ) - enable_ats_device(0, bus, devfn); + if ( !ret && ats_device(seg, bus, devfn) ) + enable_ats_device(seg, bus, devfn); break; case DEV_TYPE_PCI: if ( iommu_verbose ) - dprintk(VTDPREFIX, "d%d:PCI: map bdf = %x:%x.%x\n", - domain->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + dprintk(VTDPREFIX, "d%d:PCI: map %04x:%02x:%02x.%u\n", + domain->domain_id, seg, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn)); ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn); if ( ret ) @@ -1395,9 +1401,9 @@ static int domain_context_mapping(struct break; default: - dprintk(XENLOG_ERR VTDPREFIX, "d%d:unknown(%u): bdf = %x:%x.%x\n", + dprintk(XENLOG_ERR VTDPREFIX, "d%d:unknown(%u): %04x:%02x:%02x.%u\n", domain->domain_id, type, - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); ret = -EINVAL; break; } @@ -1456,19 +1462,21 @@ int domain_context_unmap_one( spin_unlock(&iommu->lock); unmap_vtd_domain_page(context_entries); - me_wifi_quirk(domain, bus, devfn, UNMAP_ME_PHANTOM_FUNC); + if ( !iommu->intel->drhd->segment ) + me_wifi_quirk(domain, bus, devfn, UNMAP_ME_PHANTOM_FUNC); return 0; } -static int domain_context_unmap(struct domain *domain, u8 bus, u8 devfn) +static int domain_context_unmap( + struct domain *domain, u16 seg, u8 bus, u8 devfn) { struct acpi_drhd_unit *drhd; struct iommu *iommu; int ret = 0; u32 type; u8 tmp_bus, tmp_devfn, secbus; - struct pci_dev *pdev = pci_get_pdev(0, bus, devfn); + struct pci_dev *pdev = pci_get_pdev(seg, bus, devfn); int found = 0; BUG_ON(!pdev); @@ -1488,18 +1496,19 @@ static int domain_context_unmap(struct d case DEV_TYPE_PCIe_ENDPOINT: if ( iommu_verbose ) - dprintk(VTDPREFIX, "d%d:PCIe: unmap bdf = %x:%x.%x\n", - domain->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + dprintk(VTDPREFIX, "d%d:PCIe: unmap %04x:%02x:%02x.%u\n", + domain->domain_id, seg, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn)); ret = domain_context_unmap_one(domain, iommu, bus, devfn); - if ( !ret && ats_device(0, bus, devfn) ) - disable_ats_device(0, bus, devfn); + if ( !ret && ats_device(seg, bus, devfn) ) + disable_ats_device(seg, bus, devfn); break; case DEV_TYPE_PCI: if ( iommu_verbose ) - dprintk(VTDPREFIX, "d%d:PCI: unmap bdf = %x:%x.%x\n", - domain->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + dprintk(VTDPREFIX, "d%d:PCI: unmap %04x:%02x:%02x.%u\n", + domain->domain_id, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); ret = domain_context_unmap_one(domain, iommu, bus, devfn); if ( ret ) break; @@ -1524,9 +1533,9 @@ static int domain_context_unmap(struct d break; default: - dprintk(XENLOG_ERR VTDPREFIX, "d%d:unknown(%u): bdf = %x:%x.%x\n", + dprintk(XENLOG_ERR VTDPREFIX, "d%d:unknown(%u): %04x:%02x:%02x.%u\n", domain->domain_id, type, - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); ret = -EINVAL; goto out; } @@ -1537,7 +1546,7 @@ static int domain_context_unmap(struct d */ for_each_pdev ( domain, pdev ) { - if ( pdev->bus == bus && pdev->devfn == devfn ) + if ( pdev->seg == seg && pdev->bus == bus && pdev->devfn == devfn ) continue; drhd = acpi_find_matched_drhd_unit(pdev); @@ -1592,11 +1601,11 @@ static int reassign_device_ownership( if ( (target != dom0) && !iommu_intremap ) untrusted_msi = 1; - ret = domain_context_unmap(source, bus, devfn); + ret = domain_context_unmap(source, seg, bus, devfn); if ( ret ) return ret; - ret = domain_context_mapping(target, bus, devfn); + ret = domain_context_mapping(target, seg, bus, devfn); if ( ret ) return ret; @@ -1831,7 +1840,8 @@ static int intel_iommu_add_device(struct if ( !pdev->domain ) return -EINVAL; - ret = domain_context_mapping(pdev->domain, pdev->bus, pdev->devfn); + ret = domain_context_mapping(pdev->domain, pdev->seg, pdev->bus, + pdev->devfn); if ( ret ) { dprintk(XENLOG_ERR VTDPREFIX, "d%d: context mapping failed\n", @@ -1841,7 +1851,9 @@ static int intel_iommu_add_device(struct for_each_rmrr_device ( rmrr, bdf, i ) { - if ( PCI_BUS(bdf) == pdev->bus && PCI_DEVFN2(bdf) == pdev->devfn ) + if ( rmrr->segment == pdev->seg && + PCI_BUS(bdf) == pdev->bus && + PCI_DEVFN2(bdf) == pdev->devfn ) { ret = rmrr_identity_mapping(pdev->domain, rmrr); if ( ret ) @@ -1869,13 +1881,15 @@ static int intel_iommu_remove_device(str { for_each_rmrr_device ( rmrr, bdf, i ) { - if ( PCI_BUS(bdf) == pdev->bus && + if ( rmrr->segment == pdev->seg && + PCI_BUS(bdf) == pdev->bus && PCI_DEVFN2(bdf) == pdev->devfn ) return 0; } } - return domain_context_unmap(pdev->domain, pdev->bus, pdev->devfn); + return domain_context_unmap(pdev->domain, pdev->seg, pdev->bus, + pdev->devfn); } static void __init setup_dom0_devices(struct domain *d) @@ -1894,7 +1908,7 @@ static void __init setup_dom0_devices(st pdev->domain = d; list_add(&pdev->domain_list, &d->arch.pdev_list); - domain_context_mapping(d, pdev->bus, pdev->devfn); + domain_context_mapping(d, pdev->seg, pdev->bus, pdev->devfn); pci_enable_acs(pdev); pci_vtd_quirk(pdev); } @@ -2163,7 +2177,7 @@ static int intel_iommu_assign_device( /* FIXME: Because USB RMRR conflicts with guest bios region, * ignore USB RMRR temporarily. */ - if ( is_usb_device(bus, devfn) ) + if ( is_usb_device(seg, bus, devfn) ) { ret = 0; goto done; @@ -2172,7 +2186,9 @@ static int intel_iommu_assign_device( /* Setup rmrr identity mapping */ for_each_rmrr_device( rmrr, bdf, i ) { - if ( PCI_BUS(bdf) == bus && PCI_DEVFN2(bdf) == devfn ) + if ( rmrr->segment == seg && + PCI_BUS(bdf) == bus && + PCI_DEVFN2(bdf) == devfn ) { ret = rmrr_identity_mapping(d, rmrr); if ( ret ) --- 2011-08-25.orig/xen/drivers/passthrough/vtd/utils.c 2011-08-19 17:08:35.000000000 +0200 +++ 2011-08-25/xen/drivers/passthrough/vtd/utils.c 2011-08-25 15:06:43.000000000 +0200 @@ -32,7 +32,7 @@ #include <asm/io_apic.h> #endif -int is_usb_device(u8 bus, u8 devfn) +int is_usb_device(u16 seg, u8 bus, u8 devfn) { u16 class = pci_conf_read16(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), PCI_CLASS_DEVICE); @@ -106,8 +106,9 @@ void print_vtd_entries(struct iommu *iom u64 *l, val; u32 l_index, level; - printk("print_vtd_entries: iommu = %p bdf = %x:%x.%x gmfn = %"PRIx64"\n", - iommu, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn); + printk("print_vtd_entries: iommu %p dev %04x:%02x:%02x.%u gmfn %"PRIx64"\n", + iommu, iommu->intel->drhd->segment, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn); if ( iommu->root_maddr == 0 ) { --- 2011-08-25.orig/xen/drivers/passthrough/vtd/x86/ats.c 2011-08-25 15:06:35.000000000 +0200 +++ 2011-08-25/xen/drivers/passthrough/vtd/x86/ats.c 2011-08-25 15:06:43.000000000 +0200 @@ -104,7 +104,7 @@ int ats_device(int seg, int bus, int dev !ecap_dev_iotlb(drhd->iommu->ecap) ) return 0; - if ( !acpi_find_matched_atsr_unit(bus, devfn) ) + if ( !acpi_find_matched_atsr_unit(seg, bus, devfn) ) return 0; ats_drhd = find_ats_dev_drhd(drhd->iommu); _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel