aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-msm/include/mach/iommu.h9
-rw-r--r--arch/arm/mach-msm/iommu.c58
2 files changed, 62 insertions, 5 deletions
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index 296c0f10f230..8738a4455588 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -1,4 +1,4 @@
1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. 1/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 * 2 *
3 * This program is free software; you can redistribute it and/or modify 3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and 4 * it under the terms of the GNU General Public License version 2 and
@@ -19,6 +19,7 @@
19#define MSM_IOMMU_H 19#define MSM_IOMMU_H
20 20
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/clk.h>
22 23
23/* Sharability attributes of MSM IOMMU mappings */ 24/* Sharability attributes of MSM IOMMU mappings */
24#define MSM_IOMMU_ATTR_NON_SH 0x0 25#define MSM_IOMMU_ATTR_NON_SH 0x0
@@ -74,13 +75,17 @@ struct msm_iommu_ctx_dev {
74 * struct msm_iommu_drvdata - A single IOMMU hardware instance 75 * struct msm_iommu_drvdata - A single IOMMU hardware instance
75 * @base: IOMMU config port base address (VA) 76 * @base: IOMMU config port base address (VA)
76 * @irq: Interrupt number 77 * @irq: Interrupt number
77 * 78 * @clk: The bus clock for this IOMMU hardware instance
79 * @pclk: The clock for the IOMMU bus interconnect
80 *
78 * A msm_iommu_drvdata holds the global driver data about a single piece 81 * A msm_iommu_drvdata holds the global driver data about a single piece
79 * of an IOMMU hardware instance. 82 * of an IOMMU hardware instance.
80 */ 83 */
81struct msm_iommu_drvdata { 84struct msm_iommu_drvdata {
82 void __iomem *base; 85 void __iomem *base;
83 int irq; 86 int irq;
87 struct clk *clk;
88 struct clk *pclk;
84}; 89};
85 90
86/** 91/**
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index e2d58e4cb0d7..cde3cd0f8c0c 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -1,4 +1,4 @@
1/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. 1/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 * 2 *
3 * This program is free software; you can redistribute it and/or modify 3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and 4 * it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@
26#include <linux/spinlock.h> 26#include <linux/spinlock.h>
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/iommu.h> 28#include <linux/iommu.h>
29#include <linux/clk.h>
29 30
30#include <asm/cacheflush.h> 31#include <asm/cacheflush.h>
31#include <asm/sizes.h> 32#include <asm/sizes.h>
@@ -50,6 +51,30 @@ struct msm_priv {
50 struct list_head list_attached; 51 struct list_head list_attached;
51}; 52};
52 53
54static int __enable_clocks(struct msm_iommu_drvdata *drvdata)
55{
56 int ret;
57
58 ret = clk_enable(drvdata->pclk);
59 if (ret)
60 goto fail;
61
62 if (drvdata->clk) {
63 ret = clk_enable(drvdata->clk);
64 if (ret)
65 clk_disable(drvdata->pclk);
66 }
67fail:
68 return ret;
69}
70
71static void __disable_clocks(struct msm_iommu_drvdata *drvdata)
72{
73 if (drvdata->clk)
74 clk_disable(drvdata->clk);
75 clk_disable(drvdata->pclk);
76}
77
53static int __flush_iotlb(struct iommu_domain *domain) 78static int __flush_iotlb(struct iommu_domain *domain)
54{ 79{
55 struct msm_priv *priv = domain->priv; 80 struct msm_priv *priv = domain->priv;
@@ -77,9 +102,16 @@ static int __flush_iotlb(struct iommu_domain *domain)
77 BUG(); 102 BUG();
78 103
79 iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent); 104 iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
105 BUG_ON(!iommu_drvdata);
106
107 ret = __enable_clocks(iommu_drvdata);
108 if (ret)
109 goto fail;
110
80 SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0); 111 SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0);
112 __disable_clocks(iommu_drvdata);
81 } 113 }
82 114fail:
83 return ret; 115 return ret;
84} 116}
85 117
@@ -265,9 +297,14 @@ static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
265 goto fail; 297 goto fail;
266 } 298 }
267 299
300 ret = __enable_clocks(iommu_drvdata);
301 if (ret)
302 goto fail;
303
268 __program_context(iommu_drvdata->base, ctx_dev->num, 304 __program_context(iommu_drvdata->base, ctx_dev->num,
269 __pa(priv->pgtable)); 305 __pa(priv->pgtable));
270 306
307 __disable_clocks(iommu_drvdata);
271 list_add(&(ctx_drvdata->attached_elm), &priv->list_attached); 308 list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
272 ret = __flush_iotlb(domain); 309 ret = __flush_iotlb(domain);
273 310
@@ -303,7 +340,12 @@ static void msm_iommu_detach_dev(struct iommu_domain *domain,
303 if (ret) 340 if (ret)
304 goto fail; 341 goto fail;
305 342
343 ret = __enable_clocks(iommu_drvdata);
344 if (ret)
345 goto fail;
346
306 __reset_context(iommu_drvdata->base, ctx_dev->num); 347 __reset_context(iommu_drvdata->base, ctx_dev->num);
348 __disable_clocks(iommu_drvdata);
307 list_del_init(&ctx_drvdata->attached_elm); 349 list_del_init(&ctx_drvdata->attached_elm);
308 350
309fail: 351fail:
@@ -532,6 +574,10 @@ static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
532 base = iommu_drvdata->base; 574 base = iommu_drvdata->base;
533 ctx = ctx_drvdata->num; 575 ctx = ctx_drvdata->num;
534 576
577 ret = __enable_clocks(iommu_drvdata);
578 if (ret)
579 goto fail;
580
535 /* Invalidate context TLB */ 581 /* Invalidate context TLB */
536 SET_CTX_TLBIALL(base, ctx, 0); 582 SET_CTX_TLBIALL(base, ctx, 0);
537 SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT); 583 SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT);
@@ -547,6 +593,7 @@ static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
547 if (GET_FAULT(base, ctx)) 593 if (GET_FAULT(base, ctx))
548 ret = 0; 594 ret = 0;
549 595
596 __disable_clocks(iommu_drvdata);
550fail: 597fail:
551 spin_unlock_irqrestore(&msm_iommu_lock, flags); 598 spin_unlock_irqrestore(&msm_iommu_lock, flags);
552 return ret; 599 return ret;
@@ -590,7 +637,7 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
590 struct msm_iommu_drvdata *drvdata = dev_id; 637 struct msm_iommu_drvdata *drvdata = dev_id;
591 void __iomem *base; 638 void __iomem *base;
592 unsigned int fsr; 639 unsigned int fsr;
593 int ncb, i; 640 int ncb, i, ret;
594 641
595 spin_lock(&msm_iommu_lock); 642 spin_lock(&msm_iommu_lock);
596 643
@@ -604,6 +651,10 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
604 pr_err("Unexpected IOMMU page fault!\n"); 651 pr_err("Unexpected IOMMU page fault!\n");
605 pr_err("base = %08x\n", (unsigned int) base); 652 pr_err("base = %08x\n", (unsigned int) base);
606 653
654 ret = __enable_clocks(drvdata);
655 if (ret)
656 goto fail;
657
607 ncb = GET_NCB(base)+1; 658 ncb = GET_NCB(base)+1;
608 for (i = 0; i < ncb; i++) { 659 for (i = 0; i < ncb; i++) {
609 fsr = GET_FSR(base, i); 660 fsr = GET_FSR(base, i);
@@ -614,6 +665,7 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
614 SET_FSR(base, i, 0x4000000F); 665 SET_FSR(base, i, 0x4000000F);
615 } 666 }
616 } 667 }
668 __disable_clocks(drvdata);
617fail: 669fail:
618 spin_unlock(&msm_iommu_lock); 670 spin_unlock(&msm_iommu_lock);
619 return 0; 671 return 0;