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

Commit baf0c895 authored by Laura Abbott's avatar Laura Abbott
Browse files

iommu: msm: Program all M2V tables at once



Currently, M2V tables are programmed per context bank when
attaching. Attaching to a single context bank will take the
SMMU out of pass through mode. This means that when one context
bank is attached, none of the other banks will have M2Vs
programmed until they are attached. This presents a problem if a
single context bank is expected to work in pass through mode.
As a solution, program the M2V table for all context bank when
the first context bank of an IOMMU is attached. Clear out the
M2V tables only when the last context is detached.

Change-Id: I9e63000100da88da9992eaf80c6ff958dad0b475
Signed-off-by: default avatarLaura Abbott <lauraa@codeaurora.org>
parent 86155e46
Loading
Loading
Loading
Loading
+52 −29
Original line number Diff line number Diff line
@@ -348,15 +348,14 @@ static void __reset_context(void __iomem *base, int ctx)
	mb();
}

static void __release_smg(void __iomem *base, int ctx)
static void __release_smg(void __iomem *base)
{
	int i, smt_size;
	smt_size = GET_IDR0_NUMSMRG(base);

	/* Invalidate any SMGs associated with this context */
	/* Invalidate all SMGs */
	for (i = 0; i < smt_size; i++)
		if (GET_SMR_VALID(base, i) &&
		    GET_S2CR_CBNDX(base, i) == ctx)
		if (GET_SMR_VALID(base, i))
			SET_SMR_VALID(base, i, 0);
}

@@ -468,16 +467,50 @@ static void msm_iommu_setup_pg_l2_redirect(void __iomem *base, unsigned int ctx)

#endif

static int program_m2v_table(struct device *dev, void __iomem *base)
{
	struct msm_iommu_ctx_drvdata *ctx_drvdata = dev_get_drvdata(dev);
	u32 *sids = ctx_drvdata->sids;
	unsigned int ctx = ctx_drvdata->num;
	int num = 0, i, smt_size;
	int len = ctx_drvdata->nsid;

	smt_size = GET_IDR0_NUMSMRG(base);
	/* Program the M2V tables for this context */
	for (i = 0; i < len / sizeof(*sids); i++) {
		for (; num < smt_size; num++)
			if (GET_SMR_VALID(base, num) == 0)
				break;
		BUG_ON(num >= smt_size);

		SET_SMR_VALID(base, num, 1);
		SET_SMR_MASK(base, num, 0);
		SET_SMR_ID(base, num, sids[i]);

		SET_S2CR_N(base, num, 0);
		SET_S2CR_CBNDX(base, num, ctx);
		SET_S2CR_MEMATTR(base, num, 0x0A);
		/* Set security bit override to be Non-secure */
		SET_S2CR_NSCFG(base, num, 3);
	}

	return 0;
}

static void program_all_m2v_tables(struct msm_iommu_drvdata *iommu_drvdata)
{
	device_for_each_child(iommu_drvdata->dev, iommu_drvdata->base,
						program_m2v_table);
}

static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
			      struct msm_iommu_ctx_drvdata *ctx_drvdata,
			      struct msm_iommu_priv *priv, bool is_secure)
			      struct msm_iommu_priv *priv, bool is_secure,
			      bool program_m2v)
{
	phys_addr_t pn;
	int num = 0, i, smt_size;
	void __iomem *base = iommu_drvdata->base;
	unsigned int ctx = ctx_drvdata->num;
	u32 *sids = ctx_drvdata->sids;
	int len = ctx_drvdata->nsid;
	phys_addr_t pgtable = __pa(priv->pt.fl_table);

	__reset_context(base, ctx);
@@ -503,24 +536,9 @@ static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
	SET_CB_SCTLR_ASIDPNE(base, ctx, 1);

	if (!is_secure) {
		smt_size = GET_IDR0_NUMSMRG(base);
		/* Program the M2V tables for this context */
		for (i = 0; i < len / sizeof(*sids); i++) {
			for (; num < smt_size; num++)
				if (GET_SMR_VALID(base, num) == 0)
					break;
			BUG_ON(num >= smt_size);
		if (program_m2v)
			program_all_m2v_tables(iommu_drvdata);

			SET_SMR_VALID(base, num, 1);
			SET_SMR_MASK(base, num, 0);
			SET_SMR_ID(base, num, sids[i]);

			SET_S2CR_N(base, num, 0);
			SET_S2CR_CBNDX(base, num, ctx);
			SET_S2CR_MEMATTR(base, num, 0x0A);
			/* Set security bit override to be Non-secure */
			SET_S2CR_NSCFG(base, num, 3);
		}
		SET_CBAR_N(base, ctx, 0);

		/* Stage 1 Context with Stage 2 bypass */
@@ -594,6 +612,7 @@ static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
	struct msm_iommu_ctx_drvdata *tmp_drvdata;
	int ret = 0;
	int is_secure;
	bool set_m2v = false;

	mutex_lock(&msm_iommu_lock);

@@ -659,11 +678,12 @@ static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
		}
		program_iommu_bfb_settings(iommu_drvdata->base,
					   iommu_drvdata->bfb_settings);
		set_m2v = true;
	}

	iommu_halt(iommu_drvdata);

	__program_context(iommu_drvdata, ctx_drvdata, priv, is_secure);
	__program_context(iommu_drvdata, ctx_drvdata, priv, is_secure, set_m2v);

	iommu_resume(iommu_drvdata);

@@ -725,8 +745,11 @@ static void msm_iommu_detach_dev(struct iommu_domain *domain,
	iommu_halt(iommu_drvdata);

	__reset_context(iommu_drvdata->base, ctx_drvdata->num);
	if (!is_secure)
		__release_smg(iommu_drvdata->base, ctx_drvdata->num);

	/*
	 * Only reset the M2V tables on the very last detach */
	if (!is_secure && iommu_drvdata->ctx_attach_count == 1)
		__release_smg(iommu_drvdata->base);

	iommu_resume(iommu_drvdata);