diff options
Diffstat (limited to 'arch/sh')
| -rw-r--r-- | arch/sh/mm/pmb.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 75b8861ec624..30035caeb73a 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/io.h> | 24 | #include <linux/io.h> |
| 25 | #include <linux/spinlock.h> | 25 | #include <linux/spinlock.h> |
| 26 | #include <linux/vmalloc.h> | 26 | #include <linux/vmalloc.h> |
| 27 | #include <asm/cacheflush.h> | ||
| 27 | #include <asm/sizes.h> | 28 | #include <asm/sizes.h> |
| 28 | #include <asm/system.h> | 29 | #include <asm/system.h> |
| 29 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
| @@ -292,9 +293,18 @@ static void pmb_free(struct pmb_entry *pmbe) | |||
| 292 | */ | 293 | */ |
| 293 | static void __set_pmb_entry(struct pmb_entry *pmbe) | 294 | static void __set_pmb_entry(struct pmb_entry *pmbe) |
| 294 | { | 295 | { |
| 296 | unsigned long addr, data; | ||
| 297 | |||
| 298 | addr = mk_pmb_addr(pmbe->entry); | ||
| 299 | data = mk_pmb_data(pmbe->entry); | ||
| 300 | |||
| 301 | jump_to_uncached(); | ||
| 302 | |||
| 295 | /* Set V-bit */ | 303 | /* Set V-bit */ |
| 296 | __raw_writel(pmbe->ppn | pmbe->flags | PMB_V, mk_pmb_data(pmbe->entry)); | 304 | __raw_writel(pmbe->vpn | PMB_V, addr); |
| 297 | __raw_writel(pmbe->vpn | PMB_V, mk_pmb_addr(pmbe->entry)); | 305 | __raw_writel(pmbe->ppn | pmbe->flags | PMB_V, data); |
| 306 | |||
| 307 | back_to_cached(); | ||
| 298 | } | 308 | } |
| 299 | 309 | ||
| 300 | static void __clear_pmb_entry(struct pmb_entry *pmbe) | 310 | static void __clear_pmb_entry(struct pmb_entry *pmbe) |
| @@ -326,6 +336,7 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys, | |||
| 326 | unsigned long size, pgprot_t prot) | 336 | unsigned long size, pgprot_t prot) |
| 327 | { | 337 | { |
| 328 | struct pmb_entry *pmbp, *pmbe; | 338 | struct pmb_entry *pmbp, *pmbe; |
| 339 | unsigned long orig_addr, orig_size; | ||
| 329 | unsigned long flags, pmb_flags; | 340 | unsigned long flags, pmb_flags; |
| 330 | int i, mapped; | 341 | int i, mapped; |
| 331 | 342 | ||
| @@ -334,6 +345,11 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys, | |||
| 334 | if (pmb_mapping_exists(vaddr, phys, size)) | 345 | if (pmb_mapping_exists(vaddr, phys, size)) |
| 335 | return 0; | 346 | return 0; |
| 336 | 347 | ||
| 348 | orig_addr = vaddr; | ||
| 349 | orig_size = size; | ||
| 350 | |||
| 351 | flush_tlb_kernel_range(vaddr, vaddr + size); | ||
| 352 | |||
| 337 | pmb_flags = pgprot_to_pmb_flags(prot); | 353 | pmb_flags = pgprot_to_pmb_flags(prot); |
| 338 | pmbp = NULL; | 354 | pmbp = NULL; |
| 339 | 355 | ||
| @@ -383,13 +399,15 @@ int pmb_bolt_mapping(unsigned long vaddr, phys_addr_t phys, | |||
| 383 | } | 399 | } |
| 384 | } while (size >= SZ_16M); | 400 | } while (size >= SZ_16M); |
| 385 | 401 | ||
| 402 | flush_cache_vmap(orig_addr, orig_addr + orig_size); | ||
| 403 | |||
| 386 | return 0; | 404 | return 0; |
| 387 | } | 405 | } |
| 388 | 406 | ||
| 389 | void __iomem *pmb_remap_caller(phys_addr_t phys, unsigned long size, | 407 | void __iomem *pmb_remap_caller(phys_addr_t phys, unsigned long size, |
| 390 | pgprot_t prot, void *caller) | 408 | pgprot_t prot, void *caller) |
| 391 | { | 409 | { |
| 392 | unsigned long orig_addr, vaddr; | 410 | unsigned long vaddr; |
| 393 | phys_addr_t offset, last_addr; | 411 | phys_addr_t offset, last_addr; |
| 394 | phys_addr_t align_mask; | 412 | phys_addr_t align_mask; |
| 395 | unsigned long aligned; | 413 | unsigned long aligned; |
| @@ -417,19 +435,24 @@ void __iomem *pmb_remap_caller(phys_addr_t phys, unsigned long size, | |||
| 417 | phys &= align_mask; | 435 | phys &= align_mask; |
| 418 | aligned = ALIGN(last_addr, pmb_sizes[i].size) - phys; | 436 | aligned = ALIGN(last_addr, pmb_sizes[i].size) - phys; |
| 419 | 437 | ||
| 420 | area = __get_vm_area_caller(aligned, VM_IOREMAP, uncached_end, | 438 | /* |
| 439 | * XXX: This should really start from uncached_end, but this | ||
| 440 | * causes the MMU to reset, so for now we restrict it to the | ||
| 441 | * 0xb000...0xc000 range. | ||
| 442 | */ | ||
| 443 | area = __get_vm_area_caller(aligned, VM_IOREMAP, 0xb0000000, | ||
| 421 | P3SEG, caller); | 444 | P3SEG, caller); |
| 422 | if (!area) | 445 | if (!area) |
| 423 | return NULL; | 446 | return NULL; |
| 424 | 447 | ||
| 425 | area->phys_addr = phys; | 448 | area->phys_addr = phys; |
| 426 | orig_addr = vaddr = (unsigned long)area->addr; | 449 | vaddr = (unsigned long)area->addr; |
| 427 | 450 | ||
| 428 | ret = pmb_bolt_mapping(vaddr, phys, size, prot); | 451 | ret = pmb_bolt_mapping(vaddr, phys, size, prot); |
| 429 | if (unlikely(ret != 0)) | 452 | if (unlikely(ret != 0)) |
| 430 | return ERR_PTR(ret); | 453 | return ERR_PTR(ret); |
| 431 | 454 | ||
| 432 | return (void __iomem *)(offset + (char *)orig_addr); | 455 | return (void __iomem *)(offset + (char *)vaddr); |
| 433 | } | 456 | } |
| 434 | 457 | ||
| 435 | int pmb_unmap(void __iomem *addr) | 458 | int pmb_unmap(void __iomem *addr) |
| @@ -477,6 +500,8 @@ static void __pmb_unmap_entry(struct pmb_entry *pmbe, int depth) | |||
| 477 | */ | 500 | */ |
| 478 | __clear_pmb_entry(pmbe); | 501 | __clear_pmb_entry(pmbe); |
| 479 | 502 | ||
| 503 | flush_cache_vunmap(pmbe->vpn, pmbe->vpn + pmbe->size); | ||
| 504 | |||
| 480 | pmbe = pmblink->link; | 505 | pmbe = pmblink->link; |
| 481 | 506 | ||
| 482 | pmb_free(pmblink); | 507 | pmb_free(pmblink); |
