aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2009-05-30 09:00:14 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2009-05-30 09:00:14 -0400
commitfaa7bc51c11d5bbe440ac04710fd7a3208782000 (patch)
tree8aaa4e8e2fbb14b421988762fa90a3dbe6fa76e7 /arch/arm/kernel
parentda055eb52ec067d51dc08c7e86baf92dd5c01599 (diff)
Check whether the TLB operations need broadcasting on SMP systems
ARMv7 SMP hardware can handle the TLB maintenance operations broadcasting in hardware so that the software can avoid the costly IPIs. This patch adds the necessary checks (the MMFR3 CPUID register) to avoid the broadcasting if already supported by the hardware. (this patch is based on the work done by Tony Thompson @ ARM) Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm/kernel')
-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 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 */
550static inline int tlb_ops_need_broadcast(void)
551{
552 return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
553}
554
548static inline void ipi_flush_tlb_all(void *ignored) 555static 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
588void flush_tlb_all(void) 595void 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
593void flush_tlb_mm(struct mm_struct *mm) 603void 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
598void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) 611void 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
608void flush_tlb_kernel_page(unsigned long kaddr) 622void 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
617void flush_tlb_range(struct vm_area_struct *vma, 632void 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
629void flush_tlb_kernel_range(unsigned long start, unsigned long end) 645void 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}