Newer AMD systems can support multiple PCI segments. In order to support
multiple PCI segments IVMD table in IVRS structure is enhanced to
include pci segment id. Update ivmd_header structure to include "pci_seg".

Also introduce per PCI segment unity map list. It will replace global
amd_iommu_unity_map list.

Note that we have used "reserved" field in IVMD table to include "pci_seg
id" which was set to zero. It will take care of backward compatibility
(new kernel will work fine on older systems).

Co-developed-by: Suravee Suthikulpanit <suravee.suthikulpa...@amd.com>
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpa...@amd.com>
Signed-off-by: Vasant Hegde <vasant.he...@amd.com>
---
 drivers/iommu/amd/amd_iommu_types.h | 13 +++++++------
 drivers/iommu/amd/init.c            | 30 +++++++++++++++++++----------
 drivers/iommu/amd/iommu.c           |  8 +++++++-
 3 files changed, 34 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/amd/amd_iommu_types.h 
b/drivers/iommu/amd/amd_iommu_types.h
index f9776f188e36..c4c9c35e2bf7 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -579,6 +579,13 @@ struct amd_iommu_pci_seg {
         * More than one device can share the same requestor id.
         */
        u16 *alias_table;
+
+       /*
+        * A list of required unity mappings we find in ACPI. It is not locked
+        * because as runtime it is only read. It is created at ACPI table
+        * parsing time.
+        */
+       struct list_head unity_map;
 };
 
 /*
@@ -805,12 +812,6 @@ struct unity_map_entry {
        int prot;
 };
 
-/*
- * List of all unity mappings. It is not locked because as runtime it is only
- * read. It is created at ACPI table parsing time.
- */
-extern struct list_head amd_iommu_unity_map;
-
 /*
  * Data structures for device handling
  */
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index fe31de6e764c..d613e20ea013 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -142,7 +142,8 @@ struct ivmd_header {
        u16 length;
        u16 devid;
        u16 aux;
-       u64 resv;
+       u16 pci_seg;
+       u8  resv[6];
        u64 range_start;
        u64 range_length;
 } __attribute__((packed));
@@ -162,8 +163,6 @@ static int amd_iommu_target_ivhd_type;
 
 u16 amd_iommu_last_bdf;                        /* largest PCI device id we have
                                           to handle */
-LIST_HEAD(amd_iommu_unity_map);                /* a list of required unity 
mappings
-                                          we find in ACPI */
 
 LIST_HEAD(amd_iommu_pci_seg_list);     /* list of all PCI segments */
 LIST_HEAD(amd_iommu_list);             /* list of all AMD IOMMUs in the
@@ -1562,6 +1561,7 @@ static struct amd_iommu_pci_seg *__init 
alloc_pci_segment(u16 id)
 
        pci_seg->id = id;
        init_llist_head(&pci_seg->dev_data_list);
+       INIT_LIST_HEAD(&pci_seg->unity_map);
        list_add_tail(&pci_seg->list, &amd_iommu_pci_seg_list);
 
        if (alloc_dev_table(pci_seg))
@@ -2397,10 +2397,13 @@ static int iommu_init_irq(struct amd_iommu *iommu)
 static void __init free_unity_maps(void)
 {
        struct unity_map_entry *entry, *next;
+       struct amd_iommu_pci_seg *p, *pci_seg;
 
-       list_for_each_entry_safe(entry, next, &amd_iommu_unity_map, list) {
-               list_del(&entry->list);
-               kfree(entry);
+       for_each_pci_segment_safe(pci_seg, p) {
+               list_for_each_entry_safe(entry, next, &pci_seg->unity_map, 
list) {
+                       list_del(&entry->list);
+                       kfree(entry);
+               }
        }
 }
 
@@ -2408,8 +2411,13 @@ static void __init free_unity_maps(void)
 static int __init init_unity_map_range(struct ivmd_header *m)
 {
        struct unity_map_entry *e = NULL;
+       struct amd_iommu_pci_seg *pci_seg;
        char *s;
 
+       pci_seg = get_pci_segment(m->pci_seg);
+       if (pci_seg == NULL)
+               return -ENOMEM;
+
        e = kzalloc(sizeof(*e), GFP_KERNEL);
        if (e == NULL)
                return -ENOMEM;
@@ -2447,14 +2455,16 @@ static int __init init_unity_map_range(struct 
ivmd_header *m)
        if (m->flags & IVMD_FLAG_EXCL_RANGE)
                e->prot = (IVMD_FLAG_IW | IVMD_FLAG_IR) >> 1;
 
-       DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
-                   " range_start: %016llx range_end: %016llx flags: %x\n", s,
+       DUMP_printk("%s devid_start: %04x:%02x:%02x.%x devid_end: "
+                   "%04x:%02x:%02x.%x range_start: %016llx range_end: %016llx"
+                   " flags: %x\n", s, m->pci_seg,
                    PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
-                   PCI_FUNC(e->devid_start), PCI_BUS_NUM(e->devid_end),
+                   PCI_FUNC(e->devid_start), m->pci_seg,
+                   PCI_BUS_NUM(e->devid_end),
                    PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end),
                    e->address_start, e->address_end, m->flags);
 
-       list_add_tail(&e->list, &amd_iommu_unity_map);
+       list_add_tail(&e->list, &pci_seg->unity_map);
 
        return 0;
 }
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index c6058b6f2538..0f500b1a3885 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -2242,13 +2242,19 @@ static void amd_iommu_get_resv_regions(struct device 
*dev,
 {
        struct iommu_resv_region *region;
        struct unity_map_entry *entry;
+       struct amd_iommu *iommu;
+       struct amd_iommu_pci_seg *pci_seg;
        int devid;
 
        devid = get_device_id(dev);
        if (devid < 0)
                return;
+       iommu = rlookup_amd_iommu(dev);
+       if (!iommu)
+               return;
+       pci_seg = iommu->pci_seg;
 
-       list_for_each_entry(entry, &amd_iommu_unity_map, list) {
+       list_for_each_entry(entry, &pci_seg->unity_map, list) {
                int type, prot = 0;
                size_t length;
 
-- 
2.27.0

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to