Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b03b08ba9c7235861adf4dde712dade0bb756fe0
Commit:     b03b08ba9c7235861adf4dde712dade0bb756fe0
Parent:     0d4a89bb3eb58f39831186fa6b1542893dbfdc9f
Author:     Robin Getz <[EMAIL PROTECTED]>
AuthorDate: Sun Dec 23 22:57:01 2007 +0800
Committer:  Bryan Wu <[EMAIL PROTECTED]>
CommitDate: Sun Dec 23 22:57:01 2007 +0800

    [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 <[EMAIL PROTECTED]>
    Signed-off-by: Bryan Wu <[EMAIL PROTECTED]>
---
 arch/blackfin/kernel/early_printk.c |    2 +-
 arch/blackfin/kernel/process.c      |    1 +
 arch/blackfin/kernel/traps.c        |  132 ++++++++++++++++++++++-------------
 include/asm-blackfin/bfin-global.h  |    2 +-
 4 files changed, 87 insertions(+), 50 deletions(-)

diff --git a/arch/blackfin/kernel/early_printk.c 
b/arch/blackfin/kernel/early_printk.c
index 724f4a5..c892777 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)
        if (likely(early_console == NULL))
                setup_early_printk(DEFAULT_EARLY_PORT);
 
-       dump_bfin_mem((void *)fp->retx);
+       dump_bfin_mem(fp);
        show_regs(fp);
        dump_bfin_trace_buffer();
 
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 5bf1512..fff3dd9 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)
 }
 
 #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)
 {
        if (size == 0)
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 8bbfef3..c90f168 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -39,6 +39,7 @@
 #include <linux/irq.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
+#include <asm/dma.h>
 
 #ifdef CONFIG_KGDB
 # include <linux/debugger.h>
@@ -171,7 +172,7 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
        oops_in_progress = 1;
        printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n");
        dump_bfin_process(fp);
-       dump_bfin_mem((void *)fp->retx);
+       dump_bfin_mem(fp);
        show_regs(fp);
        panic("Double Fault - unrecoverable event\n");
 
@@ -196,6 +197,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
         * we will kernel panic, so the system reboots.
         * 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)
 #ifdef CONFIG_KGDB
                && trapnr != VEC_EXCPT02
