1// 2// mem_ecc_parity.S - utility routines for the local memory ECC/parity option 3// (memory error checking and exceptions) 4// 5// $Id: //depot/rel/Foxhill/dot.8/Xtensa/OS/hal/mem_ecc_parity.S#1 $ 6 7// Copyright (c) 2006-2010 Tensilica Inc. 8// 9// Permission is hereby granted, free of charge, to any person obtaining 10// a copy of this software and associated documentation files (the 11// "Software"), to deal in the Software without restriction, including 12// without limitation the rights to use, copy, modify, merge, publish, 13// distribute, sublicense, and/or sell copies of the Software, and to 14// permit persons to whom the Software is furnished to do so, subject to 15// the following conditions: 16// 17// The above copyright notice and this permission notice shall be included 18// in all copies or substantial portions of the Software. 19// 20// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 23// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 24// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 28#include <xtensa/coreasm.h> 29 30 31/* 32 * For most functions, the link-time HAL defines two entry points: 33 * xthal_...() and xthal_..._nw(). The former is the main entry point 34 * invoked from C code, or assembly code that follows the C ABI. 35 * The latter is for use in assembly code that cannot easily follow 36 * all the requirements of the windowed ABI, e.g. in exception handlers; 37 * these use the call0 ABI instead (in most cases; some use their own conventions). 38 * 39 * When software tools are configured to use the call0 ABI, both variants 40 * are identical (with some exceptions as noted). To avoid duplicating 41 * code, we define both labels for the same function body. The Makefile 42 * defines __SPLIT__..._nw macros with windowed ABI but not with Call0 ABI. 43 * Use SYM_NW() for the _nw variants defined with the __SPLIT_..._nw macros, 44 * i.e. for call0 ABI variants when windowed ABI is in use; these are not 45 * C callable so SYM_NW() does not specify .type information. 46 * Use SYMBOL() otherwise, which defines both symbols if call0 ABI is selected. 47 */ 48 49#if defined (__XTENSA_CALL0_ABI__) 50# define SYMBOL(x) .global x ; .type x,@function ; \ 51 .global x ## _nw ; .type x ## _nw,@function ; \ 52 .align 4 ; x: ; x ## _nw: 53#else 54# define SYMBOL(x) .global x ; .type x,@function ; .align 4 ; x: 55#endif 56#define SYM_NW(x) .global x ; .align 4 ; x: 57 58 59/* Compute smaller of I and D cache line sizes: */ 60#if XCHAL_ICACHE_LINEWIDTH < XCHAL_DCACHE_LINEWIDTH && XCHAL_ICACHE_SIZE > 0 61# define CACHE_LINEWIDTH_MIN XCHAL_ICACHE_LINEWIDTH 62# define CACHE_LINESIZE_MIN XCHAL_ICACHE_LINESIZE 63#else 64# define CACHE_LINEWIDTH_MIN XCHAL_DCACHE_LINEWIDTH 65# define CACHE_LINESIZE_MIN XCHAL_DCACHE_LINESIZE 66#endif 67 68 69 .text 70 71//------------------------------------------------------------------------ 72// Inject errors into instruction and/or data RAMs, or cache data or tags 73//------------------------------------------------------------------------ 74 75 76// void xthal_memep_inject_error(void *addr, int size, int flags); 77// where: 78// addr (a2) pointer to local memory, or cache address 79// size (a3) size in bytes (gets aligned to words or lines) 80// flags (a4) is a combination of the following bits: 81// bit 31-5: (reserved) 82// bit 4: 0 = inject non-correctable error, 83// 16 = inject correctable error (if ECC) 84// bit 3: (reserved) 85// bit 2: 0 = local memory, 4 = cache 86// bit 1: 0 = data cache, 2 = instruction cache 87// bit 0: 0 = cache data, 1 = cache tag 88// 89// (note: data cache data is handled same as local memories; 90// to access specific dcache data entries, you have to setup 91// a region or page in cache-isolate mode yourself) 92 93SYMBOL(xthal_memep_inject_error) 94 abi_entry 95 96#if XCHAL_HAVE_MEM_ECC_PARITY 97 98 // These MOVIs may be L32Rs, load them before enabling test mode: 99 movi a6, 0x02020202 // XOR'ing this creates a correctable error 100 bbsi.l a4, 4, 1f // branch if correctable error requested 101 movi a6, 0x03030303 // XOR'ing this creates a non-correctable error 1021: 103 104 // Lock out all interrupts, to avoid interrupt handlers running with 105 // test mode enabled (corrupting their stores, likely leading to 106 // non-correctable memory errors). 107 // 108 // If NMI is possible, you're toast 109 // (no stores during NMI handler will have properly computed ECC/parity bits) 110 // although you might make the NMI handler check MESR.ERRTEST and save/clear 111 // it if it's set on entry, so that its stores work correctly. 112 // 113 // If memory exceptions are possible, might be okay as long as the 114 // handler checks whether test mode is on, and turns it off temporarily 115 // to do its work. 116 // 117# if XCHAL_HAVE_INTERRUPTS 118 rsil a11, 15 119# endif 120 121 // Save current MESR and set test mode: 122 123 rsr.mesr a8 124 bbsi.l a8, MESR_ERRTEST_SHIFT, .Lproceed // already in test mode? 125 addmi a9, a8, MESR_ERRTEST // enable test mode 126 bbci.l a8, MESR_ERRENAB_SHIFT, 1f 127 addmi a9, a9, - MESR_ERRENAB // disable error checks 1281: xsr.mesr a9 129 beq a8, a9, .Lproceed // clean update, continue 130 bbci.l a9, MESR_RCE_SHIFT, .Lproceed // we likely restored a lost RCE, just keep it 131 // At this point, either we: 132 // a) cleared an RCE record that got created between RSR and XSR 133 // b) cleared LCE bits that got set between RSR and XSR 134 // c) more eclectic, and presumably much less likely, cases of 135 // RCE/LCE bits being cleared and set again between RSR and XSR 136 // due to multiple memory errors and memory error exceptions 137 // in that period; for now, we ignore this possibility 138 // (decreasing returns on addressing these arbitrarily complex cases) 139 // Assuming (a) or (b), restore the bits we took away. 140 //addmi a8, a8, MESR_ERRTEST 141 addmi a9, a9, MESR_ERRTEST 142 bbci.l a9, MESR_ERRENAB_SHIFT, 1f 143 addmi a9, a9, - MESR_ERRENAB // disable error checks 1441: wsr.mesr a9 145 //xsr.mesr a9 146 //beq a8, a9, .Lproceed // updated fine, continue 147 // 148 // Above we could have used XSR instead of WSR. 149 // However, it's not clear at this point what's the cleanest thing 150 // to do if what we read back doesn't match what we expected, 151 // because at that point we have multiple errors to deal with. 152 // Unless we have code here to handle (fix and/or log) these errors, 153 // we have to chuck something away or write a bunch more code to 154 // handle another LCE bit getting set etc (also starting to be 155 // a low probability occurrence). 156.Lproceed: 157 // Test mode enabled. From this point until we restore MESR, 158 // the only loads and stores done are for injecting errors. 159 160# if XCHAL_ICACHE_SIZE || XCHAL_DCACHE_SIZE 161 bbci.l a4, 2, .L_inject_local // branch if injecting to local memory 162 bbsi.l a4, 1, .L_inject_icache // branch if injecting to icache 163 // Inject errors in dcache: 164 bbci.l a4, 0, .L_inject_local // branch if injecting to dcache data 165# if XCHAL_DCACHE_SIZE && XCHAL_HAVE_DCACHE_TEST 166 // Inject errors in dcache tags: 167 168 // Round addr/size to fully rather than partially cover 169 // all aligned cache lines: 170 extui a9, a2, 0, XCHAL_DCACHE_LINEWIDTH 171 sub a2, a2, a9 172 add a3, a3, a9 173 addi a3, a3, XCHAL_DCACHE_LINESIZE-1 174 srli a3, a3, XCHAL_DCACHE_LINEWIDTH // size in cache lines 175 176 floopgtz a3, .Ldctagloop 177 ldct a9, a2 // load dcache line tag 178 rsr.mecr a7 // get check bits 179 xor a7, a7, a6 // ECC: single-bit error; Parity: NO-OP 180 wsr.mecr a7 // setup modified check bits 181 sdct a9, a2 // store tag with modified check bits 182 addi a2, a2, XCHAL_DCACHE_LINESIZE // increment to next line 183 floopend a3, .Ldctagloop 184# endif /* have dcache */ 185 j .L_inject_done 186 187 // Inject errors in icache: 188.L_inject_icache: 189# if XCHAL_ICACHE_SIZE && XCHAL_HAVE_ICACHE_TEST 190 bbci.l a4, 0, .L_inject_icw // branch if injecting to icache data 191 192 // Inject errors in icache tags: 193 // Round addr/size to fully rather than partially cover 194 // all aligned cache lines: 195 extui a9, a2, 0, XCHAL_ICACHE_LINEWIDTH 196 sub a2, a2, a9 197 add a3, a3, a9 198 addi a3, a3, XCHAL_ICACHE_LINESIZE-1 199 srli a3, a3, XCHAL_ICACHE_LINEWIDTH // size in cache lines 200 201 floopgtz a3, .Lictagloop 202 lict a9, a2 // load icache line tag 203 rsr.mecr a7 // get check bits 204 xor a7, a7, a6 // ECC: single-bit error; Parity: NO-OP 205 wsr.mecr a7 // setup modified check bits 206 sict a9, a2 // store tag with modified check bits 207 addi a2, a2, XCHAL_ICACHE_LINESIZE // increment to next line 208 floopend a3, .Lictagloop 209 j .L_inject_done 210 211.L_inject_icw: 212# if XCHAL_ICACHE_ACCESS_SIZE <= 4 /* SICW does not work usefully (replicates data) if accessWidth > 32 bits */ 213 // Inject errors in icache data words: 214 // Round addr/size to fully rather than partially cover 215 // all aligned 32-bit words: 216 extui a9, a2, 0, 2 217 sub a2, a2, a9 218 add a3, a3, a9 219 addi a3, a3, 3 220 srli a3, a3, 2 // size in words 221 222 floopgtz a3, .Licwloop 223 licw a9, a2 // load word of icache line data 224 rsr.mecr a7 // get check bits 225 xor a7, a7, a6 // ECC: single-bit error; Parity: NO-OP 226 wsr.mecr a7 // setup modified check bits 227 sicw a9, a2 // store data with modified check bits 228 addi a2, a2, 4 // increment to next word 229 floopend a3, .Licwloop 230# endif 231# endif /* have icache */ 232 j .L_inject_done 233# endif /* have icache or dcache */ 234 235.L_inject_local: 236 // Round addr/size to fully rather than partially cover 237 // all aligned 32-bit words: 238 extui a9, a2, 0, 2 239 sub a2, a2, a9 240 add a3, a3, a9 241 addi a3, a3, 3 242 srli a3, a3, 2 // size in words 243 244 floopgtz a3, .Lendloop 245 l32i a9, a2, 0 // load data 246 rsr.mecr a7 // get check bits 247 xor a7, a7, a6 // ECC: single-bit error; Parity: NO-OP 248 wsr.mecr a7 // setup modified check bits 249 s32i a9, a2, 0 // store data with modified check bits 250 addi a2, a2, 4 // increment to next word 251 floopend a3, .Lendloop 252 253.L_inject_done: 254 // Restore MESR (a8 is the saved original MESR): 255 bbsi.l a8, MESR_ERRTEST_SHIFT, 2f // was already in test mode 256 rsr.mesr a6 257 addmi a9, a6, - MESR_ERRTEST // disable test mode 258 bbci.l a8, MESR_ERRENAB_SHIFT, 1f 259 addmi a9, a9, MESR_ERRENAB // enable error checks 2601: xsr.mesr a9 261 beq a6, a9, 2f // clean update, done 262 bbci.l a9, MESR_RCE_SHIFT, 2f // we likely restored a lost RCE, just keep it 263 addmi a9, a9, - MESR_ERRTEST 264 bbci.l a8, MESR_ERRENAB_SHIFT, 1f 265 addmi a9, a9, MESR_ERRENAB // disable error checks 2661: wsr.mesr a9 2672: 268 269 // Restore PS.INTLEVEL: 270# if XCHAL_HAVE_INTERRUPTS 271 wsr.ps a11 272 rsync 273# endif 274#endif /* XCHAL_HAVE_MEM_ECC_PARITY */ 275 276 abi_return 277 278 .size xthal_memep_inject_error, . - xthal_memep_inject_error 279 280 281 282//---------------------------------------------------------------------- 283 284