diff options
-rw-r--r-- | arch/arm/mach-msm/iommu.c | 93 |
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 | |||
44 | static int msm_iommu_tex_class[4]; | ||
45 | |||
36 | DEFINE_SPINLOCK(msm_iommu_lock); | 46 | DEFINE_SPINLOCK(msm_iommu_lock); |
37 | 47 | ||
38 | struct msm_priv { | 48 | struct msm_priv { |
@@ -98,6 +108,7 @@ static void __reset_context(void __iomem *base, int ctx) | |||
98 | 108 | ||
99 | static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable) | 109 | static 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 | ||
628 | static 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 | |||
651 | static 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 | |||
596 | static int __init msm_iommu_init(void) | 666 | static 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 | } |