mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
x86, AMD IOMMU: add functions to parse IOMMU memory mapping requirements for devices
This patch adds the functions to parse the information about IOMMU exclusion ranges and required unity mappings for the devices handled by the IOMMU. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Cc: iommu@lists.linux-foundation.org Cc: bhavna.sarathy@amd.com Cc: Sebastian.Biemueller@amd.com Cc: robert.richter@amd.com Cc: joro@8bytes.org Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
e47d402d2d
commit
be2a022c0d
1 changed files with 87 additions and 0 deletions
|
@ -556,3 +556,90 @@ static int __init init_iommu_all(struct acpi_table_header *table)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __init free_unity_maps(void)
|
||||||
|
{
|
||||||
|
struct unity_map_entry *entry, *next;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(entry, next, &amd_iommu_unity_map, list) {
|
||||||
|
list_del(&entry->list);
|
||||||
|
kfree(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init init_exclusion_range(struct ivmd_header *m)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
switch (m->type) {
|
||||||
|
case ACPI_IVMD_TYPE:
|
||||||
|
set_device_exclusion_range(m->devid, m);
|
||||||
|
break;
|
||||||
|
case ACPI_IVMD_TYPE_ALL:
|
||||||
|
for (i = 0; i < amd_iommu_last_bdf; ++i)
|
||||||
|
set_device_exclusion_range(i, m);
|
||||||
|
break;
|
||||||
|
case ACPI_IVMD_TYPE_RANGE:
|
||||||
|
for (i = m->devid; i <= m->aux; ++i)
|
||||||
|
set_device_exclusion_range(i, m);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init init_unity_map_range(struct ivmd_header *m)
|
||||||
|
{
|
||||||
|
struct unity_map_entry *e = 0;
|
||||||
|
|
||||||
|
e = kzalloc(sizeof(*e), GFP_KERNEL);
|
||||||
|
if (e == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
switch (m->type) {
|
||||||
|
default:
|
||||||
|
case ACPI_IVMD_TYPE:
|
||||||
|
e->devid_start = e->devid_end = m->devid;
|
||||||
|
break;
|
||||||
|
case ACPI_IVMD_TYPE_ALL:
|
||||||
|
e->devid_start = 0;
|
||||||
|
e->devid_end = amd_iommu_last_bdf;
|
||||||
|
break;
|
||||||
|
case ACPI_IVMD_TYPE_RANGE:
|
||||||
|
e->devid_start = m->devid;
|
||||||
|
e->devid_end = m->aux;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e->address_start = PAGE_ALIGN(m->range_start);
|
||||||
|
e->address_end = e->address_start + PAGE_ALIGN(m->range_length);
|
||||||
|
e->prot = m->flags >> 1;
|
||||||
|
|
||||||
|
list_add_tail(&e->list, &amd_iommu_unity_map);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init init_memory_definitions(struct acpi_table_header *table)
|
||||||
|
{
|
||||||
|
u8 *p = (u8 *)table, *end = (u8 *)table;
|
||||||
|
struct ivmd_header *m;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&amd_iommu_unity_map);
|
||||||
|
|
||||||
|
end += table->length;
|
||||||
|
p += IVRS_HEADER_LENGTH;
|
||||||
|
|
||||||
|
while (p < end) {
|
||||||
|
m = (struct ivmd_header *)p;
|
||||||
|
if (m->flags & IVMD_FLAG_EXCL_RANGE)
|
||||||
|
init_exclusion_range(m);
|
||||||
|
else if (m->flags & IVMD_FLAG_UNITY_MAP)
|
||||||
|
init_unity_map_range(m);
|
||||||
|
|
||||||
|
p += m->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue