aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/mach-common/entry.S
diff options
context:
space:
mode:
authorRobin Getz <robin.getz@analog.com>2009-05-18 14:33:26 -0400
committerMike Frysinger <vapier@gentoo.org>2009-06-12 06:11:44 -0400
commitb9a3899d59c3f0fc074573f0eba2419b1e4c0bca (patch)
tree09d20c3b062604d615c9d224c06c5df5a5acbcec /arch/blackfin/mach-common/entry.S
parent97b070c8e7e82be30c8a3bf19e69b8c0c71f1fac (diff)
Blackfin: make deferred hardware errors more exact
Hardware errors on the Blackfin architecture are queued by nature of the hardware design. Things that could generate a hardware level queue up at the system interface and might not process until much later, at which point the system would send a notification back to the core. As such, it is possible for user space code to do something that would trigger a hardware error, but have it delay long enough for the process context to switch. So when the hardware error does signal, we mistakenly evaluate it as a different process or as kernel context and panic (erp!). This makes it pretty difficult to find the offending context. But wait, there is good news somewhere. By forcing a SSYNC in the interrupt entry, we force all pending queues at the system level to be processed and all hardware errors to be signaled. Then we check the current interrupt state to see if the hardware error is now signaled. If so, we re-queue the current interrupt and return thus allowing the higher priority hardware error interrupt to process properly. Since we haven't done any other context processing yet, the right context will be selected and killed. There is still the possibility that the exact offending instruction will be unknown, but at least we'll have a much better idea of where to look. The downside of course is that this causes system-wide syncs at every interrupt point which results in significant performance degradation. Since this situation should not occur in any properly configured system (as hardware errors are triggered by things like bad pointers), make it a debug configuration option and disable it by default. Signed-off-by: Robin Getz <robin.getz@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin/mach-common/entry.S')
-rw-r--r--arch/blackfin/mach-common/entry.S59
1 files changed, 41 insertions, 18 deletions
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index f0636fdcb353..da0558ad1b1a 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -200,7 +200,18 @@ ENTRY(_ex_single_step)
200 cc = r7 == 0; 200 cc = r7 == 0;
201 if !cc jump 1f; 201 if !cc jump 1f;
202#endif 202#endif
203 203#ifdef CONFIG_EXACT_HWERR
204 /* Read the ILAT, and to check to see if the process we are
205 * single stepping caused a previous hardware error
206 * If so, do not single step, (which lowers to IRQ5, and makes
207 * us miss the error).
208 */
209 p5.l = lo(ILAT);
210 p5.h = hi(ILAT);
211 r7 = [p5];
212 cc = bittst(r7, EVT_IVHW_P);
213 if cc jump 1f;
214#endif
204 /* Single stepping only a single instruction, so clear the trace 215 /* Single stepping only a single instruction, so clear the trace
205 * bit here. */ 216 * bit here. */
206 r7 = syscfg; 217 r7 = syscfg;
@@ -262,15 +273,6 @@ ENTRY(_bfin_return_from_exception)
262 r6 = 0x25; 273 r6 = 0x25;
263 CC = R7 == R6; 274 CC = R7 == R6;
264 if CC JUMP _double_fault; 275 if CC JUMP _double_fault;
265
266 /* Did we cause a HW error? */
267 p5.l = lo(ILAT);
268 p5.h = hi(ILAT);
269 r6 = [p5];
270 r7 = 0x20; /* Did I just cause anther HW error? */
271 r6 = r7 & r6;
272 CC = R7 == R6;
273 if CC JUMP _double_fault;
274#endif 276#endif
275 277
276 (R7:6,P5:4) = [sp++]; 278 (R7:6,P5:4) = [sp++];
@@ -472,6 +474,16 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
472 [--sp] = ASTAT; 474 [--sp] = ASTAT;
473 [--sp] = (R7:6,P5:4); 475 [--sp] = (R7:6,P5:4);
474 476
477#ifdef CONFIG_EXACT_HWERR
478 /* Make sure all pending read/writes complete. This will ensure any
479 * accesses which could cause hardware errors completes, and signal
480 * the the hardware before we do something silly, like crash the
481 * kernel. We don't need to work around anomaly 05000312, since
482 * we are already atomic
483 */
484 ssync;
485#endif
486
475#if ANOMALY_05000283 || ANOMALY_05000315 487#if ANOMALY_05000283 || ANOMALY_05000315
476 cc = r7 == r7; 488 cc = r7 == r7;
477 p5.h = HI(CHIPID); 489 p5.h = HI(CHIPID);
@@ -854,7 +866,7 @@ ENTRY(_ret_from_exception)
854 p1.h = _schedule_and_signal; 866 p1.h = _schedule_and_signal;
855 [p0] = p1; 867 [p0] = p1;
856 csync; 868 csync;
857 raise 15; /* raise evt14 to do signal or reschedule */ 869 raise 15; /* raise evt15 to do signal or reschedule */
8584: 8704:
859 r0 = syscfg; 871 r0 = syscfg;
860 bitclr(r0, 0); 872 bitclr(r0, 0);
@@ -915,7 +927,7 @@ ENTRY(_return_from_int)
915 p1.h = _schedule_and_signal_from_int; 927 p1.h = _schedule_and_signal_from_int;
916 [p0] = p1; 928 [p0] = p1;
917 csync; 929 csync;
918#if ANOMALY_05000281 930#if ANOMALY_05000281 || ANOMALY_05000461
919 r0.l = lo(SAFE_USER_INSTRUCTION); 931 r0.l = lo(SAFE_USER_INSTRUCTION);
920 r0.h = hi(SAFE_USER_INSTRUCTION); 932 r0.h = hi(SAFE_USER_INSTRUCTION);
921 reti = r0; 933 reti = r0;
@@ -929,18 +941,27 @@ ENTRY(_return_from_int)
929ENDPROC(_return_from_int) 941ENDPROC(_return_from_int)
930 942
931ENTRY(_lower_to_irq14) 943ENTRY(_lower_to_irq14)
932#if ANOMALY_05000281 944#if ANOMALY_05000281 || ANOMALY_05000461
933 r0.l = lo(SAFE_USER_INSTRUCTION); 945 r0.l = lo(SAFE_USER_INSTRUCTION);
934 r0.h = hi(SAFE_USER_INSTRUCTION); 946 r0.h = hi(SAFE_USER_INSTRUCTION);
935 reti = r0; 947 reti = r0;
936#endif 948#endif
937 r0 = 0x401f; 949
950#ifdef CONFIG_DEBUG_HWERR
951 /* enable irq14 & hwerr interrupt, until we transition to _evt14_softirq */
952 r0 = (EVT_IVG14 | EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
953#else
954 /* Only enable irq14 interrupt, until we transition to _evt14_softirq */
955 r0 = (EVT_IVG14 | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
956#endif
938 sti r0; 957 sti r0;
939 raise 14; 958 raise 14;
940 rti; 959 rti;
960ENDPROC(_lower_to_irq14)
961
941ENTRY(_evt14_softirq) 962ENTRY(_evt14_softirq)
942#ifdef CONFIG_DEBUG_HWERR 963#ifdef CONFIG_DEBUG_HWERR
943 r0 = 0x3f; 964 r0 = (EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
944 sti r0; 965 sti r0;
945#else 966#else
946 cli r0; 967 cli r0;
@@ -948,8 +969,9 @@ ENTRY(_evt14_softirq)
948 [--sp] = RETI; 969 [--sp] = RETI;
949 SP += 4; 970 SP += 4;
950 rts; 971 rts;
972ENDPROC(_evt14_softirq)
951 973
952_schedule_and_signal_from_int: 974ENTRY(_schedule_and_signal_from_int)
953 /* To end up here, vector 15 was changed - so we have to change it 975 /* To end up here, vector 15 was changed - so we have to change it
954 * back. 976 * back.
955 */ 977 */
@@ -982,8 +1004,9 @@ _schedule_and_signal_from_int:
982 call _finish_atomic_sections; 1004 call _finish_atomic_sections;
983 sp += 12; 1005 sp += 12;
984 jump.s .Lresume_userspace; 1006 jump.s .Lresume_userspace;
1007ENDPROC(_schedule_and_signal_from_int)
985 1008
986_schedule_and_signal: 1009ENTRY(_schedule_and_signal)
987 SAVE_CONTEXT_SYSCALL 1010 SAVE_CONTEXT_SYSCALL
988 /* To end up here, vector 15 was changed - so we have to change it 1011 /* To end up here, vector 15 was changed - so we have to change it
989 * back. 1012 * back.
@@ -1001,7 +1024,7 @@ _schedule_and_signal:
10011: 10241:
1002 RESTORE_CONTEXT 1025 RESTORE_CONTEXT
1003 rti; 1026 rti;
1004ENDPROC(_lower_to_irq14) 1027ENDPROC(_schedule_and_signal)
1005 1028
1006/* We handle this 100% in exception space - to reduce overhead 1029/* We handle this 100% in exception space - to reduce overhead
1007 * Only potiential problem is if the software buffer gets swapped out of the 1030 * Only potiential problem is if the software buffer gets swapped out of the