# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1229694124 0
# Node ID d238101c1832ba178bfc00a20b461fcebe21d5df
# Parent 8c35da364ab39605839869d8eb0ac9b831c370f0
VT-d: Fix PCI-X device assignment
When assign PCI device, current code just map its bridge and its
secondary bus number and devfn 0. It doesn't work for PCI-x device
assignment, because the request may be the source-id in the original
PCI-X transaction or the source-id provided by the bridge. It needs to
map the device itself, and its upstream bridges till PCIe-to-PCI/PCI-x
bridge.
In addition, add description for DEV_TYPE_PCIe_BRIDGE and
DEV_TYPE_PCI_BRIDGE for understandability.
Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>
---
xen/drivers/passthrough/vtd/iommu.c | 77 ++++++++++++++++++++----------------
1 files changed, 44 insertions(+), 33 deletions(-)
diff -r 8c35da364ab3 -r d238101c1832 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c Thu Dec 18 17:18:28 2008 +0000
+++ b/xen/drivers/passthrough/vtd/iommu.c Fri Dec 19 13:42:04 2008 +0000
@@ -1129,8 +1129,8 @@ static int domain_context_mapping_one(
enum {
DEV_TYPE_PCIe_ENDPOINT,
- DEV_TYPE_PCIe_BRIDGE,
- DEV_TYPE_PCI_BRIDGE,
+ DEV_TYPE_PCIe_BRIDGE, // PCIe root port, switch
+ DEV_TYPE_PCI_BRIDGE, // PCIe-to-PCI/PCIx bridge, PCI-to-PCI bridge
DEV_TYPE_PCI,
};
@@ -1144,7 +1144,8 @@ int pdev_type(u8 bus, u8 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);
+ 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);
@@ -1206,7 +1207,7 @@ static int domain_context_mapping(struct
{
struct acpi_drhd_unit *drhd;
int ret = 0;
- u16 sec_bus, sub_bus, ob, odf;
+ u16 sec_bus, sub_bus;
u32 type;
u8 secbus;
@@ -1220,15 +1221,13 @@ 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);
- /*dmar_scope_add_buses(&drhd->scope, sec_bus, sub_bus);*/
-
- if ( type == DEV_TYPE_PCIe_BRIDGE )
- break;
spin_lock(&bus2bridge_lock);
for ( sub_bus &= 0xff; sec_bus <= sub_bus; sec_bus++ )
@@ -1249,25 +1248,25 @@ static int domain_context_mapping(struct
case DEV_TYPE_PCI:
gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_mapping:PCI: bdf = %x:%x.%x\n",
+ "domain_context_mapping:PCI: bdf = %x:%x.%x\n",
bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
- ob = bus; odf = devfn;
- if ( !find_pcie_endpoint(&bus, &devfn, &secbus) )
+ ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn);
+ if ( ret )
+ break;
+
+ secbus = bus;
+ /* dependent devices mapping */
+ while ( bus2bridge[bus].map )
{
- gdprintk(XENLOG_WARNING VTDPREFIX,
- "domain_context_mapping:invalid\n");
- break;
+ secbus = bus;
+ devfn = bus2bridge[bus].devfn;
+ bus = bus2bridge[bus].bus;
+ ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn);
+ if ( ret )
+ return ret;
}
- if ( ob != bus || odf != devfn )
- gdprintk(XENLOG_INFO VTDPREFIX,
- "domain_context_mapping:map: "
- "bdf = %x:%x.%x -> %x:%x.%x\n",
- ob, PCI_SLOT(odf), PCI_FUNC(odf),
- bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
- ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn);
if ( secbus != bus )
/*
* The source-id for transactions on non-PCIe buses seem
@@ -1276,7 +1275,7 @@ static int domain_context_mapping(struct
* these scanarios is not particularly well documented
* anywhere.
*/
- domain_context_mapping_one(domain, drhd->iommu, secbus, 0);
+ ret = domain_context_mapping_one(domain, drhd->iommu, secbus, 0);
break;
default:
@@ -1332,7 +1331,6 @@ static int domain_context_unmap(struct d
static int domain_context_unmap(struct domain *domain, u8 bus, u8 devfn)
{
struct acpi_drhd_unit *drhd;
- u16 sec_bus, sub_bus;
int ret = 0;
u32 type;
u8 secbus;
@@ -1346,24 +1344,37 @@ static int domain_context_unmap(struct d
{
case DEV_TYPE_PCIe_BRIDGE:
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);
- /*dmar_scope_remove_buses(&drhd->scope, sec_bus, sub_bus);*/
- if ( DEV_TYPE_PCI_BRIDGE )
- ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn);
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:
- if ( find_pcie_endpoint(&bus, &devfn, &secbus) )
+ 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;
+
+ secbus = bus;
+ /* dependent devices unmapping */
+ while ( bus2bridge[bus].map )
+ {
+ secbus = bus;
+ devfn = bus2bridge[bus].devfn;
+ bus = bus2bridge[bus].bus;
ret = domain_context_unmap_one(domain, drhd->iommu, bus, devfn);
+ if ( ret )
+ return ret;
+ }
+
if ( bus != secbus )
- domain_context_unmap_one(domain, drhd->iommu, secbus, 0);
+ ret = domain_context_unmap_one(domain, drhd->iommu, secbus, 0);
break;
default:
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|