summaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r--arch/blackfin/kernel/traps.c113
1 files changed, 97 insertions, 16 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 3909f5b3553..8823e9ade58 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -31,6 +31,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
+#include <linux/fs.h>
#include <asm/traps.h>
#include <asm/cacheflush.h>
#include <asm/blackfin.h>
@@ -50,10 +51,9 @@ void __init trap_init(void)
CSYNC();
}
-asmlinkage void trap_c(struct pt_regs *fp);
-
int kstack_depth_to_print = 48;
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
static int printk_address(unsigned long address)
{
struct vm_list_struct *vml;
@@ -130,17 +130,29 @@ static int printk_address(unsigned long address)
/* we were unable to find this address anywhere */
return printk("[<0x%p>]", (void *)address);
}
+#endif
+
+asmlinkage void double_fault_c(struct pt_regs *fp)
+{
+ printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
+ dump_bfin_regs(fp, (void *)fp->retx);
+ panic("Double Fault - unrecoverable event\n");
+
+}
asmlinkage void trap_c(struct pt_regs *fp)
{
- int j, sig = 0;
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
+ int j;
+#endif
+ int sig = 0;
siginfo_t info;
unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
#ifdef CONFIG_KGDB
# define CHK_DEBUGGER_TRAP() \
do { \
- CHK_DEBUGGER(trapnr, sig, info.si_code, fp); \
+ CHK_DEBUGGER(trapnr, sig, info.si_code, fp, ); \
} while (0)
# define CHK_DEBUGGER_TRAP_MAYBE() \
do { \
@@ -390,10 +402,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
break;
}
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_addr = (void *)fp->pc;
- force_sig_info(sig, &info, current);
if (sig != 0 && sig != SIGTRAP) {
unsigned long stack;
dump_bfin_regs(fp, (void *)fp->retx);
@@ -402,6 +410,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
if (current->mm == NULL)
panic("Kernel exception");
}
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_addr = (void *)fp->pc;
+ force_sig_info(sig, &info, current);
/* if the address that we are about to return to is not valid, set it
* to a valid address, if we have a current application or panic
@@ -428,24 +440,56 @@ asmlinkage void trap_c(struct pt_regs *fp)
/* Typical exception handling routines */
+#define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1)
+
void dump_bfin_trace_buffer(void)
{
- int tflags;
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
+ int tflags, i = 0;
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
+ int j, index;
+#endif
+
trace_buffer_save(tflags);
+ printk(KERN_EMERG "Hardware Trace:\n");
+
if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
- int i;
- printk(KERN_EMERG "Hardware Trace:\n");
- for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
- printk(KERN_EMERG "%2i Target : ", i);
+ for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
+ printk(KERN_EMERG "%4i Target : ", i);
printk_address((unsigned long)bfin_read_TBUF());
- printk("\n" KERN_EMERG " Source : ");
+ printk("\n" KERN_EMERG " Source : ");
printk_address((unsigned long)bfin_read_TBUF());
printk("\n");
}
}
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND
+ if (trace_buff_offset)
+ index = trace_buff_offset/4 - 1;
+ else
+ index = EXPAND_LEN;
+
+ j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128;
+ while (j) {
+ printk(KERN_EMERG "%4i Target : ", i);
+ printk_address(software_trace_buff[index]);
+ index -= 1;
+ if (index < 0 )
+ index = EXPAND_LEN;
+ printk("\n" KERN_EMERG " Source : ");
+ printk_address(software_trace_buff[index]);
+ index -= 1;
+ if (index < 0)
+ index = EXPAND_LEN;
+ printk("\n");
+ j--;
+ i++;
+ }
+#endif
+
trace_buffer_restore(tflags);
+#endif
}
EXPORT_SYMBOL(dump_bfin_trace_buffer);
@@ -509,7 +553,9 @@ void show_stack(struct task_struct *task, unsigned long *stack)
void dump_stack(void)
{
unsigned long stack;
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
int tflags;
+#endif
trace_buffer_save(tflags);
dump_bfin_trace_buffer();
show_stack(current, &stack);
@@ -558,8 +604,7 @@ void dump_bfin_regs(struct pt_regs *fp, void *retaddr)
unsigned short x = 0;
for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) {
if (!(i & 0xF))
- printk(KERN_EMERG "\n" KERN_EMERG
- "0x%08x: ", i);
+ printk("\n" KERN_EMERG "0x%08x: ", i);
if (get_user(x, (unsigned short *)i))
break;
@@ -654,6 +699,42 @@ asmlinkage int sys_bfin_spinlock(int *spinlock)
return ret;
}
+int bfin_request_exception(unsigned int exception, void (*handler)(void))
+{
+ void (*curr_handler)(void);
+
+ if (exception > 0x3F)
+ return -EINVAL;
+
+ curr_handler = ex_table[exception];
+
+ if (curr_handler != ex_replaceable)
+ return -EBUSY;
+
+ ex_table[exception] = handler;
+
+ return 0;
+}
+EXPORT_SYMBOL(bfin_request_exception);
+
+int bfin_free_exception(unsigned int exception, void (*handler)(void))
+{
+ void (*curr_handler)(void);
+
+ if (exception > 0x3F)
+ return -EINVAL;
+
+ curr_handler = ex_table[exception];
+
+ if (curr_handler != handler)
+ return -EBUSY;
+
+ ex_table[exception] = ex_replaceable;
+
+ return 0;
+}
+EXPORT_SYMBOL(bfin_free_exception);
+
void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
{
switch (cplb_panic) {