[PATCH V2] iommu/arm-smmu-v2: Workaround for ThunderX errata#27704
From: Tirumalesh ChalamarlaDue to Errata#27704 CN88xx SMMUv2,supports only shared ASID and VMID namespaces; specifically within a given node SMMU0 and SMMU1 share, as does SMMU2 and SMMU3. This patch tries to address these issuee by supplying asid and vmid base from devicetree. changes from V1: - rebased on top of 16 bit VMID patch - removed redundent options from DT - insted of transform, DT now supplies starting ASID/VMID Signed-off-by: Akula Geethasowjanya Signed-off-by: Tirumalesh Chalamarla --- .../devicetree/bindings/iommu/arm,smmu.txt | 8 + drivers/iommu/arm-smmu.c | 37 +++--- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index bb7e569..80b8484 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -57,6 +57,14 @@ conditions. - smmu-enable-vmid16 : Enable 16 bit VMID, if allowed. +- asid-base : Buggy SMMUv2 implementations which doesn't satisfy the + ASID namespace needs, use this field to specify starting + ASID for the SMMU. + +- vmid-base : Buggy SMMUv2 implementations which doesn't satisfy the VMID + namespace needs, use this field to specify starting VMID + for the SMMU. + Example: smmu { diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 003c442..dc46b9a 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -320,6 +320,9 @@ struct arm_smmu_device { unsigned long ipa_size; unsigned long pa_size; + u32 asid_base; + u32 vmid_base; + u32 num_global_irqs; u32 num_context_irqs; unsigned int*irqs; @@ -335,8 +338,8 @@ struct arm_smmu_cfg { }; #define INVALID_IRPTNDX0xff -#define ARM_SMMU_CB_ASID(cfg) ((cfg)->cbndx) -#define ARM_SMMU_CB_VMID(cfg) ((cfg)->cbndx + 1) +#define ARM_SMMU_CB_ASID(smmu, cfg)((u16)((smmu)->asid_base + (cfg)->cbndx)) +#define ARM_SMMU_CB_VMID(smmu, cfg)((u16)((smmu)->vmid_base + (cfg)->cbndx)) enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_S1 = 0, @@ -576,11 +579,11 @@ static void arm_smmu_tlb_inv_context(void *cookie) if (stage1) { base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); - writel_relaxed(ARM_SMMU_CB_ASID(cfg), + writel_relaxed(ARM_SMMU_CB_ASID(smmu, cfg), base + ARM_SMMU_CB_S1_TLBIASID); } else { base = ARM_SMMU_GR0(smmu); - writel_relaxed(ARM_SMMU_CB_VMID(cfg), + writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), base + ARM_SMMU_GR0_TLBIVMID); } @@ -602,7 +605,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, if (!IS_ENABLED(CONFIG_64BIT) || smmu->version == ARM_SMMU_V1) { iova &= ~12UL; - iova |= ARM_SMMU_CB_ASID(cfg); + iova |= ARM_SMMU_CB_ASID(smmu, cfg); do { writel_relaxed(iova, reg); iova += granule; @@ -610,7 +613,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, #ifdef CONFIG_64BIT } else { iova >>= 12; - iova |= (u64)ARM_SMMU_CB_ASID(cfg) << 48; + iova |= (u64)ARM_SMMU_CB_ASID(smmu, cfg) << 48; do { writeq_relaxed(iova, reg); iova += granule >> 12; @@ -630,7 +633,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, #endif } else { reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID; - writel_relaxed(ARM_SMMU_CB_VMID(cfg), reg); + writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), reg); } } @@ -744,7 +747,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, #endif /* if 16bit VMID required set VMID in CBA2R */ if (smmu->options & ARM_SMMU_OPT_ENABLE_VMID16) - reg |= ARM_SMMU_CB_VMID(cfg) << CBA2R_VMID_SHIFT; + reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBA2R_VMID_SHIFT; writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx)); } @@ -763,7 +766,7 @@ static void
[PATCH] iommu/arm-smmu-v2: Add support for 16 bit VMID
From: Tirumalesh ChalamarlaARM-SMMUv2 supports upto 16 bit VMID. This patch enables 16 bit VMID when requested from device-tree. Signed-off-by: Tirumalesh Chalamarla --- .../devicetree/bindings/iommu/arm,smmu.txt | 2 ++ drivers/iommu/arm-smmu.c| 21 - 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 7180745..bb7e569 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -55,6 +55,8 @@ conditions. aliases of secure registers have to be used during SMMU configuration. +- smmu-enable-vmid16 : Enable 16 bit VMID, if allowed. + Example: smmu { diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 59ee4b8..003c442 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -93,6 +93,7 @@ #define sCR0_VMIDPNE (1 << 11) #define sCR0_PTM (1 << 12) #define sCR0_FB(1 << 13) +#define sCR0_VMID16EN (1 << 31) #define sCR0_BSU_SHIFT 14 #define sCR0_BSU_MASK 0x3 @@ -140,6 +141,7 @@ #define ID2_PTFS_4K(1 << 12) #define ID2_PTFS_16K (1 << 13) #define ID2_PTFS_64K (1 << 14) +#define ID2_VMID16 (1 << 15) /* Global TLB invalidation */ #define ARM_SMMU_GR0_TLBIVMID 0x64 @@ -189,6 +191,8 @@ #define ARM_SMMU_GR1_CBA2R(n) (0x800 + ((n) << 2)) #define CBA2R_RW64_32BIT (0 << 0) #define CBA2R_RW64_64BIT (1 << 0) +#define CBA2R_VMID_SHIFT 16 +#define CBA2R_VMID_MASK0x /* Translation context bank */ #define ARM_SMMU_CB_BASE(smmu) ((smmu)->base + ((smmu)->size >> 1)) @@ -300,6 +304,7 @@ struct arm_smmu_device { u32 features; #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0) +#define ARM_SMMU_OPT_ENABLE_VMID16 (1 << 1) u32 options; enum arm_smmu_arch_version version; @@ -361,6 +366,7 @@ struct arm_smmu_option_prop { static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" }, + { ARM_SMMU_OPT_ENABLE_VMID16, "smmu-enable-vmid16" }, { 0, NULL}, }; @@ -736,6 +742,10 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, #else reg = CBA2R_RW64_32BIT; #endif + /* if 16bit VMID required set VMID in CBA2R */ + if (smmu->options & ARM_SMMU_OPT_ENABLE_VMID16) + reg |= ARM_SMMU_CB_VMID(cfg) << CBA2R_VMID_SHIFT; + writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx)); } @@ -751,7 +761,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, if (stage1) { reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) | (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); - } else { + } else if (!(smmu->options & ARM_SMMU_OPT_ENABLE_VMID16)) { + /*16 bit VMID is not enabled set 8 bit VMID here */ reg |= ARM_SMMU_CB_VMID(cfg) << CBAR_VMID_SHIFT; } writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx)); @@ -1508,6 +1519,14 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) /* Don't upgrade barriers */ reg &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT); + /* See if 16bit VMID is required */ + if (smmu->options & ARM_SMMU_OPT_ENABLE_VMID16) { + u32 id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2); + /* Check to see if HW accepts */ + if (id & ID2_VMID16) + reg |= (sCR0_VMID16EN); + } + /* Push the button */ __arm_smmu_tlb_sync(smmu); writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); -- 2.1.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH] iommu/arm-smmu-v2: Workaround for ThunderX errata#27704
From: Tirumalesh ChalamarlaAn issue exists whereby the Linux kernel requires that ASIDs are a unique namespace per SMMU. That ASID-local choice conflicts with the CN88xx SMMU, where only shared ASID namespaces are supported; specifically within a given node SMMU0 and SMMU1 share, as does SMMU2 and SMMU3. CN88xx SMMU also requires global VMIDs. This patch tries to address these issuee by supplying asid and vmid transformations from devicetree. Signed-off-by: Akula Geethasowjanya Signed-off-by: Tirumalesh Chalamarla --- .../devicetree/bindings/iommu/arm,smmu.txt | 16 ++ drivers/iommu/arm-smmu.c | 59 ++ 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 7180745..eef06d0 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -55,6 +55,22 @@ conditions. aliases of secure registers have to be used during SMMU configuration. +- thunderx,smmu-asid-transform : Enable proper handling for buggy + implementations that require special transformations + for smmu asid. if this property exists asid-transform + property must be present. + +- thunderx,smmu-vmid-transform : Enable proper handling for buggy + implementations that require special transformations + for smmu vmid. if this property exists vmid-transform + property must be present. + +- asid-transform : Transform mask that needs to be applied to asid. + This property has to be specified as '/bits/ 8' value. + +- vmid-transform : Transform mask that needs to be applied to vmid. + This property has to be specified as '/bits/ 8' value. + Example: smmu { diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 59ee4b8..8047834 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -300,8 +300,12 @@ struct arm_smmu_device { u32 features; #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0) +#define ARM_SMMU_OPT_TRANSFORM_ASID(1 << 1) +#define ARM_SMMU_OPT_TRANSFORM_VMID(1 << 2) u32 options; enum arm_smmu_arch_version version; + u8 asid_transform; + u8 vmid_transform; u32 num_context_banks; u32 num_s2_context_banks; @@ -330,8 +334,25 @@ struct arm_smmu_cfg { }; #define INVALID_IRPTNDX0xff -#define ARM_SMMU_CB_ASID(cfg) ((cfg)->cbndx) -#define ARM_SMMU_CB_VMID(cfg) ((cfg)->cbndx + 1) +/* + * ThunderX has a unique requirement because of ERRATA#27704 + * An issue exists whereby the Linux kernel requires that ASIDs are a + * unique namespace per SMMU. That ASID-local choice conflicts with the + * CN88xx SMMU, where only shared ASID namespaces are supported; + * specifically within a given node SMMU0 and SMMU1 share, as does SMMU2 + * and SMMU3. + * CN88xx SMMU also requires global VMIDs. + */ + +#define ARM_SMMU_CB_ASID(smmu, cfg)\ + (((smmu)->options & ARM_SMMU_OPT_TRANSFORM_ASID)\ + ? ((cfg)->cbndx | (smmu)->asid_transform) \ + : ((cfg)->cbndx)) + +#define ARM_SMMU_CB_VMID(smmu, cfg)\ + (((smmu)->options & ARM_SMMU_OPT_TRANSFORM_VMID)\ + ? (((cfg)->cbndx + 1) | (smmu)->vmid_transform) \ + : ((cfg)->cbndx + 1)) enum arm_smmu_domain_stage { ARM_SMMU_DOMAIN_S1 = 0, @@ -361,6 +382,8 @@ struct arm_smmu_option_prop { static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_SECURE_CFG_ACCESS, "calxeda,smmu-secure-config-access" }, + { ARM_SMMU_OPT_TRANSFORM_ASID, "thunderx,smmu-asid-transform" }, + { ARM_SMMU_OPT_TRANSFORM_VMID, "thunderx,smmu-vmid-transform" }, { 0, NULL}, }; @@ -570,11 +593,11 @@ static void arm_smmu_tlb_inv_context(void *cookie) if (stage1) { base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); - writel_relaxed(ARM_SMMU_CB_ASID(cfg), + writel_relaxed(ARM_SMMU_CB_ASID(smmu, cfg), base + ARM_SMMU_CB_S1_TLBIASID); } else { base = ARM_SMMU_GR0(smmu); - writel_relaxed(ARM_SMMU_CB_VMID(cfg), + writel_relaxed(ARM_SMMU_CB_VMID(smmu, cfg), base +
[PATCH V4] iommu/arm-smmu-v2: ThunderX mis-extends 64bit registers
From: Tirumalesh Chalamarla tchalama...@caviumnetworks.com The SMMU architecture defines two different behaviors when 64-bit registers are written with 32-bit writes. The first behavior causes zero extension into the upper 32-bits. The second behavior splits a 64-bit register into normal 32-bit register pairs. On some buggy implementations, registers incorrectly zero extended when they should instead behave as normal 32-bit register pairs. Signed-off-by: Tirumalesh Chalamarla tchalama...@caviumnetworks.com Changes from V3: - rebased on iommu/devel Changes from V2: - removed unused definitions Changes from V1: - Introduced smmu_writeq --- drivers/iommu/arm-smmu.c | 50 ++-- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 48a39df..b58bfa4 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -70,6 +70,18 @@ ((smmu-options ARM_SMMU_OPT_SECURE_CFG_ACCESS) \ ? 0x400 : 0)) +#ifdef CONFIG_64BIT +#define smmu_writeq(reg64, addr) writeq_relaxed((reg64), (addr)) +#else +#define smmu_writeq(reg64, addr) \ + do {\ + u64 __val = (reg64);\ + void __iomem *__addr = (addr); \ + writel_relaxed(__val 32, __addr + 4);\ + writel_relaxed(__val, __addr); \ + } while (0) +#endif + /* Configuration registers */ #define ARM_SMMU_GR0_sCR0 0x0 #define sCR0_CLIENTPD (1 0) @@ -185,10 +197,8 @@ #define ARM_SMMU_CB_SCTLR 0x0 #define ARM_SMMU_CB_RESUME 0x8 #define ARM_SMMU_CB_TTBCR2 0x10 -#define ARM_SMMU_CB_TTBR0_LO 0x20 -#define ARM_SMMU_CB_TTBR0_HI 0x24 -#define ARM_SMMU_CB_TTBR1_LO 0x28 -#define ARM_SMMU_CB_TTBR1_HI 0x2c +#define ARM_SMMU_CB_TTBR0 0x20 +#define ARM_SMMU_CB_TTBR1 0x28 #define ARM_SMMU_CB_TTBCR 0x30 #define ARM_SMMU_CB_S1_MAIR0 0x38 #define ARM_SMMU_CB_S1_MAIR1 0x3c @@ -226,7 +236,7 @@ #define TTBCR2_SEP_SHIFT 15 #define TTBCR2_SEP_UPSTREAM(0x7 TTBCR2_SEP_SHIFT) -#define TTBRn_HI_ASID_SHIFT16 +#define TTBRn_ASID_SHIFT 48 #define FSR_MULTI (1 31) #define FSR_SS (1 30) @@ -695,6 +705,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, struct io_pgtable_cfg *pgtbl_cfg) { u32 reg; + u64 reg64; bool stage1; struct arm_smmu_cfg *cfg = smmu_domain-cfg; struct arm_smmu_device *smmu = smmu_domain-smmu; @@ -738,22 +749,17 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, /* TTBRs */ if (stage1) { - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0] 32; - reg |= ARM_SMMU_CB_ASID(cfg) TTBRn_HI_ASID_SHIFT; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); - - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_LO); - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1] 32; - reg |= ARM_SMMU_CB_ASID(cfg) TTBRn_HI_ASID_SHIFT; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_HI); + reg64 = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0]; + + reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) TTBRn_ASID_SHIFT; + smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0); + + reg64 = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1]; + reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) TTBRn_ASID_SHIFT; + smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR1); } else { - reg = pgtbl_cfg-arm_lpae_s2_cfg.vttbr; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); - reg = pgtbl_cfg-arm_lpae_s2_cfg.vttbr 32; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); + reg64 = pgtbl_cfg-arm_lpae_s2_cfg.vttbr; + smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0); } /* TTBCR */ @@ -1212,11 +1218,9 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain, /* 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); + smmu_writeq(va, cb_base + ARM_SMMU_CB_ATS1PR); else -#endif
[PATCH V3] iommu/arm-smmu-v2: ThunderX mis-extends 64bit registers
From: Tirumalesh Chalamarla tchalama...@caviumnetworks.com The SMMU architecture defines two different behaviors when 64-bit registers are written with 32-bit writes. The first behavior causes zero extension into the upper 32-bits. The second behavior splits a 64-bit register into normal 32-bit register pairs. On some buggy implementations, registers incorrectly zero extended when they should instead behave as normal 32-bit register pairs. Signed-off-by: Tirumalesh Chalamarla tchalama...@caviumnetworks.com Changes from V2: - removed unused definitions Changes from V1: - Introduced smmu_writeq --- drivers/iommu/arm-smmu.c | 57 +--- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 66a803b..26572d6 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -69,6 +69,18 @@ ((smmu-options ARM_SMMU_OPT_SECURE_CFG_ACCESS) \ ? 0x400 : 0)) +#ifdef CONFIG_64BIT +#define smmu_writeq(reg64, addr) writeq_relaxed((reg64), (addr)) +#else +#define smmu_writeq(reg64, addr) \ + do {\ + u64 __val = (reg64);\ + void __iomem *__addr = (addr); \ + writel_relaxed(__val 32, __addr + 4);\ + writel_relaxed(__val, __addr); \ + } while (0) +#endif + /* Configuration registers */ #define ARM_SMMU_GR0_sCR0 0x0 #define sCR0_CLIENTPD (1 0) @@ -184,10 +196,8 @@ #define ARM_SMMU_CB_SCTLR 0x0 #define ARM_SMMU_CB_RESUME 0x8 #define ARM_SMMU_CB_TTBCR2 0x10 -#define ARM_SMMU_CB_TTBR0_LO 0x20 -#define ARM_SMMU_CB_TTBR0_HI 0x24 -#define ARM_SMMU_CB_TTBR1_LO 0x28 -#define ARM_SMMU_CB_TTBR1_HI 0x2c +#define ARM_SMMU_CB_TTBR0 0x20 +#define ARM_SMMU_CB_TTBR1 0x28 #define ARM_SMMU_CB_TTBCR 0x30 #define ARM_SMMU_CB_S1_MAIR0 0x38 #define ARM_SMMU_CB_S1_MAIR1 0x3c @@ -202,8 +212,7 @@ #define ARM_SMMU_CB_S1_TLBIVAL 0x620 #define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 #define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 -#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 SCTLR_S1_ASIDPNE (1 12) @@ -226,7 +235,7 @@ #define TTBCR2_SEP_SHIFT 15 #define TTBCR2_SEP_UPSTREAM(0x7 TTBCR2_SEP_SHIFT) -#define TTBRn_HI_ASID_SHIFT16 +#define TTBRn_ASID_SHIFT 48 #define FSR_MULTI (1 31) #define FSR_SS (1 30) @@ -719,6 +728,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, struct io_pgtable_cfg *pgtbl_cfg) { u32 reg; + u64 reg64; bool stage1; struct arm_smmu_cfg *cfg = smmu_domain-cfg; struct arm_smmu_device *smmu = smmu_domain-smmu; @@ -762,22 +772,17 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, /* TTBRs */ if (stage1) { - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0] 32; - reg |= ARM_SMMU_CB_ASID(cfg) TTBRn_HI_ASID_SHIFT; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); - - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_LO); - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1] 32; - reg |= ARM_SMMU_CB_ASID(cfg) TTBRn_HI_ASID_SHIFT; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_HI); + reg64 = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0]; + + reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) TTBRn_ASID_SHIFT; + smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0); + + reg64 = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1]; + reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) TTBRn_ASID_SHIFT; + smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR1); } else { - reg = pgtbl_cfg-arm_lpae_s2_cfg.vttbr; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); - reg = pgtbl_cfg-arm_lpae_s2_cfg.vttbr 32; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); + reg64 = pgtbl_cfg-arm_lpae_s2_cfg.vttbr; + smmu_writeq(reg64, cb_base + ARM_SMMU_CB_TTBR0); } /* TTBCR */ @@ -1234,12 +1239,10 @@ static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain
[PATCH] iommu/arm-smmu-v2: ThunderX(errata-23399) mis-extends 64bit registers
From: Tirumalesh Chalamarla tchalama...@caviumnetworks.com The SMMU architecture defines two different behaviors when 64-bit registers are written with 32-bit writes. The first behavior causes zero extension into the upper 32-bits. The second behavior splits a 64-bit register into normal 32-bit register pairs. On some passes of ThunderX, the following registers incorrectly zero extended when they should instead behave as normal 32-bit register pairs: SMMU()_(S)GFAR SMMU()_NSGFAR SMMU()_CB()_TTBR0 SMMU()_CB()_TTBR1 SMMU()_CB()_FAR Signed-off-by: Tirumalesh Chalamarla tchalama...@caviumnetworks.com --- drivers/iommu/arm-smmu.c | 51 ++-- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 66a803b..7a3cf7f 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -290,6 +290,7 @@ struct arm_smmu_device { u32 features; #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 0) +#define ARM_SMMU_OPT_64BIT_WRITES_ONLY (1 1) u32 options; enum arm_smmu_arch_version version; @@ -351,6 +352,8 @@ struct arm_smmu_option_prop { static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_SECURE_CFG_ACCESS, calxeda,smmu-secure-config-access }, + /* ThunderX errata 23399 */ + { ARM_SMMU_OPT_64BIT_WRITES_ONLY, thunderx,smmu-64-bit-writes-only }, { 0, NULL}, }; @@ -719,6 +722,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, struct io_pgtable_cfg *pgtbl_cfg) { u32 reg; + u64 reg64; bool stage1; struct arm_smmu_cfg *cfg = smmu_domain-cfg; struct arm_smmu_device *smmu = smmu_domain-smmu; @@ -762,22 +766,39 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, /* TTBRs */ if (stage1) { - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0] 32; - reg |= ARM_SMMU_CB_ASID(cfg) TTBRn_HI_ASID_SHIFT; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); - - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_LO); - reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1] 32; - reg |= ARM_SMMU_CB_ASID(cfg) TTBRn_HI_ASID_SHIFT; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_HI); + if (smmu-options ARM_SMMU_OPT_64BIT_WRITES_ONLY) { + reg64 = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0]; + reg64 |= ((u64) ARM_SMMU_CB_ASID(cfg)) + (TTBRn_HI_ASID_SHIFT + 32); + writeq_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); + + reg64 = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1]; + reg64 |= ((u64)ARM_SMMU_CB_ASID(cfg)) + (TTBRn_HI_ASID_SHIFT + 32); + writeq_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_LO); + } else { + reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0]; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); + reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[0] 32; + reg |= ARM_SMMU_CB_ASID(cfg) TTBRn_HI_ASID_SHIFT; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); + + reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1]; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_LO); + reg = pgtbl_cfg-arm_lpae_s1_cfg.ttbr[1] 32; + reg |= ARM_SMMU_CB_ASID(cfg) TTBRn_HI_ASID_SHIFT; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_HI); + } } else { - reg = pgtbl_cfg-arm_lpae_s2_cfg.vttbr; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); - reg = pgtbl_cfg-arm_lpae_s2_cfg.vttbr 32; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); + if (smmu-options ARM_SMMU_OPT_64BIT_WRITES_ONLY) { + reg64 = pgtbl_cfg-arm_lpae_s2_cfg.vttbr; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); + } else { + reg = pgtbl_cfg-arm_lpae_s2_cfg.vttbr; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); + reg = pgtbl_cfg-arm_lpae_s2_cfg.vttbr 32; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI); + } } /* TTBCR */ -- 2.1.0 ___ iommu mailing list