Commit b03b08ba authored by Robin Getz's avatar Robin Getz Committed by Bryan Wu

[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: default avatarRobin Getz <robin.getz@analog.com>
Signed-off-by: default avatarBryan Wu <bryan.wu@analog.com>
parent 0d4a89bb
...@@ -205,7 +205,7 @@ asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr) ...@@ -205,7 +205,7 @@ asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
if (likely(early_console == NULL)) if (likely(early_console == NULL))
setup_early_printk(DEFAULT_EARLY_PORT); setup_early_printk(DEFAULT_EARLY_PORT);
dump_bfin_mem((void *)fp->retx); dump_bfin_mem(fp);
show_regs(fp); show_regs(fp);
dump_bfin_trace_buffer(); dump_bfin_trace_buffer();
......
...@@ -327,6 +327,7 @@ void finish_atomic_sections (struct pt_regs *regs) ...@@ -327,6 +327,7 @@ void finish_atomic_sections (struct pt_regs *regs)
} }
#if defined(CONFIG_ACCESS_CHECK) #if defined(CONFIG_ACCESS_CHECK)
/* Return 1 if access to memory range is OK, 0 otherwise */
int _access_ok(unsigned long addr, unsigned long size) int _access_ok(unsigned long addr, unsigned long size)
{ {
if (size == 0) if (size == 0)
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/trace.h> #include <asm/trace.h>
#include <asm/fixed_code.h> #include <asm/fixed_code.h>
#include <asm/dma.h>
#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB
# include <linux/debugger.h> # include <linux/debugger.h>
...@@ -171,7 +172,7 @@ asmlinkage void double_fault_c(struct pt_regs *fp) ...@@ -171,7 +172,7 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
oops_in_progress = 1; oops_in_progress = 1;
printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
dump_bfin_process(fp); dump_bfin_process(fp);
dump_bfin_mem((void *)fp->retx); dump_bfin_mem(fp);
show_regs(fp); show_regs(fp);
panic("Double Fault - unrecoverable event\n"); panic("Double Fault - unrecoverable event\n");
...@@ -196,6 +197,10 @@ asmlinkage void trap_c(struct pt_regs *fp) ...@@ -196,6 +197,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
* we will kernel panic, so the system reboots. * we will kernel panic, so the system reboots.
* If KGDB is enabled, don't set this for kernel breakpoints * If KGDB is enabled, don't set this for kernel breakpoints
*/ */
/* TODO: check to see if we are in some sort of deferred HWERR
* that we should be able to recover from, not kernel panic
*/
if ((bfin_read_IPEND() & 0xFFC0) if ((bfin_read_IPEND() & 0xFFC0)
#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB
&& trapnr != VEC_EXCPT02 && trapnr != VEC_EXCPT02
...@@ -478,11 +483,7 @@ asmlinkage void trap_c(struct pt_regs *fp) ...@@ -478,11 +483,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
if (sig != SIGTRAP) { if (sig != SIGTRAP) {
unsigned long stack; unsigned long stack;
dump_bfin_process(fp); dump_bfin_process(fp);
/* Is it an interrupt, or an exception? */ dump_bfin_mem(fp);
if (trapnr == VEC_HWERR)
dump_bfin_mem((void *)fp->pc);
else
dump_bfin_mem((void *)fp->retx);
show_regs(fp); show_regs(fp);
/* Print out the trace buffer if it makes sense */ /* Print out the trace buffer if it makes sense */
...@@ -644,8 +645,10 @@ void dump_bfin_process(struct pt_regs *fp) ...@@ -644,8 +645,10 @@ void dump_bfin_process(struct pt_regs *fp)
if (oops_in_progress) if (oops_in_progress)
printk(KERN_EMERG "Kernel OOPS in progress\n"); printk(KERN_EMERG "Kernel OOPS in progress\n");
if (context & 0x0020) if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
printk(KERN_NOTICE "Deferred excecption or HW Error context\n"); printk(KERN_NOTICE "HW Error context\n");
else if (context & 0x0020)
printk(KERN_NOTICE "Defered Exception context\n");
else if (context & 0x3FC0) else if (context & 0x3FC0)
printk(KERN_NOTICE "Interrupt context\n"); printk(KERN_NOTICE "Interrupt context\n");
else if (context & 0x4000) else if (context & 0x4000)
...@@ -673,49 +676,82 @@ void dump_bfin_process(struct pt_regs *fp) ...@@ -673,49 +676,82 @@ void dump_bfin_process(struct pt_regs *fp)
"No Valid process in current context\n"); "No Valid process in current context\n");
} }
void dump_bfin_mem(void *retaddr) void dump_bfin_mem(struct pt_regs *fp)
{ {
unsigned short *addr, *erraddr, val = 0, err = 0;
char sti = 0, buf[6];
if (retaddr >= (void *)FIXED_CODE_START && retaddr < (void *)physical_mem_end if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR))
#if L1_CODE_LENGTH != 0 erraddr = (void *)fp->pc;
/* FIXME: Copy the code out of L1 Instruction SRAM through dma else
memcpy. */ erraddr = (void *)fp->retx;
&& !(retaddr >= (void *)L1_CODE_START
&& retaddr < (void *)(L1_CODE_START + L1_CODE_LENGTH)) printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
#endif
) { for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
int i = ((unsigned int)retaddr & 0xFFFFFFF0) - 32; addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
unsigned short x = 0; addr++) {
printk(KERN_NOTICE "return address: [0x%p]; contents of:", retaddr); if (!((unsigned long)addr & 0xF))
for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) { printk("\n" KERN_NOTICE "0x%p: ", addr);
if (!(i & 0xF))
printk("\n" KERN_NOTICE "0x%08x: ", i); if (get_user(val, addr)) {
if (addr >= (unsigned short *)L1_CODE_START &&
if (get_user(x, (unsigned short *)i)) addr < (unsigned short *)(L1_CODE_START + L1_CODE_LENGTH)) {
break; dma_memcpy(&val, addr, sizeof(val));
sprintf(buf, "%04x", val);
} else if (addr >= (unsigned short *)FIXED_CODE_START &&
addr <= (unsigned short *)memory_start) {
val = bfin_read16(addr);
sprintf(buf, "%04x", val);
} else {
val = 0;
sprintf(buf, "????");
}
} else
sprintf(buf, "%04x", val);
if (addr == erraddr) {
printk("[%s]", buf);
err = val;
} else
printk(" %s ", buf);
/* Do any previous instructions turn on interrupts? */
if (addr <= erraddr && /* in the past */
((val >= 0x0040 && val <= 0x0047) || /* STI instruction */
val == 0x017b)) /* [SP++] = RETI */
sti = 1;
}
printk("\n");
/* Hardware error interrupts can be deferred */
if (unlikely(sti && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR &&
oops_in_progress)){
printk(KERN_NOTICE "Looks like this was a deferred error - sorry\n");
#ifndef CONFIG_DEBUG_HWERR #ifndef CONFIG_DEBUG_HWERR
/* If one of the last few instructions was a STI printk(KERN_NOTICE "The remaining message may be meaningless\n"
* it is likely that the error occured awhile ago KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to get a"
* and we just noticed. This only happens in kernel " better idea where it came from\n");
* context, which should mean an oops is happening #else
*/ /* If we are handling only one peripheral interrupt
if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i <= 0) * and current mm and pid are valid, and the last error
printk(KERN_EMERG "\n" * was in that user space process's text area
KERN_EMERG "WARNING : You should reconfigure" * print it out - because that is where the problem exists
" the kernel to turn on\n" */
KERN_EMERG " 'Hardware error interrupt debugging'\n" if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
KERN_EMERG " The rest of this error is meanless\n"); (current->pid && current->mm)) {
#endif /* And the last RETI points to the current userspace context */
if (i == (unsigned int)retaddr) if ((fp + 1)->pc >= current->mm->start_code &&
printk("[%04x]", x); (fp + 1)->pc <= current->mm->end_code) {
else printk(KERN_NOTICE "It might be better to look around here : \n");
printk(" %04x ", x); printk(KERN_NOTICE "-------------------------------------------\n");
show_regs(fp + 1);
printk(KERN_NOTICE "-------------------------------------------\n");
}
} }
printk("\n"); #endif
} else }
printk("\n" KERN_NOTICE
"Cannot look at the [PC] <%p> for it is"
" in unreadable memory - sorry\n", retaddr);
} }
void show_regs(struct pt_regs *fp) void show_regs(struct pt_regs *fp)
...@@ -885,7 +921,7 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp) ...@@ -885,7 +921,7 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR()); printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR());
printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR()); printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR());
dump_bfin_process(fp); dump_bfin_process(fp);
dump_bfin_mem((void *)fp->retx); dump_bfin_mem(fp);
show_regs(fp); show_regs(fp);
dump_stack(); dump_stack();
panic("Unrecoverable event\n"); panic("Unrecoverable event\n");
......
...@@ -51,7 +51,7 @@ extern unsigned long sclk_to_usecs(unsigned long sclk); ...@@ -51,7 +51,7 @@ extern unsigned long sclk_to_usecs(unsigned long sclk);
extern unsigned long usecs_to_sclk(unsigned long usecs); extern unsigned long usecs_to_sclk(unsigned long usecs);
extern void dump_bfin_process(struct pt_regs *regs); extern void dump_bfin_process(struct pt_regs *regs);
extern void dump_bfin_mem(void *retaddr); extern void dump_bfin_mem(struct pt_regs *regs);
extern void dump_bfin_trace_buffer(void); extern void dump_bfin_trace_buffer(void);
extern int init_arch_irq(void); extern int init_arch_irq(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment