diff options
author | Marek Szyprowski <m.szyprowski@samsung.com> | 2016-11-14 11:08:10 +0100 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-11-14 17:11:59 +0100 |
commit | e11723000f16419f9b0f69f15d99cf7ab37edc24 (patch) | |
tree | 7decd469bc4a25d5b64c64d035c629b5e9d33c8f /drivers/iommu | |
parent | 92798b4566b1adcf2e259b3116c38553fe655852 (diff) |
iommu/exynos: Rework and fix internal locking
This patch reworks locking in the exynos_iommu_attach/detach_device
functions to ensure that all entries of the sysmmu_drvdata and
exynos_iommu_owner structure are updated under the respective spinlocks,
while runtime pm functions are called without any spinlocks held.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/exynos-iommu.c | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 52ded8461a74..0423dff206d4 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -769,10 +769,12 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) spin_lock_irqsave(&domain->lock, flags); list_for_each_entry_safe(data, next, &domain->clients, domain_node) { + spin_lock(&data->lock); __sysmmu_disable(data); data->pgtable = 0; data->domain = NULL; list_del_init(&data->domain_node); + spin_unlock(&data->lock); } spin_unlock_irqrestore(&domain->lock, flags); @@ -810,17 +812,22 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, if (!has_sysmmu(dev) || owner->domain != iommu_domain) return; + list_for_each_entry(data, &owner->controllers, owner_node) { + __sysmmu_disable(data); + pm_runtime_put(data->sysmmu); + } + spin_lock_irqsave(&domain->lock, flags); list_for_each_entry_safe(data, next, &domain->clients, domain_node) { - __sysmmu_disable(data); + spin_lock(&data->lock); data->pgtable = 0; data->domain = NULL; list_del_init(&data->domain_node); - pm_runtime_put(data->sysmmu); + spin_unlock(&data->lock); } + owner->domain = NULL; spin_unlock_irqrestore(&domain->lock, flags); - owner->domain = NULL; dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__, &pagetable); @@ -841,18 +848,22 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, if (owner->domain) exynos_iommu_detach_device(owner->domain, dev); + spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(data, &owner->controllers, owner_node) { + spin_lock(&data->lock); data->pgtable = pagetable; data->domain = domain; + list_add_tail(&data->domain_node, &domain->clients); + spin_unlock(&data->lock); + } + owner->domain = iommu_domain; + spin_unlock_irqrestore(&domain->lock, flags); + + list_for_each_entry(data, &owner->controllers, owner_node) { pm_runtime_get_sync(data->sysmmu); __sysmmu_enable(data); - - spin_lock_irqsave(&domain->lock, flags); - list_add_tail(&data->domain_node, &domain->clients); - spin_unlock_irqrestore(&domain->lock, flags); } - owner->domain = iommu_domain; dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa\n", __func__, &pagetable); |