]> xenbits.xensource.com Git - xen.git/commitdiff
PCI multi-seg: AMD-IOMMU specific adjustments
authorJan Beulich <jbeulich@suse.com>
Thu, 22 Sep 2011 17:28:03 +0000 (18:28 +0100)
committerJan Beulich <jbeulich@suse.com>
Thu, 22 Sep 2011 17:28:03 +0000 (18:28 +0100)
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@suse.com>
xen/drivers/passthrough/amd/iommu_acpi.c
xen/drivers/passthrough/amd/iommu_detect.c
xen/drivers/passthrough/amd/iommu_init.c
xen/drivers/passthrough/amd/iommu_intr.c
xen/drivers/passthrough/amd/iommu_map.c
xen/drivers/passthrough/amd/pci_amd_iommu.c
xen/include/asm-x86/amd-iommu.h
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h

index 332537953bbd770b5a288fdff23d8bf93117d103..a26914b6e99ec21f7e05a56a5470682110491255 100644 (file)
@@ -30,6 +30,7 @@ static unsigned short __initdata last_bdf;
 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_exclusion_range_all(
 }
 
 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_device(
 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_range_for_all_devices(
         /* 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_range_for_all_devices(
 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_range_for_device(
         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_range_for_iommu_devices(
         /* 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_extended_range(
 }
 
 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_special(
 
     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(struct acpi_ivhd_block_header *ivhd_block)
             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:
index 164a6aeb9adbda201bff77ec6f54cf63a679ccdb..7b6e932160efb54c0ef1f5dfb1eff1888c1e3460 100644 (file)
@@ -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_capabilities(u8 bus, u8 dev, u8 func,
     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(void *ivhd)
 
     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(void *ivhd)
     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);
 
index b9742f176330727401c8215f4db01b9310f04dc3..8a5e22c5aae5fa5766fb270978ef998ecc5748aa 100644 (file)
@@ -32,7 +32,7 @@
 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;
 
@@ -692,7 +692,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 )
@@ -708,40 +707,84 @@ static void __init amd_iommu_init_cleanup(void)
     }
 
     /* 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);
 
     iommu_enabled = 0;
     iommu_passthrough = 0;
     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++ )
@@ -763,10 +806,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;
@@ -832,7 +879,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 )
@@ -843,7 +891,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  */
@@ -888,7 +936,8 @@ static void invalidate_all_domain_pages(void)
         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;
@@ -896,7 +945,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 )
         {
@@ -907,6 +956,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)
index 4e6efa096fab7d1eda647b9c81a21663189129d9..70d83d9088bd86888b257645a753d569eb38eb90 100644 (file)
 #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, u8 dm)
     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_ioapic(
     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_ioapic(
     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_remapping(void)
     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_remapping(void)
                 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_remapping(void)
 
             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_msi_msg(
     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_msi_msg(
     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_msi_msg(
      * 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)
index 6a8619c0efaa7d14adaa214b9288ef322ddfbd37..1402806c5fa6f4ba9be6567d5748651577dfc3aa 100644 (file)
@@ -719,8 +719,8 @@ static int update_paging_mode(struct domain *d, unsigned long gfn)
         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__);
index 9736251cb11efa4273542d50bf26a4e7c2befe6e..14a3f489fa8e083f3a49089466cf6c494eb67cab 100644 (file)
 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(int bdf)
  * 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_device(
         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_devices(struct domain *d)
             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_device(
     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 domain *source, struct domain *target,
         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 domain *source, struct domain *target,
         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 domain *source, struct domain *target,
 
 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 pci_dev *pdev)
         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(struct pci_dev *pdev)
         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, u8 bus, u8 devfn)
     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;
 }
index 784c9d989b8a21382855693a19a8f70b1d9507da..ea40310c7810b38e2c0d10d813223017d7f16bd4 100644 (file)
@@ -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 */
index 1444e9104c57a48e40233a38f7fbd3757451c2c7..a6e600b5889f459ddda1d6b903c048bc76751455 100644 (file)
@@ -65,7 +65,7 @@ int amd_iommu_reserve_domain_unity_map(struct domain *domain,
 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 *iommu, u32 cmd[]);
 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 */