[Blackfin] arch: fix bug - trap_tests fails to recover on some tests.

http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=3719

When the CPLBs get a miss, we do:
  - find a victim in the HW table
  - remove the victim
  - find the replacement in the software table
  - put it into the HW table.

If we can't find a replacement in the software table, we accidently
leave a duplicate in the HW table. This patch ensures that duplicate
is marked as not valid.

What we should do is find the replacement in the software table, before
we find a victim in the HW table - but its too late in the release cycle
to do that much restructuring of this code.

Rather that duplicate code, connect Hardware Errors (irq5) into trap_c,
so user space processes get killed properly.

The rest of irq_panic() can be moved into traps.c (later)

There is still a small corner case that causes problems when a
pheriperal interrupt goes off a single cycle before a user space
hardware error. This causes a kernel panic, rather than the user
space process being killed.

But, this checkin makes things work in 99.9% of the cases, and is a vast
improvement from what is there today (which fails 100% of the time).

Signed-off-by: Robin Getz <robin.getz@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>

diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 21a55ef..4be5ff0 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -433,6 +433,36 @@
 	/* 0x3D - Reserved, Caught by default */
 	/* 0x3E - Reserved, Caught by default */
 	/* 0x3F - Reserved, Caught by default */
+	case VEC_HWERR:
+		info.si_code = BUS_ADRALN;
+		sig = SIGBUS;
+		switch (fp->seqstat & SEQSTAT_HWERRCAUSE) {
+		/* System MMR Error */
+		case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
+			info.si_code = BUS_ADRALN;
+			sig = SIGBUS;
+			printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
+			break;
+		/* External Memory Addressing Error */
+		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
+			info.si_code = BUS_ADRERR;
+			sig = SIGBUS;
+			printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
+			break;
+		/* Performance Monitor Overflow */
+		case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
+			printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
+			break;
+		/* RAISE 5 instruction */
+		case (SEQSTAT_HWERRCAUSE_RAISE_5):
+			printk(KERN_NOTICE HWC_x18(KERN_NOTICE));
+			break;
+		default:        /* Reserved */
+			printk(KERN_NOTICE HWC_default(KERN_NOTICE));
+			break;
+		}
+		CHK_DEBUGGER_TRAP();
+		break;
 	default:
 		info.si_code = TRAP_ILLTRAP;
 		sig = SIGTRAP;
@@ -447,7 +477,11 @@
 	if (sig != SIGTRAP) {
 		unsigned long stack;
 		dump_bfin_process(fp);
-		dump_bfin_mem((void *)fp->retx);
+		/* Is it an interrupt, or an exception? */
+		if (trapnr == VEC_HWERR)
+			dump_bfin_mem((void *)fp->pc);
+		else
+			dump_bfin_mem((void *)fp->retx);
 		show_regs(fp);
 
 		/* Print out the trace buffer if it makes sense */
@@ -672,12 +706,11 @@
 			 * context, which should mean an oops is happening
 			 */
 			if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i <= 0)
-				panic("\n\nWARNING : You should reconfigure"
+				printk(KERN_EMERG "\n"
+					KERN_EMERG "WARNING : You should reconfigure"
 					" the kernel to turn on\n"
-					" 'Hardware error interrupt"
-					" debugging'\n"
-					" The rest of this error"
-					" is meanless\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);
@@ -698,6 +731,10 @@
 	printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\n");
 	printk(KERN_NOTICE " SEQSTAT: %08lx  IPEND: %04lx  SYSCFG: %04lx\n",
 		(long)fp->seqstat, fp->ipend, fp->syscfg);
+	printk(KERN_NOTICE "  HWERRCAUSE: 0x%lx\n",
+		(fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
+	printk(KERN_NOTICE "  EXCAUSE   : 0x%lx\n",
+		fp->seqstat & SEQSTAT_EXCAUSE);
 
 	decode_address(buf, fp->rete);
 	printk(KERN_NOTICE " RETE: %s\n", buf);
@@ -708,9 +745,10 @@
 	decode_address(buf, fp->rets);
 	printk(KERN_NOTICE " RETS: %s\n", buf);
 	decode_address(buf, fp->pc);
-	printk(KERN_NOTICE " PC: %s\n", buf);
+	printk(KERN_NOTICE " PC  : %s\n", buf);
 
-	if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
+	if (((long)fp->seqstat &  SEQSTAT_EXCAUSE) &&
+	    (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
 		decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
 		printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
 		decode_address(buf, bfin_read_ICPLB_FAULT_ADDR());