Modified: trunk/arch/blackfin/include/asm/entry.h (6534 => 6535)
--- trunk/arch/blackfin/include/asm/entry.h 2009-06-02 10:43:39 UTC (rev 6534)
+++ trunk/arch/blackfin/include/asm/entry.h 2009-06-02 13:45:28 UTC (rev 6535)
@@ -37,6 +37,10 @@
#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*/ \
@@ -45,6 +49,19 @@
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.
@@ -67,9 +84,14 @@
* 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.
+ * 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*/ \
@@ -77,11 +99,13 @@
R1 = ASTAT; \
P0.L = LO(ILAT); \
P0.H = HI(ILAT); \
- SSYNC; \
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; \
@@ -90,9 +114,12 @@
(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*/ \
@@ -100,7 +127,6 @@
R1 = ASTAT; \
P0.L = LO(ILAT); \
P0.H = HI(ILAT); \
- SSYNC; \
R0 = [P0]; \
CC = BITTST(R0, EVT_IVHW_P); \
IF CC JUMP 1f; \
@@ -115,6 +141,7 @@
(R7:0, P5:0) = [SP++]; \
SP += 0x8; \
SYSCFG = [SP++]; \
+ CSYNC; \
RTI;
#endif /* CONFIG_EXACT_HWERR */
Modified: trunk/arch/blackfin/mach-common/interrupt.S (6534 => 6535)
--- trunk/arch/blackfin/mach-common/interrupt.S 2009-06-02 10:43:39 UTC (rev 6534)
+++ trunk/arch/blackfin/mach-common/interrupt.S 2009-06-02 13:45:28 UTC (rev 6535)
@@ -145,6 +145,14 @@
/* 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;
@@ -159,6 +167,25 @@
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);