Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sh: Optimized flush_icache_range() implementation.

Add implementation of flush_icache_range() suitable for signal handler
and kprobes. Remove flush_cache_sigtramp() and change signal.c to use
flush_icache_range().

Signed-off-by: Chris Smith <chris.smith@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

authored by

Chris Smith and committed by
Paul Mundt
09b5a10c 3611ee7a

+34 -36
+2 -8
arch/sh/kernel/signal_32.c
··· 398 398 pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", 399 399 current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); 400 400 401 - flush_cache_sigtramp(regs->pr); 402 - 403 - if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) 404 - flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); 401 + flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode)); 405 402 406 403 return 0; 407 404 ··· 483 486 pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", 484 487 current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); 485 488 486 - flush_cache_sigtramp(regs->pr); 487 - 488 - if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) 489 - flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); 489 + flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode)); 490 490 491 491 return 0; 492 492
+32 -27
arch/sh/mm/cache-sh4.c
··· 4 4 * Copyright (C) 1999, 2000, 2002 Niibe Yutaka 5 5 * Copyright (C) 2001 - 2007 Paul Mundt 6 6 * Copyright (C) 2003 Richard Curnow 7 + * Copyright (c) 2007 STMicroelectronics (R&D) Ltd. 7 8 * 8 9 * This file is subject to the terms and conditions of the GNU General Public 9 10 * License. See the file "COPYING" in the main directory of this archive ··· 23 22 * entirety. 24 23 */ 25 24 #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ 25 + #define MAX_ICACHE_PAGES 32 26 26 27 27 static void __flush_dcache_segment_1way(unsigned long start, 28 28 unsigned long extent); ··· 180 178 /* 181 179 * Write back the range of D-cache, and purge the I-cache. 182 180 * 183 - * Called from kernel/module.c:sys_init_module and routine for a.out format. 181 + * Called from kernel/module.c:sys_init_module and routine for a.out format, 182 + * signal handler code and kprobes code 184 183 */ 185 184 void flush_icache_range(unsigned long start, unsigned long end) 186 185 { 187 - flush_cache_all(); 188 - } 189 - 190 - /* 191 - * Write back the D-cache and purge the I-cache for signal trampoline. 192 - * .. which happens to be the same behavior as flush_icache_range(). 193 - * So, we simply flush out a line. 194 - */ 195 - void __uses_jump_to_uncached flush_cache_sigtramp(unsigned long addr) 196 - { 197 - unsigned long v, index; 198 - unsigned long flags; 186 + int icacheaddr; 187 + unsigned long flags, v; 199 188 int i; 200 189 201 - v = addr & ~(L1_CACHE_BYTES-1); 202 - asm volatile("ocbwb %0" 203 - : /* no output */ 204 - : "m" (__m(v))); 190 + /* If there are too many pages then just blow the caches */ 191 + if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { 192 + flush_cache_all(); 193 + } else { 194 + /* selectively flush d-cache then invalidate the i-cache */ 195 + /* this is inefficient, so only use for small ranges */ 196 + start &= ~(L1_CACHE_BYTES-1); 197 + end += L1_CACHE_BYTES-1; 198 + end &= ~(L1_CACHE_BYTES-1); 205 199 206 - index = CACHE_IC_ADDRESS_ARRAY | 207 - (v & boot_cpu_data.icache.entry_mask); 200 + local_irq_save(flags); 201 + jump_to_uncached(); 208 202 209 - local_irq_save(flags); 210 - jump_to_uncached(); 203 + for (v = start; v < end; v+=L1_CACHE_BYTES) { 204 + asm volatile("ocbwb %0" 205 + : /* no output */ 206 + : "m" (__m(v))); 211 207 212 - for (i = 0; i < boot_cpu_data.icache.ways; 213 - i++, index += boot_cpu_data.icache.way_incr) 214 - ctrl_outl(0, index); /* Clear out Valid-bit */ 208 + icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( 209 + v & cpu_data->icache.entry_mask); 215 210 216 - back_to_cached(); 217 - wmb(); 218 - local_irq_restore(flags); 211 + for (i = 0; i < cpu_data->icache.ways; 212 + i++, icacheaddr += cpu_data->icache.way_incr) 213 + /* Clear i-cache line valid-bit */ 214 + ctrl_outl(0, icacheaddr); 215 + } 216 + 217 + back_to_cached(); 218 + local_irq_restore(flags); 219 + } 219 220 } 220 221 221 222 static inline void flush_cache_4096(unsigned long start,
-1
include/asm-sh/cpu-sh4/cacheflush.h
··· 30 30 #define flush_dcache_mmap_unlock(mapping) do { } while (0) 31 31 32 32 void flush_icache_range(unsigned long start, unsigned long end); 33 - void flush_cache_sigtramp(unsigned long addr); 34 33 void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, 35 34 unsigned long addr, int len); 36 35