diff options
| author | Joerg Roedel <jroedel@suse.de> | 2019-03-28 06:44:59 -0400 |
|---|---|---|
| committer | Joerg Roedel <jroedel@suse.de> | 2019-03-29 12:12:57 -0400 |
| commit | 8aafaaf2212192012f5bae305bb31cdf7681d777 (patch) | |
| tree | e127f639ee1505d08551be15953eade4756caf8a /drivers | |
| parent | 8bc32a285660e13fdcf92ddaf5b8653abe112040 (diff) | |
iommu/amd: Reserve exclusion range in iova-domain
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>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/iommu/amd_iommu.c | 9 | ||||
| -rw-r--r-- | drivers/iommu/amd_iommu_init.c | 7 | ||||
| -rw-r--r-- | 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 21cb088d6687..f7cdd2ab7f11 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c | |||
| @@ -3169,21 +3169,24 @@ static void amd_iommu_get_resv_regions(struct device *dev, | |||
| 3169 | return; | 3169 | return; |
| 3170 | 3170 | ||
| 3171 | list_for_each_entry(entry, &amd_iommu_unity_map, list) { | 3171 | list_for_each_entry(entry, &amd_iommu_unity_map, list) { |
| 3172 | int type, prot = 0; | ||
| 3172 | size_t length; | 3173 | size_t length; |
| 3173 | int prot = 0; | ||
| 3174 | 3174 | ||
| 3175 | if (devid < entry->devid_start || devid > entry->devid_end) | 3175 | if (devid < entry->devid_start || devid > entry->devid_end) |
| 3176 | continue; | 3176 | continue; |
| 3177 | 3177 | ||
| 3178 | type = IOMMU_RESV_DIRECT; | ||
| 3178 | length = entry->address_end - entry->address_start; | 3179 | length = entry->address_end - entry->address_start; |
| 3179 | if (entry->prot & IOMMU_PROT_IR) | 3180 | if (entry->prot & IOMMU_PROT_IR) |
| 3180 | prot |= IOMMU_READ; | 3181 | prot |= IOMMU_READ; |
| 3181 | if (entry->prot & IOMMU_PROT_IW) | 3182 | if (entry->prot & IOMMU_PROT_IW) |
| 3182 | prot |= IOMMU_WRITE; | 3183 | prot |= IOMMU_WRITE; |
| 3184 | if (entry->prot & IOMMU_UNITY_MAP_FLAG_EXCL_RANGE) | ||
| 3185 | /* Exclusion range */ | ||
| 3186 | type = IOMMU_RESV_RESERVED; | ||
| 3183 | 3187 | ||
| 3184 | region = iommu_alloc_resv_region(entry->address_start, | 3188 | region = iommu_alloc_resv_region(entry->address_start, |
| 3185 | length, prot, | 3189 | length, prot, type); |
| 3186 | IOMMU_RESV_DIRECT); | ||
| 3187 | if (!region) { | 3190 | if (!region) { |
| 3188 | dev_err(dev, "Out of memory allocating dm-regions\n"); | 3191 | dev_err(dev, "Out of memory allocating dm-regions\n"); |
| 3189 | return; | 3192 | return; |
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index f773792d77fd..1b1378619fc9 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
| @@ -2013,6 +2013,9 @@ static int __init init_unity_map_range(struct ivmd_header *m) | |||
| 2013 | if (e == NULL) | 2013 | if (e == NULL) |
| 2014 | return -ENOMEM; | 2014 | return -ENOMEM; |
| 2015 | 2015 | ||
| 2016 | if (m->flags & IVMD_FLAG_EXCL_RANGE) | ||
| 2017 | init_exclusion_range(m); | ||
| 2018 | |||
| 2016 | switch (m->type) { | 2019 | switch (m->type) { |
| 2017 | default: | 2020 | default: |
| 2018 | kfree(e); | 2021 | kfree(e); |
| @@ -2059,9 +2062,7 @@ static int __init init_memory_definitions(struct acpi_table_header *table) | |||
| 2059 | 2062 | ||
| 2060 | while (p < end) { | 2063 | while (p < end) { |
| 2061 | m = (struct ivmd_header *)p; | 2064 | m = (struct ivmd_header *)p; |
| 2062 | if (m->flags & IVMD_FLAG_EXCL_RANGE) | 2065 | if (m->flags & (IVMD_FLAG_UNITY_MAP | IVMD_FLAG_EXCL_RANGE)) |
| 2063 | init_exclusion_range(m); | ||
| 2064 | else if (m->flags & IVMD_FLAG_UNITY_MAP) | ||
| 2065 | init_unity_map_range(m); | 2066 | init_unity_map_range(m); |
| 2066 | 2067 | ||
| 2067 | p += m->length; | 2068 | p += m->length; |
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index eae0741f72dc..87965e4d9647 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h | |||
| @@ -374,6 +374,8 @@ | |||
| 374 | #define IOMMU_PROT_IR 0x01 | 374 | #define IOMMU_PROT_IR 0x01 |
| 375 | #define IOMMU_PROT_IW 0x02 | 375 | #define IOMMU_PROT_IW 0x02 |
| 376 | 376 | ||
| 377 | #define IOMMU_UNITY_MAP_FLAG_EXCL_RANGE (1 << 2) | ||
| 378 | |||
| 377 | /* IOMMU capabilities */ | 379 | /* IOMMU capabilities */ |
| 378 | #define IOMMU_CAP_IOTLB 24 | 380 | #define IOMMU_CAP_IOTLB 24 |
| 379 | #define IOMMU_CAP_NPCACHE 26 | 381 | #define IOMMU_CAP_NPCACHE 26 |
