aboutsummaryrefslogtreecommitdiffstats
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.c132
1 files changed, 84 insertions, 48 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 8bbfef31666b..c90f16825f98 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -39,6 +39,7 @@
39#include <linux/irq.h> 39#include <linux/irq.h>
40#include <asm/trace.h> 40#include <asm/trace.h>
41#include <asm/fixed_code.h> 41#include <asm/fixed_code.h>
42#include <asm/dma.h>
42 43
43#ifdef CONFIG_KGDB 44#ifdef CONFIG_KGDB
44# include <linux/debugger.h> 45# include <linux/debugger.h>
@@ -171,7 +172,7 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
171 oops_in_progress = 1; 172 oops_in_progress = 1;
172 printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); 173 printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
173 dump_bfin_process(fp); 174 dump_bfin_process(fp);
174 dump_bfin_mem((void *)fp->retx); 175 dump_bfin_mem(fp);
175 show_regs(fp); 176 show_regs(fp);
176 panic("Double Fault - unrecoverable event\n"); 177 panic("Double Fault - unrecoverable event\n");
177 178
@@ -196,6 +197,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
196 * we will kernel panic, so the system reboots. 197 * we will kernel panic, so the system reboots.
197 * If KGDB is enabled, don't set this for kernel breakpoints 198 * If KGDB is enabled, don't set this for kernel breakpoints
198 */ 199 */
200
201 /* TODO: check to see if we are in some sort of deferred HWERR
202 * that we should be able to recover from, not kernel panic
203 */
199 if ((bfin_read_IPEND() & 0xFFC0) 204 if ((bfin_read_IPEND() & 0xFFC0)
200#ifdef CONFIG_KGDB 205#ifdef CONFIG_KGDB
201 && trapnr != VEC_EXCPT02 206 && trapnr != VEC_EXCPT02
@@ -478,11 +483,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
478 if (sig != SIGTRAP) { 483 if (sig != SIGTRAP) {
479 unsigned long stack; 484 unsigned long stack;
480 dump_bfin_process(fp); 485 dump_bfin_process(fp);
481 /* Is it an interrupt, or an exception? */ 486 dump_bfin_mem(fp);
482 if (trapnr == VEC_HWERR)
483 dump_bfin_mem((void *)fp->pc);
484 else
485 dump_bfin_mem((void *)fp->retx);
486 show_regs(fp); 487 show_regs(fp);
487 488
488 /* Print out the trace buffer if it makes sense */ 489 /* Print out the trace buffer if it makes sense */
@@ -644,8 +645,10 @@ void dump_bfin_process(struct pt_regs *fp)
644 if (oops_in_progress) 645 if (oops_in_progress)
645 printk(KERN_EMERG "Kernel OOPS in progress\n"); 646 printk(KERN_EMERG "Kernel OOPS in progress\n");
646 647
647 if (context & 0x0020) 648 if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
648 printk(KERN_NOTICE "Deferred excecption or HW Error context\n"); 649 printk(KERN_NOTICE "HW Error context\n");
650 else if (context & 0x0020)
651 printk(KERN_NOTICE "Defered Exception context\n");
649 else if (context & 0x3FC0) 652 else if (context & 0x3FC0)
650 printk(KERN_NOTICE "Interrupt context\n"); 653 printk(KERN_NOTICE "Interrupt context\n");
651 else if (context & 0x4000) 654 else if (context & 0x4000)
@@ -673,49 +676,82 @@ void dump_bfin_process(struct pt_regs *fp)
673 "No Valid process in current context\n"); 676 "No Valid process in current context\n");
674} 677}
675 678
676void dump_bfin_mem(void *retaddr) 679void dump_bfin_mem(struct pt_regs *fp)
677{ 680{
681 unsigned short *addr, *erraddr, val = 0, err = 0;
682 char sti = 0, buf[6];
678 683
679 if (retaddr >= (void *)FIXED_CODE_START && retaddr < (void *)physical_mem_end 684 if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR))
680#if L1_CODE_LENGTH != 0 685 erraddr = (void *)fp->pc;
681 /* FIXME: Copy the code out of L1 Instruction SRAM through dma 686 else
682 memcpy. */ 687 erraddr = (void *)fp->retx;
683 && !(retaddr >= (void *)L1_CODE_START 688
684 && retaddr < (void *)(L1_CODE_START + L1_CODE_LENGTH)) 689 printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
685#endif 690
686 ) { 691 for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
687 int i = ((unsigned int)retaddr & 0xFFFFFFF0) - 32; 692 addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
688 unsigned short x = 0; 693 addr++) {
689 printk(KERN_NOTICE "return address: [0x%p]; contents of:", retaddr); 694 if (!((unsigned long)addr & 0xF))
690 for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) { 695 printk("\n" KERN_NOTICE "0x%p: ", addr);
691 if (!(i & 0xF)) 696
692 printk("\n" KERN_NOTICE "0x%08x: ", i); 697 if (get_user(val, addr)) {
693 698 if (addr >= (unsigned short *)L1_CODE_START &&
694 if (get_user(x, (unsigned short *)i)) 699 addr < (unsigned short *)(L1_CODE_START + L1_CODE_LENGTH)) {
695 break; 700 dma_memcpy(&val, addr, sizeof(val));
701 sprintf(buf, "%04x", val);
702 } else if (addr >= (unsigned short *)FIXED_CODE_START &&
703 addr <= (unsigned short *)memory_start) {
704 val = bfin_read16(addr);
705 sprintf(buf, "%04x", val);
706 } else {
707 val = 0;
708 sprintf(buf, "????");
709 }
710 } else
711 sprintf(buf, "%04x", val);
712
713 if (addr == erraddr) {
714 printk("[%s]", buf);
715 err = val;
716 } else
717 printk(" %s ", buf);
718
719 /* Do any previous instructions turn on interrupts? */
720 if (addr <= erraddr && /* in the past */
721 ((val >= 0x0040 && val <= 0x0047) || /* STI instruction */
722 val == 0x017b)) /* [SP++] = RETI */
723 sti = 1;
724 }
725
726 printk("\n");
727
728 /* Hardware error interrupts can be deferred */
729 if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
730 oops_in_progress)){
731 printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
696#ifndef CONFIG_DEBUG_HWERR 732#ifndef CONFIG_DEBUG_HWERR
697 /* If one of the last few instructions was a STI 733 printk(KERN_NOTICE "The remaining message may be meaningless\n"
698 * it is likely that the error occured awhile ago 734 KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
699 * and we just noticed. This only happens in kernel 735 " better idea where it came from\n");
700 * context, which should mean an oops is happening 736#else
701 */ 737 /* If we are handling only one peripheral interrupt
702 if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i <= 0) 738 * and current mm and pid are valid, and the last error
703 printk(KERN_EMERG "\n" 739 * was in that user space process's text area
704 KERN_EMERG "WARNING : You should reconfigure" 740 * print it out - because that is where the problem exists
705 " the kernel to turn on\n" 741 */
706 KERN_EMERG " 'Hardware error interrupt debugging'\n" 742 if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
707 KERN_EMERG " The rest of this error is meanless\n"); 743 (current->pid && current->mm)) {
708#endif 744 /* And the last RETI points to the current userspace context */
709 if (i == (unsigned int)retaddr) 745 if ((fp + 1)->pc >= current->mm->start_code &&
710 printk("[%04x]", x); 746 (fp + 1)->pc <= current->mm->end_code) {
711 else 747 printk(KERN_NOTICE "It might be better to look around here : \n");
712 printk(" %04x ", x); 748 printk(KERN_NOTICE "-------------------------------------------\n");
749 show_regs(fp + 1);
750 printk(KERN_NOTICE "-------------------------------------------\n");
751 }
713 } 752 }
714 printk("\n"); 753#endif
715 } else 754 }
716 printk("\n" KERN_NOTICE
717 "Cannot look at the [PC] <%p> for it is"
718 " in unreadable memory - sorry\n", retaddr);
719} 755}
720 756
721void show_regs(struct pt_regs *fp) 757void show_regs(struct pt_regs *fp)
@@ -885,7 +921,7 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
885 printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR()); 921 printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR());
886 printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR()); 922 printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR());
887 dump_bfin_process(fp); 923 dump_bfin_process(fp);
888 dump_bfin_mem((void *)fp->retx); 924 dump_bfin_mem(fp);
889 show_regs(fp); 925 show_regs(fp);
890 dump_stack(); 926 dump_stack();
891 panic("Unrecoverable event\n"); 927 panic("Unrecoverable event\n");