WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] Restructure VT-d device scope and PCI bri

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Restructure VT-d device scope and PCI bridge handling
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 04 Jul 2008 16:20:12 -0700
Delivery-date: Fri, 04 Jul 2008 16:20:13 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1215190302 -3600
# Node ID bd7f2a120f9446337d1b6a0417eae157e0abe291
# Parent  1e9df5cb885f8848f147c21758040978019aefd0
Restructure VT-d device scope and PCI bridge handling

Create a bitmap for each device scope indicating which buses are
covered by the scope.  Upon mapping PCI-PCI bridges we now detect
whether we have a bridge to a non-PCIe bus.  If so, all devices mapped
on that bus are squashed to the requester-id of the bridge.  Bridges
to PCIe busses are ignored.  The requester-id squashing also
determines the iommu device group id for the device.

Signed-off-by: Espen Skoglund <espen.skoglund@xxxxxxxxxxxxx>
---
 xen/drivers/passthrough/vtd/dmar.c     |  358 ++++++++++++---------------------
 xen/drivers/passthrough/vtd/dmar.h     |   40 +--
 xen/drivers/passthrough/vtd/intremap.c |    4 
 xen/drivers/passthrough/vtd/iommu.c    |  329 ++++++++++++++----------------
 xen/drivers/passthrough/vtd/utils.c    |   10 
 xen/include/xen/pci.h                  |   19 +
 6 files changed, 328 insertions(+), 432 deletions(-)

diff -r 1e9df5cb885f -r bd7f2a120f94 xen/drivers/passthrough/vtd/dmar.c
--- a/xen/drivers/passthrough/vtd/dmar.c        Fri Jul 04 17:51:16 2008 +0100
+++ b/xen/drivers/passthrough/vtd/dmar.c        Fri Jul 04 17:51:42 2008 +0100
@@ -45,6 +45,26 @@ LIST_HEAD(acpi_atsr_units);
 
 u8 dmar_host_address_width;
 
+void dmar_scope_add_buses(struct dmar_scope *scope, u16 sec_bus, u16 sub_bus)
+{
+    sub_bus &= 0xff;
+    if (sec_bus > sub_bus)
+        return;
+
+    while ( sec_bus <= sub_bus )
+        set_bit(sec_bus++, scope->buses);
+}
+
+void dmar_scope_remove_buses(struct dmar_scope *scope, u16 sec_bus, u16 
sub_bus)
+{
+    sub_bus &= 0xff;
+    if (sec_bus > sub_bus)
+        return;
+
+    while ( sec_bus <= sub_bus )
+        clear_bit(sec_bus++, scope->buses);
+}
+
 static int __init acpi_register_drhd_unit(struct acpi_drhd_unit *drhd)
 {
     /*
@@ -94,21 +114,6 @@ struct iommu * ioapic_to_iommu(unsigned 
     return NULL;
 }
 
-static int acpi_pci_device_match(struct pci_dev *devices, int cnt,
-                                 struct pci_dev *dev)
-{
-    int i;
-
-    for ( i = 0; i < cnt; i++ )
-    {
-        if ( (dev->bus == devices->bus) &&
-             (dev->devfn == devices->devfn) )
-            return 1;
-        devices++;
-    }
-    return 0;
-}
-
 static int __init acpi_register_atsr_unit(struct acpi_atsr_unit *atsr)
 {
     /*
@@ -122,39 +127,36 @@ static int __init acpi_register_atsr_uni
     return 0;
 }
 
-struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *dev)
+struct acpi_drhd_unit * acpi_find_matched_drhd_unit(u8 bus, u8 devfn)
 {
     struct acpi_drhd_unit *drhd;
-    struct acpi_drhd_unit *include_all_drhd;
-
-    include_all_drhd = NULL;
+    struct acpi_drhd_unit *found = NULL, *include_all = NULL;
+    int i;
+
     list_for_each_entry ( drhd, &acpi_drhd_units, list )
     {
+        for (i = 0; i < drhd->scope.devices_cnt; i++)
+            if ( drhd->scope.devices[i] == PCI_BDF2(bus, devfn) )
+                return drhd;
+
+        if ( test_bit(bus, drhd->scope.buses) )
+            found = drhd;
+
         if ( drhd->include_all )
-        {
-            include_all_drhd = drhd;
-            continue;
-        }
-
-        if ( acpi_pci_device_match(drhd->devices,
-                                   drhd->devices_cnt, dev) )
-            return drhd;
-    }
-
-    if ( include_all_drhd )
-        return include_all_drhd;
-
-    return NULL;
-}
-
+            include_all = drhd;
+    }
+
+    return found ? found : include_all;
+}
+
+/*
+ * Count number of devices in device scope.  Do not include PCI sub
+ * hierarchies.
+ */
 static int scope_device_count(void *start, void *end)
 {
     struct acpi_dev_scope *scope;
-    u16 bus, sub_bus, sec_bus;
-    struct acpi_pci_path *path;
-    int depth, count = 0;
-    u8 dev, func;
-    u32 l;
+    int count = 0;
 
     while ( start < end )
     {
@@ -162,73 +164,14 @@ static int scope_device_count(void *star
         if ( (scope->length < MIN_SCOPE_LEN) ||
              (scope->dev_type >= ACPI_DEV_ENTRY_COUNT) )
         {
-            dprintk(XENLOG_WARNING VTDPREFIX, "Invalid device scope\n");
+            dprintk(XENLOG_WARNING VTDPREFIX, "Invalid device scope.\n");
             return -EINVAL;
         }
 
-        path = (struct acpi_pci_path *)(scope + 1);
-        bus = scope->start_bus;
-        depth = (scope->length - sizeof(struct acpi_dev_scope))
-                   / sizeof(struct acpi_pci_path);
-        while ( --depth > 0 )
-        {
-            bus = pci_conf_read8(
-                bus, path->dev, path->fn, PCI_SECONDARY_BUS);
-            path++;
-        }
-
-        if ( scope->dev_type == ACPI_DEV_ENDPOINT )
-        {
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found endpoint: bdf = %x:%x:%x\n",
-                    bus, path->dev, path->fn);
+        if ( scope->dev_type == ACPI_DEV_ENDPOINT ||
+             scope->dev_type == ACPI_DEV_IOAPIC ||
+             scope->dev_type == ACPI_DEV_MSI_HPET )
             count++;
-        }
-        else if ( scope->dev_type == ACPI_DEV_P2PBRIDGE )
-        {
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found bridge: bdf = %x:%x:%x\n",
-                    bus, path->dev, path->fn);
-            sec_bus = pci_conf_read8(
-                bus, path->dev, path->fn, PCI_SECONDARY_BUS);
-            sub_bus = pci_conf_read8(
-                bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
-
-            while ( sec_bus <= sub_bus )
-            {
-                for ( dev = 0; dev < 32; dev++ )
-                {
-                    for ( func = 0; func < 8; func++ )
-                    {
-                        l = pci_conf_read32(
-                            sec_bus, dev, func, PCI_VENDOR_ID);
-
-                        /* some broken boards return 0 or
-                         * ~0 if a slot is empty
-                         */
-                        if ( l == 0xffffffff || l == 0x00000000 ||
-                             l == 0x0000ffff || l == 0xffff0000 )
-                            break;
-                        count++;
-                    }
-                }
-                sec_bus++;
-            }
-        }
-        else if ( scope->dev_type == ACPI_DEV_IOAPIC )
-        {
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found IOAPIC: bdf = %x:%x:%x\n",
-                    bus, path->dev, path->fn);
-            count++;
-        }
-        else
-        {
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found MSI HPET: bdf = %x:%x:%x\n",
-                    bus, path->dev, path->fn);
-            count++;
-        }
 
         start += scope->length;
     }