@@ -478,11 +483,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        if (sig != SIGTRAP) {
                unsigned long stack;
                dump_bfin_process(fp);
-               /* Is it an interrupt, or an exception? */
-               if (trapnr == VEC_HWERR)
-                       dump_bfin_mem((void *)fp->pc);
-               else
-                       dump_bfin_mem((void *)fp->retx);
+               dump_bfin_mem(fp);
                show_regs(fp);
 
                /* Print out the trace buffer if it makes sense */
@@ -644,8 +645,10 @@ void dump_bfin_process(struct pt_regs *fp)
        if (oops_in_progress)
                printk(KERN_EMERG "Kernel OOPS in progress\n");
 
-       if (context & 0x0020)
-               printk(KERN_NOTICE "Deferred excecption or HW Error context\n");
+       if (context & 0x0020 && (fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR)
+               printk(KERN_NOTICE "HW Error context\n");
+       else if (context & 0x0020)
+               printk(KERN_NOTICE "Defered Exception context\n");
        else if (context & 0x3FC0)
                printk(KERN_NOTICE "Interrupt context\n");
        else if (context & 0x4000)
@@ -673,49 +676,82 @@ void dump_bfin_process(struct pt_regs *fp)
                     "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 L1_CODE_LENGTH != 0
-           /* FIXME: Copy the code out of L1 Instruction SRAM through dma
-              memcpy.  */
-           && !(retaddr >= (void *)L1_CODE_START
-                && retaddr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
-#endif
-       ) {
-               int i = ((unsigned int)retaddr & 0xFFFFFFF0) - 32;
-               unsigned short x = 0;
-               printk(KERN_NOTICE "return address: [0x%p]; contents of:", 
retaddr);
-               for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) {
-                       if (!(i & 0xF))
-                               printk("\n" KERN_NOTICE "0x%08x: ", i);
-
-                       if (get_user(x, (unsigned short *)i))
-                               break;
+       if (unlikely((fp->seqstat & SEQSTAT_EXCAUSE) == VEC_HWERR))
+               erraddr = (void *)fp->pc;
+       else
+               erraddr = (void *)fp->retx;
+
+       printk(KERN_NOTICE "return address: [0x%p]; contents of:", erraddr);
+
+       for (addr = (unsigned short *)((unsigned long)erraddr & ~0xF) - 0x10;
+            addr < (unsigned short *)((unsigned long)erraddr & ~0xF) + 0x10;
+            addr++) {
+               if (!((unsigned long)addr & 0xF))
+                       printk("\n" KERN_NOTICE "0x%p: ", addr);
+
+               if (get_user(val, addr)) {
+                       if (addr >= (unsigned short *)L1_CODE_START &&
+                           addr < (unsigned short *)(L1_CODE_START + 
L1_CODE_LENGTH)) {
+                               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
-                       /* If one of the last few instructions was a STI
-                        * it is likely that the error occured awhile ago
-                        * and we just noticed. This only happens in kernel
-                        * context, which should mean an oops is happening
-                        */
-                       if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i 
<= 0)
-                               printk(KERN_EMERG "\n"
-                                       KERN_EMERG "WARNING : You should 
reconfigure"
-                                       " the kernel to turn on\n"
-                                       KERN_EMERG " 'Hardware error interrupt 
debugging'\n"
-                                       KERN_EMERG " The rest of this error is 
meanless\n");
-#endif
-                       if (i == (unsigned int)retaddr)
-                               printk("[%04x]", x);
-                       else
-                               printk(" %04x ", x);
+               printk(KERN_NOTICE "The remaining message may be meaningless\n"
+                       KERN_NOTICE "You should enable CONFIG_DEBUG_HWERR to 
get a"
+                        " better idea where it came from\n");
+#else
+               /* If we are handling only one peripheral interrupt
+                * and current mm and pid are valid, and the last error
+                * was in that user space process's text area
+                * print it out - because that is where the problem exists
+                */
+               if ((!(((fp)->ipend & ~0x30) & (((fp)->ipend & ~0x30) - 1))) &&
+                    (current->pid && current->mm)) {
+                       /* And the last RETI points to the current userspace 
context */
+                       if ((fp + 1)->pc >= current->mm->start_code &&
+                           (fp + 1)->pc <= current->mm->end_code) {
+                               printk(KERN_NOTICE "It might be better to look 
around here : \n");
+                               printk(KERN_NOTICE 
"-------------------------------------------\n");
+                               show_regs(fp + 1);
+                               printk(KERN_NOTICE 
"-------------------------------------------\n");
+                       }
                }
-               printk("\n");
-       } else
-               printk("\n" KERN_NOTICE
-                       "Cannot look at the [PC] <%p> for it is"
-                       " in unreadable memory - sorry\n", retaddr);
+#endif
+       }
 }
 
 void show_regs(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 "ICPLB_FAULT_ADDR=%p\n", (void 
*)bfin_read_ICPLB_FAULT_ADDR());
        dump_bfin_process(fp);
-       dump_bfin_mem((void *)fp->retx);
+       dump_bfin_mem(fp);
        show_regs(fp);
        dump_stack();
        panic("Unrecoverable event\n");
diff --git a/include/asm-blackfin/bfin-global.h 
b/include/asm-blackfin/bfin-global.h
index 39bdd86..6ae0619 100644
--- a/include/asm-blackfin/bfin-global.h
+++ b/include/asm-blackfin/bfin-global.h
@@ -51,7 +51,7 @@ extern unsigned long sclk_to_usecs(unsigned long sclk);
 extern unsigned long usecs_to_sclk(unsigned long usecs);
 
 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 int init_arch_irq(void);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to