aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm/iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-msm/iommu.c')
-rw-r--r--arch/arm/mach-msm/iommu.c58
1 files changed, 55 insertions, 3 deletions
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;