@@ -236,132 +179,96 @@ static int scope_device_count(void *star
     return count;
 }
 
-static int __init acpi_parse_dev_scope(
-    void *start, void *end, void *acpi_entry, int type)
-{
-    struct acpi_dev_scope *scope;
+
+static int __init acpi_parse_dev_scope(void *start, void *end,
+                                       void *acpi_entry, int type)
+{
+    struct dmar_scope *scope = acpi_entry;
+    struct acpi_ioapic_unit *acpi_ioapic_unit;
+    struct acpi_dev_scope *acpi_scope;
     u16 bus, sub_bus, sec_bus;
     struct acpi_pci_path *path;
-    struct acpi_ioapic_unit *acpi_ioapic_unit = NULL;
-    int depth;
-    struct pci_dev *pdev;
-    u8 dev, func;
-    u32 l;
-
-    int *cnt = NULL;
-    struct pci_dev **devices = NULL;
-    struct acpi_drhd_unit *dmaru = (struct acpi_drhd_unit *) acpi_entry;
-    struct acpi_rmrr_unit *rmrru = (struct acpi_rmrr_unit *) acpi_entry;
-    struct acpi_atsr_unit *atsru = (struct acpi_atsr_unit *) acpi_entry;
-
-    switch (type) {
-        case DMAR_TYPE:
-            cnt = &(dmaru->devices_cnt);
-            devices = &(dmaru->devices);
-            break;
-        case RMRR_TYPE:
-            cnt = &(rmrru->devices_cnt);
-            devices = &(rmrru->devices);
-            break;
-        case ATSR_TYPE:
-            cnt = &(atsru->devices_cnt);
-            devices = &(atsru->devices);
-            break;
-        default:
-            dprintk(XENLOG_ERR VTDPREFIX, "invalid vt-d acpi entry type\n");
-    }
-
-    *cnt = scope_device_count(start, end);
-    if ( *cnt == 0 )
-    {
-        dprintk(XENLOG_INFO VTDPREFIX, "acpi_parse_dev_scope: no device\n");
-        return 0;
-    }
-
-    *devices = xmalloc_array(struct pci_dev,  *cnt);
-    if ( !*devices )
-        return -ENOMEM;
-    memset(*devices, 0, sizeof(struct pci_dev) * (*cnt));
-
-    pdev = *devices;
+    int depth, cnt, didx = 0;
+
+    if ( (cnt = scope_device_count(start, end)) < 0 )
+        return cnt;
+
+    scope->devices_cnt = cnt;
+    if ( cnt > 0 )
+    {
+        scope->devices = xmalloc_array(u16, cnt);
+        if ( !scope->devices )
+            return -ENOMEM;
+        memset(scope->devices, 0, sizeof(u16) * cnt);
+    }
+
     while ( start < end )
     {
-        scope = start;
-        path = (struct acpi_pci_path *)(scope + 1);
-        depth = (scope->length - sizeof(struct acpi_dev_scope))
+        acpi_scope = start;
+        path = (struct acpi_pci_path *)(acpi_scope + 1);
+        depth = (acpi_scope->length - sizeof(struct acpi_dev_scope))
                    / sizeof(struct acpi_pci_path);
-        bus = scope->start_bus;
+        bus = acpi_scope->start_bus;
 
         while ( --depth > 0 )
         {
-            bus = pci_conf_read8(
-                bus, path->dev, path->fn, PCI_SECONDARY_BUS);
+            bus = pci_conf_read8(bus, path->dev, path->fn, PCI_SECONDARY_BUS);
             path++;
         }
-
-        if ( scope->dev_type == ACPI_DEV_ENDPOINT )
-        {
+        
+        switch ( acpi_scope->dev_type )
+        {
+        case ACPI_DEV_P2PBRIDGE:
+        {
+            sec_bus = pci_conf_read8(
+               bus, path->dev, path->fn, PCI_SECONDARY_BUS);
+            sub_bus = pci_conf_read8(
+               bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
             dprintk(XENLOG_INFO VTDPREFIX,
-                    "found endpoint: bdf = %x:%x:%x\n",
+                    "found bridge: bdf = %x:%x.%x  sec = %x  sub = %x\n",
+                    bus, path->dev, path->fn, sec_bus, sub_bus);
+
+            dmar_scope_add_buses(scope, sec_bus, sub_bus);
+            break;
+        }
+
+       case ACPI_DEV_MSI_HPET:
+            dprintk(XENLOG_INFO VTDPREFIX, "found MSI HPET: bdf = %x:%x.%x\n",
                     bus, path->dev, path->fn);
-            pdev->bus = bus;
-            pdev->devfn = PCI_DEVFN(path->dev, path->fn);
-            pdev++;
-        }
-        else if ( scope->dev_type == ACPI_DEV_P2PBRIDGE )
-        {
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found bridge: bus = %x dev = %x func = %x\n",
+            scope->devices[didx++] = PCI_BDF(bus, path->dev, path->fn);
+            break;
+
+        case ACPI_DEV_ENDPOINT:
+            dprintk(XENLOG_INFO VTDPREFIX, "found endpoint: bdf = %x:%x.%x\n",
                     bus, path->dev, path->fn);
-            sec_bus = pci_conf_read8(
-                bus, path->dev, path->fn, PCI_SECONDARY_BUS);
-            sub_bus = pci_conf_read8(
-                bus, path->dev, path->fn, PCI_SUBORDINATE_BUS);
-
-            while ( sec_bus <= sub_bus )
+            scope->devices[didx++] = PCI_BDF(bus, path->dev, path->fn);
+            break;
+
+        case ACPI_DEV_IOAPIC:
+        {
+            dprintk(XENLOG_INFO VTDPREFIX, "found IOAPIC: bdf = %x:%x.%x\n",
+                    bus, path->dev, path->fn);
+
+            if ( type == DMAR_TYPE )
             {
-                for ( dev = 0; dev < 32; dev++ )
-                {
-                    for ( func = 0; func < 8; func++ )
-                    {
-                        l = pci_conf_read32(
-                            sec_bus, dev, func, PCI_VENDOR_ID);
-
-                        /* some broken boards return 0 or
-                         * ~0 if a slot is empty
-                         */
-                        if ( l == 0xffffffff || l == 0x00000000 ||
-                             l == 0x0000ffff || l == 0xffff0000 )
-                            break;
-
-                        pdev->bus = sec_bus;
-                        pdev->devfn = PCI_DEVFN(dev, func);
-                        pdev++;
-                    }
-                }
-                sec_bus++;
+                struct acpi_drhd_unit *drhd = acpi_entry;
+                acpi_ioapic_unit = xmalloc(struct acpi_ioapic_unit);
+                if ( !acpi_ioapic_unit )
+                    return -ENOMEM;
+                acpi_ioapic_unit->apic_id = acpi_scope->enum_id;
+                acpi_ioapic_unit->ioapic.bdf.bus = bus;
+                acpi_ioapic_unit->ioapic.bdf.dev = path->dev;
+                acpi_ioapic_unit->ioapic.bdf.func = path->fn;
+                list_add(&acpi_ioapic_unit->list, &drhd->ioapic_list);
             }
-        }
-        else if ( scope->dev_type == ACPI_DEV_IOAPIC )
-        {
-            acpi_ioapic_unit = xmalloc(struct acpi_ioapic_unit);
-            if ( !acpi_ioapic_unit )
-                return -ENOMEM;
-            acpi_ioapic_unit->apic_id = scope->enum_id;
-            acpi_ioapic_unit->ioapic.bdf.bus = bus;
-            acpi_ioapic_unit->ioapic.bdf.dev = path->dev;
-            acpi_ioapic_unit->ioapic.bdf.func = path->fn;
-            list_add(&acpi_ioapic_unit->list, &dmaru->ioapic_list);
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found IOAPIC: bus = %x dev = %x func = %x\n",
-                    bus, path->dev, path->fn);
-        }
-        else
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found MSI HPET: bus = %x dev = %x func = %x\n",
-                    bus, path->dev, path->fn);
-        start += scope->length;
-    }
+
+            scope->devices[didx++] = PCI_BDF(bus, path->dev, path->fn);
+            break;
+        }
+        }
+
+        start += acpi_scope->length;
+   }
 
     return 0;
 }
