summaryrefslogtreecommitdiff
path: root/drivers/iommu
diff options
context:
space:
mode:
authorKrishna Reddy <vdumpa@nvidia.com>2015-03-27 11:42:40 -0700
committerWinnie Hsu <whsu@nvidia.com>2015-04-15 11:11:51 -0700
commit0ab97b0540c717428f35b9421a396e1c79937b5e (patch)
treeb7b6c263ee2ec8d20af843183e808f1a52f27f13 /drivers/iommu
parentdf86d46c835f58e0537c8c2a8d258589963d5f17 (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.c5
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);