diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index eab3087df00d..6d1a12297aad 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -2392,14 +2392,30 @@ static void arm_smmu_domain_free(struct iommu_domain *domain) kfree(smmu_domain); } -static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx) +static int arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx) { struct arm_smmu_smr *smr = smmu->smrs + idx; u32 reg = FIELD_PREP(SMR_ID, smr->id) | FIELD_PREP(SMR_MASK, smr->mask); + u32 val; if (!(smmu->features & ARM_SMMU_FEAT_EXIDS) && smr->valid) reg |= SMR_VALID; arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_SMR(idx), reg); + + /* + * Check if the write went properly. If failed, we would have to fail + * the attach sequence to avoid any USF faults being generated in the + * future due to device transactions, since this SID entry would not + * be present in the stream mapping table. + */ + val = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_SMR(idx)); + if (val != reg) { + dev_err(smmu->dev, "SMR[%d] write err write:0x%lx, read:0x%lx\n", + idx, reg, val); + return -EINVAL; + } + + return 0; } static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx) @@ -2416,11 +2432,14 @@ static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx) arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_S2CR(idx), reg); } -static void arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx) +static int arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx) { arm_smmu_write_s2cr(smmu, idx); if (smmu->smrs) - arm_smmu_write_smr(smmu, idx); + if (arm_smmu_write_smr(smmu, idx)) + return -EINVAL; + + return 0; } /* @@ -2674,7 +2693,10 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain, s2cr[idx].type = type; s2cr[idx].privcfg = S2CR_PRIVCFG_DEFAULT; s2cr[idx].cbndx = cbndx; - arm_smmu_write_sme(smmu, idx); + if (arm_smmu_write_sme(smmu, idx)) { + mutex_unlock(&smmu->stream_map_mutex); + return -EINVAL; + } } mutex_unlock(&smmu->stream_map_mutex);