[PATCH V2] iommu/arm-smmu-v2: Workaround for ThunderX errata#27704

2016-02-18 Thread tchalamarla
From: Tirumalesh Chalamarla 

Due 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

2016-02-18 Thread tchalamarla
From: Tirumalesh Chalamarla 

ARM-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

2016-02-05 Thread tchalamarla
From: Tirumalesh Chalamarla 

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.

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

2015-08-18 Thread tchalamarla
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

2015-08-17 Thread tchalamarla
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

2015-08-03 Thread tchalamarla
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