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 | } |
