diff options
Diffstat (limited to 'arch/arm/mach-msm/iommu.c')
-rw-r--r-- | arch/arm/mach-msm/iommu.c | 58 |
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 | ||
54 | static 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 | } | ||
67 | fail: | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static 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 | |||
53 | static int __flush_iotlb(struct iommu_domain *domain) | 78 | static 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 | 114 | fail: | |
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 | ||
309 | fail: | 351 | fail: |
@@ -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); | ||
550 | fail: | 597 | fail: |
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); | ||
617 | fail: | 669 | fail: |
618 | spin_unlock(&msm_iommu_lock); | 670 | spin_unlock(&msm_iommu_lock); |
619 | return 0; | 671 | return 0; |