patch-2.4.25 linux-2.4.25/arch/mips/mm/cex-sb1.S
Next file: linux-2.4.25/arch/mips/mm/init.c
Previous file: linux-2.4.25/arch/mips/mm/cerr-sb1.c
Back to the patch index
Back to the overall index
- Lines: 169
- Date:
2004-02-18 05:36:30.000000000 -0800
- Orig file:
linux-2.4.24/arch/mips/mm/cex-sb1.S
- Orig date:
2003-08-25 04:44:40.000000000 -0700
diff -urN linux-2.4.24/arch/mips/mm/cex-sb1.S linux-2.4.25/arch/mips/mm/cex-sb1.S
@@ -22,40 +22,122 @@
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
+#include <asm/cacheops.h>
+#include <asm/processor.h>
#include <asm/sibyte/board.h>
- .text
- .set noat
- .set mips4
+#define C0_ERRCTL $26 /* CP0: Error info */
+#define C0_CERR_I $27 /* CP0: Icache error */
+#define C0_CERR_D $27,1 /* CP0: Dcache error */
+
+ /*
+ * Based on SiByte sample software cache-err/cerr.S
+ * CVS revision 1.8. Only the 'unrecoverable' case
+ * is changed.
+ */
__INIT
-
- /* Cache Error handler for SB1 */
- LEAF(except_vec2_sb1)
- mfc0 k1, $26
- # check if error was recoverable
- bltz k1, leave_cerr
-#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
- # look for signature of spurious CErr
- lui k0, 0x4000
- bne k0, k1, 1f
- .word 0x401Bd801 # mfc0 k1, $27, 1
- lui k0, 0xffe0
- and k1, k0, k1
- lui k0, 0x0200
- beq k0, k1, leave_cerr
-1:
-#endif
- j handle_vec2_sb1
-leave_cerr:
- # clear/unlock the registers
- mtc0 zero, $26
- mtc0 zero, $27
- .word 0x4080d801 # mtc0 zero, $27, 1
- .word 0x4080d803 # mtc0 zero, $27, 3
+ .set mips64
+ .set noreorder
+ .set noat
+
+ /*
+ * sb1_cerr_vec: code to be copied to the Cache Error
+ * Exception vector. The code must be pushed out to memory
+ * (either by copying to Kseg0 and Kseg1 both, or by flushing
+ * the L1 and L2) since it is fetched as 0xa0000100.
+ *
+ * NOTE: Be sure this handler is at most 28 instructions long
+ * since the final 16 bytes of the exception vector memory
+ * (0x170-0x17f) are used to preserve k0, k1, and ra.
+ */
+
+LEAF(except_vec2_sb1)
+ /*
+ * If this error is recoverable, we need to exit the handler
+ * without having dirtied any registers. To do this,
+ * save/restore k0 and k1 from low memory (Useg is direct
+ * mapped while ERL=1). Note that we can't save to a
+ * CPU-specific location without ruining a register in the
+ * process. This means we are vulnerable to data corruption
+ * whenever the handler is reentered by a second CPU.
+ */
+ sd k0,0x170($0)
+ sd k1,0x178($0)
+
+ /*
+ * M_ERRCTL_RECOVERABLE is bit 31, which makes it easy to tell
+ * if we can fast-path out of here for a h/w-recovered error.
+ */
+ mfc0 k1,C0_ERRCTL
+ bgtz k1,attempt_recovery
+ sll k0,k1,1
+
+recovered_dcache:
+ /*
+ * Unlock CacheErr-D (which in turn unlocks CacheErr-DPA).
+ * Ought to log the occurence of this recovered dcache error.
+ */
+ b recovered
+ .word 0x4080d801 # mtc0 zero, $27, 1
+
+attempt_recovery:
+ /*
+ * k0 has C0_ERRCTL << 1, which puts 'DC' at bit 31. Any
+ * Dcache errors we can recover from will take more extensive
+ * processing. For now, they are considered "unrecoverable".
+ * Note that 'DC' becoming set (outside of ERL mode) will
+ * cause 'IC' to clear; so if there's an Icache error, we'll
+ * only find out about it if we recover from this error and
+ * continue executing.
+ */
+ bltz k0,unrecoverable
+ sll k0,1
+
+ /*
+ * k0 has C0_ERRCTL << 2, which puts 'IC' at bit 31. If an
+ * Icache error isn't indicated, I'm not sure why we got here.
+ * Consider that case "unrecoverable" for now.
+ */
+ bgez k0,unrecoverable
+
+attempt_icache_recovery:
+ /*
+ * External icache errors are due to uncorrectable ECC errors
+ * in the L2 cache or Memory Controller and cannot be
+ * recovered here.
+ */
+ mfc0 k0,C0_CERR_I /* delay slot */
+ li k1,1 << 26 /* ICACHE_EXTERNAL */
+ and k1,k0
+ bnez k1,unrecoverable
+ andi k0,0x1fe0
+
+ /*
+ * Since the error is internal, the 'IDX' field from
+ * CacheErr-I is valid and we can just invalidate all blocks
+ * in that set.
+ */
+ cache Index_Invalidate_I,(0<<13)(k0)
+ cache Index_Invalidate_I,(1<<13)(k0)
+ cache Index_Invalidate_I,(2<<13)(k0)
+ cache Index_Invalidate_I,(3<<13)(k0)
+
+ /* Ought to log this recovered icache error */
+
+recovered:
+ /* Restore the saved registers */
+ ld k0,0x170($0)
+ ld k1,0x178($0)
eret
- END(except_vec2_sb1)
+
+unrecoverable:
+ /* Unrecoverable Icache or Dcache error; log it and/or fail */
+ j handle_vec2_sb1
+ nop
+
+END(except_vec2_sb1)
__FINIT
@@ -75,9 +157,16 @@
mfc0 k0, CP0_STATUS
sll k0, k0, 3 # check CU0 (kernel?)
bltz k0, 2f
+ nop
+
+ /* Get a valid Kseg0 stack pointer. Any task's stack pointer
+ * will do, although if we ever want to resume execution we
+ * better not have corrupted any state. */
GET_SAVED_SP
- move sp, k0 # want Kseg SP (so uncached)
+ move sp, k1
+
2:
j sb1_cache_error
+ nop
END(handle_vec2_sb1)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)