@@ -370,10 +277,17 @@ acpi_parse_one_drhd(struct acpi_dmar_ent
 acpi_parse_one_drhd(struct acpi_dmar_entry_header *header)
 {
     struct acpi_table_drhd * drhd = (struct acpi_table_drhd *)header;
+    void *dev_scope_start, *dev_scope_end;
     struct acpi_drhd_unit *dmaru;
     int ret = 0;
-    static int include_all;
-    void *dev_scope_start, *dev_scope_end;
+    static int include_all = 0;
+
+    if ( include_all )
+    {
+        dprintk(XENLOG_WARNING VTDPREFIX,
+                "DMAR unit with INCLUDE_ALL is not not the last unit.\n");
+        return -EINVAL;
+    }
 
     dmaru = xmalloc(struct acpi_drhd_unit);
     if ( !dmaru )
@@ -387,20 +301,13 @@ acpi_parse_one_drhd(struct acpi_dmar_ent
             dmaru->address);
 
     dev_scope_start = (void *)(drhd + 1);
-    dev_scope_end   = ((void *)drhd) + header->length;
+    dev_scope_end = ((void *)drhd) + header->length;
     ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
                                dmaru, DMAR_TYPE);
 
     if ( dmaru->include_all )
     {
         dprintk(XENLOG_INFO VTDPREFIX, "found INCLUDE_ALL\n");
-        /* Only allow one INCLUDE_ALL */
-        if ( include_all )
-        {
-            dprintk(XENLOG_WARNING VTDPREFIX,
-                    "Only one INCLUDE_ALL device scope is allowed\n");
-            ret = -EINVAL;
-        }
         include_all = 1;
     }
 
@@ -430,7 +337,8 @@ acpi_parse_one_rmrr(struct acpi_dmar_ent
     dev_scope_end   = ((void *)rmrr) + header->length;
     ret = acpi_parse_dev_scope(dev_scope_start, dev_scope_end,
                                rmrru, RMRR_TYPE);
-    if ( ret || (rmrru->devices_cnt == 0) )
+
+    if ( ret || (rmrru->scope.devices_cnt == 0) )
         xfree(rmrru);
     else
         acpi_register_rmrr_unit(rmrru);
diff -r 1e9df5cb885f -r bd7f2a120f94 xen/drivers/passthrough/vtd/dmar.h
--- a/xen/drivers/passthrough/vtd/dmar.h        Fri Jul 04 17:51:16 2008 +0100
+++ b/xen/drivers/passthrough/vtd/dmar.h        Fri Jul 04 17:51:42 2008 +0100
@@ -40,48 +40,48 @@ struct acpi_ioapic_unit {
     }ioapic;
 };
 
+struct dmar_scope {
+    DECLARE_BITMAP(buses, 256);         /* buses owned by this unit */
+    u16    *devices;                    /* devices owned by this unit */
+    int    devices_cnt;
+};
+
 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 */
-    struct pci_dev *devices; /* target devices */
-    int    devices_cnt;
+    u64    address;                     /* register base address of the unit */
     u8     include_all:1;
     struct iommu *iommu;
     struct list_head ioapic_list;
 };
 
 struct acpi_rmrr_unit {
+    struct dmar_scope scope;            /* must be first member of struct */
     struct list_head list;
     u64    base_address;
     u64    end_address;
-    struct pci_dev *devices; /* target devices */
-    int    devices_cnt;
     u8     allow_all:1;
 };
 
 struct acpi_atsr_unit {
+    struct dmar_scope scope;            /* must be first member of struct */
     struct list_head list;
-    struct pci_dev *devices; /* target devices */
-    int    devices_cnt;
     u8     all_ports:1;
 };
 
