Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e49e9c98 authored by Sudarshan Rajagopalan's avatar Sudarshan Rajagopalan Committed by Prakash Gupta
Browse files

iommu: arm-smmu: Fail device attach when SMR write fails



On systems with Hypervisor support, writes to SMR registers
are trapped by Hypervisor where the value is vetted and gets
written to the SMR register only if valid. If such SMR writes
fails, the SID value doesn't get populated to the stream mapping
table, and any device transaction would lead to USF which would
crash the system. Hence, to avoid any USF fault, fail the device
attach sequence.

Change-Id: I1435c7aa8290d7c2916cc86cc30cfa1cefae3910
Signed-off-by: default avatarSudarshan Rajagopalan <sudaraja@codeaurora.org>
Signed-off-by: default avatarPrakash Gupta <guptap@codeaurora.org>
parent 4cf5de75
Loading
Loading
Loading
Loading
+26 −4
Original line number Diff line number Diff line
@@ -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);