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

Commit 3f4f0ee3 authored by Chintan Pandya's avatar Chintan Pandya
Browse files

iommu: msm: Calculate context bank base address



Typically Context bank base address are 0x8000 apart from
global register address space. In few cases, they are not.
Consider those few cases and calculate the context bank
register offset and number accordingly.

Change-Id: Ibe49fc604af981543575e61176f676a60abd16dd
Signed-off-by: default avatarChintan Pandya <cpandya@codeaurora.org>
parent 3ae282c3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ Optional properties:
- qcom,iommu-pmu-event-classes: List of event classes supported.
- Bus scaling properties: See msm_bus.txt
- qcom,no-atos-support: boolean indicating that IOMMU doesn't have ATS support
- qcom,cb-base-offset: context bank 0's base address from global base address

- List of sub nodes, one for each of the translation context banks supported.
  Each sub node has the following required properties:
+1 −0
Original line number Diff line number Diff line
@@ -111,6 +111,7 @@ struct msm_iommu_bfb_settings {
struct msm_iommu_drvdata {
	void __iomem *base;
	void __iomem *glb_base;
	void __iomem *cb_base;
	int ncb;
	int ttbr_split;
	struct clk *clk;
+8 −9
Original line number Diff line number Diff line
@@ -14,14 +14,13 @@
#define __ARCH_ARM_MACH_MSM_IOMMU_HW_V2_H

#define CTX_SHIFT  12
#define CTX_OFFSET 0x8000

#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
#define GET_GLOBAL_REG_Q(reg, base) (readq_relaxed((base) + (reg)))
#define GET_CTX_REG(reg, base, ctx) \
	(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
	(readl_relaxed((base) + (reg) + ((ctx) << CTX_SHIFT)))
#define GET_CTX_REG_Q(reg, base, ctx) \
	(readq_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
	(readq_relaxed((base) + (reg) + ((ctx) << CTX_SHIFT)))

#define SET_GLOBAL_REG(reg, base, val)	writel_relaxed((val), ((base) + (reg)))
#define SET_GLOBAL_REG_Q(reg, base, val) \
@@ -29,10 +28,10 @@

#define SET_CTX_REG(reg, base, ctx, val) \
	writel_relaxed((val), \
		((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
		((base) + (reg) + ((ctx) << CTX_SHIFT)))
#define SET_CTX_REG_Q(reg, base, ctx, val) \
	writeq_relaxed((val), \
		((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
		((base) + (reg) + ((ctx) << CTX_SHIFT)))

/* Wrappers for numbered registers */
#define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG((b), ((r) + (n << 2)), (v))
@@ -42,19 +41,19 @@
#define GET_GLOBAL_FIELD(b, r, F) \
	GET_FIELD(((b) + (r)), r##_##F##_MASK, r##_##F##_SHIFT)
#define GET_CONTEXT_FIELD(b, c, r, F) \
	GET_FIELD(((b) + CTX_OFFSET + (r) + ((c) << CTX_SHIFT)), \
	GET_FIELD(((b) + (r) + ((c) << CTX_SHIFT)), \
			r##_##F##_MASK, r##_##F##_SHIFT)
#define GET_CONTEXT_FIELD_Q(b, c, r, F) \
	GET_FIELD_Q(((b) + CTX_OFFSET + (r) + ((c) << CTX_SHIFT)), \
	GET_FIELD_Q(((b) + (r) + ((c) << CTX_SHIFT)), \
			r##_##F##_MASK, r##_##F##_SHIFT)

#define SET_GLOBAL_FIELD(b, r, F, v) \
	SET_FIELD(((b) + (r)), r##_##F##_MASK, r##_##F##_SHIFT, (v))
#define SET_CONTEXT_FIELD(b, c, r, F, v) \
	SET_FIELD(((b) + CTX_OFFSET + (r) + ((c) << CTX_SHIFT)), \
	SET_FIELD(((b) + (r) + ((c) << CTX_SHIFT)), \
			r##_##F##_MASK, r##_##F##_SHIFT, (v))
#define SET_CONTEXT_FIELD_Q(b, c, r, F, v) \
	SET_FIELD_Q(((b) + CTX_OFFSET + (r) + ((c) << CTX_SHIFT)), \
	SET_FIELD_Q(((b) + (r) + ((c) << CTX_SHIFT)), \
			r##_##F##_MASK, r##_##F##_SHIFT, (v))

/* Wrappers for numbered field registers */
+27 −24
Original line number Diff line number Diff line
@@ -239,10 +239,10 @@ static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
		if (ret)
			goto fail;

		SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
		SET_TLBIVA(iommu_drvdata->cb_base, ctx_drvdata->num,
			   ctx_drvdata->asid | (va & CB_TLBIVA_VA));
		mb();
		__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
		__sync_tlb(iommu_drvdata->cb_base, ctx_drvdata->num);
		__disable_clocks(iommu_drvdata);
	}
fail:
@@ -266,10 +266,10 @@ static int __flush_iotlb(struct iommu_domain *domain)
		if (ret)
			goto fail;

		SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
		SET_TLBIASID(iommu_drvdata->cb_base, ctx_drvdata->num,
			     ctx_drvdata->asid);
		mb();
		__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
		__sync_tlb(iommu_drvdata->cb_base, ctx_drvdata->num);
		__disable_clocks(iommu_drvdata);
	}

@@ -410,7 +410,7 @@ static void msm_iommu_assign_ASID(const struct msm_iommu_drvdata *iommu_drvdata,
				  struct msm_iommu_priv *priv)
{
	unsigned int found = 0;
	void __iomem *base = iommu_drvdata->base;
	void __iomem *cb_base = iommu_drvdata->cb_base;
	unsigned int i;
	unsigned int ncb = iommu_drvdata->ncb;
	struct msm_iommu_ctx_drvdata *tmp_drvdata;
@@ -438,7 +438,7 @@ static void msm_iommu_assign_ASID(const struct msm_iommu_drvdata *iommu_drvdata,
		BUG_ON(!found);
	}

	msm_iommu_set_ASID(base, curr_ctx->num, curr_ctx->asid);
	msm_iommu_set_ASID(cb_base, curr_ctx->num, curr_ctx->asid);
}

#ifdef CONFIG_IOMMU_LPAE
@@ -542,30 +542,31 @@ static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
{
	phys_addr_t pn;
	void __iomem *base = iommu_drvdata->base;
	void __iomem *cb_base = iommu_drvdata->cb_base;
	unsigned int ctx = ctx_drvdata->num;
	phys_addr_t pgtable = __pa(priv->pt.fl_table);

	__reset_context(base, ctx);
	msm_iommu_setup_ctx(base, ctx);
	__reset_context(cb_base, ctx);
	msm_iommu_setup_ctx(cb_base, ctx);

	if (priv->pt.redirect)
		msm_iommu_setup_pg_l2_redirect(base, ctx);
		msm_iommu_setup_pg_l2_redirect(cb_base, ctx);

	msm_iommu_setup_memory_remap(base, ctx);
	msm_iommu_setup_memory_remap(cb_base, ctx);

	pn = pgtable >> CB_TTBR0_ADDR_SHIFT;
	SET_CB_TTBR0_ADDR(base, ctx, pn);
	SET_CB_TTBR0_ADDR(cb_base, ctx, pn);

	/* Enable context fault interrupt */
	SET_CB_SCTLR_CFIE(base, ctx, 1);
	SET_CB_SCTLR_CFIE(cb_base, ctx, 1);

	/* Redirect all cacheable requests to L2 slave port. */
	SET_CB_ACTLR_BPRCISH(base, ctx, 1);
	SET_CB_ACTLR_BPRCOSH(base, ctx, 1);
	SET_CB_ACTLR_BPRCNSH(base, ctx, 1);
	SET_CB_ACTLR_BPRCISH(cb_base, ctx, 1);
	SET_CB_ACTLR_BPRCOSH(cb_base, ctx, 1);
	SET_CB_ACTLR_BPRCNSH(cb_base, ctx, 1);

	/* Enable private ASID namespace */
	SET_CB_SCTLR_ASIDPNE(base, ctx, 1);
	SET_CB_SCTLR_ASIDPNE(cb_base, ctx, 1);

	if (!is_secure) {
		if (program_m2v)
@@ -593,7 +594,7 @@ static void __program_context(struct msm_iommu_drvdata *iommu_drvdata,
	msm_iommu_assign_ASID(iommu_drvdata, ctx_drvdata, priv);

	/* Enable the MMU */
	SET_CB_SCTLR_M(base, ctx, 1);
	SET_CB_SCTLR_M(cb_base, ctx, 1);
	mb();
}

@@ -768,7 +769,8 @@ static void msm_iommu_detach_dev(struct iommu_domain *domain,

	is_secure = iommu_drvdata->sec_id != -1;

	SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, ctx_drvdata->asid);
	SET_TLBIASID(iommu_drvdata->cb_base, ctx_drvdata->num,
					ctx_drvdata->asid);

	BUG_ON(iommu_drvdata->asid[ctx_drvdata->asid - 1] == 0);
	iommu_drvdata->asid[ctx_drvdata->asid - 1]--;
@@ -776,7 +778,7 @@ static void msm_iommu_detach_dev(struct iommu_domain *domain,

	iommu_halt(iommu_drvdata);

	__reset_context(iommu_drvdata->base, ctx_drvdata->num);
	__reset_context(iommu_drvdata->cb_base, ctx_drvdata->num);

	/*
	 * Only reset the M2V tables on the very last detach */
@@ -940,7 +942,7 @@ static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
		return ret;
	}

	base = iommu_drvdata->base;
	base = iommu_drvdata->cb_base;
	ctx = ctx_drvdata->num;

	ret = __enable_clocks(iommu_drvdata);
@@ -1180,7 +1182,7 @@ irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id)
		goto fail;
	}

	fsr = GET_FSR(drvdata->base, ctx_drvdata->num);
	fsr = GET_FSR(drvdata->cb_base, ctx_drvdata->num);
	if (fsr) {
		if (!ctx_drvdata->attached_domain) {
			pr_err("Bad domain in interrupt handler\n");
@@ -1188,7 +1190,7 @@ irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id)
		} else
			ret = report_iommu_fault(ctx_drvdata->attached_domain,
				&ctx_drvdata->pdev->dev,
				GET_FAR(drvdata->base, ctx_drvdata->num), 0);
				GET_FAR(drvdata->cb_base, ctx_drvdata->num), 0);

		if (ret == -ENOSYS) {
			pr_err("Unexpected IOMMU page fault!\n");
@@ -1196,11 +1198,12 @@ irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id)
			pr_err("context = %s (%d)\n", ctx_drvdata->name,
							ctx_drvdata->num);
			pr_err("Interesting registers:\n");
			__print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
			__print_ctx_regs(drvdata->cb_base,
					ctx_drvdata->num, fsr);
		}

		if (ret != -EBUSY)
			SET_FSR(drvdata->base, ctx_drvdata->num, fsr);
			SET_FSR(drvdata->cb_base, ctx_drvdata->num, fsr);
		ret = IRQ_HANDLED;
	} else
		ret = IRQ_NONE;
+18 −5
Original line number Diff line number Diff line
@@ -287,6 +287,7 @@ static int msm_iommu_probe(struct platform_device *pdev)
	struct resource *r;
	int ret, needs_alt_core_clk, needs_alt_iface_clk;
	int global_cfg_irq, global_client_irq;
	u32 temp;

	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
	if (!drvdata)
@@ -343,6 +344,13 @@ static int msm_iommu_probe(struct platform_device *pdev)
	drvdata->no_atos_support = of_property_read_bool(pdev->dev.of_node,
						"qcom,no-atos-support");

	if (!of_property_read_u32(pdev->dev.of_node,
				"qcom,cb-base-offset",
				&temp))
		drvdata->cb_base = drvdata->base + temp;
	else
		drvdata->cb_base = drvdata->base + 0x8000;

	if (clk_get_rate(drvdata->clk) == 0) {
		ret = clk_round_rate(drvdata->clk, 1000);
		clk_set_rate(drvdata->clk, ret);
@@ -442,7 +450,9 @@ static int msm_iommu_ctx_parse_dt(struct platform_device *pdev,
{
	struct resource *r, rp;
	int irq = 0, ret = 0;
	struct msm_iommu_drvdata *drvdata;
	u32 nsid;
	unsigned long cb_offset;

	get_secure_ctx(pdev->dev.of_node, ctx_drvdata);

@@ -484,12 +494,15 @@ static int msm_iommu_ctx_parse_dt(struct platform_device *pdev,
	if (ret)
		goto out;

	/* Calculate the context bank number using the base addresses. The
	 * first 8 pages belong to the global address space which is followed
	 * by the context banks, hence subtract by 8 to get the context bank
	 * number.
	/* Calculate the context bank number using the base addresses.
	 * Typically CB0 base address is 0x8000 pages away if the number
	 * of CBs are <=8. So, assume the offset 0x8000 until mentioned
	 * explicitely.
	 */
	ctx_drvdata->num = ((r->start - rp.start) >> CTX_SHIFT) - 8;
	drvdata = dev_get_drvdata(pdev->dev.parent);
	cb_offset = drvdata->cb_base - drvdata->base;
	ctx_drvdata->num = ((r->start - rp.start - cb_offset)
					>> CTX_SHIFT);

	if (of_property_read_string(pdev->dev.of_node, "label",
					&ctx_drvdata->name))