aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorRobin Getz <robin.getz@analog.com>2008-01-27 02:38:56 -0500
committerBryan Wu <bryan.wu@analog.com>2008-01-27 02:38:56 -0500
commit13fe24f37df20e580a5a364e67ec8cf3219d8f8c (patch)
treec790da8a840c6fdc3e6f5eacccadede92e329d7c /arch/blackfin
parentf53e86760e10abbe7ee98a5b3cb270fa6426fcdb (diff)
[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>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/kernel/traps.c54
-rw-r--r--arch/blackfin/mach-common/cplbmgr.S22
-rw-r--r--arch/blackfin/mach-common/interrupt.S40
-rw-r--r--arch/blackfin/mach-common/irqpanic.c50
4 files changed, 95 insertions, 71 deletions
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 21a55ef19cbd..4be5ff0be60f 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -433,6 +433,36 @@ asmlinkage void trap_c(struct pt_regs *fp)
433 /* 0x3D - Reserved, Caught by default */ 433 /* 0x3D - Reserved, Caught by default */
434 /* 0x3E - Reserved, Caught by default */ 434 /* 0x3E - Reserved, Caught by default */
435 /* 0x3F - Reserved, Caught by default */ 435 /* 0x3F - Reserved, Caught by default */
436 case VEC_HWERR:
437 info.si_code = BUS_ADRALN;
438 sig = SIGBUS;
439 switch (fp->seqstat & SEQSTAT_HWERRCAUSE) {
440 /* System MMR Error */
441 case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
442 info.si_code = BUS_ADRALN;
443 sig = SIGBUS;
444 printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
445 break;
446 /* External Memory Addressing Error */
447 case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
448 info.si_code = BUS_ADRERR;
449 sig = SIGBUS;
450 printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
451 break;
452 /* Performance Monitor Overflow */
453 case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
454 printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
455 break;
456 /* RAISE 5 instruction */
457 case (SEQSTAT_HWERRCAUSE_RAISE_5):
458 printk(KERN_NOTICE HWC_x18(KERN_NOTICE));
459 break;
460 default: /* Reserved */
461 printk(KERN_NOTICE HWC_default(KERN_NOTICE));
462 break;
463 }
464 CHK_DEBUGGER_TRAP();
465 break;
436 default: 466 default:
437 info.si_code = TRAP_ILLTRAP; 467 info.si_code = TRAP_ILLTRAP;
438 sig = SIGTRAP; 468 sig = SIGTRAP;
@@ -447,7 +477,11 @@ asmlinkage void trap_c(struct pt_regs *fp)
447 if (sig != SIGTRAP) { 477 if (sig != SIGTRAP) {
448 unsigned long stack; 478 unsigned long stack;
449 dump_bfin_process(fp); 479 dump_bfin_process(fp);
450 dump_bfin_mem((void *)fp->retx); 480 /* Is it an interrupt, or an exception? */
481 if (trapnr == VEC_HWERR)
482 dump_bfin_mem((void *)fp->pc);
483 else
484 dump_bfin_mem((void *)fp->retx);
451 show_regs(fp); 485 show_regs(fp);
452 486
453 /* Print out the trace buffer if it makes sense */ 487 /* Print out the trace buffer if it makes sense */
@@ -672,12 +706,11 @@ void dump_bfin_mem(void *retaddr)
672 * context, which should mean an oops is happening 706 * context, which should mean an oops is happening
673 */ 707 */
674 if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i <= 0) 708 if (oops_in_progress && x >= 0x0040 && x <= 0x0047 && i <= 0)
675 panic("\n\nWARNING : You should reconfigure" 709 printk(KERN_EMERG "\n"
710 KERN_EMERG "WARNING : You should reconfigure"
676 " the kernel to turn on\n" 711 " the kernel to turn on\n"
677 " 'Hardware error interrupt" 712 KERN_EMERG " 'Hardware error interrupt debugging'\n"
678 " debugging'\n" 713 KERN_EMERG " The rest of this error is meanless\n");
679 " The rest of this error"
680 " is meanless\n");
681#endif 714#endif
682 if (i == (unsigned int)retaddr) 715 if (i == (unsigned int)retaddr)
683 printk("[%04x]", x); 716 printk("[%04x]", x);
@@ -698,6 +731,10 @@ void show_regs(struct pt_regs *fp)
698 printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\n"); 731 printk(KERN_NOTICE "\n" KERN_NOTICE "SEQUENCER STATUS:\n");
699 printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n", 732 printk(KERN_NOTICE " SEQSTAT: %08lx IPEND: %04lx SYSCFG: %04lx\n",
700 (long)fp->seqstat, fp->ipend, fp->syscfg); 733 (long)fp->seqstat, fp->ipend, fp->syscfg);
734 printk(KERN_NOTICE " HWERRCAUSE: 0x%lx\n",
735 (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14);
736 printk(KERN_NOTICE " EXCAUSE : 0x%lx\n",
737 fp->seqstat & SEQSTAT_EXCAUSE);
701 738
702 decode_address(buf, fp->rete); 739 decode_address(buf, fp->rete);
703 printk(KERN_NOTICE " RETE: %s\n", buf); 740 printk(KERN_NOTICE " RETE: %s\n", buf);
@@ -708,9 +745,10 @@ void show_regs(struct pt_regs *fp)
708 decode_address(buf, fp->rets); 745 decode_address(buf, fp->rets);
709 printk(KERN_NOTICE " RETS: %s\n", buf); 746 printk(KERN_NOTICE " RETS: %s\n", buf);
710 decode_address(buf, fp->pc); 747 decode_address(buf, fp->pc);
711 printk(KERN_NOTICE " PC: %s\n", buf); 748 printk(KERN_NOTICE " PC : %s\n", buf);
712 749
713 if ((long)fp->seqstat & SEQSTAT_EXCAUSE) { 750 if (((long)fp->seqstat & SEQSTAT_EXCAUSE) &&
751 (((long)fp->seqstat & SEQSTAT_EXCAUSE) != VEC_HWERR)) {
714 decode_address(buf, bfin_read_DCPLB_FAULT_ADDR()); 752 decode_address(buf, bfin_read_DCPLB_FAULT_ADDR());
715 printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf); 753 printk(KERN_NOTICE "DCPLB_FAULT_ADDR: %s\n", buf);
716 decode_address(buf, bfin_read_ICPLB_FAULT_ADDR()); 754 decode_address(buf, bfin_read_ICPLB_FAULT_ADDR());
diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S
index faca1ab344d2..f5cf3accef37 100644
--- a/arch/blackfin/mach-common/cplbmgr.S
+++ b/arch/blackfin/mach-common/cplbmgr.S
@@ -190,7 +190,14 @@ ENTRY(_cplb_mgr)
190 [P0 - 4] = R0; 190 [P0 - 4] = R0;
191 R0 = [P0 - 0x100]; 191 R0 = [P0 - 0x100];
192 [P0-0x104] = R0; 192 [P0-0x104] = R0;
193.Lie_move:P0+=4; 193.Lie_move:
194 P0+=4;
195
196 /* Clear ICPLB_DATA15, in case we don't find a replacement
197 * otherwise, we would have a duplicate entry, and will crash
198 */
199 R0 = 0;
200 [P0 - 4] = R0;
194 201
195 /* We've made space in the ICPLB table, so that ICPLB15 202 /* We've made space in the ICPLB table, so that ICPLB15
196 * is now free to be overwritten. Next, we have to determine 203 * is now free to be overwritten. Next, we have to determine
@@ -515,14 +522,23 @@ ENTRY(_cplb_mgr)
515 R0 = [P0++]; /* move data */ 522 R0 = [P0++]; /* move data */
516 [P0 - 8] = R0; 523 [P0 - 8] = R0;
517 R0 = [P0-0x104] /* move address */ 524 R0 = [P0-0x104] /* move address */
518.Lde_move: [P0-0x108] = R0; 525.Lde_move:
526 [P0-0x108] = R0;
527
528.Lde_moved:
529 NOP;
530
531 /* Clear DCPLB_DATA15, in case we don't find a replacement
532 * otherwise, we would have a duplicate entry, and will crash
533 */
534 R0 = 0;
535 [P0 - 0x4] = R0;
519 536
520 /* We've now made space in DCPLB15 for the new CPLB to be 537 /* We've now made space in DCPLB15 for the new CPLB to be
521 * installed. The next stage is to locate a CPLB in the 538 * installed. The next stage is to locate a CPLB in the
522 * config table that covers the faulting address. 539 * config table that covers the faulting address.
523 */ 540 */
524 541
525.Lde_moved:NOP;
526 R0 = I0; /* Our faulting address */ 542 R0 = I0; /* Our faulting address */
527 543
528 P2.L = _dpdt_table; 544 P2.L = _dpdt_table;
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index 4de376418a18..f983ac7ea352 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -34,9 +34,13 @@
34#include <asm/entry.h> 34#include <asm/entry.h>
35#include <asm/asm-offsets.h> 35#include <asm/asm-offsets.h>
36#include <asm/trace.h> 36#include <asm/trace.h>
37#include <asm/traps.h>
38#include <asm/thread_info.h>
37 39
38#include <asm/mach-common/context.S> 40#include <asm/mach-common/context.S>
39 41
42.extern _ret_from_exception
43
40#ifdef CONFIG_I_ENTRY_L1 44#ifdef CONFIG_I_ENTRY_L1
41.section .l1.text 45.section .l1.text
42#else 46#else
@@ -134,10 +138,11 @@ __common_int_entry:
134 138
135/* interrupt routine for ivhw - 5 */ 139/* interrupt routine for ivhw - 5 */
136ENTRY(_evt_ivhw) 140ENTRY(_evt_ivhw)
137 SAVE_CONTEXT 141 SAVE_ALL_SYS
138#ifdef CONFIG_FRAME_POINTER 142#ifdef CONFIG_FRAME_POINTER
139 fp = 0; 143 fp = 0;
140#endif 144#endif
145
141#if ANOMALY_05000283 146#if ANOMALY_05000283
142 cc = r7 == r7; 147 cc = r7 == r7;
143 p5.h = 0xffc0; 148 p5.h = 0xffc0;
@@ -147,13 +152,8 @@ ENTRY(_evt_ivhw)
1471: 1521:
148#endif 153#endif
149 154
150 trace_buffer_stop(p0, r0);
151
152 r0 = IRQ_HWERR;
153 r1 = sp;
154
155#ifdef CONFIG_HARDWARE_PM 155#ifdef CONFIG_HARDWARE_PM
156 r7 = SEQSTAT; 156 r7 = [sp + PT_SEQSTAT];
157 r7 = r7 >>> 0xe; 157 r7 = r7 >>> 0xe;
158 r6 = 0x1F; 158 r6 = 0x1F;
159 r7 = r7 & r6; 159 r7 = r7 & r6;
@@ -161,11 +161,29 @@ ENTRY(_evt_ivhw)
161 cc = r7 == r5; 161 cc = r7 == r5;
162 if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */ 162 if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */
163#endif 163#endif
164 164 # We are going to dump something out, so make sure we print IPEND properly
165 p2.l = lo(IPEND);
166 p2.h = hi(IPEND);
167 r0 = [p2];
168 [sp + PT_IPEND] = r0;
169
170 /* set the EXCAUSE to HWERR for trap_c */
171 r0 = [sp + PT_SEQSTAT];
172 R1.L = LO(VEC_HWERR);
173 R1.H = HI(VEC_HWERR);
174 R0 = R0 | R1;
175 [sp + PT_SEQSTAT] = R0;
176
177 r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
165 SP += -12; 178 SP += -12;
166 call _irq_panic; 179 call _trap_c;
167 SP += 12; 180 SP += 12;
181
182 call _ret_from_exception;
183.Lcommon_restore_all_sys:
184 RESTORE_ALL_SYS
168 rti; 185 rti;
186
169#ifdef CONFIG_HARDWARE_PM 187#ifdef CONFIG_HARDWARE_PM
170.Lcall_do_ovf: 188.Lcall_do_ovf:
171 189
@@ -173,9 +191,11 @@ ENTRY(_evt_ivhw)
173 call _pm_overflow; 191 call _pm_overflow;
174 SP += 12; 192 SP += 12;
175 193
176 jump .Lcommon_restore_context; 194 jump .Lcommon_restore_all_sys;
177#endif 195#endif
178 196
197ENDPROC(_evt_ivhw)
198
179/* Interrupt routine for evt2 (NMI). 199/* Interrupt routine for evt2 (NMI).
180 * We don't actually use this, so just return. 200 * We don't actually use this, so just return.
181 * For inner circle type details, please see: 201 * For inner circle type details, please see:
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
index b22959b197e5..606ded9ff4e1 100644
--- a/arch/blackfin/mach-common/irqpanic.c
+++ b/arch/blackfin/mach-common/irqpanic.c
@@ -46,9 +46,6 @@ void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text));
46 */ 46 */
47asmlinkage void irq_panic(int reason, struct pt_regs *regs) 47asmlinkage void irq_panic(int reason, struct pt_regs *regs)
48{ 48{
49 int sig = 0;
50 siginfo_t info;
51
52#ifdef CONFIG_DEBUG_ICACHE_CHECK 49#ifdef CONFIG_DEBUG_ICACHE_CHECK
53 unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa; 50 unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
54 unsigned short i, j, die; 51 unsigned short i, j, die;
@@ -136,53 +133,6 @@ asmlinkage void irq_panic(int reason, struct pt_regs *regs)
136 } 133 }
137#endif 134#endif
138 135
139 printk(KERN_EMERG "\n");
140 printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason);
141 printk(KERN_EMERG " code=[0x%08lx], stack frame=0x%08lx, "
142 " bad PC=0x%08lx\n",
143 (unsigned long)regs->seqstat,
144 (unsigned long)regs,
145 (unsigned long)regs->pc);
146 if (reason == 0x5) {
147 printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n");
148
149 /* There is only need to check for Hardware Errors, since other
150 * EXCEPTIONS are handled in TRAPS.c (MH)
151 */
152 switch (regs->seqstat & SEQSTAT_HWERRCAUSE) {
153 case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): /* System MMR Error */
154 info.si_code = BUS_ADRALN;
155 sig = SIGBUS;
156 printk(KERN_EMERG HWC_x2(KERN_EMERG));
157 break;
158 case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): /* External Memory Addressing Error */
159 info.si_code = BUS_ADRERR;
160 sig = SIGBUS;
161 printk(KERN_EMERG HWC_x3(KERN_EMERG));
162 break;
163 case (SEQSTAT_HWERRCAUSE_PERF_FLOW): /* Performance Monitor Overflow */
164 printk(KERN_EMERG HWC_x12(KERN_EMERG));
165 break;
166 case (SEQSTAT_HWERRCAUSE_RAISE_5): /* RAISE 5 instruction */
167 printk(KERN_EMERG HWC_x18(KERN_EMERG));
168 break;
169 default: /* Reserved */
170 printk(KERN_EMERG HWC_default(KERN_EMERG));
171 break;
172 }
173 }
174
175 regs->ipend = bfin_read_IPEND();
176 dump_bfin_process(regs);
177 dump_bfin_mem((void *)regs->pc);
178 show_regs(regs);
179 if (0 == (info.si_signo = sig) || 0 == user_mode(regs)) /* in kernelspace */
180 panic("Unhandled IRQ or exceptions!\n");
181 else { /* in userspace */
182 info.si_errno = 0;
183 info.si_addr = (void *)regs->pc;
184 force_sig_info(sig, &info, current);
185 }
186} 136}
187 137
188#ifdef CONFIG_HARDWARE_PM 138#ifdef CONFIG_HARDWARE_PM