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.andersson@xxxxxxxxxx> --- 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