diff options
author | Marek Szyprowski <m.szyprowski@samsung.com> | 2016-11-14 05:08:10 -0500 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2016-11-14 11:11:59 -0500 |
commit | e11723000f16419f9b0f69f15d99cf7ab37edc24 (patch) | |
tree | 7decd469bc4a25d5b64c64d035c629b5e9d33c8f | |
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>
-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) | |||
769 | spin_lock_irqsave(&domain->lock, flags); | 769 | spin_lock_irqsave(&domain->lock, flags); |
770 | 770 | ||
771 | list_for_each_entry_safe(data, next, &domain->clients, domain_node) { | 771 | list_for_each_entry_safe(data, next, &domain->clients, domain_node) { |
772 | spin_lock(&data->lock); | ||
772 | __sysmmu_disable(data); | 773 | __sysmmu_disable(data); |
773 | data->pgtable = 0; | 774 | data->pgtable = 0; |
774 | data->domain = NULL; | 775 | data->domain = NULL; |
775 | list_del_init(&data->domain_node); | 776 | list_del_init(&data->domain_node); |
777 | spin_unlock(&data->lock); | ||
776 | } | 778 | } |
777 | 779 | ||
778 | spin_unlock_irqrestore(&domain->lock, flags); | 780 | spin_unlock_irqrestore(&domain->lock, flags); |
@@ -810,17 +812,22 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, | |||
810 | if (!has_sysmmu(dev) || owner->domain != iommu_domain) | 812 | if (!has_sysmmu(dev) || owner->domain != iommu_domain) |
811 | return; | 813 | return; |
812 | 814 | ||
815 | list_for_each_entry(data, &owner->controllers, owner_node) { | ||
816 | __sysmmu_disable(data); | ||
817 | pm_runtime_put(data->sysmmu); | ||
818 | } | ||
819 | |||
813 | spin_lock_irqsave(&domain->lock, flags); | 820 | spin_lock_irqsave(&domain->lock, flags); |
814 | list_for_each_entry_safe(data, next, &domain->clients, domain_node) { | 821 | list_for_each_entry_safe(data, next, &domain->clients, domain_node) { |
815 | __sysmmu_disable(data); | 822 | spin_lock(&data->lock); |
816 | data->pgtable = 0; | 823 | data->pgtable = 0; |
817 | data->domain = NULL; | 824 | data->domain = NULL; |
818 | list_del_init(&data->domain_node); | 825 | list_del_init(&data->domain_node); |
819 | pm_runtime_put(data->sysmmu); | 826 | spin_unlock(&data->lock); |
820 | } | 827 | } |
828 | owner->domain = NULL; | ||
821 | spin_unlock_irqrestore(&domain->lock, flags); | 829 | spin_unlock_irqrestore(&domain->lock, flags); |
822 | 830 | ||
823 | owner->domain = NULL; | ||
824 | 831 | ||
825 | dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__, | 832 | dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__, |
826 | &pagetable); | 833 | &pagetable); |
@@ -841,18 +848,22 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, | |||
841 | if (owner->domain) | 848 | if (owner->domain) |
842 | exynos_iommu_detach_device(owner->domain, dev); | 849 | exynos_iommu_detach_device(owner->domain, dev); |
843 | 850 | ||
851 | spin_lock_irqsave(&domain->lock, flags); | ||
844 | list_for_each_entry(data, &owner->controllers, owner_node) { | 852 | list_for_each_entry(data, &owner->controllers, owner_node) { |
853 | spin_lock(&data->lock); | ||
845 | data->pgtable = pagetable; | 854 | data->pgtable = pagetable; |
846 | data->domain = domain; | 855 | data->domain = domain; |
856 | list_add_tail(&data->domain_node, &domain->clients); | ||
857 | spin_unlock(&data->lock); | ||
858 | } | ||
859 | owner->domain = iommu_domain; | ||
860 | spin_unlock_irqrestore(&domain->lock, flags); | ||
861 | |||
862 | list_for_each_entry(data, &owner->controllers, owner_node) { | ||
847 | pm_runtime_get_sync(data->sysmmu); | 863 | pm_runtime_get_sync(data->sysmmu); |
848 | __sysmmu_enable(data); | 864 | __sysmmu_enable(data); |
849 | |||
850 | spin_lock_irqsave(&domain->lock, flags); | ||
851 | list_add_tail(&data->domain_node, &domain->clients); | ||
852 | spin_unlock_irqrestore(&domain->lock, flags); | ||
853 | } | 865 | } |
854 | 866 | ||
855 | owner->domain = iommu_domain; | ||
856 | dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa\n", __func__, | 867 | dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa\n", __func__, |
857 | &pagetable); | 868 | &pagetable); |
858 | 869 | ||