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-devel

[Xen-devel] [PATCH 2/7] PCI device register/unregister + pci_dev cleanup

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 2/7] PCI device register/unregister + pci_dev cleanups
From: Espen Skoglund <espen.skoglund@xxxxxxxxxxxxx>
Date: Fri, 4 Jul 2008 17:35:51 +0100
Delivery-date: Fri, 04 Jul 2008 09:36:48 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <18542.20587.995970.962113@xxxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <18542.20587.995970.962113@xxxxxxxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
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>


--
 drivers/passthrough/vtd/dmar.c     |  338 +++++++++++++------------------------
 drivers/passthrough/vtd/dmar.h     |   40 ++--
 drivers/passthrough/vtd/intremap.c |    4 
 drivers/passthrough/vtd/iommu.c    |  319 ++++++++++++++++------------------
 drivers/passthrough/vtd/utils.c    |    8 
 include/xen/pci.h                  |   19 +-
 6 files changed, 312 insertions(+), 416 deletions(-)
--
diff -r b03d6bcc0178 xen/drivers/passthrough/vtd/dmar.c
--- a/xen/drivers/passthrough/vtd/dmar.c        Fri Jul 04 16:12:44 2008 +0100
+++ b/xen/drivers/passthrough/vtd/dmar.c        Fri Jul 04 16:27:43 2008 +0100
@@ -44,6 +44,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 @@
     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 @@
     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;
+    struct acpi_drhd_unit *found = NULL, *include_all = NULL;
+    int i;
 
-    include_all_drhd = NULL;
     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;
+            include_all = drhd;
     }
 
-    if ( include_all_drhd )
-        return include_all_drhd;
-
-    return NULL;
+    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 @@
         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 @@
     return count;
 }
 
-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)
 {
-    struct acpi_dev_scope *scope;
+    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 depth, cnt, didx = 0;
 
-    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;
+    if ( (cnt = scope_device_count(start, end)) < 0 )
+        return cnt;
 
-    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");
+    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);
     }
 
-    *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;
     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++;
         }
+        
+        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 bridge: bdf = %x:%x.%x  sec = %x  sub = %x\n",
+                    bus, path->dev, path->fn, sec_bus, sub_bus);
 
-        if ( scope->dev_type == ACPI_DEV_ENDPOINT )
+            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);
+            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);
+            scope->devices[didx++] = PCI_BDF(bus, path->dev, path->fn);
+            break;
+
+        case ACPI_DEV_IOAPIC:
         {
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found endpoint: bdf = %x:%x:%x\n",
+            dprintk(XENLOG_INFO VTDPREFIX, "found IOAPIC: bdf = %x:%x.%x\n",
                     bus, path->dev, path->fn);
-            pdev->bus = bus;
-            pdev->devfn = PCI_DEVFN(path->dev, path->fn);
-            pdev++;
+
+            if ( type == DMAR_TYPE )
+            {
+                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);
+            }
+
+            scope->devices[didx++] = PCI_BDF(bus, path->dev, path->fn);
+            break;
         }
-        else if ( scope->dev_type == ACPI_DEV_P2PBRIDGE )
-        {
-            dprintk(XENLOG_INFO VTDPREFIX,
-                    "found bridge: bus = %x dev = %x func = %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;
-
-                        pdev->bus = sec_bus;
-                        pdev->devfn = PCI_DEVFN(dev, func);
-                        pdev++;
-                    }
-                }
-                sec_bus++;
-            }
-        }
-        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;
-    }
+        start += acpi_scope->length;
+   }
 
     return 0;
 }
@@ -370,10 +277,17 @@
 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 @@
             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 @@
     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 b03d6bcc0178 xen/drivers/passthrough/vtd/dmar.h
--- a/xen/drivers/passthrough/vtd/dmar.h        Fri Jul 04 16:12:44 2008 +0100
+++ b/xen/drivers/passthrough/vtd/dmar.h        Fri Jul 04 16:27:43 2008 +0100
@@ -40,48 +40,48 @@
     }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 @@
 
 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 b03d6bcc0178 xen/drivers/passthrough/vtd/intremap.c
--- a/xen/drivers/passthrough/vtd/intremap.c    Fri Jul 04 16:12:44 2008 +0100
+++ b/xen/drivers/passthrough/vtd/intremap.c    Fri Jul 04 16:27:43 2008 +0100
@@ -394,7 +394,7 @@
     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);
@@ -412,7 +412,7 @@
     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 b03d6bcc0178 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c       Fri Jul 04 16:12:44 2008 +0100
+++ b/xen/drivers/passthrough/vtd/iommu.c       Fri Jul 04 16:27:43 2008 +0100
@@ -1089,8 +1089,8 @@
     if ( ecap_pass_thru(iommu->ecap) && (domain->domain_id == 0) )
         context_set_translation_type(*context, CONTEXT_TT_PASS_THRU);
     else
