| From 0127197897eefa7c687921a5effb7a21eaf8c1fb Mon Sep 17 00:00:00 2001 |
| From: Joerg Roedel <jroedel@suse.de> |
| Date: Thu, 28 Mar 2019 11:44:59 +0100 |
| Subject: iommu/amd: Reserve exclusion range in iova-domain |
| |
| [ Upstream commit 8aafaaf2212192012f5bae305bb31cdf7681d777 ] |
| |
| If a device has an exclusion range specified in the IVRS |
| table, this region needs to be reserved in the iova-domain |
| of that device. This hasn't happened until now and can cause |
| data corruption on data transfered with these devices. |
| |
| Treat exclusion ranges as reserved regions in the iommu-core |
| to fix the problem. |
| |
| Fixes: be2a022c0dd0 ('x86, AMD IOMMU: add functions to parse IOMMU memory mapping requirements for devices') |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| Reviewed-by: Gary R Hook <gary.hook@amd.com> |
| Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org> |
| --- |
| drivers/iommu/amd_iommu.c | 9 ++++++--- |
| drivers/iommu/amd_iommu_init.c | 7 ++++--- |
| drivers/iommu/amd_iommu_types.h | 2 ++ |
| 3 files changed, 12 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c |
| index bd339bfe0d15..684f7cdd814b 100644 |
| --- a/drivers/iommu/amd_iommu.c |
| +++ b/drivers/iommu/amd_iommu.c |
| @@ -3127,21 +3127,24 @@ static void amd_iommu_get_resv_regions(struct device *dev, |
| return; |
| |
| list_for_each_entry(entry, &amd_iommu_unity_map, list) { |
| + int type, prot = 0; |
| size_t length; |
| - int prot = 0; |
| |
| if (devid < entry->devid_start || devid > entry->devid_end) |
| continue; |
| |
| + type = IOMMU_RESV_DIRECT; |
| length = entry->address_end - entry->address_start; |
| if (entry->prot & IOMMU_PROT_IR) |
| prot |= IOMMU_READ; |
| if (entry->prot & IOMMU_PROT_IW) |
| prot |= IOMMU_WRITE; |
| + if (entry->prot & IOMMU_UNITY_MAP_FLAG_EXCL_RANGE) |
| + /* Exclusion range */ |
| + type = IOMMU_RESV_RESERVED; |
| |
| region = iommu_alloc_resv_region(entry->address_start, |
| - length, prot, |
| - IOMMU_RESV_DIRECT); |
| + length, prot, type); |
| if (!region) { |
| pr_err("Out of memory allocating dm-regions for %s\n", |
| dev_name(dev)); |
| diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c |
| index b97984a5ddad..91d7718625a6 100644 |
| --- a/drivers/iommu/amd_iommu_init.c |
| +++ b/drivers/iommu/amd_iommu_init.c |
| @@ -1980,6 +1980,9 @@ static int __init init_unity_map_range(struct ivmd_header *m) |
| if (e == NULL) |
| return -ENOMEM; |
| |
| + if (m->flags & IVMD_FLAG_EXCL_RANGE) |
| + init_exclusion_range(m); |
| + |
| switch (m->type) { |
| default: |
| kfree(e); |
| @@ -2026,9 +2029,7 @@ static int __init init_memory_definitions(struct acpi_table_header *table) |
| |
| 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) |
| + if (m->flags & (IVMD_FLAG_UNITY_MAP | IVMD_FLAG_EXCL_RANGE)) |
| init_unity_map_range(m); |
| |
| p += m->length; |
| diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h |
| index f6b24c7d8b70..3054c0971759 100644 |
| --- a/drivers/iommu/amd_iommu_types.h |
| +++ b/drivers/iommu/amd_iommu_types.h |
| @@ -369,6 +369,8 @@ |
| #define IOMMU_PROT_IR 0x01 |
| #define IOMMU_PROT_IW 0x02 |
| |
| +#define IOMMU_UNITY_MAP_FLAG_EXCL_RANGE (1 << 2) |
| + |
| /* IOMMU capabilities */ |
| #define IOMMU_CAP_IOTLB 24 |
| #define IOMMU_CAP_NPCACHE 26 |
| -- |
| 2.19.1 |
| |