Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 148567
b: refs/heads/master
c: b9a3899
h: refs/heads/master
i:
  148565: af516fd
  148563: 7e771ff
  148559: b0ee20e
v: v3
  • Loading branch information
Robin Getz authored and Mike Frysinger committed Jun 12, 2009
1 parent b29fd46 commit 77051d3
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 97b070c8e7e82be30c8a3bf19e69b8c0c71f1fac
refs/heads/master: b9a3899d59c3f0fc074573f0eba2419b1e4c0bca
13 changes: 13 additions & 0 deletions trunk/arch/blackfin/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,19 @@ config DEBUG_HWERR
hardware error interrupts and need to know where they are coming
from.

config EXACT_HWERR
bool "Try to make Hardware errors exact"
depends on DEBUG_HWERR
help
By default, the Blackfin hardware errors are not exact - the error
be reported multiple cycles after the error happens. This delay
can cause the wrong application, or even the kernel to receive a
signal to be killed. If you are getting HW errors in your system,
try turning this on to ensure they are at least comming from the
proper thread.

On production systems, it is safe (and a small optimization) to say N.

config DEBUG_DOUBLEFAULT
bool "Debug Double Faults"
default n
Expand Down
92 changes: 89 additions & 3 deletions trunk/arch/blackfin/include/asm/entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,39 @@
#else
# define LOAD_IPIPE_IPEND
#endif

#ifndef CONFIG_EXACT_HWERR
/* As a debugging aid - we save IPEND when DEBUG_KERNEL is on,
* otherwise it is a waste of cycles.
*/
# ifndef CONFIG_DEBUG_KERNEL
#define INTERRUPT_ENTRY(N) \
[--sp] = SYSCFG; \
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
R0 = (N); \
LOAD_IPIPE_IPEND \
jump __common_int_entry;
# else /* CONFIG_DEBUG_KERNEL */
#define INTERRUPT_ENTRY(N) \
[--sp] = SYSCFG; \
\
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
p0.l = lo(IPEND); \
p0.h = hi(IPEND); \
r1 = [p0]; \
R0 = (N); \
LOAD_IPIPE_IPEND \
jump __common_int_entry;
# endif /* CONFIG_DEBUG_KERNEL */

/* For timer interrupts, we need to save IPEND, since the user_mode
macro accesses it to determine where to account time. */
*macro accesses it to determine where to account time.
*/
#define TIMER_INTERRUPT_ENTRY(N) \
[--sp] = SYSCFG; \
\
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
Expand All @@ -58,6 +76,74 @@
r1 = [p0]; \
R0 = (N); \
jump __common_int_entry;
#else /* CONFIG_EXACT_HWERR is defined */

/* if we want hardware error to be exact, we need to do a SSYNC (which forces
* read/writes to complete to the memory controllers), and check to see that
* caused a pending HW error condition. If so, we assume it was caused by user
* space, by setting the same interrupt that we are in (so it goes off again)
* and context restore, and a RTI (without servicing anything). This should
* cause the pending HWERR to fire, and when that is done, this interrupt will
* be re-serviced properly.
* As you can see by the code - we actually need to do two SSYNCS - one to
* make sure the read/writes complete, and another to make sure the hardware
* error is recognized by the core.
*/
#define INTERRUPT_ENTRY(N) \
SSYNC; \
SSYNC; \
[--sp] = SYSCFG; \
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
R1 = ASTAT; \
P0.L = LO(ILAT); \
P0.H = HI(ILAT); \
R0 = [P0]; \
CC = BITTST(R0, EVT_IVHW_P); \
IF CC JUMP 1f; \
ASTAT = R1; \
p0.l = lo(IPEND); \
p0.h = hi(IPEND); \
r1 = [p0]; \
R0 = (N); \
LOAD_IPIPE_IPEND \
jump __common_int_entry; \
1: ASTAT = R1; \
RAISE N; \
(R7:0, P5:0) = [SP++]; \
SP += 0x8; \
SYSCFG = [SP++]; \
CSYNC; \
RTI;

#define TIMER_INTERRUPT_ENTRY(N) \
SSYNC; \
SSYNC; \
[--sp] = SYSCFG; \
[--sp] = P0; /*orig_p0*/ \
[--sp] = R0; /*orig_r0*/ \
[--sp] = (R7:0,P5:0); \
R1 = ASTAT; \
P0.L = LO(ILAT); \
P0.H = HI(ILAT); \
R0 = [P0]; \
CC = BITTST(R0, EVT_IVHW_P); \
IF CC JUMP 1f; \
ASTAT = R1; \
p0.l = lo(IPEND); \
p0.h = hi(IPEND); \
r1 = [p0]; \
R0 = (N); \
jump __common_int_entry; \
1: ASTAT = R1; \
RAISE N; \
(R7:0, P5:0) = [SP++]; \
SP += 0x8; \
SYSCFG = [SP++]; \
CSYNC; \
RTI;
#endif /* CONFIG_EXACT_HWERR */

/* This one pushes RETI without using CLI. Interrupts are enabled. */
#define SAVE_CONTEXT_SYSCALL save_context_syscall
Expand Down
59 changes: 41 additions & 18 deletions trunk/arch/blackfin/mach-common/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,18 @@ ENTRY(_ex_single_step)
cc = r7 == 0;
if !cc jump 1f;
#endif