+#endif
     {
-#endif
         /* Ensure we have pagetables allocated down to leaf PTE. */
         if ( hd->pgd_maddr == 0 )
         {
@@ -1119,9 +1119,7 @@
 
         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 @@
 #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
+enum {
+    DEV_TYPE_PCIe_ENDPOINT,
+    DEV_TYPE_PCIe_BRIDGE,
+    DEV_TYPE_PCI_BRIDGE,
+    DEV_TYPE_PCI,
+};
 
-int pdev_type(struct pci_dev *dev)
+int pdev_type(u8 bus, u8 devfn)
 {
     u16 class_device;
-    u16 status;
+    u16 status, creg;
+    int pos;
+    u8 d = PCI_SLOT(devfn), f = PCI_FUNC(devfn);
 
-    class_device = pci_conf_read16(dev->bus, PCI_SLOT(dev->devfn),
-                                   PCI_FUNC(dev->devfn), PCI_CLASS_DEVICE);
+    class_device = pci_conf_read16(bus, d, f, PCI_CLASS_DEVICE);
     if ( class_device == PCI_CLASS_BRIDGE_PCI )
-        return DEV_TYPE_PCI_BRIDGE;
+    {
+        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(dev->bus, PCI_SLOT(dev->devfn),
-                             PCI_FUNC(dev->devfn), PCI_STATUS);
-
+    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 struct { u8 map, bus, devfn; } bus2bridge[MAX_BUSES];
 
-static int domain_context_mapping(
-    struct domain *domain,
-    struct iommu *iommu,
-    struct pci_dev *pdev)
+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);
+        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);
 
-        if ( bus2bridge[sec_bus].bus == 0 )
+        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;
+        }
+        break;
+
+    case DEV_TYPE_PCIe_ENDPOINT:
+        gdprintk(XENLOG_INFO VTDPREFIX,
+                 "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",
+                 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+        ob = bus; odf = devfn;
+        if ( !find_pcie_endpoint(&bus, &devfn) )
+        {
+            gdprintk(XENLOG_WARNING VTDPREFIX, 
"domain_context_mapping:invalid");
+            break;
         }
 
-        sub_bus = pci_conf_read8(
-            pdev->bus, PCI_SLOT(pdev->devfn),
-            PCI_FUNC(pdev->devfn), PCI_SUBORDINATE_BUS);
+        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;
 
-        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));
-        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
-        {
-            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;
-                }
-            }
-        }
-        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 @@
     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 @@
     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);
+        if ( find_pcie_endpoint(&bus, &devfn) )
+            ret = domain_context_unmap_one(drhd->iommu, bus, devfn);
+        break;
 
-            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;
-                }
-            }
-        }
-        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 @@
     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 @@
 
     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 )
+    for_each_pdev ( source, pdev )
     {
-        drhd = acpi_find_matched_drhd_unit(pdev2);
+        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 @@
     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 @@
     return 0;
 }
 
-static int iommu_prepare_rmrr_dev(
-    struct domain *d,
-    struct acpi_rmrr_unit *rmrr,
-    struct pci_dev *pdev)
+static int iommu_prepare_rmrr_dev(struct domain *d,
+                                  struct acpi_rmrr_unit *rmrr,
+                                  u8 bus, u8 devfn)
 {
-    struct acpi_drhd_unit *drhd;
     u64 size;
     int ret;
 
@@ -1587,10 +1567,9 @@
     if ( ret )
         return ret;
 
-    if ( domain_context_mapped(pdev) == 0 )
+    if ( domain_context_mapped(bus, devfn) == 0 )
     {
-        drhd = acpi_find_matched_drhd_unit(pdev);
-        ret = domain_context_mapping(d, drhd->iommu, pdev);
+        ret = domain_context_mapping(d, bus, devfn);
         if ( !ret )
             return 0;
     }
@@ -1601,7 +1580,6 @@
 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 @@
                 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 domain *d)
 {
     struct acpi_rmrr_unit *rmrr;
-    struct pci_dev *pdev;
-    int ret;
+    u16 bdf;
+    int ret, i;
 
-    for_each_rmrr_device ( rmrr, pdev )
-        ret = iommu_prepare_rmrr_dev(d, rmrr, pdev);
+    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 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 @@
                 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 @@
     .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 b03d6bcc0178 xen/drivers/passthrough/vtd/utils.c
--- a/xen/drivers/passthrough/vtd/utils.c       Fri Jul 04 16:12:44 2008 +0100
+++ b/xen/drivers/passthrough/vtd/utils.c       Fri Jul 04 16:27:43 2008 +0100
@@ -32,12 +32,10 @@
 #define SEABURG 0x4000
 #define C_STEP  2
 
-int is_usb_device(struct pci_dev *pdev)
+int is_usb_device(u8 bus, u8 devfn)
 {
-    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);
+    u16 class = pci_conf_read16(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                                PCI_CLASS_DEVICE);
     return (class == 0xc03);
 }
 
diff -r b03d6bcc0178 xen/include/xen/pci.h
--- a/xen/include/xen/pci.h     Fri Jul 04 16:12:44 2008 +0100
+++ b/xen/include/xen/pci.h     Fri Jul 04 16:27:43 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 @@
     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, 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-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel