Commit b618ae62 authored by Vasant Hegde's avatar Vasant Hegde Committed by Joerg Roedel

iommu/amd: Introduce per PCI segment unity map list

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: default avatarSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: default avatarSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: default avatarVasant Hegde <vasant.hegde@amd.com>
Link: https://lore.kernel.org/r/20220706113825.25582-10-vasant.hegde@amd.comSigned-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 99fc4ac3
...@@ -587,6 +587,13 @@ struct amd_iommu_pci_seg { ...@@ -587,6 +587,13 @@ struct amd_iommu_pci_seg {
* More than one device can share the same requestor id. * More than one device can share the same requestor id.
*/ */
u16 *alias_table; 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;
}; };
/* /*
...@@ -813,12 +820,6 @@ struct unity_map_entry { ...@@ -813,12 +820,6 @@ struct unity_map_entry {
int prot; 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 * Data structures for device handling
*/ */
......
...@@ -141,7 +141,8 @@ struct ivmd_header { ...@@ -141,7 +141,8 @@ struct ivmd_header {
u16 length; u16 length;
u16 devid; u16 devid;
u16 aux; u16 aux;
u64 resv; u16 pci_seg;
u8 resv[6];
u64 range_start; u64 range_start;
u64 range_length; u64 range_length;
} __attribute__((packed)); } __attribute__((packed));
...@@ -161,8 +162,6 @@ static int amd_iommu_target_ivhd_type; ...@@ -161,8 +162,6 @@ static int amd_iommu_target_ivhd_type;
u16 amd_iommu_last_bdf; /* largest PCI device id we have u16 amd_iommu_last_bdf; /* largest PCI device id we have
to handle */ 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_pci_seg_list); /* list of all PCI segments */
LIST_HEAD(amd_iommu_list); /* list of all AMD IOMMUs in the 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) ...@@ -1564,6 +1563,7 @@ static struct amd_iommu_pci_seg *__init alloc_pci_segment(u16 id)
pci_seg->id = id; pci_seg->id = id;
init_llist_head(&pci_seg->dev_data_list); 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); list_add_tail(&pci_seg->list, &amd_iommu_pci_seg_list);
if (alloc_dev_table(pci_seg)) if (alloc_dev_table(pci_seg))
...@@ -2401,10 +2401,13 @@ static int iommu_init_irq(struct amd_iommu *iommu) ...@@ -2401,10 +2401,13 @@ static int iommu_init_irq(struct amd_iommu *iommu)
static void __init free_unity_maps(void) static void __init free_unity_maps(void)
{ {
struct unity_map_entry *entry, *next; 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) { for_each_pci_segment_safe(pci_seg, p) {
list_del(&entry->list); list_for_each_entry_safe(entry, next, &pci_seg->unity_map, list) {
kfree(entry); list_del(&entry->list);
kfree(entry);
}
} }
} }
...@@ -2412,8 +2415,13 @@ static void __init free_unity_maps(void) ...@@ -2412,8 +2415,13 @@ static void __init free_unity_maps(void)
static int __init init_unity_map_range(struct ivmd_header *m) static int __init init_unity_map_range(struct ivmd_header *m)
{ {
struct unity_map_entry *e = NULL; struct unity_map_entry *e = NULL;
struct amd_iommu_pci_seg *pci_seg;
char *s; char *s;
pci_seg = get_pci_segment(m->pci_seg);
if (pci_seg == NULL)
return -ENOMEM;
e = kzalloc(sizeof(*e), GFP_KERNEL); e = kzalloc(sizeof(*e), GFP_KERNEL);
if (e == NULL) if (e == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -2451,14 +2459,16 @@ static int __init init_unity_map_range(struct ivmd_header *m) ...@@ -2451,14 +2459,16 @@ static int __init init_unity_map_range(struct ivmd_header *m)
if (m->flags & IVMD_FLAG_EXCL_RANGE) if (m->flags & IVMD_FLAG_EXCL_RANGE)
e->prot = (IVMD_FLAG_IW | IVMD_FLAG_IR) >> 1; e->prot = (IVMD_FLAG_IW | IVMD_FLAG_IR) >> 1;
DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x" DUMP_printk("%s devid_start: %04x:%02x:%02x.%x devid_end: "
" range_start: %016llx range_end: %016llx flags: %x\n", s, "%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_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), PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end),
e->address_start, e->address_end, m->flags); 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; return 0;
} }
......
...@@ -2237,13 +2237,19 @@ static void amd_iommu_get_resv_regions(struct device *dev, ...@@ -2237,13 +2237,19 @@ static void amd_iommu_get_resv_regions(struct device *dev,
{ {
struct iommu_resv_region *region; struct iommu_resv_region *region;
struct unity_map_entry *entry; struct unity_map_entry *entry;
struct amd_iommu *iommu;
struct amd_iommu_pci_seg *pci_seg;
int devid; int devid;
devid = get_device_id(dev); devid = get_device_id(dev);
if (devid < 0) if (devid < 0)
return; 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; int type, prot = 0;
size_t length; size_t length;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment