diff options
Diffstat (limited to 'arch/blackfin/kernel/traps.c')
-rw-r--r-- | arch/blackfin/kernel/traps.c | 113 |
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) { |