Commit 09b5a10c authored by Chris Smith's avatar Chris Smith Committed by Paul Mundt

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: default avatarChris Smith <chris.smith@st.com>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 3611ee7a
...@@ -398,10 +398,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, ...@@ -398,10 +398,7 @@ static int setup_frame(int sig, struct k_sigaction *ka,
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); current->comm, task_pid_nr(current), frame, regs->pc, regs->pr);
flush_cache_sigtramp(regs->pr); flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode));
if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
return 0; return 0;
...@@ -486,10 +483,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -486,10 +483,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
current->comm, task_pid_nr(current), frame, regs->pc, regs->pr); current->comm, task_pid_nr(current), frame, regs->pc, regs->pr);
flush_cache_sigtramp(regs->pr); flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode));
if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
return 0; return 0;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
* Copyright (C) 2001 - 2007 Paul Mundt * Copyright (C) 2001 - 2007 Paul Mundt
* Copyright (C) 2003 Richard Curnow * Copyright (C) 2003 Richard Curnow
* Copyright (c) 2007 STMicroelectronics (R&D) Ltd.
* *
* This file is subject to the terms and conditions of the GNU General Public * This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
...@@ -22,6 +23,7 @@ ...@@ -22,6 +23,7 @@
* entirety. * entirety.
*/ */
#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */
#define MAX_ICACHE_PAGES 32
static void __flush_dcache_segment_1way(unsigned long start, static void __flush_dcache_segment_1way(unsigned long start,
unsigned long extent); unsigned long extent);
...@@ -178,42 +180,45 @@ void __flush_invalidate_region(void *start, int size) ...@@ -178,42 +180,45 @@ void __flush_invalidate_region(void *start, int size)
/* /*
* Write back the range of D-cache, and purge the I-cache. * Write back the range of D-cache, and purge the I-cache.
* *
* Called from kernel/module.c:sys_init_module and routine for a.out format. * Called from kernel/module.c:sys_init_module and routine for a.out format,
* signal handler code and kprobes code
*/ */
void flush_icache_range(unsigned long start, unsigned long end) void flush_icache_range(unsigned long start, unsigned long end)
{ {
flush_cache_all(); int icacheaddr;
} unsigned long flags, v;
/*
* Write back the D-cache and purge the I-cache for signal trampoline.
* .. which happens to be the same behavior as flush_icache_range().
* So, we simply flush out a line.
*/
void __uses_jump_to_uncached flush_cache_sigtramp(unsigned long addr)
{
unsigned long v, index;
unsigned long flags;
int i; int i;
v = addr & ~(L1_CACHE_BYTES-1); /* If there are too many pages then just blow the caches */
asm volatile("ocbwb %0" if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) {
: /* no output */ flush_cache_all();
: "m" (__m(v))); } else {
/* selectively flush d-cache then invalidate the i-cache */
index = CACHE_IC_ADDRESS_ARRAY | /* this is inefficient, so only use for small ranges */
(v & boot_cpu_data.icache.entry_mask); start &= ~(L1_CACHE_BYTES-1);
end += L1_CACHE_BYTES-1;
local_irq_save(flags); end &= ~(L1_CACHE_BYTES-1);
jump_to_uncached();
local_irq_save(flags);
for (i = 0; i < boot_cpu_data.icache.ways; jump_to_uncached();
i++, index += boot_cpu_data.icache.way_incr)
ctrl_outl(0, index); /* Clear out Valid-bit */ for (v = start; v < end; v+=L1_CACHE_BYTES) {
asm volatile("ocbwb %0"
back_to_cached(); : /* no output */
wmb(); : "m" (__m(v)));
local_irq_restore(flags);
icacheaddr = CACHE_IC_ADDRESS_ARRAY | (
v & cpu_data->icache.entry_mask);
for (i = 0; i < cpu_data->icache.ways;
i++, icacheaddr += cpu_data->icache.way_incr)
/* Clear i-cache line valid-bit */
ctrl_outl(0, icacheaddr);
}
back_to_cached();
local_irq_restore(flags);
}
} }
static inline void flush_cache_4096(unsigned long start, static inline void flush_cache_4096(unsigned long start,
......
...@@ -30,7 +30,6 @@ void flush_dcache_page(struct page *pg); ...@@ -30,7 +30,6 @@ void flush_dcache_page(struct page *pg);
#define flush_dcache_mmap_unlock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0)
void flush_icache_range(unsigned long start, unsigned long end); void flush_icache_range(unsigned long start, unsigned long end);
void flush_cache_sigtramp(unsigned long addr);
void flush_icache_user_range(struct vm_area_struct *vma, struct page *page, void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
unsigned long addr, int len); unsigned long addr, int len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment