diff options
author | Robin Getz <robin.getz@analog.com> | 2008-01-27 02:38:56 -0500 |
---|---|---|
committer | Bryan Wu <bryan.wu@analog.com> | 2008-01-27 02:38:56 -0500 |
commit | 13fe24f37df20e580a5a364e67ec8cf3219d8f8c (patch) | |
tree | c790da8a840c6fdc3e6f5eacccadede92e329d7c /arch/blackfin/kernel/traps.c | |
parent | f53e86760e10abbe7ee98a5b3cb270fa6426fcdb (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/kernel/traps.c')
-rw-r--r-- | arch/blackfin/kernel/traps.c | 54 |
1 files changed, 46 insertions, 8 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()); |