diff options
author | Chris Smith <chris.smith@st.com> | 2008-07-02 02:17:11 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2008-07-28 05:10:32 -0400 |
commit | 09b5a10c1944214a6008712bfa92b29f00b84a1a (patch) | |
tree | 0769016c78424356596bb0a8d854056b083246ef /arch/sh/mm | |
parent | 3611ee7acc113e5e482b7d20d5133935226f3129 (diff) |
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>
Diffstat (limited to 'arch/sh/mm')
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 67 |
1 files changed, 36 insertions, 31 deletions
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 43d7ff6b6ec7..1fdc8d90254a 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | 4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka |
5 | * Copyright (C) 2001 - 2007 Paul Mundt | 5 | * Copyright (C) 2001 - 2007 Paul Mundt |
6 | * Copyright (C) 2003 Richard Curnow | 6 | * Copyright (C) 2003 Richard Curnow |
7 | * Copyright (c) 2007 STMicroelectronics (R&D) Ltd. | ||
7 | * | 8 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 9 | * This file is subject to the terms and conditions of the GNU General Public |
9 | * License. See the file "COPYING" in the main directory of this archive | 10 | * License. See the file "COPYING" in the main directory of this archive |
@@ -22,6 +23,7 @@ | |||
22 | * entirety. | 23 | * entirety. |
23 | */ | 24 | */ |
24 | #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ | 25 | #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ |
26 | #define MAX_ICACHE_PAGES 32 | ||
25 | 27 | ||
26 | static void __flush_dcache_segment_1way(unsigned long start, | 28 | static void __flush_dcache_segment_1way(unsigned long start, |
27 | unsigned long extent); | 29 | unsigned long extent); |
@@ -178,42 +180,45 @@ void __flush_invalidate_region(void *start, int size) | |||
178 | /* | 180 | /* |
179 | * Write back the range of D-cache, and purge the I-cache. | 181 | * Write back the range of D-cache, and purge the I-cache. |
180 | * | 182 | * |
181 | * Called from kernel/module.c:sys_init_module and routine for a.out format. | 183 | * Called from kernel/module.c:sys_init_module and routine for a.out format, |
184 | * signal handler code and kprobes code | ||
182 | */ | 185 | */ |
183 | void flush_icache_range(unsigned long start, unsigned long end) | 186 | void flush_icache_range(unsigned long start, unsigned long end) |
184 | { | 187 | { |
185 | flush_cache_all(); | 188 | int icacheaddr; |
186 | } | 189 | unsigned long flags, v; |
187 | |||
188 | /* | ||
189 | * Write back the D-cache and purge the I-cache for signal trampoline. | ||
190 | * .. which happens to be the same behavior as flush_icache_range(). | ||
191 | * So, we simply flush out a line. | ||
192 | */ | ||
193 | void __uses_jump_to_uncached flush_cache_sigtramp(unsigned long addr) | ||
194 | { | ||
195 | unsigned long v, index; | ||
196 | unsigned long flags; | ||
197 | int i; | 190 | int i; |
198 | 191 | ||
199 | v = addr & ~(L1_CACHE_BYTES-1); | 192 | /* If there are too many pages then just blow the caches */ |
200 | asm volatile("ocbwb %0" | 193 | if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { |
201 | : /* no output */ | 194 | flush_cache_all(); |
202 | : "m" (__m(v))); | 195 | } else { |
203 | 196 | /* selectively flush d-cache then invalidate the i-cache */ | |
204 | index = CACHE_IC_ADDRESS_ARRAY | | 197 | /* this is inefficient, so only use for small ranges */ |
205 | (v & boot_cpu_data.icache.entry_mask); | 198 | start &= ~(L1_CACHE_BYTES-1); |
206 | 199 | end += L1_CACHE_BYTES-1; | |
207 | local_irq_save(flags); | 200 | end &= ~(L1_CACHE_BYTES-1); |
208 | jump_to_uncached(); | 201 | |
209 | 202 | local_irq_save(flags); | |
210 | for (i = 0; i < boot_cpu_data.icache.ways; | 203 | jump_to_uncached(); |
211 | i++, index += boot_cpu_data.icache.way_incr) | 204 | |
212 | ctrl_outl(0, index); /* Clear out Valid-bit */ | 205 | for (v = start; v < end; v+=L1_CACHE_BYTES) { |
213 | 206 | asm volatile("ocbwb %0" | |
214 | back_to_cached(); | 207 | : /* no output */ |
215 | wmb(); | 208 | : "m" (__m(v))); |
216 | local_irq_restore(flags); | 209 | |
210 | icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( | ||
211 | v & cpu_data->icache.entry_mask); | ||
212 | |||
213 | for (i = 0; i < cpu_data->icache.ways; | ||
214 | i++, icacheaddr += cpu_data->icache.way_incr) | ||
215 | /* Clear i-cache line valid-bit */ | ||
216 | ctrl_outl(0, icacheaddr); | ||
217 | } | ||
218 | |||
219 | back_to_cached(); | ||
220 | local_irq_restore(flags); | ||
221 | } | ||
217 | } | 222 | } |
218 | 223 | ||
219 | static inline void flush_cache_4096(unsigned long start, | 224 | static inline void flush_cache_4096(unsigned long start, |