-#define for_each_iommu(domain, iommu) \
-    list_for_each_entry(iommu, \
-        &(domain->arch.hvm_domain.hvm_iommu.iommu_list), list)
 
 #define for_each_drhd_unit(drhd) \
     list_for_each_entry(drhd, &acpi_drhd_units, list)
-#define for_each_rmrr_device(rmrr, pdev) \
-    list_for_each_entry(rmrr, &acpi_rmrr_units, list) { \
-        int _i; \
-        for (_i = 0; _i < rmrr->devices_cnt; _i++) { \
-            pdev = &(rmrr->devices[_i]);
-#define end_for_each_rmrr_device(rmrr, pdev) \
-        } \
-    }
 
-struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *dev);
+#define for_each_rmrr_device(rmrr, bdf, idx)            \
+    list_for_each_entry(rmrr, &acpi_rmrr_units, list)   \
+        /* assume there never is a bdf == 0 */          \
+        for (idx = 0; (bdf = rmrr->scope.devices[i]) && \
+                 idx < rmrr->scope.devices_cnt; idx++)
+
+struct acpi_drhd_unit * acpi_find_matched_drhd_unit(u8 bus, u8 devfn);
+void dmar_scope_add_buses(struct dmar_scope *scope, u16 sec, u16 sub);
+void dmar_scope_remove_buses(struct dmar_scope *scope, u16 sec, u16 sub);
 
 #define DMAR_TYPE 1
 #define RMRR_TYPE 2
@@ -91,6 +91,6 @@ struct acpi_drhd_unit * acpi_find_matche
 
 int vtd_hw_check(void);
 void disable_pmr(struct iommu *iommu);
-int is_usb_device(struct pci_dev *pdev);
+int is_usb_device(u8 bus, u8 devfn);
 
 #endif /* _DMAR_H_ */
