diff options
Diffstat (limited to 'arch/parisc/kernel/cache.c')
-rw-r--r-- | arch/parisc/kernel/cache.c | 88 |
1 files changed, 58 insertions, 30 deletions
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 19c0c141bc3f..e3b45546d589 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c | |||
@@ -465,10 +465,10 @@ EXPORT_SYMBOL(copy_user_page); | |||
465 | int __flush_tlb_range(unsigned long sid, unsigned long start, | 465 | int __flush_tlb_range(unsigned long sid, unsigned long start, |
466 | unsigned long end) | 466 | unsigned long end) |
467 | { | 467 | { |
468 | unsigned long flags, size; | 468 | unsigned long flags; |
469 | 469 | ||
470 | size = (end - start); | 470 | if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && |
471 | if (size >= parisc_tlb_flush_threshold) { | 471 | end - start >= parisc_tlb_flush_threshold) { |
472 | flush_tlb_all(); | 472 | flush_tlb_all(); |
473 | return 1; | 473 | return 1; |
474 | } | 474 | } |
@@ -539,13 +539,12 @@ void flush_cache_mm(struct mm_struct *mm) | |||
539 | struct vm_area_struct *vma; | 539 | struct vm_area_struct *vma; |
540 | pgd_t *pgd; | 540 | pgd_t *pgd; |
541 | 541 | ||
542 | /* Flush the TLB to avoid speculation if coherency is required. */ | ||
543 | if (parisc_requires_coherency()) | ||
544 | flush_tlb_all(); | ||
545 | |||
546 | /* Flushing the whole cache on each cpu takes forever on | 542 | /* Flushing the whole cache on each cpu takes forever on |
547 | rp3440, etc. So, avoid it if the mm isn't too big. */ | 543 | rp3440, etc. So, avoid it if the mm isn't too big. */ |
548 | if (mm_total_size(mm) >= parisc_cache_flush_threshold) { | 544 | if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && |
545 | mm_total_size(mm) >= parisc_cache_flush_threshold) { | ||
546 | if (mm->context) | ||
547 | flush_tlb_all(); | ||
549 | flush_cache_all(); | 548 | flush_cache_all(); |
550 | return; | 549 | return; |
551 | } | 550 | } |
@@ -553,9 +552,9 @@ void flush_cache_mm(struct mm_struct *mm) | |||
553 | if (mm->context == mfsp(3)) { | 552 | if (mm->context == mfsp(3)) { |
554 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | 553 | for (vma = mm->mmap; vma; vma = vma->vm_next) { |
555 | flush_user_dcache_range_asm(vma->vm_start, vma->vm_end); | 554 | flush_user_dcache_range_asm(vma->vm_start, vma->vm_end); |
556 | if ((vma->vm_flags & VM_EXEC) == 0) | 555 | if (vma->vm_flags & VM_EXEC) |
557 | continue; | 556 | flush_user_icache_range_asm(vma->vm_start, vma->vm_end); |
558 | flush_user_icache_range_asm(vma->vm_start, vma->vm_end); | 557 | flush_tlb_range(vma, vma->vm_start, vma->vm_end); |
559 | } | 558 | } |
560 | return; | 559 | return; |
561 | } | 560 | } |
@@ -573,6 +572,8 @@ void flush_cache_mm(struct mm_struct *mm) | |||
573 | pfn = pte_pfn(*ptep); | 572 | pfn = pte_pfn(*ptep); |
574 | if (!pfn_valid(pfn)) | 573 | if (!pfn_valid(pfn)) |
575 | continue; | 574 | continue; |
575 | if (unlikely(mm->context)) | ||
576 | flush_tlb_page(vma, addr); | ||
576 | __flush_cache_page(vma, addr, PFN_PHYS(pfn)); | 577 | __flush_cache_page(vma, addr, PFN_PHYS(pfn)); |
577 | } | 578 | } |
578 | } | 579 | } |
@@ -581,30 +582,45 @@ void flush_cache_mm(struct mm_struct *mm) | |||
581 | void flush_cache_range(struct vm_area_struct *vma, | 582 | void flush_cache_range(struct vm_area_struct *vma, |
582 | unsigned long start, unsigned long end) | 583 | unsigned long start, unsigned long end) |
583 | { | 584 | { |
584 | BUG_ON(!vma->vm_mm->context); | 585 | pgd_t *pgd; |
585 | 586 | unsigned long addr; | |
586 | /* Flush the TLB to avoid speculation if coherency is required. */ | ||
587 | if (parisc_requires_coherency()) | ||
588 | flush_tlb_range(vma, start, end); | ||
589 | 587 | ||
590 | if ((end - start) >= parisc_cache_flush_threshold | 588 | if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && |
591 | || vma->vm_mm->context != mfsp(3)) { | 589 | end - start >= parisc_cache_flush_threshold) { |
590 | if (vma->vm_mm->context) | ||
591 | flush_tlb_range(vma, start, end); | ||
592 | flush_cache_all(); | 592 | flush_cache_all(); |
593 | return; | 593 | return; |
594 | } | 594 | } |
595 | 595 | ||
596 | flush_user_dcache_range_asm(start, end); | 596 | if (vma->vm_mm->context == mfsp(3)) { |
597 | if (vma->vm_flags & VM_EXEC) | 597 | flush_user_dcache_range_asm(start, end); |
598 | flush_user_icache_range_asm(start, end); | 598 | if (vma->vm_flags & VM_EXEC) |
599 | flush_user_icache_range_asm(start, end); | ||
600 | flush_tlb_range(vma, start, end); | ||
601 | return; | ||
602 | } | ||
603 | |||
604 | pgd = vma->vm_mm->pgd; | ||
605 | for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) { | ||
606 | unsigned long pfn; | ||
607 | pte_t *ptep = get_ptep(pgd, addr); | ||
608 | if (!ptep) | ||
609 | continue; | ||
610 | pfn = pte_pfn(*ptep); | ||
611 | if (pfn_valid(pfn)) { | ||
612 | if (unlikely(vma->vm_mm->context)) | ||
613 | flush_tlb_page(vma, addr); | ||
614 | __flush_cache_page(vma, addr, PFN_PHYS(pfn)); | ||
615 | } | ||
616 | } | ||
599 | } | 617 | } |
600 | 618 | ||
601 | void | 619 | void |
602 | flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn) | 620 | flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn) |
603 | { | 621 | { |
604 | BUG_ON(!vma->vm_mm->context); | ||
605 | |||
606 | if (pfn_valid(pfn)) { | 622 | if (pfn_valid(pfn)) { |
607 | if (parisc_requires_coherency()) | 623 | if (likely(vma->vm_mm->context)) |
608 | flush_tlb_page(vma, vmaddr); | 624 | flush_tlb_page(vma, vmaddr); |
609 | __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); | 625 | __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); |
610 | } | 626 | } |
@@ -613,21 +629,33 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long | |||
613 | void flush_kernel_vmap_range(void *vaddr, int size) | 629 | void flush_kernel_vmap_range(void *vaddr, int size) |
614 | { | 630 | { |
615 | unsigned long start = (unsigned long)vaddr; | 631 | unsigned long start = (unsigned long)vaddr; |
632 | unsigned long end = start + size; | ||
616 | 633 | ||
617 | if ((unsigned long)size > parisc_cache_flush_threshold) | 634 | if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && |
635 | (unsigned long)size >= parisc_cache_flush_threshold) { | ||
636 | flush_tlb_kernel_range(start, end); | ||
618 | flush_data_cache(); | 637 | flush_data_cache(); |
619 | else | 638 | return; |
620 | flush_kernel_dcache_range_asm(start, start + size); | 639 | } |
640 | |||
641 | flush_kernel_dcache_range_asm(start, end); | ||
642 | flush_tlb_kernel_range(start, end); | ||
621 | } | 643 | } |
622 | EXPORT_SYMBOL(flush_kernel_vmap_range); | 644 | EXPORT_SYMBOL(flush_kernel_vmap_range); |
623 | 645 | ||
624 | void invalidate_kernel_vmap_range(void *vaddr, int size) | 646 | void invalidate_kernel_vmap_range(void *vaddr, int size) |
625 | { | 647 | { |
626 | unsigned long start = (unsigned long)vaddr; | 648 | unsigned long start = (unsigned long)vaddr; |
649 | unsigned long end = start + size; | ||
627 | 650 | ||
628 | if ((unsigned long)size > parisc_cache_flush_threshold) | 651 | if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && |
652 | (unsigned long)size >= parisc_cache_flush_threshold) { | ||
653 | flush_tlb_kernel_range(start, end); | ||
629 | flush_data_cache(); | 654 | flush_data_cache(); |
630 | else | 655 | return; |
631 | flush_kernel_dcache_range_asm(start, start + size); | 656 | } |
657 | |||
658 | purge_kernel_dcache_range_asm(start, end); | ||
659 | flush_tlb_kernel_range(start, end); | ||
632 | } | 660 | } |
633 | EXPORT_SYMBOL(invalidate_kernel_vmap_range); | 661 | EXPORT_SYMBOL(invalidate_kernel_vmap_range); |