iommu/arm-smmu: workaround some ATOS hw errata

qcom,smmuv2 has a hardware errata that requires that the SMMU be halted
during atos operations

Change-Id: Ic40c7b93d64eebb97fe77082d8335debab624af1
Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
Signed-off-by: Patrick Daly <pdaly@codeaurora.org>
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index c2a890e..6ae647e 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -447,6 +447,9 @@
 	{ 0, NULL},
 };
 
+static int arm_smmu_halt(struct arm_smmu_device *smmu);
+static void arm_smmu_resume(struct arm_smmu_device *smmu);
+
 static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 {
 	return container_of(dom, struct arm_smmu_domain, domain);
@@ -1320,6 +1323,11 @@
 	unsigned long va;
 
 	spin_lock_irqsave(&smmu->atos_lock, flags);
+	if (arm_smmu_halt(smmu)) {
+		phys = 0;
+		goto out_unlock;
+	}
+
 	cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
 
 	/* ATS1 registers can only be written atomically */
@@ -1334,20 +1342,23 @@
 		dev_err(dev,
 			"iova to phys timed out on %pad. Falling back to software table walk.\n",
 			&iova);
-		spin_unlock_irqrestore(&smmu->atos_lock, flags);
-		return ops->iova_to_phys(ops, iova);
+		phys = ops->iova_to_phys(ops, iova);
+		goto out_resume;
 	}
 
 	phys = readq_relaxed(cb_base + ARM_SMMU_CB_PAR);
 	if (phys & CB_PAR_F) {
 		dev_err(dev, "translation fault!\n");
 		dev_err(dev, "PAR = 0x%llx\n", phys);
-		spin_unlock_irqrestore(&smmu->atos_lock, flags);
-		return 0;
+		phys = 0;
+	} else {
+		phys = (phys & (PHYS_MASK & ~0xfffULL)) | (iova & 0xfff);
 	}
-
+out_resume:
+	arm_smmu_resume(smmu);
+out_unlock:
 	spin_unlock_irqrestore(&smmu->atos_lock, flags);
-	return (phys & (PHYS_MASK & ~0xfffULL)) | (iova & 0xfff);
+	return phys;
 }
 
 static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,