With the SMRs inherited from the bootloader the first SMR might actually
be valid and in use. As such probing the SMR mask using the first SMR
might break a stream in use. Search for an unused stream and use this to
probe the SMR mask.

Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.org>
---

Changes since RFC:
- Deal with EXIDS
- Use arm_smmu_gr0_read/write()

 drivers/iommu/arm-smmu.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 4f1a350d9529..6ca6a4e072c8 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -945,24 +945,43 @@ static void arm_smmu_write_sme(struct arm_smmu_device 
*smmu, int idx)
  */
 static void arm_smmu_test_smr_masks(struct arm_smmu_device *smmu)
 {
+       u32 s2cr;
        u32 smr;
+       int idx;
 
        if (!smmu->smrs)
                return;
 
+       for (idx = 0; idx < smmu->num_mapping_groups; idx++) {
+               if (smmu->features & ARM_SMMU_FEAT_EXIDS) {
+                       s2cr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_S2CR(idx));
+                       if (!FIELD_GET(S2CR_EXIDVALID, s2cr))
+                               break;
+               } else {
+                       smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(idx));
+                       if (!FIELD_GET(SMR_VALID, smr))
+                               break;
+               }
+       }
+
+       if (idx == smmu->num_mapping_groups) {
+               dev_err(smmu->dev, "Unable to compute streamid_mask\n");
+               return;
+       }
+
        /*
         * SMR.ID bits may not be preserved if the corresponding MASK
         * bits are set, so check each one separately. We can reject
         * masters later if they try to claim IDs outside these masks.
         */
        smr = FIELD_PREP(SMR_ID, smmu->streamid_mask);
-       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(0), smr);
-       smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(0));
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(idx), smr);
+       smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(idx));
        smmu->streamid_mask = FIELD_GET(SMR_ID, smr);
 
        smr = FIELD_PREP(SMR_MASK, smmu->streamid_mask);
-       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(0), smr);
-       smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(0));
+       arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(idx), smr);
+       smr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(idx));
        smmu->smr_mask_mask = FIELD_GET(SMR_MASK, smr);
 }
 
-- 
2.24.0

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

Reply via email to