Merge tag 'reset-for-v5.3' of git://git.pengutronix.de/git/pza/linux into arm/drivers
[sfrench/cifs-2.6.git] / arch / mips / mm / cex-sb1.S
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Copyright (C) 2001,2002,2003 Broadcom Corporation
4  */
5
6 #include <asm/asm.h>
7 #include <asm/regdef.h>
8 #include <asm/mipsregs.h>
9 #include <asm/stackframe.h>
10 #include <asm/cacheops.h>
11 #include <asm/sibyte/board.h>
12
13 #define C0_ERRCTL     $26             /* CP0: Error info */
14 #define C0_CERR_I     $27             /* CP0: Icache error */
15 #define C0_CERR_D     $27,1           /* CP0: Dcache error */
16
17         /*
18          * Based on SiByte sample software cache-err/cerr.S
19          * CVS revision 1.8.  Only the 'unrecoverable' case
20          * is changed.
21          */
22
23         .set    mips64
24         .set    noreorder
25         .set    noat
26
27         /*
28          * sb1_cerr_vec: code to be copied to the Cache Error
29          * Exception vector.  The code must be pushed out to memory
30          * (either by copying to Kseg0 and Kseg1 both, or by flushing
31          * the L1 and L2) since it is fetched as 0xa0000100.
32          *
33          * NOTE: Be sure this handler is at most 28 instructions long
34          * since the final 16 bytes of the exception vector memory
35          * (0x170-0x17f) are used to preserve k0, k1, and ra.
36          */
37
38 LEAF(except_vec2_sb1)
39         /*
40          * If this error is recoverable, we need to exit the handler
41          * without having dirtied any registers.  To do this,
42          * save/restore k0 and k1 from low memory (Useg is direct
43          * mapped while ERL=1). Note that we can't save to a
44          * CPU-specific location without ruining a register in the
45          * process.  This means we are vulnerable to data corruption
46          * whenever the handler is reentered by a second CPU.
47          */
48         sd      k0,0x170($0)
49         sd      k1,0x178($0)
50
51 #ifdef CONFIG_SB1_CEX_ALWAYS_FATAL
52         j       handle_vec2_sb1
53          nop
54 #else
55         /*
56          * M_ERRCTL_RECOVERABLE is bit 31, which makes it easy to tell
57          * if we can fast-path out of here for a h/w-recovered error.
58          */
59         mfc0    k1,C0_ERRCTL
60         bgtz    k1,attempt_recovery
61          sll    k0,k1,1
62
63 recovered_dcache:
64         /*
65          * Unlock CacheErr-D (which in turn unlocks CacheErr-DPA).
66          * Ought to log the occurrence of this recovered dcache error.
67          */
68         b       recovered
69          mtc0   $0,C0_CERR_D
70
71 attempt_recovery:
72         /*
73          * k0 has C0_ERRCTL << 1, which puts 'DC' at bit 31.  Any
74          * Dcache errors we can recover from will take more extensive
75          * processing.  For now, they are considered "unrecoverable".
76          * Note that 'DC' becoming set (outside of ERL mode) will
77          * cause 'IC' to clear; so if there's an Icache error, we'll
78          * only find out about it if we recover from this error and
79          * continue executing.
80          */
81         bltz    k0,unrecoverable
82          sll    k0,1
83
84         /*
85          * k0 has C0_ERRCTL << 2, which puts 'IC' at bit 31.  If an
86          * Icache error isn't indicated, I'm not sure why we got here.
87          * Consider that case "unrecoverable" for now.
88          */
89         bgez    k0,unrecoverable
90
91 attempt_icache_recovery:
92         /*
93          * External icache errors are due to uncorrectable ECC errors
94          * in the L2 cache or Memory Controller and cannot be
95          * recovered here.
96          */
97          mfc0   k0,C0_CERR_I            /* delay slot */
98         li      k1,1 << 26              /* ICACHE_EXTERNAL */
99         and     k1,k0
100         bnez    k1,unrecoverable
101          andi   k0,0x1fe0
102
103         /*
104          * Since the error is internal, the 'IDX' field from
105          * CacheErr-I is valid and we can just invalidate all blocks
106          * in that set.
107          */
108         cache   Index_Invalidate_I,(0<<13)(k0)
109         cache   Index_Invalidate_I,(1<<13)(k0)
110         cache   Index_Invalidate_I,(2<<13)(k0)
111         cache   Index_Invalidate_I,(3<<13)(k0)
112
113         /* Ought to log this recovered icache error */
114
115 recovered:
116         /* Restore the saved registers */
117         ld      k0,0x170($0)
118         ld      k1,0x178($0)
119         eret
120
121 unrecoverable:
122         /* Unrecoverable Icache or Dcache error; log it and/or fail */
123         j       handle_vec2_sb1
124          nop
125 #endif
126
127 END(except_vec2_sb1)
128
129         LEAF(handle_vec2_sb1)
130         mfc0    k0,CP0_CONFIG
131         li      k1,~CONF_CM_CMASK
132         and     k0,k0,k1
133         ori     k0,k0,CONF_CM_UNCACHED
134         mtc0    k0,CP0_CONFIG
135
136         SSNOP
137         SSNOP
138         SSNOP
139         SSNOP
140         bnezl   $0, 1f
141 1:
142         mfc0    k0, CP0_STATUS
143         sll     k0, k0, 3                       # check CU0 (kernel?)
144         bltz    k0, 2f
145          nop
146
147         /* Get a valid Kseg0 stack pointer.  Any task's stack pointer
148          * will do, although if we ever want to resume execution we
149          * better not have corrupted any state. */
150         get_saved_sp
151         move    sp, k1
152
153 2:
154         j       sb1_cache_error
155          nop
156
157         END(handle_vec2_sb1)