aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/smp.c')
-rw-r--r--arch/arm/kernel/smp.c69
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 */
590static inline int tlb_ops_need_broadcast(void)
591{
592 return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
593}
594
588static inline void ipi_flush_tlb_all(void *ignored) 595static 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
628void flush_tlb_all(void) 635void 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
633void flush_tlb_mm(struct mm_struct *mm) 643void 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
638void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) 651void 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
648void flush_tlb_kernel_page(unsigned long kaddr) 662void 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
657void flush_tlb_range(struct vm_area_struct *vma, 672void 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
669void flush_tlb_kernel_range(unsigned long start, unsigned long end) 685void 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}