Blackfin: clean up trace buffer handling when crashing
authorMike Frysinger <vapier@gentoo.org>
Thu, 29 Apr 2010 04:31:36 +0000 (00:31 -0400)
committerMike Frysinger <vapier@gentoo.org>
Mon, 5 Jul 2010 08:18:18 +0000 (04:18 -0400)
Avoid banging on the trace MMRs when debugging is disabled, avoid calling
the funcs multiple times in a row, disable the trace buffer earlier in the
exception handler to avoid eating more user entries, and dump the buffer
before calling the kgdb hook.  This way we maximize useful debugging info
up front rather than needing external tools (like gdb/serial/etc...).

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
arch/blackfin/cpu/cpu.h
arch/blackfin/cpu/traps.c

index 0a13c285e0e468601be51a6206e5b830f1fa0f86..c8bec115a13580b496f6c2867180f67855837347 100644 (file)
@@ -29,6 +29,7 @@
 
 void board_reset(void) __attribute__((__weak__));
 void bfin_reset_or_hang(void) __attribute__((__noreturn__));
+void bfin_dump(struct pt_regs *reg);
 void bfin_panic(struct pt_regs *reg);
 void dump(struct pt_regs *regs);
 
index caaea94106a556d2095a85847967743a3eabfd19..09388aa3d53a15ed8b34d188732ee31eded5499f 100644 (file)
 #include <asm/deferred.h>
 #include "cpu.h"
 
+#ifdef CONFIG_DEBUG_DUMP
+# define ENABLE_DUMP 1
+#else
+# define ENABLE_DUMP 0
+#endif
+
 #define trace_buffer_save(x) \
        do { \
+               if (!ENABLE_DUMP) \
+                       break; \
                (x) = bfin_read_TBUFCTL(); \
                bfin_write_TBUFCTL((x) & ~TBUFEN); \
        } while (0)
 
 #define trace_buffer_restore(x) \
-       bfin_write_TBUFCTL((x))
+       do { \
+               if (!ENABLE_DUMP) \
+                       break; \
+               bfin_write_TBUFCTL((x)); \
+       } while (0);
 
 /* The purpose of this map is to provide a mapping of address<->cplb settings
  * rather than an exact map of what is actually addressable on the part.  This
@@ -82,8 +94,16 @@ int trap_c(struct pt_regs *regs, uint32_t level)
 {
        uint32_t ret = 0;
        uint32_t trapnr = (regs->seqstat & EXCAUSE);
+       unsigned long tflags;
        bool data = false;
 
+       /*
+        * Keep the trace buffer so that a miss here points people
+        * to the right place (their code).  Crashes here rarely
+        * happen.  If they do, only the Blackfin maintainer cares.
+        */
+       trace_buffer_save(tflags);
+
        switch (trapnr) {
        /* 0x26 - Data CPLB Miss */
        case VEC_CPLB_M:
@@ -97,7 +117,7 @@ int trap_c(struct pt_regs *regs, uint32_t level)
                         */
                        if (last_cplb_fault_retx != regs->retx) {
                                last_cplb_fault_retx = regs->retx;
-                               return ret;
+                               break;
                        }
                }
 
@@ -110,7 +130,6 @@ int trap_c(struct pt_regs *regs, uint32_t level)
                uint32_t new_cplb_addr = 0, new_cplb_data = 0;
                static size_t last_evicted;
                size_t i;
-               unsigned long tflags;
 
 #ifdef CONFIG_EXCEPTION_DEFER
                /* This should never happen */
@@ -118,13 +137,6 @@ int trap_c(struct pt_regs *regs, uint32_t level)
                        bfin_panic(regs);
 #endif
 
-               /*
-                * Keep the trace buffer so that a miss here points people
-                * to the right place (their code).  Crashes here rarely
-                * happen.  If they do, only the Blackfin maintainer cares.
-                */
-               trace_buffer_save(tflags);
-
                new_cplb_addr = (data ? bfin_read_DCPLB_FAULT_ADDR() : bfin_read_ICPLB_FAULT_ADDR()) & ~(4 * 1024 * 1024 - 1);
 
                for (i = 0; i < ARRAY_SIZE(bfin_memory_map); ++i) {
@@ -180,7 +192,6 @@ int trap_c(struct pt_regs *regs, uint32_t level)
                for (i = 0; i < 16; ++i)
                        debug("%2i 0x%p 0x%08X\n", i, *CPLB_ADDR++, *CPLB_DATA++);
 
-               trace_buffer_restore(tflags);
                break;
        }
 #ifdef CONFIG_CMD_KGDB
@@ -208,23 +219,21 @@ int trap_c(struct pt_regs *regs, uint32_t level)
 #ifdef CONFIG_CMD_KGDB
                if (level == 3) {
                        /* We need to handle this at EVT5, so try again */
+                       bfin_dump(regs);
                        ret = 1;
                        break;
                }
                if (debugger_exception_handler && (*debugger_exception_handler)(regs))
-                       return 0;
+                       break;
 #endif
                bfin_panic(regs);
        }
+
+       trace_buffer_restore(tflags);
+
        return ret;
 }
 
-#ifdef CONFIG_DEBUG_DUMP
-# define ENABLE_DUMP 1
-#else
-# define ENABLE_DUMP 0
-#endif
-
 #ifndef CONFIG_KALLSYMS
 const char *symbol_lookup(unsigned long addr, unsigned long *caddr)
 {
@@ -364,17 +373,14 @@ void dump(struct pt_regs *fp)
        printf("\n");
 }
 
-void dump_bfin_trace_buffer(void)
+static void _dump_bfin_trace_buffer(void)
 {
        char buf[150];
-       unsigned long tflags;
        int i = 0;
 
        if (!ENABLE_DUMP)
                return;
 
-       trace_buffer_save(tflags);
-
        printf("Hardware Trace:\n");
 
        if (bfin_read_TBUFSTAT() & TBUFCNT) {
@@ -385,16 +391,21 @@ void dump_bfin_trace_buffer(void)
                        printf("     Source : %s\n", buf);
                }
        }
+}
 
+void dump_bfin_trace_buffer(void)
+{
+       unsigned long tflags;
+       trace_buffer_save(tflags);
+       _dump_bfin_trace_buffer();
        trace_buffer_restore(tflags);
 }
 
-void bfin_panic(struct pt_regs *regs)
+void bfin_dump(struct pt_regs *regs)
 {
-       if (ENABLE_DUMP) {
-               unsigned long tflags;
-               trace_buffer_save(tflags);
-       }
+       unsigned long tflags;
+
+       trace_buffer_save(tflags);
 
        puts(
                "\n"
@@ -404,7 +415,16 @@ void bfin_panic(struct pt_regs *regs)
                "\n"
        );
        dump(regs);
-       dump_bfin_trace_buffer();
+       _dump_bfin_trace_buffer();
        puts("\n");
+
+       trace_buffer_restore(tflags);
+}
+
+void bfin_panic(struct pt_regs *regs)
+{
+       unsigned long tflags;
+       trace_buffer_save(tflags);
+       bfin_dump(regs);
        bfin_reset_or_hang();
 }