#ifdef CONFIG_EXACT_HWERR
/* Read the ILAT, and to check to see if the process we are
* single stepping caused a previous hardware error
* If so, do not single step, (which lowers to IRQ5, and makes
* us miss the error).
*/
p5.l = lo(ILAT);
p5.h = hi(ILAT);
r7 = [p5];
cc = bittst(r7, EVT_IVHW_P);
if cc jump 1f;
#endif
/* Single stepping only a single instruction, so clear the trace
* bit here. */
r7 = syscfg;
Expand Down Expand Up @@ -262,15 +273,6 @@ ENTRY(_bfin_return_from_exception)
r6 = 0x25;
CC = R7 == R6;
if CC JUMP _double_fault;

/* Did we cause a HW error? */
p5.l = lo(ILAT);
p5.h = hi(ILAT);
r6 = [p5];
r7 = 0x20; /* Did I just cause anther HW error? */
r6 = r7 & r6;
CC = R7 == R6;
if CC JUMP _double_fault;
#endif

(R7:6,P5:4) = [sp++];
Expand Down Expand Up @@ -472,6 +474,16 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
[--sp] = ASTAT;
[--sp] = (R7:6,P5:4);

#ifdef CONFIG_EXACT_HWERR
/* Make sure all pending read/writes complete. This will ensure any
* accesses which could cause hardware errors completes, and signal
* the the hardware before we do something silly, like crash the
* kernel. We don't need to work around anomaly 05000312, since
* we are already atomic
*/
ssync;
#endif

#if ANOMALY_05000283 || ANOMALY_05000315
cc = r7 == r7;
p5.h = HI(CHIPID);
Expand Down Expand Up @@ -854,7 +866,7 @@ ENTRY(_ret_from_exception)
p1.h = _schedule_and_signal;
[p0] = p1;
csync;
raise 15; /* raise evt14 to do signal or reschedule */
raise 15; /* raise evt15 to do signal or reschedule */
4:
r0 = syscfg;
bitclr(r0, 0);
Expand Down Expand Up @@ -915,7 +927,7 @@ ENTRY(_return_from_int)
p1.h = _schedule_and_signal_from_int;
[p0] = p1;
csync;
#if ANOMALY_05000281
#if ANOMALY_05000281 || ANOMALY_05000461
r0.l = lo(SAFE_USER_INSTRUCTION);
r0.h = hi(SAFE_USER_INSTRUCTION);
reti = r0;
Expand All @@ -929,27 +941,37 @@ ENTRY(_return_from_int)
ENDPROC(_return_from_int)

ENTRY(_lower_to_irq14)
#if ANOMALY_05000281
#if ANOMALY_05000281 || ANOMALY_05000461
r0.l = lo(SAFE_USER_INSTRUCTION);
r0.h = hi(SAFE_USER_INSTRUCTION);
reti = r0;
#endif
r0 = 0x401f;

#ifdef CONFIG_DEBUG_HWERR
/* enable irq14 & hwerr interrupt, until we transition to _evt14_softirq */
r0 = (EVT_IVG14 | EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
#else
/* Only enable irq14 interrupt, until we transition to _evt14_softirq */
r0 = (EVT_IVG14 | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
#endif
sti r0;
raise 14;
rti;
ENDPROC(_lower_to_irq14)

ENTRY(_evt14_softirq)
#ifdef CONFIG_DEBUG_HWERR
r0 = 0x3f;
r0 = (EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
sti r0;
#else
cli r0;
#endif
[--sp] = RETI;
SP += 4;
rts;
ENDPROC(_evt14_softirq)

_schedule_and_signal_from_int:
ENTRY(_schedule_and_signal_from_int)
/* To end up here, vector 15 was changed - so we have to change it
* back.
*/
Expand Down Expand Up @@ -982,8 +1004,9 @@ _schedule_and_signal_from_int:
call _finish_atomic_sections;
sp += 12;
jump.s .Lresume_userspace;
ENDPROC(_schedule_and_signal_from_int)

_schedule_and_signal:
ENTRY(_schedule_and_signal)
SAVE_CONTEXT_SYSCALL
/* To end up here, vector 15 was changed - so we have to change it
* back.
Expand All @@ -1001,7 +1024,7 @@ _schedule_and_signal:
1:
RESTORE_CONTEXT
rti;
ENDPROC(_lower_to_irq14)
ENDPROC(_schedule_and_signal)

/* We handle this 100% in exception space - to reduce overhead
* Only potiential problem is if the software buffer gets swapped out of the
Expand Down
27 changes: 27 additions & 0 deletions trunk/arch/blackfin/mach-common/interrupt.S
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ __common_int_entry:

/* interrupt routine for ivhw - 5 */
ENTRY(_evt_ivhw)
/* In case a single action kicks off multiple memory transactions, (like
* a cache line fetch, - this can cause multiple hardware errors, let's
* catch them all. First - make sure all the actions are complete, and
* the core sees the hardware errors.
*/
SSYNC;
SSYNC;

SAVE_ALL_SYS
#ifdef CONFIG_FRAME_POINTER
fp = 0;
Expand All @@ -159,6 +167,25 @@ ENTRY(_evt_ivhw)
1:
#endif

/* Handle all stacked hardware errors
* To make sure we don't hang forever, only do it 10 times
*/
R0 = 0;
R2 = 10;
1:
P0.L = LO(ILAT);
P0.H = HI(ILAT);
R1 = [P0];
CC = BITTST(R1, EVT_IVHW_P);
IF ! CC JUMP 2f;
/* OK a hardware error is pending - clear it */
R1 = EVT_IVHW_P;
[P0] = R1;
R0 += 1;
CC = R1 == R2;
if CC JUMP 2f;
JUMP 1b;
2:
# We are going to dump something out, so make sure we print IPEND properly
p2.l = lo(IPEND);
p2.h = hi(IPEND);
Expand Down

0 comments on commit 77051d3

Please sign in to comment.