From 590f6b97ce9d808e4e738acd03dfccb392ecae9b Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 27 May 2015 17:09:34 +0100 Subject: [PATCH] iommu/arm-smmu: Fix ATS1* register writes The ATS1* address translation registers only support being written atomically - in SMMUv2 where they are 64 bits wide, 32-bit writes to the lower half are automatically zero-extended, whilst 32-bit writes to the upper half are ignored. Thus, the current logic of performing 64-bit writes as two 32-bit accesses is wrong. Since we already limit IOVAs to 32 bits on 32-bit ARM, the lack of a suitable writeq() implementation there is not an issue, and we only need a little preprocessor ugliness to safely hide the 64-bit case. Change-Id: Ice82b1276d30605d335f9400f8cc3da3e3348bb6 Signed-off-by: Robin Murphy Signed-off-by: Will Deacon Signed-off-by: Joerg Roedel [pdaly@codeaurora.org Resolve minor conflicts] --- drivers/iommu/arm-smmu.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index a5ff66d4144b..4cd58374c9ca 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -216,8 +216,7 @@ #define ARM_SMMU_CB_TLBSYNC 0x7f0 #define ARM_SMMU_CB_TLBSTATUS 0x7f4 #define TLBSTATUS_SACTIVE (1 << 0) -#define ARM_SMMU_CB_ATS1PR_LO 0x800 -#define ARM_SMMU_CB_ATS1PR_HI 0x804 +#define ARM_SMMU_CB_ATS1PR 0x800 #define ARM_SMMU_CB_ATSR 0x8f0 #define ARM_SMMU_GR1_CBFRSYNRA(n) (0x400 + ((n) << 2)) @@ -2409,6 +2408,7 @@ static phys_addr_t __arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, void __iomem *cb_base; u32 tmp; u64 phys; + unsigned long va; unsigned long flags; if (arm_smmu_enable_clocks(smmu)) @@ -2421,11 +2421,14 @@ static phys_addr_t __arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, if (do_halt && arm_smmu_halt(smmu)) goto err_unlock; - if (smmu->version == 1) - writel_relaxed(iova & ~0xfff, cb_base + ARM_SMMU_CB_ATS1PR_LO); + /* ATS1 registers can only be written atomically */ + va = iova & ~0xfffUL; +#ifdef CONFIG_64BIT + if (smmu->version == ARM_SMMU_V2) + writeq_relaxed(va, cb_base + ARM_SMMU_CB_ATS1PR); else - writeq_relaxed(iova & ~0xfffULL, - cb_base + ARM_SMMU_CB_ATS1PR_LO); +#endif + writel_relaxed(va, cb_base + ARM_SMMU_CB_ATS1PR); if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp, !(tmp & ATSR_ACTIVE), 5, 50)) {