iommu/amd: Introduce per PCI segment unity map list
authorVasant Hegde <vasant.hegde@amd.com>
Wed, 6 Jul 2022 11:37:59 +0000 (17:07 +0530)
committerJoerg Roedel <jroedel@suse.de>
Thu, 7 Jul 2022 07:37:38 +0000 (09:37 +0200)
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.suthikulpanit@amd.com>
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Vasant Hegde <vasant.hegde@amd.com>
Link: https://lore.kernel.org/r/20220706113825.25582-10-vasant.hegde@amd.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/init.c
drivers/iommu/amd/iommu.c

index c9dd0ab..3099a01 100644 (file)
@@ -587,6 +587,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;
 };
 
 /*
@@ -814,12 +821,6 @@ struct unity_map_entry {
 };
 
 /*
- * 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
  */
 
index 2c8dbf2..7795056 100644 (file)
@@ -141,7 +141,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));
@@ -161,8 +162,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
@@ -1564,6 +1563,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))
@@ -2401,10 +2401,13 @@ enable_faults:
 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);
+               }
        }
 }
 
@@ -2412,8 +2415,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;
@@ -2451,14 +2459,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;
 }
index 378fa68..53ccee5 100644 (file)
@@ -2237,13 +2237,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;