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 6014dfd22af4..ece658e773a6 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/processor.h> | 32 | #include <asm/processor.h> |
33 | #include <asm/tlbflush.h> | 33 | #include <asm/tlbflush.h> |
34 | #include <asm/ptrace.h> | 34 | #include <asm/ptrace.h> |
35 | #include <asm/cputype.h> | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * as from 2.5, kernels no longer have an init_tasks structure | 38 | * as from 2.5, kernels no longer have an init_tasks structure |
@@ -545,6 +546,12 @@ struct tlb_args { | |||
545 | unsigned long ta_end; | 546 | unsigned long ta_end; |
546 | }; | 547 | }; |
547 | 548 | ||
549 | /* all SMP configurations have the extended CPUID registers */ | ||
550 | static inline int tlb_ops_need_broadcast(void) | ||
551 | { | ||
552 | return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2; | ||
553 | } | ||
554 | |||
548 | static inline void ipi_flush_tlb_all(void *ignored) | 555 | static inline void ipi_flush_tlb_all(void *ignored) |
549 | { | 556 | { |
550 | local_flush_tlb_all(); | 557 | local_flush_tlb_all(); |
@@ -587,51 +594,61 @@ static inline void ipi_flush_tlb_kernel_range(void *arg) | |||
587 | 594 | ||
588 | void flush_tlb_all(void) | 595 | void flush_tlb_all(void) |
589 | { | 596 | { |
590 | on_each_cpu(ipi_flush_tlb_all, NULL, 1); | 597 | if (tlb_ops_need_broadcast()) |
598 | on_each_cpu(ipi_flush_tlb_all, NULL, 1); | ||
599 | else | ||
600 | local_flush_tlb_all(); | ||
591 | } | 601 | } |
592 | 602 | ||
593 | void flush_tlb_mm(struct mm_struct *mm) | 603 | void flush_tlb_mm(struct mm_struct *mm) |
594 | { | 604 | { |
595 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask); | 605 | if (tlb_ops_need_broadcast()) |
606 | on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, &mm->cpu_vm_mask); | ||
607 | else | ||
608 | local_flush_tlb_mm(mm); | ||
596 | } | 609 | } |
597 | 610 | ||
598 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) | 611 | void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) |
599 | { | 612 | { |
600 | struct tlb_args ta; | 613 | if (tlb_ops_need_broadcast()) { |
601 | 614 | struct tlb_args ta; | |
602 | ta.ta_vma = vma; | 615 | ta.ta_vma = vma; |
603 | ta.ta_start = uaddr; | 616 | ta.ta_start = uaddr; |
604 | 617 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask); | |
605 | on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, &vma->vm_mm->cpu_vm_mask); | 618 | } else |
619 | local_flush_tlb_page(vma, uaddr); | ||
606 | } | 620 | } |
607 | 621 | ||
608 | void flush_tlb_kernel_page(unsigned long kaddr) | 622 | void flush_tlb_kernel_page(unsigned long kaddr) |
609 | { | 623 | { |
610 | struct tlb_args ta; | 624 | if (tlb_ops_need_broadcast()) { |
611 | 625 | struct tlb_args ta; | |
612 | ta.ta_start = kaddr; | 626 | ta.ta_start = kaddr; |
613 | 627 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | |
614 | on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1); | 628 | } else |
629 | local_flush_tlb_kernel_page(kaddr); | ||
615 | } | 630 | } |
616 | 631 | ||
617 | void flush_tlb_range(struct vm_area_struct *vma, | 632 | void flush_tlb_range(struct vm_area_struct *vma, |
618 | unsigned long start, unsigned long end) | 633 | unsigned long start, unsigned long end) |
619 | { | 634 | { |
620 | struct tlb_args ta; | 635 | if (tlb_ops_need_broadcast()) { |
621 | 636 | struct tlb_args ta; | |
622 | ta.ta_vma = vma; | 637 | ta.ta_vma = vma; |
623 | ta.ta_start = start; | 638 | ta.ta_start = start; |
624 | ta.ta_end = end; | 639 | ta.ta_end = end; |
625 | 640 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask); | |
626 | on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, &vma->vm_mm->cpu_vm_mask); | 641 | } else |
642 | local_flush_tlb_range(vma, start, end); | ||
627 | } | 643 | } |
628 | 644 | ||
629 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | 645 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) |
630 | { | 646 | { |
631 | struct tlb_args ta; | 647 | if (tlb_ops_need_broadcast()) { |
632 | 648 | struct tlb_args ta; | |
633 | ta.ta_start = start; | 649 | ta.ta_start = start; |
634 | ta.ta_end = end; | 650 | ta.ta_end = end; |
635 | 651 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | |
636 | on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1); | 652 | } else |
653 | local_flush_tlb_kernel_range(start, end); | ||
637 | } | 654 | } |