iommu/arm-smmu-v3: Avoid ILLEGAL setting of STE.S1STALLD and CD.S
[sfrench/cifs-2.6.git] / drivers / iommu / arm-smmu-v3.c
index 80532d9ecaaf49481fb54e438e33c1eb9f69c7aa..159117e2c5ad378e20d6359e45c0f998bd28dd0a 100644 (file)
 #define ARM64_TCR_TBI0_MASK            0x1UL
 
 #define CTXDESC_CD_0_AA64              (1UL << 41)
+#define CTXDESC_CD_0_S                 (1UL << 44)
 #define CTXDESC_CD_0_R                 (1UL << 45)
 #define CTXDESC_CD_0_A                 (1UL << 46)
 #define CTXDESC_CD_0_ASET_SHIFT                47
@@ -595,6 +596,7 @@ struct arm_smmu_device {
 #define ARM_SMMU_FEAT_TRANS_S2         (1 << 10)
 #define ARM_SMMU_FEAT_STALLS           (1 << 11)
 #define ARM_SMMU_FEAT_HYP              (1 << 12)
+#define ARM_SMMU_FEAT_STALL_FORCE      (1 << 13)
        u32                             features;
 
 #define ARM_SMMU_OPT_SKIP_PREFETCH     (1 << 0)
@@ -987,6 +989,11 @@ static void arm_smmu_write_ctx_desc(struct arm_smmu_device *smmu,
              CTXDESC_CD_0_R | CTXDESC_CD_0_A | CTXDESC_CD_0_ASET_PRIVATE |
              CTXDESC_CD_0_AA64 | (u64)cfg->cd.asid << CTXDESC_CD_0_ASID_SHIFT |
              CTXDESC_CD_0_V;
+
+       /* STALL_MODEL==0b10 && CD.S==0 is ILLEGAL */
+       if (smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
+               val |= CTXDESC_CD_0_S;
+
        cfg->cdptr[0] = cpu_to_le64(val);
 
        val = cfg->cd.ttbr & CTXDESC_CD_1_TTB0_MASK << CTXDESC_CD_1_TTB0_SHIFT;
@@ -1107,7 +1114,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid,
 #endif
                         STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT);
 
-               if (smmu->features & ARM_SMMU_FEAT_STALLS)
+               if (smmu->features & ARM_SMMU_FEAT_STALLS &&
+                  !(smmu->features & ARM_SMMU_FEAT_STALL_FORCE))
                        dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
 
                val |= (ste->s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK
@@ -2531,9 +2539,10 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
                         coherent ? "true" : "false");
 
        switch (reg & IDR0_STALL_MODEL_MASK << IDR0_STALL_MODEL_SHIFT) {
-       case IDR0_STALL_MODEL_STALL:
-               /* Fallthrough */
        case IDR0_STALL_MODEL_FORCE:
+               smmu->features |= ARM_SMMU_FEAT_STALL_FORCE;
+               /* Fallthrough */
+       case IDR0_STALL_MODEL_STALL:
                smmu->features |= ARM_SMMU_FEAT_STALLS;
        }