aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm
diff options
context:
space:
mode:
authorStepan Moskovchenko <stepanm@codeaurora.org>2010-11-15 21:20:08 -0500
committerDaniel Walker <dwalker@codeaurora.org>2010-11-30 19:10:53 -0500
commit100832c9b6adb3d63407416931caeba3f3b9a777 (patch)
tree8b1a7ba23f7555ce7fae33c792fe4fcf02d71764 /arch/arm/mach-msm
parent08bd6839783319085ee0db4c888534e626225774 (diff)
msm: iommu: Support cache-coherent memory access
Add support for allowing IOMMU memory transactions to be cache coherent, eliminating the need for software cache management in certain situations. This can lead to improvements in performance and power usage, assuming the multimedia core's access pattern exhibits spatial locality and that its working set fits into the cache. Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org> Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
Diffstat (limited to 'arch/arm/mach-msm')
-rw-r--r--arch/arm/mach-msm/iommu.c93
1 files changed, 82 insertions, 11 deletions
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 67e8f531b7af..a468ee309d65 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -33,6 +33,16 @@
33#include <mach/iommu_hw-8xxx.h> 33#include <mach/iommu_hw-8xxx.h>
34#include <mach/iommu.h> 34#include <mach/iommu.h>
35 35
36#define MRC(reg, processor, op1, crn, crm, op2) \
37__asm__ __volatile__ ( \
38" mrc " #processor "," #op1 ", %0," #crn "," #crm "," #op2 "\n" \
39: "=r" (reg))
40
41#define RCP15_PRRR(reg) MRC(reg, p15, 0, c10, c2, 0)
42#define RCP15_NMRR(reg) MRC(reg, p15, 0, c10, c2, 1)
43
44static int msm_iommu_tex_class[4];
45
36DEFINE_SPINLOCK(msm_iommu_lock); 46DEFINE_SPINLOCK(msm_iommu_lock);
37 47
38struct msm_priv { 48struct msm_priv {
@@ -98,6 +108,7 @@ static void __reset_context(void __iomem *base, int ctx)
98 108
99static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable) 109static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
100{ 110{
111 unsigned int prrr, nmrr;
101 __reset_context(base, ctx); 112 __reset_context(base, ctx);
102 113
103 /* Set up HTW mode */ 114 /* Set up HTW mode */
@@ -130,11 +141,11 @@ static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
130 /* Turn on TEX Remap */ 141 /* Turn on TEX Remap */
131 SET_TRE(base, ctx, 1); 142 SET_TRE(base, ctx, 1);
132 143
133 /* Do not configure PRRR / NMRR on the IOMMU for now. We will assume 144 /* Set TEX remap attributes */
134 * TEX class 0 for everything until attributes are properly worked out 145 RCP15_PRRR(prrr);
135 */ 146 RCP15_NMRR(nmrr);
136 SET_PRRR(base, ctx, 0); 147 SET_PRRR(base, ctx, prrr);
137 SET_NMRR(base, ctx, 0); 148 SET_NMRR(base, ctx, nmrr);
138 149
139 /* Turn on BFB prefetch */ 150 /* Turn on BFB prefetch */
140 SET_BFBDFE(base, ctx, 1); 151 SET_BFBDFE(base, ctx, 1);
@@ -304,12 +315,21 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
304 unsigned long *sl_table; 315 unsigned long *sl_table;
305 unsigned long *sl_pte; 316 unsigned long *sl_pte;
306 unsigned long sl_offset; 317 unsigned long sl_offset;
318 unsigned int pgprot;
307 size_t len = 0x1000UL << order; 319 size_t len = 0x1000UL << order;
308 int ret = 0; 320 int ret = 0, tex, sh;
309 321
310 spin_lock_irqsave(&msm_iommu_lock, flags); 322 spin_lock_irqsave(&msm_iommu_lock, flags);
311 priv = domain->priv;
312 323
324 sh = (prot & MSM_IOMMU_ATTR_SH) ? 1 : 0;
325 tex = msm_iommu_tex_class[prot & MSM_IOMMU_CP_MASK];
326
327 if (tex < 0 || tex > NUM_TEX_CLASS - 1) {
328 ret = -EINVAL;
329 goto fail;
330 }
331
332 priv = domain->priv;
313 if (!priv) { 333 if (!priv) {
314 ret = -EINVAL; 334 ret = -EINVAL;
315 goto fail; 335 goto fail;
@@ -330,6 +350,18 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
330 goto fail; 350 goto fail;
331 } 351 }
332 352
353 if (len == SZ_16M || len == SZ_1M) {
354 pgprot = sh ? FL_SHARED : 0;
355 pgprot |= tex & 0x01 ? FL_BUFFERABLE : 0;
356 pgprot |= tex & 0x02 ? FL_CACHEABLE : 0;
357 pgprot |= tex & 0x04 ? FL_TEX0 : 0;
358 } else {
359 pgprot = sh ? SL_SHARED : 0;
360 pgprot |= tex & 0x01 ? SL_BUFFERABLE : 0;
361 pgprot |= tex & 0x02 ? SL_CACHEABLE : 0;
362 pgprot |= tex & 0x04 ? SL_TEX0 : 0;
363 }
364
333 fl_offset = FL_OFFSET(va); /* Upper 12 bits */ 365 fl_offset = FL_OFFSET(va); /* Upper 12 bits */
334 fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */ 366 fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */
335 367
@@ -338,12 +370,12 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
338 for (i = 0; i < 16; i++) 370 for (i = 0; i < 16; i++)
339 *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION | 371 *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
340 FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT | 372 FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT |
341 FL_SHARED; 373 FL_SHARED | pgprot;
342 } 374 }
343 375
344 if (len == SZ_1M) 376 if (len == SZ_1M)
345 *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE | 377 *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE |
346 FL_TYPE_SECT | FL_SHARED; 378 FL_TYPE_SECT | FL_SHARED | pgprot;
347 379
348 /* Need a 2nd level table */ 380 /* Need a 2nd level table */
349 if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) { 381 if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) {
@@ -368,14 +400,14 @@ static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
368 400
369 if (len == SZ_4K) 401 if (len == SZ_4K)
370 *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 | 402 *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 |
371 SL_SHARED | SL_TYPE_SMALL; 403 SL_SHARED | SL_TYPE_SMALL | pgprot;
372 404
373 if (len == SZ_64K) { 405 if (len == SZ_64K) {
374 int i; 406 int i;
375 407
376 for (i = 0; i < 16; i++) 408 for (i = 0; i < 16; i++)
377 *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 | 409 *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 |
378 SL_AP1 | SL_SHARED | SL_TYPE_LARGE; 410 SL_AP1 | SL_SHARED | SL_TYPE_LARGE | pgprot;
379 } 411 }
380 412
381 __flush_iotlb(domain); 413 __flush_iotlb(domain);
@@ -593,8 +625,47 @@ static struct iommu_ops msm_iommu_ops = {
593 .domain_has_cap = msm_iommu_domain_has_cap 625 .domain_has_cap = msm_iommu_domain_has_cap
594}; 626};
595 627
628static int __init get_tex_class(int icp, int ocp, int mt, int nos)
629{
630 int i = 0;
631 unsigned int prrr = 0;
632 unsigned int nmrr = 0;
633 int c_icp, c_ocp, c_mt, c_nos;
634
635 RCP15_PRRR(prrr);
636 RCP15_NMRR(nmrr);
637
638 for (i = 0; i < NUM_TEX_CLASS; i++) {
639 c_nos = PRRR_NOS(prrr, i);
640 c_mt = PRRR_MT(prrr, i);
641 c_icp = NMRR_ICP(nmrr, i);
642 c_ocp = NMRR_OCP(nmrr, i);
643
644 if (icp == c_icp && ocp == c_ocp && c_mt == mt && c_nos == nos)
645 return i;
646 }
647
648 return -ENODEV;
649}
650
651static void __init setup_iommu_tex_classes(void)
652{
653 msm_iommu_tex_class[MSM_IOMMU_ATTR_NONCACHED] =
654 get_tex_class(CP_NONCACHED, CP_NONCACHED, MT_NORMAL, 1);
655
656 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_WA] =
657 get_tex_class(CP_WB_WA, CP_WB_WA, MT_NORMAL, 1);
658
659 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_NWA] =
660 get_tex_class(CP_WB_NWA, CP_WB_NWA, MT_NORMAL, 1);
661
662 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WT] =
663 get_tex_class(CP_WT, CP_WT, MT_NORMAL, 1);
664}
665
596static int __init msm_iommu_init(void) 666static int __init msm_iommu_init(void)
597{ 667{
668 setup_iommu_tex_classes();
598 register_iommu(&msm_iommu_ops); 669 register_iommu(&msm_iommu_ops);
599 return 0; 670 return 0;
600} 671}