Blackfin: clean up trace buffer handling when crashing

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>
diff --git a/arch/blackfin/cpu/traps.c b/arch/blackfin/cpu/traps.c
index caaea94..09388aa 100644
--- a/arch/blackfin/cpu/traps.c
+++ b/arch/blackfin/cpu/traps.c
@@ -29,14 +29,26 @@
 #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 @@
 {
 	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 @@
 			 */
 			if (last_cplb_fault_retx != regs->retx) {
 				last_cplb_fault_retx = regs->retx;
-				return ret;
+				break;
 			}
 		}
 
@@ -110,7 +130,6 @@
 		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 @@
 			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 @@
 		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 @@
 #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 @@
 	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 @@
 			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 @@
 		"\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();
 }