diff options
author | Krishna Reddy <vdumpa@nvidia.com> | 2015-03-27 11:42:40 -0700 |
---|---|---|
committer | Winnie Hsu <whsu@nvidia.com> | 2015-04-15 11:11:51 -0700 |
commit | 0ab97b0540c717428f35b9421a396e1c79937b5e (patch) | |
tree | b7b6c263ee2ec8d20af843183e808f1a52f27f13 /drivers/iommu | |
parent | df86d46c835f58e0537c8c2a8d258589963d5f17 (diff) |
iommu/tegra: smmu: Fix race condition in writing PTC registers
Fix race condition in programming PTC flush registers.
This race condition results in PTC flush not happening as intended and
can cause either SMMU fault or previous stale mapping access.
Bug 1625885
Bug 1603840
Change-Id: Ie94a8cfe947d8363a252f05dcd98fac10920586a
Signed-off-by: Krishna Reddy <vdumpa@nvidia.com>
Reviewed-on: http://git-master/r/724503
Reviewed-by: Hiroshi Doyu <hdoyu@nvidia.com>
Tested-by: Hiroshi Doyu <hdoyu@nvidia.com>
GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/tegra-smmu.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 93986d6eddb5..0db793621eae 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -297,6 +297,7 @@ struct smmu_device { unsigned long iovmm_base; /* remappable base address */ unsigned long page_count; /* total remappable size */ spinlock_t lock; + spinlock_t ptc_lock; char *name; struct device *dev; u64 swgids; /* memory client ID bitmap */ @@ -548,12 +549,14 @@ static void __smmu_flush_ptc(struct smmu_device *smmu, u32 *pte, struct page *page) { u32 val; + ulong flags; if (!pte) { smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH); return; } + spin_lock_irqsave(&smmu->ptc_lock, flags); if ((IS_ENABLED(CONFIG_ARCH_TEGRA_12x_SOC) && (tegra_get_chipid() == TEGRA_CHIPID_TEGRA12)) || (IS_ENABLED(CONFIG_ARCH_TEGRA_13x_SOC) && @@ -566,6 +569,7 @@ static void __smmu_flush_ptc(struct smmu_device *smmu, u32 *pte, (VA_PAGE_TO_PA(pte, page) & SMMU_PTC_FLUSH_ADR_MASK); smmu_write(smmu, val, SMMU_PTC_FLUSH); + spin_unlock_irqrestore(&smmu->ptc_lock, flags); } static void smmu_flush_ptc(struct smmu_device *smmu, u32 *pte, @@ -1955,6 +1959,7 @@ static int tegra_smmu_probe(struct platform_device *pdev) INIT_LIST_HEAD(&as->client); } spin_lock_init(&smmu->lock); + spin_lock_init(&smmu->ptc_lock); smmu_setup_regs(smmu); platform_set_drvdata(pdev, smmu); |