msm_iommu.c revision 41f3f5138a5ea71ee603f3d556953fce9aba3074
1/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. 2 * 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 5 * only version 2 as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 15 * 02110-1301, USA. 16 */ 17 18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19#include <linux/kernel.h> 20#include <linux/module.h> 21#include <linux/platform_device.h> 22#include <linux/errno.h> 23#include <linux/io.h> 24#include <linux/interrupt.h> 25#include <linux/list.h> 26#include <linux/spinlock.h> 27#include <linux/slab.h> 28#include <linux/iommu.h> 29#include <linux/clk.h> 30 31#include <asm/cacheflush.h> 32#include <asm/sizes.h> 33 34#include <mach/iommu_hw-8xxx.h> 35#include <mach/iommu.h> 36 37#define MRC(reg, processor, op1, crn, crm, op2) \ 38__asm__ __volatile__ ( \ 39" mrc " #processor "," #op1 ", %0," #crn "," #crm "," #op2 "\n" \ 40: "=r" (reg)) 41 42#define RCP15_PRRR(reg) MRC(reg, p15, 0, c10, c2, 0) 43#define RCP15_NMRR(reg) MRC(reg, p15, 0, c10, c2, 1) 44 45static int msm_iommu_tex_class[4]; 46 47DEFINE_SPINLOCK(msm_iommu_lock); 48 49struct msm_priv { 50 unsigned long *pgtable; 51 struct list_head list_attached; 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 78static int __flush_iotlb(struct iommu_domain *domain) 79{ 80 struct msm_priv *priv = domain->priv; 81 struct msm_iommu_drvdata *iommu_drvdata; 82 struct msm_iommu_ctx_drvdata *ctx_drvdata; 83 int ret = 0; 84#ifndef CONFIG_IOMMU_PGTABLES_L2 85 unsigned long *fl_table = priv->pgtable; 86 int i; 87 88 if (!list_empty(&priv->list_attached)) { 89 dmac_flush_range(fl_table, fl_table + SZ_16K); 90 91 for (i = 0; i < NUM_FL_PTE; i++) 92 if ((fl_table[i] & 0x03) == FL_TYPE_TABLE) { 93 void *sl_table = __va(fl_table[i] & 94 FL_BASE_MASK); 95 dmac_flush_range(sl_table, sl_table + SZ_4K); 96 } 97 } 98#endif 99 100 list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) { 101 if (!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent) 102 BUG(); 103 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 111 SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0); 112 __disable_clocks(iommu_drvdata); 113 } 114fail: 115 return ret; 116} 117 118static void __reset_context(void __iomem *base, int ctx) 119{ 120 SET_BPRCOSH(base, ctx, 0); 121 SET_BPRCISH(base, ctx, 0); 122 SET_BPRCNSH(base, ctx, 0); 123 SET_BPSHCFG(base, ctx, 0); 124 SET_BPMTCFG(base, ctx, 0); 125 SET_ACTLR(base, ctx, 0); 126 SET_SCTLR(base, ctx, 0); 127 SET_FSRRESTORE(base, ctx, 0); 128 SET_TTBR0(base, ctx, 0); 129 SET_TTBR1(base, ctx, 0); 130 SET_TTBCR(base, ctx, 0); 131 SET_BFBCR(base, ctx, 0); 132 SET_PAR(base, ctx, 0); 133 SET_FAR(base, ctx, 0); 134 SET_CTX_TLBIALL(base, ctx, 0); 135 SET_TLBFLPTER(base, ctx, 0); 136 SET_TLBSLPTER(base, ctx, 0); 137 SET_TLBLKCR(base, ctx, 0); 138 SET_PRRR(base, ctx, 0); 139 SET_NMRR(base, ctx, 0); 140 SET_CONTEXTIDR(base, ctx, 0); 141} 142 143static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable) 144{ 145 unsigned int prrr, nmrr; 146 __reset_context(base, ctx); 147 148 /* Set up HTW mode */ 149 /* TLB miss configuration: perform HTW on miss */ 150 SET_TLBMCFG(base, ctx, 0x3); 151 152 /* V2P configuration: HTW for access */ 153 SET_V2PCFG(base, ctx, 0x3); 154 155 SET_TTBCR(base, ctx, 0); 156 SET_TTBR0_PA(base, ctx, (pgtable >> 14)); 157 158 /* Invalidate the TLB for this context */ 159 SET_CTX_TLBIALL(base, ctx, 0); 160 161 /* Set interrupt number to "secure" interrupt */ 162 SET_IRPTNDX(base, ctx, 0); 163 164 /* Enable context fault interrupt */ 165 SET_CFEIE(base, ctx, 1); 166 167 /* Stall access on a context fault and let the handler deal with it */ 168 SET_CFCFG(base, ctx, 1); 169 170 /* Redirect all cacheable requests to L2 slave port. */ 171 SET_RCISH(base, ctx, 1); 172 SET_RCOSH(base, ctx, 1); 173 SET_RCNSH(base, ctx, 1); 174 175 /* Turn on TEX Remap */ 176 SET_TRE(base, ctx, 1); 177 178 /* Set TEX remap attributes */ 179 RCP15_PRRR(prrr); 180 RCP15_NMRR(nmrr); 181 SET_PRRR(base, ctx, prrr); 182 SET_NMRR(base, ctx, nmrr); 183 184 /* Turn on BFB prefetch */ 185 SET_BFBDFE(base, ctx, 1); 186 187#ifdef CONFIG_IOMMU_PGTABLES_L2 188 /* Configure page tables as inner-cacheable and shareable to reduce 189 * the TLB miss penalty. 190 */ 191 SET_TTBR0_SH(base, ctx, 1); 192 SET_TTBR1_SH(base, ctx, 1); 193 194 SET_TTBR0_NOS(base, ctx, 1); 195 SET_TTBR1_NOS(base, ctx, 1); 196 197 SET_TTBR0_IRGNH(base, ctx, 0); /* WB, WA */ 198 SET_TTBR0_IRGNL(base, ctx, 1); 199 200 SET_TTBR1_IRGNH(base, ctx, 0); /* WB, WA */ 201 SET_TTBR1_IRGNL(base, ctx, 1); 202 203 SET_TTBR0_ORGN(base, ctx, 1); /* WB, WA */ 204 SET_TTBR1_ORGN(base, ctx, 1); /* WB, WA */ 205#endif 206 207 /* Enable the MMU */ 208 SET_M(base, ctx, 1); 209} 210 211static int msm_iommu_domain_init(struct iommu_domain *domain) 212{ 213 struct msm_priv *priv = kzalloc(sizeof(*priv), GFP_KERNEL); 214 215 if (!priv) 216 goto fail_nomem; 217 218 INIT_LIST_HEAD(&priv->list_attached); 219 priv->pgtable = (unsigned long *)__get_free_pages(GFP_KERNEL, 220 get_order(SZ_16K)); 221 222 if (!priv->pgtable) 223 goto fail_nomem; 224 225 memset(priv->pgtable, 0, SZ_16K); 226 domain->priv = priv; 227 return 0; 228 229fail_nomem: 230 kfree(priv); 231 return -ENOMEM; 232} 233 234static void msm_iommu_domain_destroy(struct iommu_domain *domain) 235{ 236 struct msm_priv *priv; 237 unsigned long flags; 238 unsigned long *fl_table; 239 int i; 240 241 spin_lock_irqsave(&msm_iommu_lock, flags); 242 priv = domain->priv; 243 domain->priv = NULL; 244 245 if (priv) { 246 fl_table = priv->pgtable; 247 248 for (i = 0; i < NUM_FL_PTE; i++) 249 if ((fl_table[i] & 0x03) == FL_TYPE_TABLE) 250 free_page((unsigned long) __va(((fl_table[i]) & 251 FL_BASE_MASK))); 252 253 free_pages((unsigned long)priv->pgtable, get_order(SZ_16K)); 254 priv->pgtable = NULL; 255 } 256 257 kfree(priv); 258 spin_unlock_irqrestore(&msm_iommu_lock, flags); 259} 260 261static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) 262{ 263 struct msm_priv *priv; 264 struct msm_iommu_ctx_dev *ctx_dev; 265 struct msm_iommu_drvdata *iommu_drvdata; 266 struct msm_iommu_ctx_drvdata *ctx_drvdata; 267 struct msm_iommu_ctx_drvdata *tmp_drvdata; 268 int ret = 0; 269 unsigned long flags; 270 271 spin_lock_irqsave(&msm_iommu_lock, flags); 272 273 priv = domain->priv; 274 275 if (!priv || !dev) { 276 ret = -EINVAL; 277 goto fail; 278 } 279 280 iommu_drvdata = dev_get_drvdata(dev->parent); 281 ctx_drvdata = dev_get_drvdata(dev); 282 ctx_dev = dev->platform_data; 283 284 if (!iommu_drvdata || !ctx_drvdata || !ctx_dev) { 285 ret = -EINVAL; 286 goto fail; 287 } 288 289 if (!list_empty(&ctx_drvdata->attached_elm)) { 290 ret = -EBUSY; 291 goto fail; 292 } 293 294 list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm) 295 if (tmp_drvdata == ctx_drvdata) { 296 ret = -EBUSY; 297 goto fail; 298 } 299 300 ret = __enable_clocks(iommu_drvdata); 301 if (ret) 302 goto fail; 303 304 __program_context(iommu_drvdata->base, ctx_dev->num, 305 __pa(priv->pgtable)); 306 307 __disable_clocks(iommu_drvdata); 308 list_add(&(ctx_drvdata->attached_elm), &priv->list_attached); 309 ret = __flush_iotlb(domain); 310 311fail: 312 spin_unlock_irqrestore(&msm_iommu_lock, flags); 313 return ret; 314} 315 316static void msm_iommu_detach_dev(struct iommu_domain *domain, 317 struct device *dev) 318{ 319 struct msm_priv *priv; 320 struct msm_iommu_ctx_dev *ctx_dev; 321 struct msm_iommu_drvdata *iommu_drvdata; 322 struct msm_iommu_ctx_drvdata *ctx_drvdata; 323 unsigned long flags; 324 int ret; 325 326 spin_lock_irqsave(&msm_iommu_lock, flags); 327 priv = domain->priv; 328 329 if (!priv || !dev) 330 goto fail; 331 332 iommu_drvdata = dev_get_drvdata(dev->parent); 333 ctx_drvdata = dev_get_drvdata(dev); 334 ctx_dev = dev->platform_data; 335 336 if (!iommu_drvdata || !ctx_drvdata || !ctx_dev) 337 goto fail; 338 339 ret = __flush_iotlb(domain); 340 if (ret) 341 goto fail; 342 343 ret = __enable_clocks(iommu_drvdata); 344 if (ret) 345 goto fail; 346 347 __reset_context(iommu_drvdata->base, ctx_dev->num); 348 __disable_clocks(iommu_drvdata); 349 list_del_init(&ctx_drvdata->attached_elm); 350 351fail: 352 spin_unlock_irqrestore(&msm_iommu_lock, flags); 353} 354 355static int msm_iommu_map(struct iommu_domain *domain, unsigned long va, 356 phys_addr_t pa, int order, int prot) 357{ 358 struct msm_priv *priv; 359 unsigned long flags; 360 unsigned long *fl_table; 361 unsigned long *fl_pte; 362 unsigned long fl_offset; 363 unsigned long *sl_table; 364 unsigned long *sl_pte; 365 unsigned long sl_offset; 366 unsigned int pgprot; 367 size_t len = 0x1000UL << order; 368 int ret = 0, tex, sh; 369 370 spin_lock_irqsave(&msm_iommu_lock, flags); 371 372 sh = (prot & MSM_IOMMU_ATTR_SH) ? 1 : 0; 373 tex = msm_iommu_tex_class[prot & MSM_IOMMU_CP_MASK]; 374 375 if (tex < 0 || tex > NUM_TEX_CLASS - 1) { 376 ret = -EINVAL; 377 goto fail; 378 } 379 380 priv = domain->priv; 381 if (!priv) { 382 ret = -EINVAL; 383 goto fail; 384 } 385 386 fl_table = priv->pgtable; 387 388 if (len != SZ_16M && len != SZ_1M && 389 len != SZ_64K && len != SZ_4K) { 390 pr_debug("Bad size: %d\n", len); 391 ret = -EINVAL; 392 goto fail; 393 } 394 395 if (!fl_table) { 396 pr_debug("Null page table\n"); 397 ret = -EINVAL; 398 goto fail; 399 } 400 401 if (len == SZ_16M || len == SZ_1M) { 402 pgprot = sh ? FL_SHARED : 0; 403 pgprot |= tex & 0x01 ? FL_BUFFERABLE : 0; 404 pgprot |= tex & 0x02 ? FL_CACHEABLE : 0; 405 pgprot |= tex & 0x04 ? FL_TEX0 : 0; 406 } else { 407 pgprot = sh ? SL_SHARED : 0; 408 pgprot |= tex & 0x01 ? SL_BUFFERABLE : 0; 409 pgprot |= tex & 0x02 ? SL_CACHEABLE : 0; 410 pgprot |= tex & 0x04 ? SL_TEX0 : 0; 411 } 412 413 fl_offset = FL_OFFSET(va); /* Upper 12 bits */ 414 fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */ 415 416 if (len == SZ_16M) { 417 int i = 0; 418 for (i = 0; i < 16; i++) 419 *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION | 420 FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT | 421 FL_SHARED | pgprot; 422 } 423 424 if (len == SZ_1M) 425 *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE | 426 FL_TYPE_SECT | FL_SHARED | pgprot; 427 428 /* Need a 2nd level table */ 429 if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) { 430 unsigned long *sl; 431 sl = (unsigned long *) __get_free_pages(GFP_ATOMIC, 432 get_order(SZ_4K)); 433 434 if (!sl) { 435 pr_debug("Could not allocate second level table\n"); 436 ret = -ENOMEM; 437 goto fail; 438 } 439 440 memset(sl, 0, SZ_4K); 441 *fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | FL_TYPE_TABLE); 442 } 443 444 sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK)); 445 sl_offset = SL_OFFSET(va); 446 sl_pte = sl_table + sl_offset; 447 448 449 if (len == SZ_4K) 450 *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 | 451 SL_SHARED | SL_TYPE_SMALL | pgprot; 452 453 if (len == SZ_64K) { 454 int i; 455 456 for (i = 0; i < 16; i++) 457 *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 | 458 SL_AP1 | SL_SHARED | SL_TYPE_LARGE | pgprot; 459 } 460 461 ret = __flush_iotlb(domain); 462fail: 463 spin_unlock_irqrestore(&msm_iommu_lock, flags); 464 return ret; 465} 466 467static int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va, 468 int order) 469{ 470 struct msm_priv *priv; 471 unsigned long flags; 472 unsigned long *fl_table; 473 unsigned long *fl_pte; 474 unsigned long fl_offset; 475 unsigned long *sl_table; 476 unsigned long *sl_pte; 477 unsigned long sl_offset; 478 size_t len = 0x1000UL << order; 479 int i, ret = 0; 480 481 spin_lock_irqsave(&msm_iommu_lock, flags); 482 483 priv = domain->priv; 484 485 if (!priv) { 486 ret = -ENODEV; 487 goto fail; 488 } 489 490 fl_table = priv->pgtable; 491 492 if (len != SZ_16M && len != SZ_1M && 493 len != SZ_64K && len != SZ_4K) { 494 pr_debug("Bad length: %d\n", len); 495 ret = -EINVAL; 496 goto fail; 497 } 498 499 if (!fl_table) { 500 pr_debug("Null page table\n"); 501 ret = -EINVAL; 502 goto fail; 503 } 504 505 fl_offset = FL_OFFSET(va); /* Upper 12 bits */ 506 fl_pte = fl_table + fl_offset; /* int pointers, 4 bytes */ 507 508 if (*fl_pte == 0) { 509 pr_debug("First level PTE is 0\n"); 510 ret = -ENODEV; 511 goto fail; 512 } 513 514 /* Unmap supersection */ 515 if (len == SZ_16M) 516 for (i = 0; i < 16; i++) 517 *(fl_pte+i) = 0; 518 519 if (len == SZ_1M) 520 *fl_pte = 0; 521 522 sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK)); 523 sl_offset = SL_OFFSET(va); 524 sl_pte = sl_table + sl_offset; 525 526 if (len == SZ_64K) { 527 for (i = 0; i < 16; i++) 528 *(sl_pte+i) = 0; 529 } 530 531 if (len == SZ_4K) 532 *sl_pte = 0; 533 534 if (len == SZ_4K || len == SZ_64K) { 535 int used = 0; 536 537 for (i = 0; i < NUM_SL_PTE; i++) 538 if (sl_table[i]) 539 used = 1; 540 if (!used) { 541 free_page((unsigned long)sl_table); 542 *fl_pte = 0; 543 } 544 } 545 546 ret = __flush_iotlb(domain); 547fail: 548 spin_unlock_irqrestore(&msm_iommu_lock, flags); 549 return ret; 550} 551 552static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain, 553 unsigned long va) 554{ 555 struct msm_priv *priv; 556 struct msm_iommu_drvdata *iommu_drvdata; 557 struct msm_iommu_ctx_drvdata *ctx_drvdata; 558 unsigned int par; 559 unsigned long flags; 560 void __iomem *base; 561 phys_addr_t ret = 0; 562 int ctx; 563 564 spin_lock_irqsave(&msm_iommu_lock, flags); 565 566 priv = domain->priv; 567 if (list_empty(&priv->list_attached)) 568 goto fail; 569 570 ctx_drvdata = list_entry(priv->list_attached.next, 571 struct msm_iommu_ctx_drvdata, attached_elm); 572 iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent); 573 574 base = iommu_drvdata->base; 575 ctx = ctx_drvdata->num; 576 577 ret = __enable_clocks(iommu_drvdata); 578 if (ret) 579 goto fail; 580 581 /* Invalidate context TLB */ 582 SET_CTX_TLBIALL(base, ctx, 0); 583 SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT); 584 585 par = GET_PAR(base, ctx); 586 587 /* We are dealing with a supersection */ 588 if (GET_NOFAULT_SS(base, ctx)) 589 ret = (par & 0xFF000000) | (va & 0x00FFFFFF); 590 else /* Upper 20 bits from PAR, lower 12 from VA */ 591 ret = (par & 0xFFFFF000) | (va & 0x00000FFF); 592 593 if (GET_FAULT(base, ctx)) 594 ret = 0; 595 596 __disable_clocks(iommu_drvdata); 597fail: 598 spin_unlock_irqrestore(&msm_iommu_lock, flags); 599 return ret; 600} 601 602static int msm_iommu_domain_has_cap(struct iommu_domain *domain, 603 unsigned long cap) 604{ 605 return 0; 606} 607 608static void print_ctx_regs(void __iomem *base, int ctx) 609{ 610 unsigned int fsr = GET_FSR(base, ctx); 611 pr_err("FAR = %08x PAR = %08x\n", 612 GET_FAR(base, ctx), GET_PAR(base, ctx)); 613 pr_err("FSR = %08x [%s%s%s%s%s%s%s%s%s%s]\n", fsr, 614 (fsr & 0x02) ? "TF " : "", 615 (fsr & 0x04) ? "AFF " : "", 616 (fsr & 0x08) ? "APF " : "", 617 (fsr & 0x10) ? "TLBMF " : "", 618 (fsr & 0x20) ? "HTWDEEF " : "", 619 (fsr & 0x40) ? "HTWSEEF " : "", 620 (fsr & 0x80) ? "MHF " : "", 621 (fsr & 0x10000) ? "SL " : "", 622 (fsr & 0x40000000) ? "SS " : "", 623 (fsr & 0x80000000) ? "MULTI " : ""); 624 625 pr_err("FSYNR0 = %08x FSYNR1 = %08x\n", 626 GET_FSYNR0(base, ctx), GET_FSYNR1(base, ctx)); 627 pr_err("TTBR0 = %08x TTBR1 = %08x\n", 628 GET_TTBR0(base, ctx), GET_TTBR1(base, ctx)); 629 pr_err("SCTLR = %08x ACTLR = %08x\n", 630 GET_SCTLR(base, ctx), GET_ACTLR(base, ctx)); 631 pr_err("PRRR = %08x NMRR = %08x\n", 632 GET_PRRR(base, ctx), GET_NMRR(base, ctx)); 633} 634 635irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id) 636{ 637 struct msm_iommu_drvdata *drvdata = dev_id; 638 void __iomem *base; 639 unsigned int fsr; 640 int ncb, i, ret; 641 642 spin_lock(&msm_iommu_lock); 643 644 if (!drvdata) { 645 pr_err("Invalid device ID in context interrupt handler\n"); 646 goto fail; 647 } 648 649 base = drvdata->base; 650 651 pr_err("Unexpected IOMMU page fault!\n"); 652 pr_err("base = %08x\n", (unsigned int) base); 653 654 ret = __enable_clocks(drvdata); 655 if (ret) 656 goto fail; 657 658 ncb = GET_NCB(base)+1; 659 for (i = 0; i < ncb; i++) { 660 fsr = GET_FSR(base, i); 661 if (fsr) { 662 pr_err("Fault occurred in context %d.\n", i); 663 pr_err("Interesting registers:\n"); 664 print_ctx_regs(base, i); 665 SET_FSR(base, i, 0x4000000F); 666 } 667 } 668 __disable_clocks(drvdata); 669fail: 670 spin_unlock(&msm_iommu_lock); 671 return 0; 672} 673 674static struct iommu_ops msm_iommu_ops = { 675 .domain_init = msm_iommu_domain_init, 676 .domain_destroy = msm_iommu_domain_destroy, 677 .attach_dev = msm_iommu_attach_dev, 678 .detach_dev = msm_iommu_detach_dev, 679 .map = msm_iommu_map, 680 .unmap = msm_iommu_unmap, 681 .iova_to_phys = msm_iommu_iova_to_phys, 682 .domain_has_cap = msm_iommu_domain_has_cap 683}; 684 685static int __init get_tex_class(int icp, int ocp, int mt, int nos) 686{ 687 int i = 0; 688 unsigned int prrr = 0; 689 unsigned int nmrr = 0; 690 int c_icp, c_ocp, c_mt, c_nos; 691 692 RCP15_PRRR(prrr); 693 RCP15_NMRR(nmrr); 694 695 for (i = 0; i < NUM_TEX_CLASS; i++) { 696 c_nos = PRRR_NOS(prrr, i); 697 c_mt = PRRR_MT(prrr, i); 698 c_icp = NMRR_ICP(nmrr, i); 699 c_ocp = NMRR_OCP(nmrr, i); 700 701 if (icp == c_icp && ocp == c_ocp && c_mt == mt && c_nos == nos) 702 return i; 703 } 704 705 return -ENODEV; 706} 707 708static void __init setup_iommu_tex_classes(void) 709{ 710 msm_iommu_tex_class[MSM_IOMMU_ATTR_NONCACHED] = 711 get_tex_class(CP_NONCACHED, CP_NONCACHED, MT_NORMAL, 1); 712 713 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_WA] = 714 get_tex_class(CP_WB_WA, CP_WB_WA, MT_NORMAL, 1); 715 716 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WB_NWA] = 717 get_tex_class(CP_WB_NWA, CP_WB_NWA, MT_NORMAL, 1); 718 719 msm_iommu_tex_class[MSM_IOMMU_ATTR_CACHED_WT] = 720 get_tex_class(CP_WT, CP_WT, MT_NORMAL, 1); 721} 722 723static int __init msm_iommu_init(void) 724{ 725 setup_iommu_tex_classes(); 726 register_iommu(&msm_iommu_ops); 727 return 0; 728} 729 730subsys_initcall(msm_iommu_init); 731 732MODULE_LICENSE("GPL v2"); 733MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>"); 734