diff options
author | Eric Auger <eric.auger@redhat.com> | 2019-06-03 02:53:31 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2019-06-12 04:32:59 -0400 |
commit | 5f64ce5411b467f1cfea6c63e2494c22b773582b (patch) | |
tree | 9837f8989e06c2f76cf720346842341c5e80b3da /drivers/iommu/intel-iommu.c | |
parent | ad0834dedaa15c3a176f783c0373f836e44b4700 (diff) |
iommu/vt-d: Duplicate iommu_resv_region objects per device list
intel_iommu_get_resv_regions() aims to return the list of
reserved regions accessible by a given @device. However several
devices can access the same reserved memory region and when
building the list it is not safe to use a single iommu_resv_region
object, whose container is the RMRR. This iommu_resv_region must
be duplicated per device reserved region list.
Let's remove the struct iommu_resv_region from the RMRR unit
and allocate the iommu_resv_region directly in
intel_iommu_get_resv_regions(). We hold the dmar_global_lock instead
of the rcu-lock to allow sleeping.
Fixes: 0659b8dc45a6 ("iommu/vt-d: Implement reserved region get/put callbacks")
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu/intel-iommu.c')
-rw-r--r-- | drivers/iommu/intel-iommu.c | 34 |
1 files changed, 17 insertions, 17 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 876096c1f91b..082fbb1bdeaf 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -324,7 +324,6 @@ struct dmar_rmrr_unit { | |||
324 | u64 end_address; /* reserved end address */ | 324 | u64 end_address; /* reserved end address */ |
325 | struct dmar_dev_scope *devices; /* target devices */ | 325 | struct dmar_dev_scope *devices; /* target devices */ |
326 | int devices_cnt; /* target device count */ | 326 | int devices_cnt; /* target device count */ |
327 | struct iommu_resv_region *resv; /* reserved region handle */ | ||
328 | }; | 327 | }; |
329 | 328 | ||
330 | struct dmar_atsr_unit { | 329 | struct dmar_atsr_unit { |
@@ -4050,7 +4049,6 @@ static inline void init_iommu_pm_ops(void) {} | |||
4050 | int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) | 4049 | int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) |
4051 | { | 4050 | { |
4052 | struct acpi_dmar_reserved_memory *rmrr; | 4051 | struct acpi_dmar_reserved_memory *rmrr; |
4053 | int prot = DMA_PTE_READ|DMA_PTE_WRITE; | ||
4054 | struct dmar_rmrr_unit *rmrru; | 4052 | struct dmar_rmrr_unit *rmrru; |
4055 | size_t length; | 4053 | size_t length; |
4056 | 4054 | ||
@@ -4064,22 +4062,16 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) | |||
4064 | rmrru->end_address = rmrr->end_address; | 4062 | rmrru->end_address = rmrr->end_address; |
4065 | 4063 | ||
4066 | length = rmrr->end_address - rmrr->base_address + 1; | 4064 | length = rmrr->end_address - rmrr->base_address + 1; |
4067 | rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot, | ||
4068 | IOMMU_RESV_DIRECT); | ||
4069 | if (!rmrru->resv) | ||
4070 | goto free_rmrru; | ||
4071 | 4065 | ||
4072 | rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1), | 4066 | rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1), |
4073 | ((void *)rmrr) + rmrr->header.length, | 4067 | ((void *)rmrr) + rmrr->header.length, |
4074 | &rmrru->devices_cnt); | 4068 | &rmrru->devices_cnt); |
4075 | if (rmrru->devices_cnt && rmrru->devices == NULL) | 4069 | if (rmrru->devices_cnt && rmrru->devices == NULL) |
4076 | goto free_all; | 4070 | goto free_rmrru; |
4077 | 4071 | ||
4078 | list_add(&rmrru->list, &dmar_rmrr_units); | 4072 | list_add(&rmrru->list, &dmar_rmrr_units); |
4079 | 4073 | ||
4080 | return 0; | 4074 | return 0; |
4081 | free_all: | ||
4082 | kfree(rmrru->resv); | ||
4083 | free_rmrru: | 4075 | free_rmrru: |
4084 | kfree(rmrru); | 4076 | kfree(rmrru); |
4085 | out: | 4077 | out: |
@@ -4297,7 +4289,6 @@ static void intel_iommu_free_dmars(void) | |||
4297 | list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) { | 4289 | list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) { |
4298 | list_del(&rmrru->list); | 4290 | list_del(&rmrru->list); |
4299 | dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt); | 4291 | dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt); |
4300 | kfree(rmrru->resv); | ||
4301 | kfree(rmrru); | 4292 | kfree(rmrru); |
4302 | } | 4293 | } |
4303 | 4294 | ||
@@ -5400,22 +5391,33 @@ static void intel_iommu_remove_device(struct device *dev) | |||
5400 | static void intel_iommu_get_resv_regions(struct device *device, | 5391 | static void intel_iommu_get_resv_regions(struct device *device, |
5401 | struct list_head *head) | 5392 | struct list_head *head) |
5402 | { | 5393 | { |
5394 | int prot = DMA_PTE_READ | DMA_PTE_WRITE; | ||
5403 | struct iommu_resv_region *reg; | 5395 | struct iommu_resv_region *reg; |
5404 | struct dmar_rmrr_unit *rmrr; | 5396 | struct dmar_rmrr_unit *rmrr; |
5405 | struct device *i_dev; | 5397 | struct device *i_dev; |
5406 | int i; | 5398 | int i; |
5407 | 5399 | ||
5408 | rcu_read_lock(); | 5400 | down_read(&dmar_global_lock); |
5409 | for_each_rmrr_units(rmrr) { | 5401 | for_each_rmrr_units(rmrr) { |
5410 | for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, | 5402 | for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, |
5411 | i, i_dev) { | 5403 | i, i_dev) { |
5404 | struct iommu_resv_region *resv; | ||
5405 | size_t length; | ||
5406 | |||
5412 | if (i_dev != device) | 5407 | if (i_dev != device) |
5413 | continue; | 5408 | continue; |
5414 | 5409 | ||
5415 | list_add_tail(&rmrr->resv->list, head); | 5410 | length = rmrr->end_address - rmrr->base_address + 1; |
5411 | resv = iommu_alloc_resv_region(rmrr->base_address, | ||
5412 | length, prot, | ||
5413 | IOMMU_RESV_DIRECT); | ||
5414 | if (!resv) | ||
5415 | break; | ||
5416 | |||
5417 | list_add_tail(&resv->list, head); | ||
5416 | } | 5418 | } |
5417 | } | 5419 | } |
5418 | rcu_read_unlock(); | 5420 | up_read(&dmar_global_lock); |
5419 | 5421 | ||
5420 | #ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA | 5422 | #ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA |
5421 | if (dev_is_pci(device)) { | 5423 | if (dev_is_pci(device)) { |
@@ -5443,10 +5445,8 @@ static void intel_iommu_put_resv_regions(struct device *dev, | |||
5443 | { | 5445 | { |
5444 | struct iommu_resv_region *entry, *next; | 5446 | struct iommu_resv_region *entry, *next; |
5445 | 5447 | ||
5446 | list_for_each_entry_safe(entry, next, head, list) { | 5448 | list_for_each_entry_safe(entry, next, head, list) |
5447 | if (entry->type == IOMMU_RESV_MSI) | 5449 | kfree(entry); |
5448 | kfree(entry); | ||
5449 | } | ||
5450 | } | 5450 | } |
5451 | 5451 | ||
5452 | int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev) | 5452 | int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev) |