aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel
diff options
context:
space:
mode:
authorRobin Getz <robin.getz@analog.com>2007-12-23 09:57:01 -0500
committerBryan Wu <bryan.wu@analog.com>2007-12-23 09:57:01 -0500
commitb03b08ba9c7235861adf4dde712dade0bb756fe0 (patch)
tree224d56e1403405be9306702506102989f7a5e110 /arch/blackfin/kernel
parent0d4a89bb3eb58f39831186fa6b1542893dbfdc9f (diff)
[Blackfin] arch: Clean up dump_bfin_mem
Clean up dump_bfin_mem so that it will display content from the kernel, as well as l1 instruction, when deferred HW errors happen, print out the last frame info if it makes sense. Signed-off-by: Robin Getz <robin.getz@analog.com> Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r--arch/blackfin/kernel/early_printk.c2
-rw-r--r--arch/blackfin/kernel/process.c1
-rw-r--r--arch/blackfin/kernel/traps.c132
3 files changed, 86 insertions, 49 deletions
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
index 724f4a5a1d46..c892777267d5 100644
--- a/arch/blackfin/kernel/early_printk.c
+++ b/arch/blackfin/kernel/early_printk.c
@@ -205,7 +205,7 @@ asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
205 if (likely(early_console == NULL)) 205 if (likely(early_console == NULL))
206 setup_early_printk(DEFAULT_EARLY_PORT); 206 setup_early_printk(DEFAULT_EARLY_PORT);
207 207
208 dump_bfin_mem((void *)fp->retx); 208 dump_bfin_mem(fp);
209 show_regs(fp); 209 show_regs(fp);
210 dump_bfin_trace_buffer(); 210 dump_bfin_trace_buffer();
211 211
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 5bf15125f0d6..fff3dd9eadda 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -327,6 +327,7 @@ void finish_atomic_sections (struct pt_regs *regs)
327} 327}
328 328
329#if defined(CONFIG_ACCESS_CHECK) 329#if defined(CONFIG_ACCESS_CHECK)
330/* Return 1 if access to memory range is OK, 0 otherwise */
330int _access_ok(unsigned long addr, unsigned long size) 331int _access_ok(unsigned long addr, unsigned long size)
331{ 332{
332 if (size == 0) 333 if (size == 0)
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");