summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2016-07-13 15:12:55 +0200
committerRalf Baechle <ralf@linux-mips.org>2016-07-29 10:19:30 +0200
commitf70ddc07b637e8859dbdc9073fa80c95e218750d (patch)
tree2103101d5f17ba0842752a3f644b8208800c0d95
parentMIPS: c-r4k: Local flush_icache_range cache op override (diff)
downloadlinux-f70ddc07b637e8859dbdc9073fa80c95e218750d.tar.xz
linux-f70ddc07b637e8859dbdc9073fa80c95e218750d.zip
MIPS: c-r4k: Avoid small flush_icache_range SMP calls
Avoid SMP calls for flushing small icache ranges. On non-CM platforms, and CM platforms too after we make r4k_on_each_cpu() take the cache op type into account, it will be called on multiple CPUs due to the possibility that local_r4k_flush_icache_range_ipi() could do non-globalized indexed cache ops. This rougly copies the range size check out into r4k_flush_icache_range(), which can disallow indexed cache ops and allow r4k_on_each_cpu() to skip the SMP call. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: Leonid Yegoshin <leonid.yegoshin@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/13805/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/mm/c-r4k.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index cfcb336f57a0..8016babe5c84 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -784,12 +784,33 @@ static inline void local_r4k_flush_icache_range_ipi(void *args)
static void r4k_flush_icache_range(unsigned long start, unsigned long end)
{
struct flush_icache_range_args args;
+ unsigned long size, cache_size;
args.start = start;
args.end = end;
args.type = R4K_HIT | R4K_INDEX;
+ /*
+ * Indexed cache ops require an SMP call.
+ * Consider if that can or should be avoided.
+ */
+ preempt_disable();
+ if (r4k_op_needs_ipi(R4K_INDEX) && !r4k_op_needs_ipi(R4K_HIT)) {
+ /*
+ * If address-based cache ops don't require an SMP call, then
+ * use them exclusively for small flushes.
+ */
+ size = start - end;
+ cache_size = icache_size;
+ if (!cpu_has_ic_fills_f_dc) {
+ size *= 2;
+ cache_size += dcache_size;
+ }
+ if (size <= cache_size)
+ args.type &= ~R4K_INDEX;
+ }
r4k_on_each_cpu(args.type, local_r4k_flush_icache_range_ipi, &args);
+ preempt_enable();
instruction_hazard();
}