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

Commit 53867802 authored by Robin Murphy's avatar Robin Murphy Committed by Patrick Daly
Browse files

iommu/arm-smmu: Handle stream IDs more dynamically



Rather than assuming fixed worst-case values for stream IDs and SMR
masks, keep track of whatever implemented bits the hardware actually
reports. This also obviates the slightly questionable validation of SMR
fields in isolation - rather than aborting the whole SMMU probe for a
hardware configuration which is still architecturally valid, we can
simply refuse masters later if they try to claim an unrepresentable ID
or mask (which almost certainly implies a DT error anyway).

Change-Id: Id33e0db8d8f3c5f855849d7ddd002c42e3ac85b5
Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Tested-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Git-commit: 21174240
Git-repo: https://source.codeaurora.org/quic/la/kernel/msm-4.4


Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent b94df6fa
Loading
Loading
Loading
Loading
+25 −26
Original line number Diff line number Diff line
@@ -169,9 +169,7 @@
#define ARM_SMMU_GR0_SMR(n)		(0x800 + ((n) << 2))
#define SMR_VALID			(1 << 31)
#define SMR_MASK_SHIFT			16
#define SMR_MASK_MASK			0x7fff
#define SMR_ID_SHIFT			0
#define SMR_ID_MASK			0x7fff

#define ARM_SMMU_GR0_S2CR(n)		(0xc00 + ((n) << 2))
#define S2CR_CBNDX_SHIFT		0
@@ -406,6 +404,8 @@ struct arm_smmu_device {
	atomic_t			irptndx;

	u32				num_mapping_groups;
	u16				streamid_mask;
	u16				smr_mask_mask;
	DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);

	unsigned long			va_size;
@@ -3432,41 +3432,40 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
		dev_notice(smmu->dev,
			   "\t(IDR0.CTTW overridden by dma-coherent property)\n");

	/* Max. number of entries we have for stream matching/indexing */
	size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK);
	smmu->streamid_mask = size - 1;
	if (id & ID0_SMS) {
		u32 smr, sid, mask;
		u32 smr;

		smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH;
		smmu->num_mapping_groups = (id >> ID0_NUMSMRG_SHIFT) &
					   ID0_NUMSMRG_MASK;
		if (smmu->num_mapping_groups == 0) {
		size = (id >> ID0_NUMSMRG_SHIFT) & ID0_NUMSMRG_MASK;
		if (size == 0) {
			dev_err(smmu->dev,
				"stream-matching supported, but no SMRs present!\n");
			return -ENODEV;
		}

		if (!(smmu->options & ARM_SMMU_OPT_SKIP_INIT)) {
			smr = SMR_MASK_MASK << SMR_MASK_SHIFT;
			smr |= (SMR_ID_MASK << SMR_ID_SHIFT);
		/*
		 * 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 = smmu->streamid_mask << SMR_ID_SHIFT;
		writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0));
		smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0));
		smmu->streamid_mask = smr >> SMR_ID_SHIFT;

			mask = (smr >> SMR_MASK_SHIFT) & SMR_MASK_MASK;
			sid = (smr >> SMR_ID_SHIFT) & SMR_ID_MASK;
			if ((mask & sid) != sid) {
				dev_err(smmu->dev,
					"SMR mask bits (0x%x) insufficient for ID field (0x%x)\n",
					mask, sid);
				return -ENODEV;
			}
		smr = smmu->streamid_mask << SMR_MASK_SHIFT;
		writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0));
		smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0));
		smmu->smr_mask_mask = smr >> SMR_MASK_SHIFT;

			dev_dbg(smmu->dev,
				   "\tstream matching with %u register groups, mask 0x%x",
				   smmu->num_mapping_groups, mask);
		}
	} else {
		smmu->num_mapping_groups = (id >> ID0_NUMSIDB_SHIFT) &
					   ID0_NUMSIDB_MASK;
		dev_notice(smmu->dev,
			   "\tstream matching with %lu register groups, mask 0x%x",
			   size, smmu->smr_mask_mask);
	}
	smmu->num_mapping_groups = size;

	if (smmu->version < ARM_SMMU_V2 || !(id & ID0_PTFS_NO_AARCH32)) {
		smmu->features |= ARM_SMMU_FEAT_FMT_AARCH32_L;