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

Commit b2ab4fce authored by Patrick Daly's avatar Patrick Daly
Browse files

iommu: arm-smmu: Enable sid switch usecase



Some usecases require moving a stream-id from the nonsecure to secure
domain. In order to do so, ensure that the stream-id is removed from
the nonsecure SMR and S2CR registers by the iommu_detach_device()
call.

Change-Id: Ieb1317f7b056b743e6c9e61f02405d0ed1cabdbb
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent 47681b98
Loading
Loading
Loading
Loading
+44 −6
Original line number Diff line number Diff line
@@ -332,9 +332,17 @@ struct arm_smmu_impl_def_reg {
	u32 value;
};

/*
 * attach_count
 *	The SMR and S2CR registers are only programmed when the number of
 *	devices attached to the iommu using these registers is > 0. This
 *	is required for the "SID switch" use case for secure display.
 *	Protected by stream_map_mutex.
 */
struct arm_smmu_s2cr {
	struct iommu_group		*group;
	int				count;
	int				attach_count;
	enum arm_smmu_s2cr_type		type;
	enum arm_smmu_s2cr_privcfg	privcfg;
	u8				cbndx;
@@ -2010,11 +2018,9 @@ static int arm_smmu_master_alloc_smes(struct device *dev)
	}
	iommu_group_put(group);

	/* It worked! Now, poke the actual hardware */
	for_each_cfg_sme(fwspec, i, idx) {
		arm_smmu_write_sme(smmu, idx);
	/* It worked! Don't poke the actual hardware until we've attached */
	for_each_cfg_sme(fwspec, i, idx)
		smmu->s2crs[idx].group = group;
	}

	mutex_unlock(&smmu->stream_map_mutex);
	return 0;
@@ -2043,6 +2049,33 @@ static void arm_smmu_master_free_smes(struct iommu_fwspec *fwspec)
	mutex_unlock(&smmu->stream_map_mutex);
}

static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
					  struct iommu_fwspec *fwspec)
{
	struct arm_smmu_device *smmu = smmu_domain->smmu;
	struct arm_smmu_s2cr *s2cr = smmu->s2crs;
	int i, idx;
	const struct iommu_gather_ops *tlb;

	tlb = smmu_domain->pgtbl_cfg.tlb;

	mutex_lock(&smmu->stream_map_mutex);
	for_each_cfg_sme(fwspec, i, idx) {
		WARN_ON(s2cr[idx].attach_count == 0);
		s2cr[idx].attach_count -= 1;

		if (s2cr[idx].attach_count > 0)
			continue;

		writel_relaxed(0, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx));
		writel_relaxed(0, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx));
	}
	mutex_unlock(&smmu->stream_map_mutex);

	/* Ensure there are no stale mappings for this context bank */
	tlb->tlb_flush_all(smmu_domain);
}

static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
				      struct iommu_fwspec *fwspec)
{
@@ -2052,15 +2085,17 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
	u8 cbndx = smmu_domain->cfg.cbndx;
	int i, idx;

	mutex_lock(&smmu->stream_map_mutex);
	for_each_cfg_sme(fwspec, i, idx) {
		if (type == s2cr[idx].type && cbndx == s2cr[idx].cbndx)
		if (s2cr[idx].attach_count++ > 0)
			continue;

		s2cr[idx].type = type;
		s2cr[idx].privcfg = S2CR_PRIVCFG_DEFAULT;
		s2cr[idx].cbndx = cbndx;
		arm_smmu_write_s2cr(smmu, idx);
		arm_smmu_write_sme(smmu, idx);
	}
	mutex_unlock(&smmu->stream_map_mutex);

	return 0;
}
@@ -2070,6 +2105,7 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain,
{
	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
	struct arm_smmu_device *smmu = smmu_domain->smmu;
	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
	int dynamic = smmu_domain->attributes & (1 << DOMAIN_ATTR_DYNAMIC);
	int atomic_domain = smmu_domain->attributes & (1 << DOMAIN_ATTR_ATOMIC);

@@ -2081,6 +2117,8 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain,
		return;
	}

	arm_smmu_domain_remove_master(smmu_domain, fwspec);

	/* Remove additional vote for atomic power */
	if (atomic_domain) {
		WARN_ON(arm_smmu_power_on_atomic(smmu->pwr));