MIPS: c-r4k: Avoid small flush_icache_range SMP calls
authorJames Hogan <james.hogan@imgtec.com>
Wed, 13 Jul 2016 13:12:55 +0000 (14:12 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 29 Jul 2016 08:19:30 +0000 (10:19 +0200)
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>
arch/mips/mm/c-r4k.c

index cfcb336f57a0590dcb001b083807800b750b56eb..8016babe5c842161330324dad74c4653ba879ab4 100644 (file)
@@ -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();
 }