summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchel Humpherys <mitchelh@codeaurora.org>2014-09-30 16:15:45 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:11:14 -0700
commitc52f08085e88a299219cce1476bc38665158fe1b (patch)
tree9eb124c1e835216c651a66975991c25730a90c74
parent5ce5498b6628697d34349d063951f2b9e90e69e4 (diff)
iommu/arm-smmu: lock the domain during ATOS
Currently there could be races between different domains performing an ATOS operation. Fix this by taking the domain lock around the ATOS. Change-Id: I32e6e0a0c67ce82aff5abfc892098c684d399b2d Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
-rw-r--r--drivers/iommu/arm-smmu.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index c49a10c27dc6..4fbdda71c987 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -246,7 +246,6 @@
#define ARM_SMMU_CB_ATS1PR_LO 0x800
#define ARM_SMMU_CB_ATS1PR_HI 0x804
#define ARM_SMMU_CB_ATSR 0x8f0
-#define ATSR_LOOP_TIMEOUT 1000000 /* 1s! */
#define SCTLR_S1_ASIDPNE (1 << 12)
#define SCTLR_CFCFG (1 << 7)
@@ -1817,11 +1816,14 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
void __iomem *cb_base;
u32 tmp;
u64 phys;
+ unsigned long flags;
arm_smmu_enable_clocks(smmu);
cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ spin_lock_irqsave(&smmu_domain->lock, flags);
+
if (smmu->version == 1) {
u32 reg = iova & ~0xfff;
writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO);
@@ -1832,8 +1834,9 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_HI);
}
- if (readl_poll_timeout(cb_base + ARM_SMMU_CB_ATSR, tmp,
- !(tmp & ATSR_ACTIVE), 10, ATSR_LOOP_TIMEOUT)) {
+ if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp,
+ !(tmp & ATSR_ACTIVE), 10, 5)) {
+ spin_unlock_irqrestore(&smmu_domain->lock, flags);
dev_err(dev,
"iova to phys timed out on 0x%pa for %s. Falling back to software table walk.\n",
&iova, dev_name(dev));
@@ -1844,6 +1847,8 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
phys = readl_relaxed(cb_base + ARM_SMMU_CB_PAR_LO);
phys |= ((u64) readl_relaxed(cb_base + ARM_SMMU_CB_PAR_HI)) << 32;
+ spin_unlock_irqrestore(&smmu_domain->lock, flags);
+
if (phys & CB_PAR_F) {
dev_err(dev, "translation fault on %s!\n", dev_name(dev));
dev_err(dev, "PAR = 0x%llx\n", phys);