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: 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>
This commit is contained in:
parent
99fc4ac3d2
commit
b618ae6247
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -813,12 +820,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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue