[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] AMD IOMMU: cover all functions of a device even if ACPI only tells us of func 0



commit a90bc1471a74c42b9618f0ec3bc0cc0e76f0f5ee
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Tue Feb 26 10:12:57 2013 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Feb 26 10:12:57 2013 +0100

    AMD IOMMU: cover all functions of a device even if ACPI only tells us of 
func 0
    
    This ought to work as all functions of a device have the same place in
    the bus topology, i.e. use the same IOMMU.
    
    Also fix the type of ivrs_bdf_entries (when it's 'unsigned short' and
    the last device found on a segment is ff:1f.x, it would otherwise end
    up being zero).
    
    And drop the bogus 'last_bdf' static variable, which conflicted anyway
    with various functions' parameters.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
 xen/drivers/passthrough/amd/iommu_acpi.c    |   27 ++++++++++++++--------
 xen/drivers/passthrough/amd/iommu_init.c    |    2 +-
 xen/drivers/passthrough/amd/pci_amd_iommu.c |   32 +++++++++++++++++++++++++-
 xen/include/asm-x86/amd-iommu.h             |    2 +-
 4 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/xen/drivers/passthrough/amd/iommu_acpi.c 
b/xen/drivers/passthrough/amd/iommu_acpi.c
index 679c2a4..8a6038c 100644
--- a/xen/drivers/passthrough/amd/iommu_acpi.c
+++ b/xen/drivers/passthrough/amd/iommu_acpi.c
@@ -54,8 +54,6 @@ union acpi_ivhd_device {
    struct acpi_ivrs_device8c special;
 };
 
-static unsigned short __initdata last_bdf;
-
 static void __init add_ivrs_mapping_entry(
     u16 bdf, u16 alias_id, u8 flags, struct amd_iommu *iommu)
 {
@@ -991,6 +989,7 @@ static int __init get_last_bdf_ivhd(
 {
     const union acpi_ivhd_device *ivhd_device;
     u16 block_length, dev_length;
+    int last_bdf = 0;
 
     if ( ivhd_block->header.length < sizeof(*ivhd_block) )
     {
@@ -1051,27 +1050,34 @@ static int __init get_last_bdf_ivhd(
             return -ENODEV;
     }
 
-    return 0;
+    return last_bdf;
 }
 
 static int __init get_last_bdf_acpi(struct acpi_table_header *table)
 {
     const struct acpi_ivrs_header *ivrs_block;
     unsigned long length = sizeof(struct acpi_table_ivrs);
+    int last_bdf = 0;
 
     while ( table->length > (length + sizeof(*ivrs_block)) )
     {
         ivrs_block = (struct acpi_ivrs_header *)((u8 *)table + length);
         if ( table->length < (length + ivrs_block->length) )
             return -ENODEV;
-        if ( ivrs_block->type == ACPI_IVRS_TYPE_HARDWARE &&
-             get_last_bdf_ivhd(
+        if ( ivrs_block->type == ACPI_IVRS_TYPE_HARDWARE )
+        {
+            int ret = get_last_bdf_ivhd(
                  container_of(ivrs_block, const struct acpi_ivrs_hardware,
-                              header)) != 0 )
-            return -ENODEV;
+                              header));
+
+            if ( ret < 0 )
+                return ret;
+            UPDATE_LAST_BDF(ret);
+        }
         length += ivrs_block->length;
     }
-   return 0;
+
+    return last_bdf;
 }
 
 int __init amd_iommu_detect_acpi(void)
@@ -1081,8 +1087,9 @@ int __init amd_iommu_detect_acpi(void)
 
 int __init amd_iommu_get_ivrs_dev_entries(void)
 {
-    acpi_table_parse(ACPI_SIG_IVRS, get_last_bdf_acpi);
-    return last_bdf + 1;
+    int ret = acpi_table_parse(ACPI_SIG_IVRS, get_last_bdf_acpi);
+
+    return ret < 0 ? ret : (ret | PCI_FUNC(~0)) + 1;
 }
 
 int __init amd_iommu_update_ivrs_mapping_acpi(void)
diff --git a/xen/drivers/passthrough/amd/iommu_init.c 
b/xen/drivers/passthrough/amd/iommu_init.c
index 780e206..137531a 100644
--- a/xen/drivers/passthrough/amd/iommu_init.c
+++ b/xen/drivers/passthrough/amd/iommu_init.c
@@ -35,7 +35,7 @@ static int __initdata nr_amd_iommus;
 
 static struct tasklet amd_iommu_irq_tasklet;
 
-unsigned short ivrs_bdf_entries;
+unsigned int __read_mostly ivrs_bdf_entries;
 static struct radix_tree_root ivrs_maps;
 struct list_head amd_iommu_head;
 struct table_struct device_table;
diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c 
b/xen/drivers/passthrough/amd/pci_amd_iommu.c
index 0f8cfeb..2098e41 100644
--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c
+++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c
@@ -28,12 +28,38 @@
 #include <asm/hvm/svm/amd-iommu-proto.h>
 #include "../ats.h"
 
+static bool_t __read_mostly init_done;
+
 struct amd_iommu *find_iommu_for_device(int seg, int bdf)
 {
     struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
 
-    return ivrs_mappings && bdf < ivrs_bdf_entries ? ivrs_mappings[bdf].iommu
-                                                   : NULL;
+    if ( !ivrs_mappings || bdf >= ivrs_bdf_entries )
+        return NULL;
+
+    if ( unlikely(!ivrs_mappings[bdf].iommu) && likely(init_done) )
+    {
+        unsigned int bd0 = bdf & ~PCI_FUNC(~0);
+
+        if ( ivrs_mappings[bd0].iommu )
+        {
+            struct ivrs_mappings tmp = ivrs_mappings[bd0];
+
+            tmp.iommu = NULL;
+            if ( tmp.dte_requestor_id == bd0 )
+                tmp.dte_requestor_id = bdf;
+            ivrs_mappings[bdf] = tmp;
+
+            printk(XENLOG_WARNING "%04x:%02x:%02x.%u not found in ACPI tables;"
+                   " using same IOMMU as function 0\n",
+                   seg, PCI_BUS(bdf), PCI_SLOT(bdf), PCI_FUNC(bdf));
+
+            /* write iommu field last */
+            ivrs_mappings[bdf].iommu = ivrs_mappings[bd0].iommu;
+        }
+    }
+
+    return ivrs_mappings[bdf].iommu;
 }
 
 /*
@@ -179,6 +205,8 @@ int __init amd_iov_detect(void)
         return -ENODEV;
     }
 
+    init_done = 1;
+
     /*
      * AMD IOMMUs don't distinguish between vectors destined for
      * different cpus when doing interrupt remapping.  This means
diff --git a/xen/include/asm-x86/amd-iommu.h b/xen/include/asm-x86/amd-iommu.h
index 66c1eba..54f7e56 100644
--- a/xen/include/asm-x86/amd-iommu.h
+++ b/xen/include/asm-x86/amd-iommu.h
@@ -125,7 +125,7 @@ struct ivrs_mappings {
     u8 device_flags;
 };
 
-extern unsigned short ivrs_bdf_entries;
+extern unsigned int ivrs_bdf_entries;
 
 struct ivrs_mappings *get_ivrs_mappings(u16 seg);
 int iterate_ivrs_mappings(int (*)(u16 seg, struct ivrs_mappings *));
--
generated by git-patchbot for /home/xen/git/xen.git#master

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.