diff options
author | James Hogan <james.hogan@imgtec.com> | 2016-07-13 14:12:55 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2016-07-29 10:19:30 +0200 |
commit | f70ddc07b637e8859dbdc9073fa80c95e218750d (patch) | |
tree | 2103101d5f17ba0842752a3f644b8208800c0d95 /arch/mips/mm | |
parent | 27b93d9c1de70bb8191882964d7fa58d01d3c06b (diff) | |
download | linux-stable-f70ddc07b637e8859dbdc9073fa80c95e218750d.tar.gz linux-stable-f70ddc07b637e8859dbdc9073fa80c95e218750d.tar.bz2 linux-stable-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>
Diffstat (limited to 'arch/mips/mm')
-rw-r--r-- | arch/mips/mm/c-r4k.c | 21 |
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(); } |