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

Commit 43b412be authored by Will Deacon's avatar Will Deacon
Browse files

iommu/arm-smmu: fix s2cr and smr teardown on device detach from domain



When we attach a device to a domain, we configure the SMRs (if we have
any) to match the Stream IDs for the corresponding SMMU master and
program the s2crs accordingly. However, on detach we tear down the s2crs
assuming stream-indexing (as opposed to stream-matching) and SMRs
assuming they are present.

This patch fixes the device detach code so that it operates as a
converse of the attach code.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 93b14135
Loading
Loading
Loading
Loading
+12 −15
Original line number Diff line number Diff line
@@ -1116,6 +1116,9 @@ static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu,
	void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
	struct arm_smmu_smr *smrs = cfg->smrs;

	if (!smrs)
		return;

	/* Invalidate the SMRs before freeing back to the allocator */
	for (i = 0; i < cfg->num_streamids; ++i) {
		u8 idx = smrs[i].idx;
@@ -1128,20 +1131,6 @@ static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu,
	kfree(smrs);
}

static void arm_smmu_bypass_stream_mapping(struct arm_smmu_device *smmu,
					   struct arm_smmu_master_cfg *cfg)
{
	int i;
	void __iomem *gr0_base = ARM_SMMU_GR0(smmu);

	for (i = 0; i < cfg->num_streamids; ++i) {
		u16 sid = cfg->streamids[i];

		writel_relaxed(S2CR_TYPE_BYPASS,
			       gr0_base + ARM_SMMU_GR0_S2CR(sid));
	}
}

static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
				      struct arm_smmu_master_cfg *cfg)
{
@@ -1168,13 +1157,21 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
					  struct arm_smmu_master_cfg *cfg)
{
	int i;
	struct arm_smmu_device *smmu = smmu_domain->smmu;
	void __iomem *gr0_base = ARM_SMMU_GR0(smmu);

	/*
	 * We *must* clear the S2CR first, because freeing the SMR means
	 * that it can be re-allocated immediately.
	 */
	arm_smmu_bypass_stream_mapping(smmu, cfg);
	for (i = 0; i < cfg->num_streamids; ++i) {
		u32 idx = cfg->smrs ? cfg->smrs[i].idx : cfg->streamids[i];

		writel_relaxed(S2CR_TYPE_BYPASS,
			       gr0_base + ARM_SMMU_GR0_S2CR(idx));
	}

	arm_smmu_master_free_smrs(smmu, cfg);
}