diff -r 1e9df5cb885f -r bd7f2a120f94 xen/drivers/passthrough/vtd/intremap.c
--- a/xen/drivers/passthrough/vtd/intremap.c    Fri Jul 04 17:51:16 2008 +0100
+++ b/xen/drivers/passthrough/vtd/intremap.c    Fri Jul 04 17:51:42 2008 +0100
@@ -396,7 +396,7 @@ void msi_msg_read_remap_rte(
     struct iommu *iommu = NULL;
     struct ir_ctrl *ir_ctrl;
 
-    drhd = acpi_find_matched_drhd_unit(pdev);
+    drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
     iommu = drhd->iommu;
 
     ir_ctrl = iommu_ir_ctrl(iommu);
@@ -414,7 +414,7 @@ void msi_msg_write_remap_rte(
     struct iommu *iommu = NULL;
     struct ir_ctrl *ir_ctrl;
 
-    drhd = acpi_find_matched_drhd_unit(msi_desc->dev);
+    drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
     iommu = drhd->iommu;
 
     ir_ctrl = iommu_ir_ctrl(iommu);
diff -r 1e9df5cb885f -r bd7f2a120f94 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c       Fri Jul 04 17:51:16 2008 +0100
+++ b/xen/drivers/passthrough/vtd/iommu.c       Fri Jul 04 17:51:42 2008 +0100
@@ -1089,8 +1089,8 @@ static int domain_context_mapping_one(
     if ( ecap_pass_thru(iommu->ecap) && (domain->domain_id == 0) )
         context_set_translation_type(*context, CONTEXT_TT_PASS_THRU);
     else
-    {
 #endif
+    {
         /* Ensure we have pagetables allocated down to leaf PTE. */
         if ( hd->pgd_maddr == 0 )
         {
@@ -1119,9 +1119,7 @@ static int domain_context_mapping_one(
 
         context_set_address_root(*context, pgd_maddr);
         context_set_translation_type(*context, CONTEXT_TT_MULTI_LEVEL);
-#ifdef CONTEXT_PASSTHRU
-    }
-#endif
+    }
 
     /*
      * domain_id 0 is not valid on Intel's IOMMU, force domain_id to
@@ -1150,115 +1148,128 @@ static int domain_context_mapping_one(
 #define PCI_BASE_CLASS_BRIDGE    0x06
 #define PCI_CLASS_BRIDGE_PCI     0x0604
 
-#define DEV_TYPE_PCIe_ENDPOINT   1
-#define DEV_TYPE_PCI_BRIDGE      2
-#define DEV_TYPE_PCI             3
-
-int pdev_type(struct pci_dev *dev)
+enum {
+    DEV_TYPE_PCIe_ENDPOINT,
+    DEV_TYPE_PCIe_BRIDGE,
+    DEV_TYPE_PCI_BRIDGE,
+    DEV_TYPE_PCI,
+};
+
+int pdev_type(u8 bus, u8 devfn)
 {
     u16 class_device;
-    u16 status;
-
-    class_device = pci_conf_read16(dev->bus, PCI_SLOT(dev->devfn),
-                                   PCI_FUNC(dev->devfn), PCI_CLASS_DEVICE);
+    u16 status, creg;
+    int pos;
+    u8 d = PCI_SLOT(devfn), f = PCI_FUNC(devfn);
+
+    class_device = pci_conf_read16(bus, d, f, PCI_CLASS_DEVICE);
     if ( class_device == PCI_CLASS_BRIDGE_PCI )
-        return DEV_TYPE_PCI_BRIDGE;
-
-    status = pci_conf_read16(dev->bus, PCI_SLOT(dev->devfn),
-                             PCI_FUNC(dev->devfn), PCI_STATUS);
-
+    {
+        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);
+        return ((creg & PCI_EXP_FLAGS_TYPE) >> 4) == PCI_EXP_TYPE_PCI_BRIDGE ?
+            DEV_TYPE_PCI_BRIDGE : DEV_TYPE_PCIe_BRIDGE;
+    }
+
+    status = pci_conf_read16(bus, d, f, PCI_STATUS);
     if ( !(status & PCI_STATUS_CAP_LIST) )
         return DEV_TYPE_PCI;
 
-    if ( pci_find_next_cap(dev->bus, dev->devfn,
-                            PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP) )
+    if ( pci_find_next_cap(bus, devfn, PCI_CAPABILITY_LIST, PCI_CAP_ID_EXP) )
         return DEV_TYPE_PCIe_ENDPOINT;
 
     return DEV_TYPE_PCI;
 }
 
 #define MAX_BUSES 256
-struct pci_dev bus2bridge[MAX_BUSES];
-
-static int domain_context_mapping(
-    struct domain *domain,
-    struct iommu *iommu,
-    struct pci_dev *pdev)
-{
+static struct { u8 map, bus, devfn; } bus2bridge[MAX_BUSES];
+
+static int find_pcie_endpoint(u8 *bus, u8 *devfn)
+{
+    int cnt = 0;
+
+    if ( *bus == 0 )
+        /* assume integrated PCI devices in RC have valid requester-id */
+        return 1;
+
+    if ( !bus2bridge[*bus].map )
+        return 0;
+
+    while ( bus2bridge[*bus].map )
+    {
+        *devfn = bus2bridge[*bus].devfn;
+        *bus = bus2bridge[*bus].bus;
+        if ( cnt++ >= MAX_BUSES )
+            return 0;
+    }
+
+    return 1;
+}
+
+static int domain_context_mapping(struct domain *domain, u8 bus, u8 devfn)
+{
+    struct acpi_drhd_unit *drhd;
     int ret = 0;
-    int dev, func, sec_bus, sub_bus;
+    u16 sec_bus, sub_bus, ob, odf;
     u32 type;
 
-    type = pdev_type(pdev);
+    drhd = acpi_find_matched_drhd_unit(bus, devfn);
+    if ( !drhd )
+        return -ENODEV;
+
+    type = pdev_type(bus, devfn);
     switch ( type )
     {
+    case DEV_TYPE_PCIe_BRIDGE:
+        break;
+
     case DEV_TYPE_PCI_BRIDGE:
-        sec_bus = pci_conf_read8(
-            pdev->bus, PCI_SLOT(pdev->devfn),
-            PCI_FUNC(pdev->devfn), PCI_SECONDARY_BUS);
-
-        if ( bus2bridge[sec_bus].bus == 0 )
+        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);
+
+        for ( sub_bus &= 0xff; sec_bus <= sub_bus; sec_bus++ )
         {
-            bus2bridge[sec_bus].bus   =  pdev->bus;
-            bus2bridge[sec_bus].devfn =  pdev->devfn;
+            bus2bridge[sec_bus].map = 1;
+            bus2bridge[sec_bus].bus =  bus;
+            bus2bridge[sec_bus].devfn =  devfn;
         }
-
-        sub_bus = pci_conf_read8(
-            pdev->bus, PCI_SLOT(pdev->devfn),
-            PCI_FUNC(pdev->devfn), PCI_SUBORDINATE_BUS);
-
-        if ( sec_bus != sub_bus )
-            gdprintk(XENLOG_WARNING VTDPREFIX,
-                     "context_context_mapping: nested PCI bridge not "
-                     "supported: bdf = %x:%x:%x sec_bus = %x sub_bus = %x\n",
-                     pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-                     sec_bus, sub_bus);
         break;
+
     case DEV_TYPE_PCIe_ENDPOINT:
         gdprintk(XENLOG_INFO VTDPREFIX,
-                 "domain_context_mapping:PCIe : bdf = %x:%x:%x\n",
-                 pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
-        ret = domain_context_mapping_one(domain, iommu,
-                                         (u8)(pdev->bus), (u8)(pdev->devfn));
+                 "domain_context_mapping:PCIe: bdf = %x:%x.%x\n",
+                 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+        ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn);
         break;
+
     case DEV_TYPE_PCI:
         gdprintk(XENLOG_INFO VTDPREFIX,
-                 "domain_context_mapping:PCI: bdf = %x:%x:%x\n",
-                 pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
-
-        if ( pdev->bus == 0 )
-            ret = domain_context_mapping_one(
-                domain, iommu, (u8)(pdev->bus), (u8)(pdev->devfn));
-        else
+                 "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) )
         {
-            if ( bus2bridge[pdev->bus].bus != 0 )
-                gdprintk(XENLOG_WARNING VTDPREFIX,
-                         "domain_context_mapping:bus2bridge"
-                         "[%d].bus != 0\n", pdev->bus);
-
-            ret = domain_context_mapping_one(
-                domain, iommu,
-                (u8)(bus2bridge[pdev->bus].bus),
-                (u8)(bus2bridge[pdev->bus].devfn));
-
-            /* now map everything behind the PCI bridge */
-            for ( dev = 0; dev < 32; dev++ )
-            {
-                for ( func = 0; func < 8; func++ )
-                {
-                    ret = domain_context_mapping_one(
-                        domain, iommu,
-                        pdev->bus, (u8)PCI_DEVFN(dev, func));
-                    if ( ret )
-                        return ret;
-                }
-            }
+            gdprintk(XENLOG_WARNING VTDPREFIX, 
"domain_context_mapping:invalid");
+            break;
         }
+
+        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);
         break;
+
     default:
         gdprintk(XENLOG_ERR VTDPREFIX,
-                 "domain_context_mapping:unknown type : bdf = %x:%x:%x\n",
-                 pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+                 "domain_context_mapping:unknown type : bdf = %x:%x.%x\n",
+                 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
         ret = -EINVAL;
         break;
     }
@@ -1266,9 +1277,7 @@ static int domain_context_mapping(
     return ret;
 }
 
-static int domain_context_unmap_one(
-    struct iommu *iommu,
-    u8 bus, u8 devfn)
+static int domain_context_unmap_one(struct iommu *iommu, u8 bus, u8 devfn)
 {
     struct context_entry *context, *context_entries;
     unsigned long flags;
@@ -1296,61 +1305,39 @@ static int domain_context_unmap_one(
     return 0;
 }
 
-static int domain_context_unmap(
-    struct iommu *iommu,
-    struct pci_dev *pdev)
-{
+static int domain_context_unmap(u8 bus, u8 devfn)
+{
+    struct acpi_drhd_unit *drhd;
     int ret = 0;
-    int dev, func, sec_bus, sub_bus;
     u32 type;
 
-    type = pdev_type(pdev);
+    drhd = acpi_find_matched_drhd_unit(bus, devfn);
+    if ( !drhd )
+        return -ENODEV;
+
+    type = pdev_type(bus, devfn);
     switch ( type )
     {
+    case DEV_TYPE_PCIe_BRIDGE:
+        break;
+
     case DEV_TYPE_PCI_BRIDGE:
-        sec_bus = pci_conf_read8(
-            pdev->bus, PCI_SLOT(pdev->devfn),
-            PCI_FUNC(pdev->devfn), PCI_SECONDARY_BUS);
-        sub_bus = pci_conf_read8(
-            pdev->bus, PCI_SLOT(pdev->devfn),
-            PCI_FUNC(pdev->devfn), PCI_SUBORDINATE_BUS);
+        ret = domain_context_unmap_one(drhd->iommu, bus, devfn);
         break;
+
     case DEV_TYPE_PCIe_ENDPOINT:
-        ret = domain_context_unmap_one(iommu,
-                                       (u8)(pdev->bus), (u8)(pdev->devfn));
+        ret = domain_context_unmap_one(drhd->iommu, bus, devfn);
         break;
+
     case DEV_TYPE_PCI:
-        if ( pdev->bus == 0 )
-            ret = domain_context_unmap_one(
-                iommu, (u8)(pdev->bus), (u8)(pdev->devfn));
-        else
-        {
-            if ( bus2bridge[pdev->bus].bus != 0 )
-                gdprintk(XENLOG_WARNING VTDPREFIX,
-                         "domain_context_unmap:"
-                         "bus2bridge[%d].bus != 0\n", pdev->bus);
-
-            ret = domain_context_unmap_one(iommu,
-                                           (u8)(bus2bridge[pdev->bus].bus),
-                                           (u8)(bus2bridge[pdev->bus].devfn));
-
-            /* Unmap everything behind the PCI bridge */
-            for ( dev = 0; dev < 32; dev++ )
-            {
-                for ( func = 0; func < 8; func++ )
-                {
-                    ret = domain_context_unmap_one(
-                        iommu, pdev->bus, (u8)PCI_DEVFN(dev, func));
-                    if ( ret )
-                        return ret;
-                }
-            }
-        }
+        if ( find_pcie_endpoint(&bus, &devfn) )
+            ret = domain_context_unmap_one(drhd->iommu, bus, devfn);
         break;
+
     default:
         gdprintk(XENLOG_ERR VTDPREFIX,
                  "domain_context_unmap:unknown type: bdf = %x:%x:%x\n",
-                 pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+                 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
         ret = -EINVAL;
         break;
     }
@@ -1364,7 +1351,7 @@ void reassign_device_ownership(
     u8 bus, u8 devfn)
 {
     struct hvm_iommu *source_hd = domain_hvm_iommu(source);
-    struct pci_dev *pdev, *pdev2;
+    struct pci_dev *pdev;
     struct acpi_drhd_unit *drhd;
     struct iommu *iommu;
     int status;
@@ -1378,27 +1365,28 @@ void reassign_device_ownership(
 
     return;
 
- found:
-    drhd = acpi_find_matched_drhd_unit(pdev);
+found:
+    drhd = acpi_find_matched_drhd_unit(bus, devfn);
     iommu = drhd->iommu;
-    domain_context_unmap(iommu, pdev);
+    domain_context_unmap(bus, devfn);
 
     /* Move pci device from the source domain to target domain. */
     list_move(&pdev->domain_list, &target->arch.pdev_list);
 
-    for_each_pdev ( source, pdev2 )
-    {
-        drhd = acpi_find_matched_drhd_unit(pdev2);
+    for_each_pdev ( source, pdev )
+    {
+        drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
         if ( drhd->iommu == iommu )
         {
             found = 1;
             break;
         }
     }
+
     if ( !found )
         clear_bit(iommu->index, &source_hd->iommu_bitmap);
 
-    status = domain_context_mapping(target, iommu, pdev);
+    status = domain_context_mapping(target, bus, devfn);
     if ( status != 0 )
         gdprintk(XENLOG_ERR VTDPREFIX, "domain_context_mapping failed\n");
 }
@@ -1436,19 +1424,13 @@ void iommu_domain_teardown(struct domain
     iommu_domid_release(d);
 }
 
-static int domain_context_mapped(struct pci_dev *pdev)
+static int domain_context_mapped(u8 bus, u8 devfn)
 {
     struct acpi_drhd_unit *drhd;
-    struct iommu *iommu;
-    int ret;
 
     for_each_drhd_unit ( drhd )
-    {
-        iommu = drhd->iommu;
-        ret = device_context_mapped(iommu, pdev->bus, pdev->devfn);
-        if ( ret )
-            return ret;
-    }
+        if ( device_context_mapped(drhd->iommu, bus, devfn) )
+            return 1;
 
     return 0;
 }
@@ -1570,12 +1552,10 @@ int iommu_page_unmapping(struct domain *
     return 0;
 }
 
-static int iommu_prepare_rmrr_dev(
-    struct domain *d,
-    struct acpi_rmrr_unit *rmrr,
-    struct pci_dev *pdev)
-{
-    struct acpi_drhd_unit *drhd;
+static int iommu_prepare_rmrr_dev(struct domain *d,
+                                  struct acpi_rmrr_unit *rmrr,
+                                  u8 bus, u8 devfn)
+{
     u64 size;
     int ret;
 
@@ -1587,10 +1567,9 @@ static int iommu_prepare_rmrr_dev(
     if ( ret )
         return ret;
 
-    if ( domain_context_mapped(pdev) == 0 )
-    {
-        drhd = acpi_find_matched_drhd_unit(pdev);
-        ret = domain_context_mapping(d, drhd->iommu, pdev);
+    if ( domain_context_mapped(bus, devfn) == 0 )
+    {
+        ret = domain_context_mapping(d, bus, devfn);
         if ( !ret )
             return 0;
     }
@@ -1601,7 +1580,6 @@ static void setup_dom0_devices(struct do
 static void setup_dom0_devices(struct domain *d)
 {
     struct hvm_iommu *hd;
-    struct acpi_drhd_unit *drhd;
     struct pci_dev *pdev;
     int bus, dev, func, ret;
     u32 l;
@@ -1624,8 +1602,7 @@ static void setup_dom0_devices(struct do
                 pdev->devfn = PCI_DEVFN(dev, func);
                 list_add_tail(&pdev->domain_list, &d->arch.pdev_list);
 
-                drhd = acpi_find_matched_drhd_unit(pdev);
-                ret = domain_context_mapping(d, drhd->iommu, pdev);
+                ret = domain_context_mapping(d, pdev->bus, pdev->devfn);
                 if ( ret != 0 )
                     gdprintk(XENLOG_ERR VTDPREFIX,
                              "domain_context_mapping failed\n");
@@ -1701,15 +1678,16 @@ static void setup_dom0_rmrr(struct domai
 static void setup_dom0_rmrr(struct domain *d)
 {
     struct acpi_rmrr_unit *rmrr;
-    struct pci_dev *pdev;
-    int ret;
-
-    for_each_rmrr_device ( rmrr, pdev )
-        ret = iommu_prepare_rmrr_dev(d, rmrr, pdev);
+    u16 bdf;
+    int ret, i;
+
+    for_each_rmrr_device ( rmrr, bdf, i )
+    {
+        ret = iommu_prepare_rmrr_dev(d, rmrr, PCI_BUS(bdf), PCI_DEVFN2(bdf));
         if ( ret )
             gdprintk(XENLOG_ERR VTDPREFIX,
                      "IOMMU: mapping reserved region failed\n");
-    end_for_each_rmrr_device ( rmrr, pdev )
+    }
 }
 
 int intel_vtd_setup(void)
@@ -1769,25 +1747,26 @@ int intel_iommu_assign_device(struct dom
 int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
 {
     struct acpi_rmrr_unit *rmrr;
-    struct pci_dev *pdev;
-    int ret = 0;
+    int ret = 0, i;
+    u16 bdf;
 
     if ( list_empty(&acpi_drhd_units) )
         return ret;
 
     reassign_device_ownership(dom0, d, bus, devfn);
 
-    /* Setup rmrr identify mapping */
-    for_each_rmrr_device( rmrr, pdev )
-        if ( pdev->bus == bus && pdev->devfn == devfn )
+    /* Setup rmrr identity mapping */
+    for_each_rmrr_device( rmrr, bdf, i )
+    {
+        if ( PCI_BUS(bdf) == bus && PCI_DEVFN2(bdf) == devfn )
         {
             /* FIXME: Because USB RMRR conflicts with guest bios region,
              * ignore USB RMRR temporarily.
              */
-            if ( is_usb_device(pdev) )
+            if ( is_usb_device(bus, devfn) )
                 return 0;
 
-            ret = iommu_prepare_rmrr_dev(d, rmrr, pdev);
+            ret = iommu_prepare_rmrr_dev(d, rmrr, bus, devfn);
             if ( ret )
             {
                 gdprintk(XENLOG_ERR VTDPREFIX,
@@ -1795,9 +1774,17 @@ int intel_iommu_assign_device(struct dom
                 return ret;
             }
         }
-    end_for_each_rmrr_device(rmrr, pdev)
+    }
 
     return ret;
+}
+
+static int intel_iommu_group_id(u8 bus, u8 devfn)
+{
+    if ( !bus2bridge[bus].map || find_pcie_endpoint(&bus, &devfn) )
+        return PCI_BDF2(bus, devfn);
+    else
+        return -1;
 }
 
 u8 iommu_state[MAX_IOMMU_REGS * MAX_IOMMUS];
@@ -1881,7 +1868,7 @@ struct iommu_ops intel_iommu_ops = {
     .map_page = intel_iommu_map_page,
     .unmap_page = intel_iommu_unmap_page,
     .reassign_device = reassign_device_ownership,
-    .get_device_group_id = NULL,
+    .get_device_group_id = intel_iommu_group_id,
 };
 
 /*
diff -r 1e9df5cb885f -r bd7f2a120f94 xen/drivers/passthrough/vtd/utils.c
--- a/xen/drivers/passthrough/vtd/utils.c       Fri Jul 04 17:51:16 2008 +0100
+++ b/xen/drivers/passthrough/vtd/utils.c       Fri Jul 04 17:51:42 2008 +0100
@@ -32,12 +32,10 @@
 #define SEABURG 0x4000
 #define C_STEP  2
 
-int is_usb_device(struct pci_dev *pdev)
-{
-    u8 bus = pdev->bus;
-    u8 dev = PCI_SLOT(pdev->devfn);
-    u8 func = PCI_FUNC(pdev->devfn);
-    u16 class = pci_conf_read16(bus, dev, func, PCI_CLASS_DEVICE);
+int is_usb_device(u8 bus, u8 devfn)
+{
+    u16 class = pci_conf_read16(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                                PCI_CLASS_DEVICE);
     return (class == 0xc03);
 }
 
diff -r 1e9df5cb885f -r bd7f2a120f94 xen/include/xen/pci.h
--- a/xen/include/xen/pci.h     Fri Jul 04 17:51:16 2008 +0100
+++ b/xen/include/xen/pci.h     Fri Jul 04 17:51:42 2008 +0100
@@ -20,9 +20,13 @@
  *  7:3 = slot
  *  2:0 = function
  */
-#define PCI_DEVFN(slot,func)  (((slot & 0x1f) << 3) | (func & 0x07))
-#define PCI_SLOT(devfn)       (((devfn) >> 3) & 0x1f)
-#define PCI_FUNC(devfn)       ((devfn) & 0x07)
+#define PCI_BUS(bdf)    (((bdf) >> 8) & 0xff)
+#define PCI_SLOT(bdf)   (((bdf) >> 3) & 0x1f)
+#define PCI_FUNC(bdf)   ((bdf) & 0x07)
+#define PCI_DEVFN(d,f)  (((d & 0x1f) << 3) | (f & 0x07))
+#define PCI_DEVFN2(bdf) ((bdf) & 0xff)
+#define PCI_BDF(b,d,f)  (((b * 0xff) << 8) | PCI_DEVFN(d,f))
+#define PCI_BDF2(b,df)  (((b & 0xff) << 8) | (df & 0xff))
 
 struct pci_dev {
     struct list_head domain_list;
@@ -31,6 +35,10 @@ struct pci_dev {
     u8 devfn;
     struct list_head msi_list;
 };
+
+#define for_each_pdev(domain, pdev) \
+    list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
+
 
 uint8_t pci_conf_read8(
     unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg);
@@ -50,9 +58,4 @@ int pci_find_cap_offset(u8 bus, u8 dev, 
 int pci_find_cap_offset(u8 bus, u8 dev, u8 func, u8 cap);
 int pci_find_next_cap(u8 bus, unsigned int devfn, u8 pos, int cap);
 
-
-#define for_each_pdev(domain, pdev) \
-    list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
-
-
 #endif /* __XEN_PCI_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Restructure VT-d device scope and PCI bridge handling, Xen patchbot-unstable <=