The SMMUv3 can handle invalidation targeted at TLB entries with shared
ASIDs. If the implementation supports broadcast TLB maintenance, enable it
and keep track of it in a feature bit. The SMMU will then be affected by
inner-shareable TLB invalidations from other agents.

A major side-effect of this change is that stage-2 translation contexts
are now affected by all invalidations by VMID. VMIDs are all shared and
the only ways to prevent over-invalidation, since the stage-2 page tables
are not shared between CPU and SMMU, are to either disable BTM or allocate
different VMIDs. This patch does not address the problem.

Signed-off-by: Jean-Philippe Brucker <jean-phili...@linaro.org>
---
 drivers/iommu/arm-smmu-v3.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 7e1933e7e35f..9332253e3608 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -56,6 +56,7 @@
 #define IDR0_ASID16                    (1 << 12)
 #define IDR0_ATS                       (1 << 10)
 #define IDR0_HYP                       (1 << 9)
+#define IDR0_BTM                       (1 << 5)
 #define IDR0_COHACC                    (1 << 4)
 #define IDR0_TTF                       GENMASK(3, 2)
 #define IDR0_TTF_AARCH64               2
@@ -658,6 +659,7 @@ struct arm_smmu_device {
 #define ARM_SMMU_FEAT_VAX              (1 << 14)
 #define ARM_SMMU_FEAT_RANGE_INV                (1 << 15)
 #define ARM_SMMU_FEAT_E2H              (1 << 16)
+#define ARM_SMMU_FEAT_BTM              (1 << 17)
        u32                             features;
 
 #define ARM_SMMU_OPT_SKIP_PREFETCH     (1 << 0)
@@ -3819,11 +3821,14 @@ static int arm_smmu_device_reset(struct arm_smmu_device 
*smmu, bool bypass)
        writel_relaxed(reg, smmu->base + ARM_SMMU_CR1);
 
        /* CR2 (random crap) */
-       reg = CR2_PTM | CR2_RECINVSID;
+       reg = CR2_RECINVSID;
 
        if (smmu->features & ARM_SMMU_FEAT_E2H)
                reg |= CR2_E2H;
 
+       if (!(smmu->features & ARM_SMMU_FEAT_BTM))
+               reg |= CR2_PTM;
+
        writel_relaxed(reg, smmu->base + ARM_SMMU_CR2);
 
        /* Stream table */
@@ -3934,6 +3939,7 @@ static int arm_smmu_device_hw_probe(struct 
arm_smmu_device *smmu)
 {
        u32 reg;
        bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY;
+       bool vhe = cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN);
 
        /* IDR0 */
        reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
@@ -3983,10 +3989,19 @@ static int arm_smmu_device_hw_probe(struct 
arm_smmu_device *smmu)
 
        if (reg & IDR0_HYP) {
                smmu->features |= ARM_SMMU_FEAT_HYP;
-               if (cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN))
+               if (vhe)
                        smmu->features |= ARM_SMMU_FEAT_E2H;
        }
 
+       /*
+        * If the CPU is using VHE, but the SMMU doesn't support it, the SMMU
+        * will create TLB entries for NH-EL1 world and will miss the
+        * broadcasted TLB invalidations that target EL2-E2H world. Don't enable
+        * BTM in that case.
+        */
+       if (reg & IDR0_BTM && (!vhe || reg & IDR0_HYP))
+               smmu->features |= ARM_SMMU_FEAT_BTM;
+
        /*
         * The coherency feature as set by FW is used in preference to the ID
         * register, but warn on mismatch.
-- 
2.26.2

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to