msm_iommu.c revision 294b2dea83ba0a6d6034a7521bc62c317efab17b
10720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
20720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko *
30720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * This program is free software; you can redistribute it and/or modify
40720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * it under the terms of the GNU General Public License version 2 and
50720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * only version 2 as published by the Free Software Foundation.
60720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko *
70720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * This program is distributed in the hope that it will be useful,
80720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * but WITHOUT ANY WARRANTY; without even the implied warranty of
90720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
100720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * GNU General Public License for more details.
110720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko *
120720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * You should have received a copy of the GNU General Public License
130720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * along with this program; if not, write to the Free Software
140720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
150720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko * 02110-1301, USA.
160720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko */
170720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
180720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
190720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/kernel.h>
200720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/module.h>
210720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/platform_device.h>
220720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/errno.h>
230720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/io.h>
240720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/interrupt.h>
250720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/list.h>
260720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/spinlock.h>
270720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/slab.h>
280720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <linux/iommu.h>
290720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
300720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <asm/cacheflush.h>
310720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <asm/sizes.h>
320720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
330720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <mach/iommu_hw-8xxx.h>
340720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#include <mach/iommu.h>
350720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
36100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko#define MRC(reg, processor, op1, crn, crm, op2)				\
37100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko__asm__ __volatile__ (							\
38100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko"   mrc   "   #processor "," #op1 ", %0,"  #crn "," #crm "," #op2 "\n"  \
39100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko: "=r" (reg))
40100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
41100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko#define RCP15_PRRR(reg)		MRC(reg, p15, 0, c10, c2, 0)
42100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko#define RCP15_NMRR(reg)		MRC(reg, p15, 0, c10, c2, 1)
43100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
44100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenkostatic int msm_iommu_tex_class[4];
45100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
460720d1f052dc1576396a39b327da6e60082c4efaStepan MoskovchenkoDEFINE_SPINLOCK(msm_iommu_lock);
470720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
480720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostruct msm_priv {
490720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *pgtable;
500720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct list_head list_attached;
510720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko};
520720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5333069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenkostatic int __flush_iotlb(struct iommu_domain *domain)
540720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
550720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_priv *priv = domain->priv;
560720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_drvdata *iommu_drvdata;
570720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_ctx_drvdata *ctx_drvdata;
5833069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	int ret = 0;
590720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#ifndef CONFIG_IOMMU_PGTABLES_L2
600720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *fl_table = priv->pgtable;
610720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	int i;
620720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
63f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko	if (!list_empty(&priv->list_attached)) {
64f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko		dmac_flush_range(fl_table, fl_table + SZ_16K);
650720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
66f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko		for (i = 0; i < NUM_FL_PTE; i++)
67f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko			if ((fl_table[i] & 0x03) == FL_TYPE_TABLE) {
68f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko				void *sl_table = __va(fl_table[i] &
69f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko								FL_BASE_MASK);
70f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko				dmac_flush_range(sl_table, sl_table + SZ_4K);
71f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko			}
72f6f41eb9ccc0e6fad0ccba4c5e0a97de935db734Stepan Moskovchenko	}
730720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#endif
740720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
750720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
760720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		if (!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent)
770720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			BUG();
780720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
790720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
800720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0);
810720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
8233069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko
8333069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	return ret;
840720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
850720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
860720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic void __reset_context(void __iomem *base, int ctx)
870720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
880720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_BPRCOSH(base, ctx, 0);
890720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_BPRCISH(base, ctx, 0);
900720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_BPRCNSH(base, ctx, 0);
910720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_BPSHCFG(base, ctx, 0);
920720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_BPMTCFG(base, ctx, 0);
930720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_ACTLR(base, ctx, 0);
940720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_SCTLR(base, ctx, 0);
950720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_FSRRESTORE(base, ctx, 0);
960720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR0(base, ctx, 0);
970720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR1(base, ctx, 0);
980720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBCR(base, ctx, 0);
990720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_BFBCR(base, ctx, 0);
1000720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_PAR(base, ctx, 0);
1010720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_FAR(base, ctx, 0);
1020720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_CTX_TLBIALL(base, ctx, 0);
1030720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TLBFLPTER(base, ctx, 0);
1040720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TLBSLPTER(base, ctx, 0);
1050720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TLBLKCR(base, ctx, 0);
1060720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_PRRR(base, ctx, 0);
1070720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_NMRR(base, ctx, 0);
1080720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_CONTEXTIDR(base, ctx, 0);
1090720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
1100720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1110720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
1120720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
113100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	unsigned int prrr, nmrr;
1140720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	__reset_context(base, ctx);
1150720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1160720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Set up HTW mode */
1170720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* TLB miss configuration: perform HTW on miss */
1180720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TLBMCFG(base, ctx, 0x3);
1190720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1200720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* V2P configuration: HTW for access */
1210720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_V2PCFG(base, ctx, 0x3);
1220720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1230720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBCR(base, ctx, 0);
1240720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR0_PA(base, ctx, (pgtable >> 14));
1250720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1260720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Invalidate the TLB for this context */
1270720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_CTX_TLBIALL(base, ctx, 0);
1280720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1290720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Set interrupt number to "secure" interrupt */
1300720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_IRPTNDX(base, ctx, 0);
1310720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1320720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Enable context fault interrupt */
1330720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_CFEIE(base, ctx, 1);
1340720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1350720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Stall access on a context fault and let the handler deal with it */
1360720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_CFCFG(base, ctx, 1);
1370720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1380720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Redirect all cacheable requests to L2 slave port. */
1390720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_RCISH(base, ctx, 1);
1400720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_RCOSH(base, ctx, 1);
1410720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_RCNSH(base, ctx, 1);
1420720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1430720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Turn on TEX Remap */
1440720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TRE(base, ctx, 1);
1450720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
146100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	/* Set TEX remap attributes */
147100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	RCP15_PRRR(prrr);
148100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	RCP15_NMRR(nmrr);
149100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	SET_PRRR(base, ctx, prrr);
150100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	SET_NMRR(base, ctx, nmrr);
1510720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1520720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Turn on BFB prefetch */
1530720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_BFBDFE(base, ctx, 1);
1540720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1550720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#ifdef CONFIG_IOMMU_PGTABLES_L2
1560720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Configure page tables as inner-cacheable and shareable to reduce
1570720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	 * the TLB miss penalty.
1580720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	 */
1590720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR0_SH(base, ctx, 1);
1600720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR1_SH(base, ctx, 1);
1610720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1620720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR0_NOS(base, ctx, 1);
1630720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR1_NOS(base, ctx, 1);
1640720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1650720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR0_IRGNH(base, ctx, 0); /* WB, WA */
1660720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR0_IRGNL(base, ctx, 1);
1670720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1680720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR1_IRGNH(base, ctx, 0); /* WB, WA */
1690720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR1_IRGNL(base, ctx, 1);
1700720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1710720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR0_ORGN(base, ctx, 1); /* WB, WA */
1720720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_TTBR1_ORGN(base, ctx, 1); /* WB, WA */
1730720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko#endif
1740720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1750720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Enable the MMU */
1760720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_M(base, ctx, 1);
1770720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
1780720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1790720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic int msm_iommu_domain_init(struct iommu_domain *domain)
1800720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
1810720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_priv *priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1820720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1830720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!priv)
1840720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail_nomem;
1850720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1860720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	INIT_LIST_HEAD(&priv->list_attached);
1870720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	priv->pgtable = (unsigned long *)__get_free_pages(GFP_KERNEL,
1880720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko							  get_order(SZ_16K));
1890720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1900720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!priv->pgtable)
1910720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail_nomem;
1920720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1930720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	memset(priv->pgtable, 0, SZ_16K);
1940720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	domain->priv = priv;
1950720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return 0;
1960720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
1970720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkofail_nomem:
1980720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	kfree(priv);
1990720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return -ENOMEM;
2000720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
2010720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2020720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic void msm_iommu_domain_destroy(struct iommu_domain *domain)
2030720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
2040720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_priv *priv;
2050720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long flags;
2060720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *fl_table;
2070720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	int i;
2080720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2090720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_lock_irqsave(&msm_iommu_lock, flags);
2100720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	priv = domain->priv;
2110720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	domain->priv = NULL;
2120720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2130720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (priv) {
2140720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		fl_table = priv->pgtable;
2150720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2160720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		for (i = 0; i < NUM_FL_PTE; i++)
2170720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			if ((fl_table[i] & 0x03) == FL_TYPE_TABLE)
2180720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko				free_page((unsigned long) __va(((fl_table[i]) &
2190720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko								FL_BASE_MASK)));
2200720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2210720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		free_pages((unsigned long)priv->pgtable, get_order(SZ_16K));
2220720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		priv->pgtable = NULL;
2230720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
2240720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2250720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	kfree(priv);
2260720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_unlock_irqrestore(&msm_iommu_lock, flags);
2270720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
2280720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2290720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
2300720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
2310720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_priv *priv;
2320720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_ctx_dev *ctx_dev;
2330720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_drvdata *iommu_drvdata;
2340720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_ctx_drvdata *ctx_drvdata;
2350720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_ctx_drvdata *tmp_drvdata;
2360720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	int ret = 0;
2370720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long flags;
2380720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2390720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_lock_irqsave(&msm_iommu_lock, flags);
2400720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2410720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	priv = domain->priv;
2420720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2430720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!priv || !dev) {
2440720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -EINVAL;
2450720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
2460720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
2470720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2480720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	iommu_drvdata = dev_get_drvdata(dev->parent);
2490720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	ctx_drvdata = dev_get_drvdata(dev);
2500720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	ctx_dev = dev->platform_data;
2510720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2520720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!iommu_drvdata || !ctx_drvdata || !ctx_dev) {
2530720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -EINVAL;
2540720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
2550720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
2560720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
25700d4b2bb03b9ed27f28336b0a68f2bd7f67caa40Stepan Moskovchenko	if (!list_empty(&ctx_drvdata->attached_elm)) {
25800d4b2bb03b9ed27f28336b0a68f2bd7f67caa40Stepan Moskovchenko		ret = -EBUSY;
25900d4b2bb03b9ed27f28336b0a68f2bd7f67caa40Stepan Moskovchenko		goto fail;
26000d4b2bb03b9ed27f28336b0a68f2bd7f67caa40Stepan Moskovchenko	}
26100d4b2bb03b9ed27f28336b0a68f2bd7f67caa40Stepan Moskovchenko
2620720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm)
2630720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		if (tmp_drvdata == ctx_drvdata) {
2640720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			ret = -EBUSY;
2650720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			goto fail;
2660720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		}
2670720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2680720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	__program_context(iommu_drvdata->base, ctx_dev->num,
2690720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			  __pa(priv->pgtable));
2700720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2710720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
27233069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	ret = __flush_iotlb(domain);
2730720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2740720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkofail:
2750720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_unlock_irqrestore(&msm_iommu_lock, flags);
2760720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return ret;
2770720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
2780720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2790720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic void msm_iommu_detach_dev(struct iommu_domain *domain,
2800720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko				 struct device *dev)
2810720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
2820720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_priv *priv;
2830720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_ctx_dev *ctx_dev;
2840720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_drvdata *iommu_drvdata;
2850720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_ctx_drvdata *ctx_drvdata;
2860720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long flags;
28733069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	int ret;
2880720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2890720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_lock_irqsave(&msm_iommu_lock, flags);
2900720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	priv = domain->priv;
2910720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2920720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!priv || !dev)
2930720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
2940720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2950720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	iommu_drvdata = dev_get_drvdata(dev->parent);
2960720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	ctx_drvdata = dev_get_drvdata(dev);
2970720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	ctx_dev = dev->platform_data;
2980720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
2990720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!iommu_drvdata || !ctx_drvdata || !ctx_dev)
3000720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
3010720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
30233069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	ret = __flush_iotlb(domain);
30333069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	if (ret)
30433069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko		goto fail;
30533069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko
3060720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	__reset_context(iommu_drvdata->base, ctx_dev->num);
3070720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	list_del_init(&ctx_drvdata->attached_elm);
3080720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3090720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkofail:
3100720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_unlock_irqrestore(&msm_iommu_lock, flags);
3110720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
3120720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3130720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
3140720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			 phys_addr_t pa, int order, int prot)
3150720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
3160720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_priv *priv;
3170720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long flags;
3180720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *fl_table;
3190720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *fl_pte;
3200720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long fl_offset;
3210720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *sl_table;
3220720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *sl_pte;
3230720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long sl_offset;
324100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	unsigned int pgprot;
3250720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	size_t len = 0x1000UL << order;
326100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	int ret = 0, tex, sh;
3270720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3280720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_lock_irqsave(&msm_iommu_lock, flags);
3290720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
330100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	sh = (prot & MSM_IOMMU_ATTR_SH) ? 1 : 0;
331100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	tex = msm_iommu_tex_class[prot & MSM_IOMMU_CP_MASK];
332100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
333100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	if (tex < 0 || tex > NUM_TEX_CLASS - 1) {
334100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		ret = -EINVAL;
335100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		goto fail;
336100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	}
337100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
338100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	priv = domain->priv;
3390720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!priv) {
3400720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -EINVAL;
3410720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
3420720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
3430720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3440720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	fl_table = priv->pgtable;
3450720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3460720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len != SZ_16M && len != SZ_1M &&
3470720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	    len != SZ_64K && len != SZ_4K) {
3480720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		pr_debug("Bad size: %d\n", len);
3490720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -EINVAL;
3500720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
3510720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
3520720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3530720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!fl_table) {
3540720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		pr_debug("Null page table\n");
3550720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -EINVAL;
3560720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
3570720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
3580720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
359100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	if (len == SZ_16M || len == SZ_1M) {
360100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		pgprot = sh ? FL_SHARED : 0;
361100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		pgprot |= tex & 0x01 ? FL_BUFFERABLE : 0;
362100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		pgprot |= tex & 0x02 ? FL_CACHEABLE : 0;
363100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		pgprot |= tex & 0x04 ? FL_TEX0 : 0;
364100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	} else	{
365100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		pgprot = sh ? SL_SHARED : 0;
366100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		pgprot |= tex & 0x01 ? SL_BUFFERABLE : 0;
367100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		pgprot |= tex & 0x02 ? SL_CACHEABLE : 0;
368100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		pgprot |= tex & 0x04 ? SL_TEX0 : 0;
369100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	}
370100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
3710720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	fl_offset = FL_OFFSET(va);	/* Upper 12 bits */
3720720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	fl_pte = fl_table + fl_offset;	/* int pointers, 4 bytes */
3730720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3740720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_16M) {
3750720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		int i = 0;
3760720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		for (i = 0; i < 16; i++)
3770720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			*(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
3780720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko				  FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT |
379100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko				  FL_SHARED | pgprot;
3800720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
3810720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3820720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_1M)
3830720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		*fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE |
384100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko					    FL_TYPE_SECT | FL_SHARED | pgprot;
3850720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3860720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Need a 2nd level table */
3870720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) {
3880720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		unsigned long *sl;
389294b2dea83ba0a6d6034a7521bc62c317efab17bStepan Moskovchenko		sl = (unsigned long *) __get_free_pages(GFP_ATOMIC,
3900720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko							get_order(SZ_4K));
3910720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3920720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		if (!sl) {
3930720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			pr_debug("Could not allocate second level table\n");
3940720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			ret = -ENOMEM;
3950720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			goto fail;
3960720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		}
3970720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
3980720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		memset(sl, 0, SZ_4K);
3990720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | FL_TYPE_TABLE);
4000720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
4010720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4020720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
4030720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	sl_offset = SL_OFFSET(va);
4040720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	sl_pte = sl_table + sl_offset;
4050720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4060720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4070720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_4K)
4080720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		*sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 |
409100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko					  SL_SHARED | SL_TYPE_SMALL | pgprot;
4100720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4110720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_64K) {
4120720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		int i;
4130720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4140720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		for (i = 0; i < 16; i++)
4150720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			*(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 |
416100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko				SL_AP1 | SL_SHARED | SL_TYPE_LARGE | pgprot;
4170720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
4180720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
41933069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	ret = __flush_iotlb(domain);
4200720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkofail:
4210720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_unlock_irqrestore(&msm_iommu_lock, flags);
4220720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return ret;
4230720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
4240720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4250720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
4260720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			    int order)
4270720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
4280720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_priv *priv;
4290720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long flags;
4300720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *fl_table;
4310720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *fl_pte;
4320720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long fl_offset;
4330720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *sl_table;
4340720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long *sl_pte;
4350720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long sl_offset;
4360720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	size_t len = 0x1000UL << order;
4370720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	int i, ret = 0;
4380720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4390720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_lock_irqsave(&msm_iommu_lock, flags);
4400720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4410720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	priv = domain->priv;
4420720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4430720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!priv) {
4440720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -ENODEV;
4450720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
4460720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
4470720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4480720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	fl_table = priv->pgtable;
4490720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4500720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len != SZ_16M && len != SZ_1M &&
4510720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	    len != SZ_64K && len != SZ_4K) {
4520720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		pr_debug("Bad length: %d\n", len);
4530720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -EINVAL;
4540720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
4550720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
4560720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4570720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!fl_table) {
4580720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		pr_debug("Null page table\n");
4590720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -EINVAL;
4600720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
4610720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
4620720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4630720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	fl_offset = FL_OFFSET(va);	/* Upper 12 bits */
4640720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	fl_pte = fl_table + fl_offset;	/* int pointers, 4 bytes */
4650720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4660720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (*fl_pte == 0) {
4670720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		pr_debug("First level PTE is 0\n");
4680720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = -ENODEV;
4690720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
4700720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
4710720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4720720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Unmap supersection */
4730720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_16M)
4740720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		for (i = 0; i < 16; i++)
4750720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			*(fl_pte+i) = 0;
4760720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4770720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_1M)
4780720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		*fl_pte = 0;
4790720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4800720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
4810720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	sl_offset = SL_OFFSET(va);
4820720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	sl_pte = sl_table + sl_offset;
4830720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4840720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_64K) {
4850720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		for (i = 0; i < 16; i++)
4860720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			*(sl_pte+i) = 0;
4870720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
4880720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4890720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_4K)
4900720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		*sl_pte = 0;
4910720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4920720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (len == SZ_4K || len == SZ_64K) {
4930720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		int used = 0;
4940720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
4950720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		for (i = 0; i < NUM_SL_PTE; i++)
4960720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			if (sl_table[i])
4970720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko				used = 1;
4980720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		if (!used) {
4990720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			free_page((unsigned long)sl_table);
5000720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			*fl_pte = 0;
5010720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		}
5020720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
5030720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
50433069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	ret = __flush_iotlb(domain);
5050720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkofail:
5060720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_unlock_irqrestore(&msm_iommu_lock, flags);
5070720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return ret;
5080720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
5090720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5100720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
5110720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko					  unsigned long va)
5120720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
5130720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_priv *priv;
5140720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_drvdata *iommu_drvdata;
5150720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_ctx_drvdata *ctx_drvdata;
5160720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned int par;
5170720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned long flags;
5180720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	void __iomem *base;
5190720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	phys_addr_t ret = 0;
5200720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	int ctx;
5210720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5220720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_lock_irqsave(&msm_iommu_lock, flags);
5230720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5240720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	priv = domain->priv;
5250720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (list_empty(&priv->list_attached))
5260720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
5270720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5280720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	ctx_drvdata = list_entry(priv->list_attached.next,
5290720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko				 struct msm_iommu_ctx_drvdata, attached_elm);
5300720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
5310720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5320720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	base = iommu_drvdata->base;
5330720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	ctx = ctx_drvdata->num;
5340720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5350720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* Invalidate context TLB */
5360720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_CTX_TLBIALL(base, ctx, 0);
5370720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT);
5380720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5390720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	par = GET_PAR(base, ctx);
5400720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5410720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	/* We are dealing with a supersection */
5420720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (GET_NOFAULT_SS(base, ctx))
5430720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = (par & 0xFF000000) | (va & 0x00FFFFFF);
5440720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	else	/* Upper 20 bits from PAR, lower 12 from VA */
5450720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		ret = (par & 0xFFFFF000) | (va & 0x00000FFF);
5460720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
54733069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	if (GET_FAULT(base, ctx))
54833069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko		ret = 0;
54933069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko
5500720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkofail:
5510720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_unlock_irqrestore(&msm_iommu_lock, flags);
5520720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return ret;
5530720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
5540720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5550720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic int msm_iommu_domain_has_cap(struct iommu_domain *domain,
5560720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko				    unsigned long cap)
5570720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
5580720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return 0;
5590720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
5600720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5610720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic void print_ctx_regs(void __iomem *base, int ctx)
5620720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
5630720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	unsigned int fsr = GET_FSR(base, ctx);
5640720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	pr_err("FAR    = %08x    PAR    = %08x\n",
5650720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	       GET_FAR(base, ctx), GET_PAR(base, ctx));
5660720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	pr_err("FSR    = %08x [%s%s%s%s%s%s%s%s%s%s]\n", fsr,
5670720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x02) ? "TF " : "",
5680720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x04) ? "AFF " : "",
5690720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x08) ? "APF " : "",
5700720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x10) ? "TLBMF " : "",
5710720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x20) ? "HTWDEEF " : "",
5720720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x40) ? "HTWSEEF " : "",
5730720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x80) ? "MHF " : "",
5740720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x10000) ? "SL " : "",
5750720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x40000000) ? "SS " : "",
5760720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			(fsr & 0x80000000) ? "MULTI " : "");
5770720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5780720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	pr_err("FSYNR0 = %08x    FSYNR1 = %08x\n",
5790720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	       GET_FSYNR0(base, ctx), GET_FSYNR1(base, ctx));
5800720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	pr_err("TTBR0  = %08x    TTBR1  = %08x\n",
5810720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	       GET_TTBR0(base, ctx), GET_TTBR1(base, ctx));
5820720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	pr_err("SCTLR  = %08x    ACTLR  = %08x\n",
5830720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	       GET_SCTLR(base, ctx), GET_ACTLR(base, ctx));
5840720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	pr_err("PRRR   = %08x    NMRR   = %08x\n",
5850720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	       GET_PRRR(base, ctx), GET_NMRR(base, ctx));
5860720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
5870720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5880720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkoirqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
5890720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
5900720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	struct msm_iommu_drvdata *drvdata = dev_id;
5910720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	void __iomem *base;
59233069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	unsigned int fsr;
59333069739d1c2f03734d5b5b003593e9552d412c1Stepan Moskovchenko	int ncb, i;
5940720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5950720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_lock(&msm_iommu_lock);
5960720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
5970720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	if (!drvdata) {
5980720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		pr_err("Invalid device ID in context interrupt handler\n");
5990720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		goto fail;
6000720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
6010720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
6020720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	base = drvdata->base;
6030720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
6040720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	pr_err("Unexpected IOMMU page fault!\n");
6050720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	pr_err("base = %08x\n", (unsigned int) base);
6060720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
6070720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	ncb = GET_NCB(base)+1;
6080720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	for (i = 0; i < ncb; i++) {
6090720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		fsr = GET_FSR(base, i);
6100720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		if (fsr) {
6110720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			pr_err("Fault occurred in context %d.\n", i);
6120720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			pr_err("Interesting registers:\n");
6130720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			print_ctx_regs(base, i);
6140720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko			SET_FSR(base, i, 0x4000000F);
6150720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko		}
6160720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	}
6170720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkofail:
6180720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	spin_unlock(&msm_iommu_lock);
6190720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return 0;
6200720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
6210720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
6220720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkostatic struct iommu_ops msm_iommu_ops = {
6230720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	.domain_init = msm_iommu_domain_init,
6240720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	.domain_destroy = msm_iommu_domain_destroy,
6250720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	.attach_dev = msm_iommu_attach_dev,
6260720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	.detach_dev = msm_iommu_detach_dev,
6270720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	.map = msm_iommu_map,
6280720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	.unmap = msm_iommu_unmap,
6290720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	.iova_to_phys = msm_iommu_iova_to_phys,
6300720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	.domain_has_cap = msm_iommu_domain_has_cap
6310720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko};
6320720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
633100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenkostatic int __init get_tex_class(int icp, int ocp, int mt, int nos)
634100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko{
635100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	int i = 0;
636100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	unsigned int prrr = 0;
637100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	unsigned int nmrr = 0;
638100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	int c_icp, c_ocp, c_mt, c_nos;
639100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
640100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	RCP15_PRRR(prrr);
641100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	RCP15_NMRR(nmrr);
642100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
643100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	for (i = 0; i < NUM_TEX_CLASS; i++) {
644100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		c_nos = PRRR_NOS(prrr, i);
645100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		c_mt = PRRR_MT(prrr, i);
646100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		c_icp = NMRR_ICP(nmrr, i);
647100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		c_ocp = NMRR_OCP(nmrr, i);
648100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
649100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko		if (icp == c_icp && ocp == c_ocp && c_mt == mt && c_nos == nos)
650100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko			return i;
651100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	}
652100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
653100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	return -ENODEV;
654100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko}
655100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
656100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenkostatic void __init setup_iommu_tex_classes(void)
657100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko{
658100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	msm_iommu_tex_class[MSM_IOMMU_ATTR_NONCACHED] =
659100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko			get_tex_class(CP_NONCACHED, CP_NONCACHED, MT_NORMAL, 1);
660100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
661100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_WA] =
662100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko			get_tex_class(CP_WB_WA, CP_WB_WA, MT_NORMAL, 1);
663100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
664100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_NWA] =
665100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko			get_tex_class(CP_WB_NWA, CP_WB_NWA, MT_NORMAL, 1);
666100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
667100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WT] =
668100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko			get_tex_class(CP_WT, CP_WT, MT_NORMAL, 1);
669100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko}
670100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko
671516cbc793eb4be5123289d067b54dfcdabeddb25Stepan Moskovchenkostatic int __init msm_iommu_init(void)
6720720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko{
673100832c9b6adb3d63407416931caeba3f3b9a777Stepan Moskovchenko	setup_iommu_tex_classes();
6740720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	register_iommu(&msm_iommu_ops);
6750720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko	return 0;
6760720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko}
6770720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
6780720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenkosubsys_initcall(msm_iommu_init);
6790720d1f052dc1576396a39b327da6e60082c4efaStepan Moskovchenko
6800720d1f052dc1576396a39b327da6e60082c4efaStepan MoskovchenkoMODULE_LICENSE("GPL v2");
6810720d1f052dc1576396a39b327da6e60082c4efaStepan MoskovchenkoMODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
682