[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] VT-d: fix iommu_domid for PCI/PCIx devices assignment
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1262596048 0 # Node ID d179be07680e4fa4c30b66e330b2081c17331c8a # Parent bf43d35585fb283f33df02ec9bfd4887de24cf11 VT-d: fix iommu_domid for PCI/PCIx devices assignment Currently, it clears iommu_domid and domid_map at the end of domain_context_unmap_one() if no other devices under the same iommu owned by this domain. But, when assign a PCI/PCIx device to a guest, it also assigns its upstream bridge to the guest, and they use the same iommu_domid. In the deassignment, the iommu_domid and domid_map are cleared in domain_context_unmap_one() for the assigned PCI/PCIx device, therefore it cannot get valid iommu_domid in followed domain_context_unmap_one for its upstream bridge. It causes PCI/PCIx device re-assignment failure. This patch moves the iommu_domid and domid_map clearing code to the end of domain_context_unmap, where all dependent domain_context_unmap_one()s are completed, thus fix above issue. Signed-off-by: Weidong Han <Weidong.han@xxxxxxxxx> --- xen/drivers/passthrough/vtd/iommu.c | 152 +++++++++++++++++++----------------- 1 files changed, 81 insertions(+), 71 deletions(-) diff -r bf43d35585fb -r d179be07680e xen/drivers/passthrough/vtd/iommu.c --- a/xen/drivers/passthrough/vtd/iommu.c Mon Jan 04 09:06:36 2010 +0000 +++ b/xen/drivers/passthrough/vtd/iommu.c Mon Jan 04 09:07:28 2010 +0000 @@ -1351,9 +1351,6 @@ static int domain_context_unmap_one( struct context_entry *context, *context_entries; u64 maddr; int iommu_domid; - struct pci_dev *pdev; - struct acpi_drhd_unit *drhd; - int found = 0; ASSERT(spin_is_locked(&pcidevs_lock)); spin_lock(&iommu->lock); @@ -1391,6 +1388,78 @@ static int domain_context_unmap_one( iommu_flush_iotlb_dsi(iommu, iommu_domid, 0, flush_dev_iotlb); } + spin_unlock(&iommu->lock); + unmap_vtd_domain_page(context_entries); + + return 0; +} + +static int domain_context_unmap(struct domain *domain, 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(bus, devfn); + int found = 0; + + BUG_ON(!pdev); + + drhd = acpi_find_matched_drhd_unit(pdev); + if ( !drhd ) + return -ENODEV; + iommu = drhd->iommu; + + type = pdev_type(bus, devfn); + switch ( type ) + { + case DEV_TYPE_PCIe_BRIDGE: + case DEV_TYPE_PCIe2PCI_BRIDGE: + case DEV_TYPE_LEGACY_PCI_BRIDGE: + goto out; + + case DEV_TYPE_PCIe_ENDPOINT: + gdprintk(XENLOG_INFO VTDPREFIX, + "domain_context_unmap:PCIe: bdf = %x:%x.%x\n", + bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + ret = domain_context_unmap_one(domain, iommu, bus, devfn); + break; + + case DEV_TYPE_PCI: + gdprintk(XENLOG_INFO VTDPREFIX, + "domain_context_unmap:PCI: bdf = %x:%x.%x\n", + bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + ret = domain_context_unmap_one(domain, iommu, bus, devfn); + if ( ret ) + break; + + tmp_bus = bus; + tmp_devfn = devfn; + if ( find_upstream_bridge(&tmp_bus, &tmp_devfn, &secbus) < 1 ) + break; + + /* PCIe to PCI/PCIx bridge */ + if ( pdev_type(tmp_bus, tmp_devfn) == DEV_TYPE_PCIe2PCI_BRIDGE ) + { + ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn); + if ( ret ) + return ret; + + ret = domain_context_unmap_one(domain, iommu, secbus, 0); + } + else /* Legacy PCI bridge */ + ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn); + + break; + + default: + gdprintk(XENLOG_ERR VTDPREFIX, + "domain_context_unmap:unknown type: bdf = %x:%x.%x\n", + bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + ret = -EINVAL; + goto out; + } /* * if no other devices under the same iommu owned by this domain, @@ -1412,81 +1481,22 @@ static int domain_context_unmap_one( if ( found == 0 ) { struct hvm_iommu *hd = domain_hvm_iommu(domain); + int iommu_domid; clear_bit(iommu->index, &hd->iommu_bitmap); + + iommu_domid = domain_iommu_domid(domain, iommu); + if ( iommu_domid == -1 ) + { + ret = -EINVAL; + goto out; + } clear_bit(iommu_domid, iommu->domid_bitmap); iommu->domid_map[iommu_domid] = 0; } - spin_unlock(&iommu->lock); - unmap_vtd_domain_page(context_entries); - - return 0; -} - -static int domain_context_unmap(struct domain *domain, u8 bus, u8 devfn) -{ - struct acpi_drhd_unit *drhd; - int ret = 0; - u32 type; - u8 secbus; - struct pci_dev *pdev = pci_get_pdev(bus, devfn); - - BUG_ON(!pdev); - - drhd = acpi_find_matched_drhd_unit(pdev); - if ( !drhd ) - return -ENODEV; - - type = pdev_type(bus, devfn); - switch ( type ) - { - case DEV_TYPE_PCIe_BRIDGE: - case DEV_TYPE_PCIe2PCI_BRIDGE: - case DEV_TYPE_LEGACY_PCI_BRIDGE: - break; - - case DEV_TYPE_PCIe_ENDPOINT: - gdprintk(XENLOG_INFO VTDPREFIX, - "domain_context_unmap:PCIe: bdf = %x:%x.%x\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn); - break; - - case DEV_TYPE_PCI: - gdprintk(XENLOG_INFO VTDPREFIX, - "domain_context_unmap:PCI: bdf = %x:%x.%x\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn); - if ( ret ) - 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_unmap_one(domain, drhd->iommu, bus, devfn); - if ( ret ) - return ret; - - 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: - gdprintk(XENLOG_ERR VTDPREFIX, - "domain_context_unmap:unknown type: bdf = %x:%x.%x\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - ret = -EINVAL; - break; - } - +out: return ret; } _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |