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 5/7] PCI multi-seg: AMD-IOMMU specific adjustments

To: "xen-devel@xxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 5/7] PCI multi-seg: AMD-IOMMU specific adjustments
From: "Jan Beulich" <JBeulich@xxxxxxxx>
Date: Tue, 20 Sep 2011 16:19:20 +0100
Delivery-date: Tue, 20 Sep 2011 08:22:59 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
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>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
There are two places here where it is entirely unclear to me where the
necessary PCI segment number should be taken from (as IVMD descriptors
don't have such, only IVHD ones do). AMD confirmed that for the time
being it is acceptable to imply that only segment 0 exists.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

--- 2011-09-20.orig/xen/drivers/passthrough/amd/iommu_acpi.c    2011-06-28 
09:41:39.000000000 +0200
+++ 2011-09-20/xen/drivers/passthrough/amd/iommu_acpi.c 2011-09-20 
15:13:42.000000000 +0200
@@ -30,6 +30,7 @@ static unsigned short __initdata last_bd
 static void __init add_ivrs_mapping_entry(
     u16 bdf, u16 alias_id, u8 flags, struct amd_iommu *iommu)
 {
+    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(iommu->seg);
     u8 sys_mgt, lint1_pass, lint0_pass, nmi_pass, ext_int_pass, init_pass;
     ASSERT( ivrs_mappings != NULL );
 
@@ -118,9 +119,10 @@ static void __init reserve_iommu_exclusi
 }
 
 static void __init reserve_unity_map_for_device(
-    u16 bdf, unsigned long base,
+    u16 seg, u16 bdf, unsigned long base,
     unsigned long length, u8 iw, u8 ir)
 {
+    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
     unsigned long old_top, new_top;
 
     /* need to extend unity-mapped range? */
@@ -147,6 +149,7 @@ static void __init reserve_unity_map_for
 static int __init register_exclusion_range_for_all_devices(
     unsigned long base, unsigned long limit, u8 iw, u8 ir)
 {
+    int seg = 0; /* XXX */
     unsigned long range_top, iommu_top, length;
     struct amd_iommu *iommu;
     u16 bdf;
@@ -163,7 +166,7 @@ static int __init register_exclusion_ran
         /* reserve r/w unity-mapped page entries for devices */
         /* note: these entries are part of the exclusion range */
         for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ )
-            reserve_unity_map_for_device(bdf, base, length, iw, ir);
+            reserve_unity_map_for_device(seg, bdf, base, length, iw, ir);
         /* push 'base' just outside of virtual address space */
         base = iommu_top;
     }
@@ -180,11 +183,13 @@ static int __init register_exclusion_ran
 static int __init register_exclusion_range_for_device(
     u16 bdf, unsigned long base, unsigned long limit, u8 iw, u8 ir)
 {
+    int seg = 0; /* XXX */
+    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
     unsigned long range_top, iommu_top, length;
     struct amd_iommu *iommu;
     u16 req;
 
-    iommu = find_iommu_for_device(bdf);
+    iommu = find_iommu_for_device(seg, bdf);
     if ( !iommu )
     {
         AMD_IOMMU_DEBUG("IVMD Error: No IOMMU for Dev_Id 0x%x!\n", bdf);
@@ -202,8 +207,8 @@ static int __init register_exclusion_ran
         length = range_top - base;
         /* reserve unity-mapped page entries for device */
         /* note: these entries are part of the exclusion range */
-        reserve_unity_map_for_device(bdf, base, length, iw, ir);
-        reserve_unity_map_for_device(req, base, length, iw, ir);
+        reserve_unity_map_for_device(seg, bdf, base, length, iw, ir);
+        reserve_unity_map_for_device(seg, req, base, length, iw, ir);
 
         /* push 'base' just outside of virtual address space */
         base = iommu_top;
@@ -240,11 +245,13 @@ static int __init register_exclusion_ran
         /* note: these entries are part of the exclusion range */
         for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ )
         {
-            if ( iommu == find_iommu_for_device(bdf) )
+            if ( iommu == find_iommu_for_device(iommu->seg, bdf) )
             {
-                reserve_unity_map_for_device(bdf, base, length, iw, ir);
-                req = ivrs_mappings[bdf].dte_requestor_id;
-                reserve_unity_map_for_device(req, base, length, iw, ir);
+                reserve_unity_map_for_device(iommu->seg, bdf, base, length,
+                                             iw, ir);
+                req = get_ivrs_mappings(iommu->seg)[bdf].dte_requestor_id;
+                reserve_unity_map_for_device(iommu->seg, req, base, length,
+                                             iw, ir);
             }
         }
 
@@ -627,7 +634,7 @@ static u16 __init parse_ivhd_device_exte
 }
 
 static u16 __init parse_ivhd_device_special(
-    union acpi_ivhd_device *ivhd_device,
+    union acpi_ivhd_device *ivhd_device, u16 seg,
     u16 header_length, u16 block_length, struct amd_iommu *iommu)
 {
     u16 dev_length, bdf;
@@ -648,7 +655,8 @@ static u16 __init parse_ivhd_device_spec
 
     add_ivrs_mapping_entry(bdf, bdf, ivhd_device->header.flags, iommu);
     /* set device id of ioapic */
-    ioapic_bdf[ivhd_device->special.handle] = bdf;
+    ioapic_sbdf[ivhd_device->special.handle].bdf = bdf;
+    ioapic_sbdf[ivhd_device->special.handle].seg = seg;
     return dev_length;
 }
 
@@ -729,7 +737,7 @@ static int __init parse_ivhd_block(struc
             break;
         case AMD_IOMMU_ACPI_IVHD_DEV_SPECIAL:
             dev_length = parse_ivhd_device_special(
-                ivhd_device,
+                ivhd_device, ivhd_block->pci_segment,
                 ivhd_block->header.length, block_length, iommu);
             break;
         default:
--- 2011-09-20.orig/xen/drivers/passthrough/amd/iommu_detect.c  2011-04-04 
09:11:24.000000000 +0200
+++ 2011-09-20/xen/drivers/passthrough/amd/iommu_detect.c       2011-08-25 
15:06:47.000000000 +0200
@@ -27,8 +27,8 @@
 #include <asm/hvm/svm/amd-iommu-proto.h>
 #include <asm/hvm/svm/amd-iommu-acpi.h>
 
-static int __init get_iommu_msi_capabilities(u8 bus, u8 dev, u8 func,
-            struct amd_iommu *iommu)
+static int __init get_iommu_msi_capabilities(
+    u16 seg, u8 bus, u8 dev, u8 func, struct amd_iommu *iommu)
 {
     int cap_ptr, cap_id;
     u32 cap_header;
@@ -66,8 +66,8 @@ static int __init get_iommu_msi_capabili
     return 0;
 }
 
-static int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
-                                  struct amd_iommu *iommu)
+static int __init get_iommu_capabilities(
+    u16 seg, u8 bus, u8 dev, u8 func, u8 cap_ptr, struct amd_iommu *iommu)
 {
     u32 cap_header, cap_range, misc_info;
 
@@ -121,6 +121,11 @@ int __init amd_iommu_detect_one_acpi(voi
 
     spin_lock_init(&iommu->lock);
 
+    iommu->seg = ivhd_block->pci_segment;
+    if (alloc_ivrs_mappings(ivhd_block->pci_segment)) {
+        xfree(iommu);
+        return -ENOMEM;
+    }
     iommu->bdf = ivhd_block->header.dev_id;
     iommu->cap_offset = ivhd_block->cap_offset;
     iommu->mmio_base_phys = ivhd_block->mmio_base;
@@ -147,8 +152,9 @@ int __init amd_iommu_detect_one_acpi(voi
     bus = iommu->bdf >> 8;
     dev = PCI_SLOT(iommu->bdf & 0xFF);
     func = PCI_FUNC(iommu->bdf & 0xFF);
-    get_iommu_capabilities(bus, dev, func, iommu->cap_offset, iommu);
-    get_iommu_msi_capabilities(bus, dev, func, iommu);
+    get_iommu_capabilities(iommu->seg, bus, dev, func,
+                           iommu->cap_offset, iommu);
+    get_iommu_msi_capabilities(iommu->seg, bus, dev, func, iommu);
 
     list_add_tail(&iommu->list, &amd_iommu_head);
 
--- 2011-09-20.orig/xen/drivers/passthrough/amd/iommu_init.c    2011-09-12 
08:34:38.000000000 +0200
+++ 2011-09-20/xen/drivers/passthrough/amd/iommu_init.c 2011-08-25 
15:06:47.000000000 +0200
@@ -33,7 +33,7 @@ static struct amd_iommu **__read_mostly 
 static int __initdata nr_amd_iommus;
 
 unsigned short ivrs_bdf_entries;
-struct ivrs_mappings *ivrs_mappings;
+static struct radix_tree_root ivrs_maps;
 struct list_head amd_iommu_head;
 struct table_struct device_table;
 
@@ -697,7 +697,6 @@ error_out:
 static void __init amd_iommu_init_cleanup(void)
 {
     struct amd_iommu *iommu, *next;
-    int bdf;
 
     /* free amd iommu list */
     list_for_each_entry_safe ( iommu, next, &amd_iommu_head, list )
@@ -713,21 +712,13 @@ static void __init amd_iommu_init_cleanu
     }
 
     /* free interrupt remapping table */
-    for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ )
-    {
-        if ( ivrs_mappings[bdf].intremap_table )
-            amd_iommu_free_intremap_table(bdf);
-    }
+    iterate_ivrs_entries(amd_iommu_free_intremap_table);
 
     /* free device table */
     deallocate_iommu_table_struct(&device_table);
 
     /* free ivrs_mappings[] */
-    if ( ivrs_mappings )
-    {
-        xfree(ivrs_mappings);
-        ivrs_mappings = NULL;
-    }
+    radix_tree_destroy(&ivrs_maps, xfree);
 
     /* free irq_to_iommu[] */
     if ( irq_to_iommu )
@@ -741,19 +732,71 @@ static void __init amd_iommu_init_cleanu
     iommu_intremap = 0;
 }
 
-static int __init init_ivrs_mapping(void)
+/*
+ * We allocate an extra array element to store the segment number
+ * (and in the future perhaps other global information).
+ */
+#define IVRS_MAPPINGS_SEG(m) m[ivrs_bdf_entries].dte_requestor_id
+
+struct ivrs_mappings *get_ivrs_mappings(u16 seg)
+{
+    return radix_tree_lookup(&ivrs_maps, seg);
+}
+
+int iterate_ivrs_mappings(int (*handler)(u16 seg, struct ivrs_mappings *))
 {
+    u16 seg = 0;
+    int rc = 0;
+
+    do {
+        struct ivrs_mappings *map;
+
+        if ( !radix_tree_gang_lookup(&ivrs_maps, (void **)&map, seg, 1) )
+            break;
+        seg = IVRS_MAPPINGS_SEG(map);
+        rc = handler(seg, map);
+    } while ( !rc && ++seg );
+
+    return rc;
+}
+
+int iterate_ivrs_entries(int (*handler)(u16 seg, struct ivrs_mappings *))
+{
+    u16 seg = 0;
+    int rc = 0;
+
+    do {
+        struct ivrs_mappings *map;
+        int bdf;
+
+        if ( !radix_tree_gang_lookup(&ivrs_maps, (void **)&map, seg, 1) )
+            break;
+        seg = IVRS_MAPPINGS_SEG(map);
+        for ( bdf = 0; !rc && bdf < ivrs_bdf_entries; ++bdf )
+            rc = handler(seg, map + bdf);
+    } while ( !rc && ++seg );
+
+    return rc;
+}
+
+int __init alloc_ivrs_mappings(u16 seg)
+{
+    struct ivrs_mappings *ivrs_mappings;
     int bdf;
 
     BUG_ON( !ivrs_bdf_entries );
 
-    ivrs_mappings = xmalloc_array( struct ivrs_mappings, ivrs_bdf_entries);
+    if ( get_ivrs_mappings(seg) )
+        return 0;
+
+    ivrs_mappings = xmalloc_array(struct ivrs_mappings, ivrs_bdf_entries + 1);
     if ( ivrs_mappings == NULL )
     {
         AMD_IOMMU_DEBUG("Error allocating IVRS Mappings table\n");
         return -ENOMEM;
     }
     memset(ivrs_mappings, 0, ivrs_bdf_entries * sizeof(struct ivrs_mappings));
+    IVRS_MAPPINGS_SEG(ivrs_mappings) = seg;
 
     /* assign default values for device entries */
     for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ )
@@ -775,10 +818,14 @@ static int __init init_ivrs_mapping(void
         if ( amd_iommu_perdev_intremap )
             spin_lock_init(&ivrs_mappings[bdf].intremap_lock);
     }
+
+    radix_tree_insert(&ivrs_maps, seg, ivrs_mappings);
+
     return 0;
 }
 
-static int __init amd_iommu_setup_device_table(void)
+static int __init amd_iommu_setup_device_table(
+    u16 seg, struct ivrs_mappings *ivrs_mappings)
 {
     int bdf;
     void *intr_tb, *dte;
@@ -849,7 +896,8 @@ int __init amd_iommu_init(void)
     if ( !ivrs_bdf_entries )
         goto error_out;
 
-    if ( init_ivrs_mapping() != 0 )
+    radix_tree_init(&ivrs_maps);
+    if ( alloc_ivrs_mappings(0) != 0 )
         goto error_out;
 
     if ( amd_iommu_update_ivrs_mapping_acpi() != 0 )
@@ -860,7 +908,7 @@ int __init amd_iommu_init(void)
         goto error_out;
 
     /* allocate and initialize a global device table shared by all iommus */
-    if ( amd_iommu_setup_device_table() != 0 )
+    if ( iterate_ivrs_mappings(amd_iommu_setup_device_table) != 0 )
         goto error_out;
 
     /* per iommu initialization  */
@@ -905,7 +953,8 @@ static void invalidate_all_domain_pages(
         amd_iommu_flush_all_pages(d);
 }
 
-static void invalidate_all_devices(void)
+static int _invalidate_all_devices(
+    u16 seg, struct ivrs_mappings *ivrs_mappings)
 {
     int bdf, req_id;
     unsigned long flags;
@@ -913,7 +962,7 @@ static void invalidate_all_devices(void)
 
     for ( bdf = 0; bdf < ivrs_bdf_entries; bdf++ )
     {
-        iommu = find_iommu_for_device(bdf);
+        iommu = find_iommu_for_device(seg, bdf);
         req_id = ivrs_mappings[bdf].dte_requestor_id;
         if ( iommu )
         {
@@ -924,6 +973,13 @@ static void invalidate_all_devices(void)
             spin_unlock_irqrestore(&iommu->lock, flags);
         }
     }
+
+    return 0;
+}
+
+static void invalidate_all_devices(void)
+{
+    iterate_ivrs_mappings(_invalidate_all_devices);
 }
 
 void amd_iommu_suspend(void)
--- 2011-09-20.orig/xen/drivers/passthrough/amd/iommu_intr.c    2011-08-19 
17:08:35.000000000 +0200
+++ 2011-09-20/xen/drivers/passthrough/amd/iommu_intr.c 2011-09-20 
15:19:03.000000000 +0200
@@ -27,21 +27,21 @@
 #define INTREMAP_LENGTH 0xB
 #define INTREMAP_ENTRIES (1 << INTREMAP_LENGTH)
 
-int ioapic_bdf[MAX_IO_APICS];
+struct ioapic_sbdf ioapic_sbdf[MAX_IO_APICS];
 void *shared_intremap_table;
 static DEFINE_SPINLOCK(shared_intremap_lock);
 
-static spinlock_t* get_intremap_lock(int req_id)
+static spinlock_t* get_intremap_lock(int seg, int req_id)
 {
     return (amd_iommu_perdev_intremap ?
-           &ivrs_mappings[req_id].intremap_lock:
+           &get_ivrs_mappings(seg)[req_id].intremap_lock:
            &shared_intremap_lock);
 }
 
-static int get_intremap_requestor_id(int bdf)
+static int get_intremap_requestor_id(int seg, int bdf)
 {
     ASSERT( bdf < ivrs_bdf_entries );
-    return ivrs_mappings[bdf].dte_requestor_id;
+    return get_ivrs_mappings(seg)[bdf].dte_requestor_id;
 }
 
 static int get_intremap_offset(u8 vector, u8 dm)
@@ -53,20 +53,20 @@ static int get_intremap_offset(u8 vector
     return offset;
 }
 
-static u8 *get_intremap_entry(int bdf, int offset)
+static u8 *get_intremap_entry(int seg, int bdf, int offset)
 {
     u8 *table;
 
-    table = (u8*)ivrs_mappings[bdf].intremap_table;
+    table = (u8*)get_ivrs_mappings(seg)[bdf].intremap_table;
     ASSERT( (table != NULL) && (offset < INTREMAP_ENTRIES) );
 
     return (u8*) (table + offset);
 }
 
-static void free_intremap_entry(int bdf, int offset)
+static void free_intremap_entry(int seg, int bdf, int offset)
 {
     u32* entry;
-    entry = (u32*)get_intremap_entry(bdf, offset);
+    entry = (u32*)get_intremap_entry(seg, bdf, offset);
     memset(entry, 0, sizeof(u32));
 }
 
@@ -125,8 +125,8 @@ static void update_intremap_entry_from_i
     spinlock_t *lock;
     int offset;
 
-    req_id = get_intremap_requestor_id(bdf);
-    lock = get_intremap_lock(req_id);
+    req_id = get_intremap_requestor_id(iommu->seg, bdf);
+    lock = get_intremap_lock(iommu->seg, req_id);
 
     delivery_mode = rte->delivery_mode;
     vector = rte->vector;
@@ -136,7 +136,7 @@ static void update_intremap_entry_from_i
     spin_lock_irqsave(lock, flags);
 
     offset = get_intremap_offset(vector, delivery_mode);
-    entry = (u32*)get_intremap_entry(req_id, offset);
+    entry = (u32*)get_intremap_entry(iommu->seg, req_id, offset);
     update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
 
     spin_unlock_irqrestore(lock, flags);
@@ -157,7 +157,7 @@ int __init amd_iommu_setup_ioapic_remapp
     u32* entry;
     int apic, pin;
     u8 delivery_mode, dest, vector, dest_mode;
-    u16 bdf, req_id;
+    u16 seg, bdf, req_id;
     struct amd_iommu *iommu;
     spinlock_t *lock;
     int offset;
@@ -174,17 +174,18 @@ int __init amd_iommu_setup_ioapic_remapp
                 continue;
 
             /* get device id of ioapic devices */
-            bdf = ioapic_bdf[IO_APIC_ID(apic)];
-            iommu = find_iommu_for_device(bdf);
+            bdf = ioapic_sbdf[IO_APIC_ID(apic)].bdf;
+            seg = ioapic_sbdf[IO_APIC_ID(apic)].seg;
+            iommu = find_iommu_for_device(seg, bdf);
             if ( !iommu )
             {
                 AMD_IOMMU_DEBUG("Fail to find iommu for ioapic "
-                                "device id = 0x%x\n", bdf);
+                                "device id = %04x:%04x\n", seg, bdf);
                 continue;
             }
 
-            req_id = get_intremap_requestor_id(bdf);
-            lock = get_intremap_lock(req_id);
+            req_id = get_intremap_requestor_id(iommu->seg, bdf);
+            lock = get_intremap_lock(iommu->seg, req_id);
 
             delivery_mode = rte.delivery_mode;
             vector = rte.vector;
@@ -193,7 +194,7 @@ int __init amd_iommu_setup_ioapic_remapp
 
             spin_lock_irqsave(lock, flags);
             offset = get_intremap_offset(vector, delivery_mode);
-            entry = (u32*)get_intremap_entry(req_id, offset);
+            entry = (u32*)get_intremap_entry(iommu->seg, req_id, offset);
             update_intremap_entry(entry, vector,
                                   delivery_mode, dest_mode, dest);
             spin_unlock_irqrestore(lock, flags);
@@ -216,7 +217,7 @@ void amd_iommu_ioapic_update_ire(
     struct IO_APIC_route_entry old_rte = { 0 };
     struct IO_APIC_route_entry new_rte = { 0 };
     unsigned int rte_lo = (reg & 1) ? reg - 1 : reg;
-    int saved_mask, bdf;
+    int saved_mask, seg, bdf;
     struct amd_iommu *iommu;
 
     if ( !iommu_intremap )
@@ -226,12 +227,13 @@ void amd_iommu_ioapic_update_ire(
     }
 
     /* get device id of ioapic devices */
-    bdf = ioapic_bdf[IO_APIC_ID(apic)];
-    iommu = find_iommu_for_device(bdf);
+    bdf = ioapic_sbdf[IO_APIC_ID(apic)].bdf;
+    seg = ioapic_sbdf[IO_APIC_ID(apic)].seg;
+    iommu = find_iommu_for_device(seg, bdf);
     if ( !iommu )
     {
-        AMD_IOMMU_DEBUG("Fail to find iommu for ioapic device id = 0x%x\n",
-                        bdf);
+        AMD_IOMMU_DEBUG("Fail to find iommu for ioapic device id ="
+                        " %04x:%04x\n", seg, bdf);
         __io_apic_write(apic, reg, value);
         return;
     }
@@ -289,28 +291,28 @@ static void update_intremap_entry_from_m
     int offset;
 
     bdf = (pdev->bus << 8) | pdev->devfn;
-    req_id = get_dma_requestor_id(bdf);
-    alias_id = get_intremap_requestor_id(bdf);
+    req_id = get_dma_requestor_id(pdev->seg, bdf);
+    alias_id = get_intremap_requestor_id(pdev->seg, bdf);
 
     if ( msg == NULL )
     {
-        lock = get_intremap_lock(req_id);
+        lock = get_intremap_lock(iommu->seg, req_id);
         spin_lock_irqsave(lock, flags);
-        free_intremap_entry(req_id, msi_desc->remap_index);
+        free_intremap_entry(iommu->seg, req_id, msi_desc->remap_index);
         spin_unlock_irqrestore(lock, flags);
 
         if ( ( req_id != alias_id ) &&
-            ivrs_mappings[alias_id].intremap_table != NULL )
+             get_ivrs_mappings(pdev->seg)[alias_id].intremap_table != NULL )
         {
-            lock = get_intremap_lock(alias_id);
+            lock = get_intremap_lock(iommu->seg, alias_id);
             spin_lock_irqsave(lock, flags);
-            free_intremap_entry(alias_id, msi_desc->remap_index);
+            free_intremap_entry(iommu->seg, alias_id, msi_desc->remap_index);
             spin_unlock_irqrestore(lock, flags);
         }
         goto done;
     }
 
-    lock = get_intremap_lock(req_id);
+    lock = get_intremap_lock(iommu->seg, req_id);
 
     spin_lock_irqsave(lock, flags);
     dest_mode = (msg->address_lo >> MSI_ADDR_DESTMODE_SHIFT) & 0x1;
@@ -320,7 +322,7 @@ static void update_intremap_entry_from_m
     offset = get_intremap_offset(vector, delivery_mode);
     msi_desc->remap_index = offset;
 
-    entry = (u32*)get_intremap_entry(req_id, offset);
+    entry = (u32*)get_intremap_entry(iommu->seg, req_id, offset);
     update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
     spin_unlock_irqrestore(lock, flags);
 
@@ -331,12 +333,12 @@ static void update_intremap_entry_from_m
      * devices.
      */
 
-    lock = get_intremap_lock(alias_id);
+    lock = get_intremap_lock(iommu->seg, alias_id);
     if ( ( req_id != alias_id ) &&
-        ivrs_mappings[alias_id].intremap_table != NULL )
+         get_ivrs_mappings(pdev->seg)[alias_id].intremap_table != NULL )
     {
         spin_lock_irqsave(lock, flags);
-        entry = (u32*)get_intremap_entry(alias_id, offset);
+        entry = (u32*)get_intremap_entry(iommu->seg, alias_id, offset);
         update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
         spin_unlock_irqrestore(lock, flags);
     }
@@ -362,7 +364,7 @@ void amd_iommu_msi_msg_update_ire(
     if ( !iommu_intremap )
         return;
 
-    iommu = find_iommu_for_device((pdev->bus << 8) | pdev->devfn);
+    iommu = find_iommu_for_device(pdev->seg, (pdev->bus << 8) | pdev->devfn);
 
     if ( !iommu )
     {
@@ -379,15 +381,18 @@ void amd_iommu_read_msi_from_ire(
 {
 }
 
-void __init amd_iommu_free_intremap_table(int bdf)
+int __init amd_iommu_free_intremap_table(
+    u16 seg, struct ivrs_mappings *ivrs_mapping)
 {
-    void *tb = ivrs_mappings[bdf].intremap_table;
+    void *tb = ivrs_mapping->intremap_table;
 
     if ( tb )
     {
         __free_amd_iommu_tables(tb, INTREMAP_TABLE_ORDER);
-        ivrs_mappings[bdf].intremap_table = NULL;
+        ivrs_mapping->intremap_table = NULL;
     }
+
+    return 0;
 }
 
 void* __init amd_iommu_alloc_intremap_table(void)
--- 2011-09-20.orig/xen/drivers/passthrough/amd/iommu_map.c     2011-08-25 
08:21:53.000000000 +0200
+++ 2011-09-20/xen/drivers/passthrough/amd/iommu_map.c  2011-08-25 
15:06:47.000000000 +0200
@@ -719,8 +719,8 @@ static int update_paging_mode(struct dom
         for_each_pdev( d, pdev )
         {
             bdf = (pdev->bus << 8) | pdev->devfn;
-            req_id = get_dma_requestor_id(bdf);
-            iommu = find_iommu_for_device(bdf);
+            req_id = get_dma_requestor_id(pdev->seg, bdf);
+            iommu = find_iommu_for_device(pdev->seg, bdf);
             if ( !iommu )
             {
                 AMD_IOMMU_DEBUG("%s Fail to find iommu.\n", __func__);
--- 2011-09-20.orig/xen/drivers/passthrough/amd/pci_amd_iommu.c 2011-09-20 
16:04:06.000000000 +0200
+++ 2011-09-20/xen/drivers/passthrough/amd/pci_amd_iommu.c      2011-09-20 
16:06:32.000000000 +0200
@@ -29,10 +29,12 @@
 extern bool_t __read_mostly opt_irq_perdev_vector_map;
 extern bool_t __read_mostly iommu_amd_perdev_vector_map;
 
-struct amd_iommu *find_iommu_for_device(int bdf)
+struct amd_iommu *find_iommu_for_device(int seg, int bdf)
 {
+    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
+
     BUG_ON ( bdf >= ivrs_bdf_entries );
-    return ivrs_mappings[bdf].iommu;
+    return ivrs_mappings ? ivrs_mappings[bdf].iommu : NULL;
 }
 
 /*
@@ -43,8 +45,9 @@ struct amd_iommu *find_iommu_for_device(
  * Return original device id, if device has valid interrupt remapping
  * table setup for both select entry and alias entry.
  */
-int get_dma_requestor_id(u16 bdf)
+int get_dma_requestor_id(u16 seg, u16 bdf)
 {
+    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
     int req_id;
 
     BUG_ON ( bdf >= ivrs_bdf_entries );
@@ -95,7 +98,7 @@ static void amd_iommu_setup_domain_devic
         valid = 0;
 
     /* get device-table entry */
-    req_id = get_dma_requestor_id(bdf);
+    req_id = get_dma_requestor_id(iommu->seg, bdf);
     dte = iommu->dev_table.buffer + (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
 
     spin_lock_irqsave(&iommu->lock, flags);
@@ -139,7 +142,7 @@ static void __init amd_iommu_setup_dom0_
             list_add(&pdev->domain_list, &d->arch.pdev_list);
 
             bdf = (bus << 8) | devfn;
-            iommu = find_iommu_for_device(bdf);
+            iommu = find_iommu_for_device(pdev->seg, bdf);
 
             if ( likely(iommu != NULL) )
                 amd_iommu_setup_domain_device(d, iommu, bdf);
@@ -287,7 +290,7 @@ static void amd_iommu_disable_domain_dev
     int req_id;
 
     BUG_ON ( iommu->dev_table.buffer == NULL );
-    req_id = get_dma_requestor_id(bdf);
+    req_id = get_dma_requestor_id(iommu->seg, bdf);
     dte = iommu->dev_table.buffer + (req_id * IOMMU_DEV_TABLE_ENTRY_SIZE);
 
     spin_lock_irqsave(&iommu->lock, flags);
@@ -318,12 +321,12 @@ static int reassign_device( struct domai
         return -ENODEV;
 
     bdf = (bus << 8) | devfn;
-    iommu = find_iommu_for_device(bdf);
+    iommu = find_iommu_for_device(seg, bdf);
     if ( !iommu )
     {
         AMD_IOMMU_DEBUG("Fail to find iommu."
-                        " %02x:%x02.%x cannot be assigned to domain %d\n", 
-                        bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                        " %04x:%02x:%x02.%x cannot be assigned to dom%d\n",
+                        seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
                         target->domain_id);
         return -ENODEV;
     }
@@ -339,8 +342,8 @@ static int reassign_device( struct domai
         allocate_domain_resources(t);
 
     amd_iommu_setup_domain_device(target, iommu, bdf);
-    AMD_IOMMU_DEBUG("Re-assign %02x:%02x.%x from domain %d to domain %d\n",
-                    bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+    AMD_IOMMU_DEBUG("Re-assign %04x:%02x:%02x.%u from dom%d to dom%d\n",
+                    seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
                     source->domain_id, target->domain_id);
 
     return 0;
@@ -348,8 +351,9 @@ static int reassign_device( struct domai
 
 static int amd_iommu_assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn)
 {
+    struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
     int bdf = (bus << 8) | devfn;
-    int req_id = get_dma_requestor_id(bdf);
+    int req_id = get_dma_requestor_id(seg, bdf);
 
     if ( ivrs_mappings[req_id].unity_map_enable )
     {
@@ -439,12 +443,12 @@ static int amd_iommu_add_device(struct p
         return -EINVAL;
 
     bdf = (pdev->bus << 8) | pdev->devfn;
-    iommu = find_iommu_for_device(bdf);
+    iommu = find_iommu_for_device(pdev->seg, bdf);
     if ( !iommu )
     {
         AMD_IOMMU_DEBUG("Fail to find iommu."
-                        " %02x:%02x.%x cannot be assigned to domain %d\n", 
-                        pdev->bus, PCI_SLOT(pdev->devfn),
+                        " %04x:%02x:%02x.%u cannot be assigned to dom%d\n",
+                        pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
                         PCI_FUNC(pdev->devfn), pdev->domain->domain_id);
         return -ENODEV;
     }
@@ -461,12 +465,12 @@ static int amd_iommu_remove_device(struc
         return -EINVAL;
 
     bdf = (pdev->bus << 8) | pdev->devfn;
-    iommu = find_iommu_for_device(bdf);
+    iommu = find_iommu_for_device(pdev->seg, bdf);
     if ( !iommu )
     {
         AMD_IOMMU_DEBUG("Fail to find iommu."
-                        " %02x:%02x.%x cannot be removed from domain %d\n", 
-                        pdev->bus, PCI_SLOT(pdev->devfn),
+                        " %04x:%02x:%02x.%u cannot be removed from dom%d\n",
+                        pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
                         PCI_FUNC(pdev->devfn), pdev->domain->domain_id);
         return -ENODEV;
     }
@@ -480,7 +484,7 @@ static int amd_iommu_group_id(u16 seg, u
     int rt;
     int bdf = (bus << 8) | devfn;
     rt = ( bdf < ivrs_bdf_entries ) ?
-        get_dma_requestor_id(bdf) :
+        get_dma_requestor_id(seg, bdf) :
         bdf;
     return rt;
 }
--- 2011-09-20.orig/xen/include/asm-x86/amd-iommu.h     2011-06-16 
09:21:02.000000000 +0200
+++ 2011-09-20/xen/include/asm-x86/amd-iommu.h  2011-08-25 15:06:47.000000000 
+0200
@@ -40,6 +40,7 @@ struct amd_iommu {
     struct list_head list;
     spinlock_t lock; /* protect iommu */
 
+    u16 seg;
     u16 bdf;
     u8  cap_offset;
     u8  revision;
@@ -101,6 +102,10 @@ struct ivrs_mappings {
 };
 
 extern unsigned short ivrs_bdf_entries;
-extern struct ivrs_mappings *ivrs_mappings;
+
+int alloc_ivrs_mappings(u16 seg);
+struct ivrs_mappings *get_ivrs_mappings(u16 seg);
+int iterate_ivrs_mappings(int (*)(u16 seg, struct ivrs_mappings *));
+int iterate_ivrs_entries(int (*)(u16 seg, struct ivrs_mappings *));
 
 #endif /* _ASM_X86_64_AMD_IOMMU_H */
--- 2011-09-20.orig/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h       
2011-08-19 17:08:35.000000000 +0200
+++ 2011-09-20/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h    2011-09-20 
15:12:40.000000000 +0200
@@ -65,7 +65,7 @@ int amd_iommu_reserve_domain_unity_map(s
 void amd_iommu_share_p2m(struct domain *d);
 
 /* device table functions */
-int get_dma_requestor_id(u16 bdf);
+int get_dma_requestor_id(u16 seg, u16 bdf);
 void amd_iommu_add_dev_table_entry(
     u32 *dte, u8 sys_mgt, u8 dev_ex, u8 lint1_pass, u8 lint0_pass, 
     u8 nmi_pass, u8 ext_int_pass, u8 init_pass);
@@ -80,12 +80,12 @@ int send_iommu_command(struct amd_iommu 
 void flush_command_buffer(struct amd_iommu *iommu);
 
 /* find iommu for bdf */
-struct amd_iommu *find_iommu_for_device(int bdf);
+struct amd_iommu *find_iommu_for_device(int seg, int bdf);
 
 /* interrupt remapping */
 int amd_iommu_setup_ioapic_remapping(void);
 void *amd_iommu_alloc_intremap_table(void);
-void amd_iommu_free_intremap_table(int bdf);
+int amd_iommu_free_intremap_table(u16 seg, struct ivrs_mappings *);
 void invalidate_interrupt_table(struct amd_iommu *iommu, u16 device_id);
 void amd_iommu_ioapic_update_ire(
     unsigned int apic, unsigned int reg, unsigned int value);
@@ -94,7 +94,9 @@ void amd_iommu_msi_msg_update_ire(
 void amd_iommu_read_msi_from_ire(
     struct msi_desc *msi_desc, struct msi_msg *msg);
 
-extern int ioapic_bdf[MAX_IO_APICS];
+extern struct ioapic_sbdf {
+    u16 bdf, seg;
+} ioapic_sbdf[MAX_IO_APICS];
 extern void *shared_intremap_table;
 
 /* power management support */


Attachment: pci-multi-seg-amd-iommu.patch
Description: Text document

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 5/7] PCI multi-seg: AMD-IOMMU specific adjustments, Jan Beulich <=