Commit 661d962f authored by Robin Murphy's avatar Robin Murphy Committed by Joerg Roedel

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.
Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent ba155e2d
...@@ -202,8 +202,7 @@ ...@@ -202,8 +202,7 @@
#define ARM_SMMU_CB_S1_TLBIVAL 0x620 #define ARM_SMMU_CB_S1_TLBIVAL 0x620
#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 #define ARM_SMMU_CB_S2_TLBIIPAS2 0x630
#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 #define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638
#define ARM_SMMU_CB_ATS1PR_LO 0x800 #define ARM_SMMU_CB_ATS1PR 0x800
#define ARM_SMMU_CB_ATS1PR_HI 0x804
#define ARM_SMMU_CB_ATSR 0x8f0 #define ARM_SMMU_CB_ATSR 0x8f0
#define SCTLR_S1_ASIDPNE (1 << 12) #define SCTLR_S1_ASIDPNE (1 << 12)
...@@ -1229,18 +1228,18 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, ...@@ -1229,18 +1228,18 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
void __iomem *cb_base; void __iomem *cb_base;
u32 tmp; u32 tmp;
u64 phys; u64 phys;
unsigned long va;
cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
if (smmu->version == 1) { /* ATS1 registers can only be written atomically */
u32 reg = iova & ~0xfff; va = iova & ~0xfffUL;
writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO); #ifdef CONFIG_64BIT
} else { if (smmu->version == ARM_SMMU_V2)
u32 reg = iova & ~0xfff; writeq_relaxed(va, cb_base + ARM_SMMU_CB_ATS1PR);
writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO); else
reg = ((u64)iova & ~0xfff) >> 32; #endif
writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_HI); writel_relaxed(va, cb_base + ARM_SMMU_CB_ATS1PR);
}
if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp, if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp,
!(tmp & ATSR_ACTIVE), 5, 50)) { !(tmp & ATSR_ACTIVE), 5, 50)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment