diff options
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r-- | arch/arm/kernel/smp.c | 69 |
1 files changed, 43 insertions, 26 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 0d8097fa4ca5..de885fd256c5 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/atomic.h> | 28 | #include <asm/atomic.h> |
29 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
30 | #include <asm/cpu.h> | 30 | #include <asm/cpu.h> |
31 | #include <asm/cputype.h> | ||
31 | #include <asm/mmu_context.h> | 32 | #include <asm/mmu_context.h> |
32 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
33 | #include <asm/pgalloc.h> | 34 | #include <asm/pgalloc.h> |
@@ -585,6 +586,12 @@ struct tlb_args { | |||
585 | unsigned long ta_end; | 586 | unsigned long ta_end; |
586 | }; | 587 | }; |
587 | 588 | ||
589 | /* all SMP configurations have the extended CPUID registers */ | ||
590 | static inline int tlb_ops_need_broadcast(void) | ||
591 | { | ||
592 | return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2; | ||
593 | } | ||
594 | |||
588 | static inline void ipi_flush_tlb_all(void *ignored) | 595 | static inline void ipi_flush_tlb_all(void *ignored) |
589 | { | 596 | { |
590 | local_flush_tlb_all(); | 597 | local_flush_tlb_all(); |
@@ -627,51 +634,61 @@ static inline void ipi_flush_tlb_kernel_range(void *arg) | |||
627 | 634 | ||
628 | void flush_tlb_all(void) | 635 | void flush_tlb_all(void) |
629 | { | 636 | { |
630 | on_each_cpu(ipi_flush_tlb_all, NULL, 1); | 637 | if (tlb_ops_need_broadcast()) |
638 | on_each_cpu(ipi_flush_tlb_all, NULL, 1); | ||
639 | else | ||
640 | local_flush_tlb_all(); | ||
631 | } | 641 | } |
632 | 642 | ||
633 | void flush_tlb_mm(struct mm_struct *mm) | 643 | void flush_tlb_mm(struct mm_struct *mm) |
634 | { | 644 | { |
635 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask); | 645 | if (tlb_ops_need_broadcast()) |
646 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask); | ||
647 | else | ||
648 | local_flush_tlb_mm(mm); | ||
636 | } | 649 | } |
637 | 650 | ||
638 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) | 651 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) |
639 | { | 652 | { |
640 | struct tlb_args ta; | 653 | if (tlb_ops_need_broadcast()) { |
641 | 654 | struct tlb_args ta; | |
642 | ta.ta_vma = vma; | 655 | ta.ta_vma = vma; |
643 | ta.ta_start = uaddr; | 656 | ta.ta_start = uaddr; |
644 | 657 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask); | |
645 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask); | 658 | } else |
659 | local_flush_tlb_page(vma, uaddr); | ||
646 | } | 660 | } |
647 | 661 | ||
648 | void flush_tlb_kernel_page(unsigned long kaddr) | 662 | void flush_tlb_kernel_page(unsigned long kaddr) |
649 | { | 663 | { |
650 | struct tlb_args ta; | 664 | if (tlb_ops_need_broadcast()) { |
651 | 665 | struct tlb_args ta; | |
652 | ta.ta_start = kaddr; | 666 | ta.ta_start = kaddr; |
653 | 667 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | |
654 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | 668 | } else |
669 | local_flush_tlb_kernel_page(kaddr); | ||
655 | } | 670 | } |
656 | 671 | ||
657 | void flush_tlb_range(struct vm_area_struct *vma, | 672 | void flush_tlb_range(struct vm_area_struct *vma, |
658 | unsigned long start, unsigned long end) | 673 | unsigned long start, unsigned long end) |
659 | { | 674 | { |
660 | struct tlb_args ta; | 675 | if (tlb_ops_need_broadcast()) { |
661 | 676 | struct tlb_args ta; | |
662 | ta.ta_vma = vma; | 677 | ta.ta_vma = vma; |
663 | ta.ta_start = start; | 678 | ta.ta_start = start; |
664 | ta.ta_end = end; | 679 | ta.ta_end = end; |
665 | 680 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask); | |
666 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask); | 681 | } else |
682 | local_flush_tlb_range(vma, start, end); | ||
667 | } | 683 | } |
668 | 684 | ||
669 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | 685 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) |
670 | { | 686 | { |
671 | struct tlb_args ta; | 687 | if (tlb_ops_need_broadcast()) { |
672 | 688 | struct tlb_args ta; | |
673 | ta.ta_start = start; | 689 | ta.ta_start = start; |
674 | ta.ta_end = end; | 690 | ta.ta_end = end; |
675 | 691 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | |
676 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | 692 | } else |
693 | local_flush_tlb_kernel_range(start, end); | ||
677 | } | 694 | } |