diff options
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r-- | arch/blackfin/kernel/setup.c | 30 | ||||
-rw-r--r-- | arch/blackfin/kernel/traps.c | 34 |
2 files changed, 50 insertions, 14 deletions
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 7a82d10b4eb..8e639dc886a 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -52,7 +52,8 @@ EXPORT_SYMBOL(mtd_size); #endif char __initdata command_line[COMMAND_LINE_SIZE]; -unsigned int __initdata *__retx; +void __initdata *init_retx, *init_saved_retx, *init_saved_seqstat, + *init_saved_icplb_fault_addr, *init_saved_dcplb_fault_addr; /* boot memmap, for parsing "memmap=" */ #define BFIN_MEMMAP_MAX 128 /* number of entries in bfin_memmap */ @@ -782,16 +783,25 @@ void __init setup_arch(char **cmdline_p) _bfin_swrst = bfin_read_SWRST(); - /* If we double fault, reset the system - otherwise we hang forever */ - bfin_write_SWRST(DOUBLE_FAULT); +#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT + bfin_write_SWRST(_bfin_swrst & ~DOUBLE_FAULT); +#endif +#ifdef CONFIG_DEBUG_DOUBLEFAULT_RESET + bfin_write_SWRST(_bfin_swrst | DOUBLE_FAULT); +#endif - if (_bfin_swrst & RESET_DOUBLE) - /* - * don't decode the address, since you don't know if this - * kernel's symbol map is the same as the crashing kernel - */ - printk(KERN_INFO "Recovering from Double Fault event at %pF\n", __retx); - else if (_bfin_swrst & RESET_WDOG) + if (_bfin_swrst & RESET_DOUBLE) { + printk(KERN_EMERG "Recovering from DOUBLE FAULT event\n"); +#ifdef CONFIG_DEBUG_DOUBLEFAULT + /* We assume the crashing kernel, and the current symbol table match */ + printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n", + (int)init_saved_seqstat & SEQSTAT_EXCAUSE, init_saved_retx); + printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr); + printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr); +#endif + printk(KERN_NOTICE " The instruction at %pF caused a double exception\n", + init_retx); + } else if (_bfin_swrst & RESET_WDOG) printk(KERN_INFO "Recovering from Watchdog event\n"); else if (_bfin_swrst & RESET_SOFTWARE) printk(KERN_NOTICE "Reset caused by Software reset\n"); diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index fd24e04fc19..bd41fca315d 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -68,7 +68,15 @@ void __init trap_init(void) CSYNC(); } -unsigned long saved_icplb_fault_addr, saved_dcplb_fault_addr; +/* + * Used to save the RETX, SEQSTAT, I/D CPLB FAULT ADDR + * values across the transition from exception to IRQ5. + * We put these in L1, so they are going to be in a valid + * location during exception context + */ +__attribute__((l1_data)) +unsigned long saved_retx, saved_seqstat, + saved_icplb_fault_addr, saved_dcplb_fault_addr; static void decode_address(char *buf, unsigned long address) { @@ -186,9 +194,27 @@ asmlinkage void double_fault_c(struct pt_regs *fp) console_verbose(); oops_in_progress = 1; printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); - dump_bfin_process(fp); - dump_bfin_mem(fp); - show_regs(fp); +#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT + if (((long)fp->seqstat & SEQSTAT_EXCAUSE) == VEC_UNCOV) { + char buf[150]; + decode_address(buf, saved_retx); + printk(KERN_EMERG "While handling exception (EXCAUSE = 0x%x) at %s:\n", + (int)saved_seqstat & SEQSTAT_EXCAUSE, buf); + decode_address(buf, saved_dcplb_fault_addr); + printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %s\n", buf); + decode_address(buf, saved_icplb_fault_addr); + printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %s\n", buf); + + decode_address(buf, fp->retx); + printk(KERN_NOTICE "The instruction at %s caused a double exception\n", + buf); + } else +#endif + { + dump_bfin_process(fp); + dump_bfin_mem(fp); + show_regs(fp); + } panic("Double Fault - unrecoverable event\n"); } |