aboutsummaryrefslogtreecommitdiff
path: root/arch/blackfin/kernel
diff options
context:
space:
mode:
authorSonic Zhang2010-09-06 10:16:04 +0000
committerMike Frysinger2010-10-22 03:48:59 -0400
commit99a5b2878b56d24919eb7e646f2d8e02f63a6efc (patch)
tree5db99463ad9f68e383aa54c9d102f91f5b890091 /arch/blackfin/kernel
parent73775b892ee70bdc0dbd6aeeebb50894d062f9a1 (diff)
Blackfin: add new cacheflush syscall
Flushing caches sometimes requires anomaly workarounds which require supervisor-only insns. Normally we don't need to flush caches from userspace so this isn't a problem, but when gcc generates trampolines on the stack, we do. So add a new syscall for gcc to use modeled after the mips version. Signed-off-by: Sonic Zhang <sonic.zhang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r--arch/blackfin/kernel/ptrace.c4
-rw-r--r--arch/blackfin/kernel/sys_bfin.c15
2 files changed, 17 insertions, 2 deletions
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index d890c1e35ec6..b35839354130 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -114,8 +114,8 @@ put_reg(struct task_struct *task, long regno, unsigned long data)
/*
* check that an address falls within the bounds of the target process's memory mappings
*/
-static inline int is_user_addr_valid(struct task_struct *child,
- unsigned long start, unsigned long len)
+int
+is_user_addr_valid(struct task_struct *child, unsigned long start, unsigned long len)
{
struct vm_area_struct *vma;
struct sram_list_struct *sraml;
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
index bdc1e2f0da32..89448ed7065d 100644
--- a/arch/blackfin/kernel/sys_bfin.c
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -21,6 +21,8 @@
#include <asm/cacheflush.h>
#include <asm/dma.h>
+#include <asm/cachectl.h>
+#include <asm/ptrace.h>
asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
{
@@ -70,3 +72,16 @@ asmlinkage int sys_bfin_spinlock(int *p)
return ret;
}
+
+SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, len, int, op)
+{
+ if (is_user_addr_valid(current, addr, len) != 0)
+ return -EINVAL;
+
+ if (op & DCACHE)
+ blackfin_dcache_flush_range(addr, addr + len);
+ if (op & ICACHE)
+ blackfin_icache_flush_range(addr, addr + len);
+
+ return 0;
+}