iommu/arm-smmu: set CBARn.BPSHCFG to NSH for s1-s2-bypass contexts
authorWill Deacon <will.deacon@arm.com>
Thu, 6 Feb 2014 14:59:05 +0000 (14:59 +0000)
committerWill Deacon <will.deacon@arm.com>
Mon, 10 Feb 2014 17:02:23 +0000 (17:02 +0000)
Whilst trying to bring-up an SMMUv2 implementation with the table
walker plumbed into a coherent interconnect, I noticed that the memory
transactions targetting the CPU caches from the SMMU were marked as
outer-shareable instead of inner-shareable.

After a bunch of digging, it seems that we actually need to program
CBARn.BPSHCFG for s1-s2-bypass contexts to act as non-shareable in order
for the shareability configured in the corresponding TTBCR not to be
overridden with an outer-shareable attribute.

Cc: <stable@vger.kernel.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
drivers/iommu/arm-smmu.c

index 509f01f054d9da4f801c4aecac938884ce4bda84..0ae4dd39197f90e46cc298d9b89756dadfcf8d94 100644 (file)
 #define ARM_SMMU_GR1_CBAR(n)           (0x0 + ((n) << 2))
 #define CBAR_VMID_SHIFT                        0
 #define CBAR_VMID_MASK                 0xff
+#define CBAR_S1_BPSHCFG_SHIFT          8
+#define CBAR_S1_BPSHCFG_MASK           3
+#define CBAR_S1_BPSHCFG_NSH            3
 #define CBAR_S1_MEMATTR_SHIFT          12
 #define CBAR_S1_MEMATTR_MASK           0xf
 #define CBAR_S1_MEMATTR_WB             0xf
@@ -671,11 +674,16 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
        if (smmu->version == 1)
              reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
 
-       /* Use the weakest memory type, so it is overridden by the pte */
-       if (stage1)
-               reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
-       else
+       /*
+        * Use the weakest shareability/memory types, so they are
+        * overridden by the ttbcr/pte.
+        */
+       if (stage1) {
+               reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) |
+                       (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+       } else {
                reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT;
+       }
        writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
 
        if (smmu->version > 1) {