Merge "msm: iommu: Support IOMMU page fault reporting" into msm-3.0
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 994150f..a6f27d7 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -73,7 +73,6 @@
*/
struct msm_iommu_drvdata {
void __iomem *base;
- int irq;
int ncb;
int ttbr_split;
struct clk *clk;
@@ -95,6 +94,8 @@
int num;
struct platform_device *pdev;
struct list_head attached_elm;
+ struct iommu_domain *attached_domain;
+ const char *name;
};
/*
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 19e1684..0652f3b 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -374,6 +374,7 @@
__disable_clocks(iommu_drvdata);
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
+ ctx_drvdata->attached_domain = domain;
fail:
mutex_unlock(&msm_iommu_lock);
return ret;
@@ -411,7 +412,7 @@
__reset_context(iommu_drvdata->base, ctx_dev->num);
__disable_clocks(iommu_drvdata);
list_del_init(&ctx_drvdata->attached_elm);
-
+ ctx_drvdata->attached_domain = NULL;
fail:
mutex_unlock(&msm_iommu_lock);
}
@@ -974,41 +975,55 @@
irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
{
- struct msm_iommu_drvdata *drvdata = dev_id;
+ struct msm_iommu_ctx_drvdata *ctx_drvdata = dev_id;
+ struct msm_iommu_drvdata *drvdata;
void __iomem *base;
- unsigned int fsr;
- int i, ret;
+ unsigned int fsr, num;
+ int ret;
mutex_lock(&msm_iommu_lock);
+ BUG_ON(!ctx_drvdata);
- if (!drvdata) {
- pr_err("Invalid device ID in context interrupt handler\n");
- goto fail;
- }
+ drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+ BUG_ON(!drvdata);
base = drvdata->base;
-
- pr_err("Unexpected IOMMU page fault!\n");
- pr_err("base = %08x\n", (unsigned int) base);
- pr_err("name = %s\n", drvdata->name);
+ num = ctx_drvdata->num;
ret = __enable_clocks(drvdata);
if (ret)
goto fail;
- for (i = 0; i < drvdata->ncb; i++) {
- fsr = GET_FSR(base, i);
- if (fsr) {
- pr_err("Fault occurred in context %d.\n", i);
+ fsr = GET_FSR(base, num);
+
+ if (fsr) {
+ if (!ctx_drvdata->attached_domain) {
+ pr_err("Bad domain in interrupt handler\n");
+ ret = -ENOSYS;
+ } else
+ ret = report_iommu_fault(ctx_drvdata->attached_domain,
+ &ctx_drvdata->pdev->dev,
+ GET_FAR(base, num), 0);
+
+ if (ret == -ENOSYS) {
+ pr_err("Unexpected IOMMU page fault!\n");
+ pr_err("name = %s\n", drvdata->name);
+ pr_err("context = %s (%d)\n", ctx_drvdata->name, num);
pr_err("Interesting registers:\n");
- print_ctx_regs(base, i);
- SET_FSR(base, i, 0x4000000F);
+ print_ctx_regs(base, num);
}
- }
+
+ SET_FSR(base, num, fsr);
+ SET_RESUME(base, num, 1);
+
+ ret = IRQ_HANDLED;
+ } else
+ ret = IRQ_NONE;
+
__disable_clocks(drvdata);
fail:
mutex_unlock(&msm_iommu_lock);
- return 0;
+ return ret;
}
static phys_addr_t msm_iommu_get_pt_base_addr(struct iommu_domain *domain)
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
index 6633cae..b8b5aa3 100644
--- a/arch/arm/mach-msm/iommu_dev.c
+++ b/arch/arm/mach-msm/iommu_dev.c
@@ -131,7 +131,7 @@
struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
void __iomem *regs_base;
resource_size_t len;
- int ret, irq, par;
+ int ret, par;
if (pdev->id == -1) {
msm_iommu_root_dev = pdev;
@@ -202,12 +202,6 @@
goto fail_mem;
}
- irq = platform_get_irq_byname(pdev, "nonsecure_irq");
- if (irq < 0) {
- ret = -ENODEV;
- goto fail_io;
- }
-
msm_iommu_reset(regs_base, iommu_dev->ncb);
SET_M(regs_base, 0, 1);
@@ -226,24 +220,15 @@
goto fail_io;
}
- ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
- IRQF_ONESHOT, "msm_iommu_secure_irpt_handler", drvdata);
- if (ret) {
- pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
- goto fail_io;
- }
-
-
drvdata->pclk = iommu_pclk;
drvdata->clk = iommu_clk;
drvdata->base = regs_base;
- drvdata->irq = irq;
drvdata->ncb = iommu_dev->ncb;
drvdata->ttbr_split = iommu_dev->ttbr_split;
drvdata->name = iommu_dev->name;
- pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
- iommu_dev->name, regs_base, irq, iommu_dev->ncb);
+ pr_info("device %s mapped at %p, with %d ctx banks\n",
+ iommu_dev->name, regs_base, iommu_dev->ncb);
platform_set_drvdata(pdev, drvdata);
@@ -292,7 +277,7 @@
struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
- int i, ret;
+ int i, ret, irq;
if (!c || !pdev->dev.parent) {
ret = -EINVAL;
goto fail;
@@ -312,6 +297,23 @@
}
ctx_drvdata->num = c->num;
ctx_drvdata->pdev = pdev;
+ ctx_drvdata->name = c->name;
+
+ irq = platform_get_irq_byname(to_platform_device(pdev->dev.parent),
+ "nonsecure_irq");
+ if (irq < 0) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ ret = request_threaded_irq(irq, NULL, msm_iommu_fault_handler,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "msm_iommu_nonsecure_irq", ctx_drvdata);
+
+ if (ret) {
+ pr_err("request_threaded_irq %d failed: %d\n", irq, ret);
+ goto fail;
+ }
INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
platform_set_drvdata(pdev, ctx_drvdata);