Setting up repository
[linux-libre-firmware.git] / ath9k_htc / sboot / magpie_1_1 / sboot / athos / src / xtos / memerror-vector.S
1 /* memerror-vector.S  --  Memory Error Exception Vector and Handler */
2
3 /* $Id: //depot/rel/Cottonwood/Xtensa/OS/xtos/memerror-vector.S#3 $ */
4
5 /*
6  * Copyright (c) 2006-2010 Tensilica Inc.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sublicense, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject to
14  * the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27
28 //#include <xtensa/config/specreg.h>
29 #include <xtensa/coreasm.h>
30 #include <xtensa/corebits.h>
31
32 #if XCHAL_HAVE_MEM_ECC_PARITY
33 # if defined(__SPLIT__vector)
34
35         //  Place this code in the memory error exception vector:
36         .begin  literal_prefix  .MemoryExceptionVector
37         .section                .MemoryExceptionVector.text, "ax"
38
39         .global _MemErrorVector
40         .align 4
41 _MemErrorVector:
42 # if 0 /* XCHAL_HAVE_DEBUG */
43         //  Memory errors raise PS.INTLEVEL above DEBUGLEVEL, so
44         //  break instructions have no effect within them (debug
45         //  exceptions are masked).  So leave commented out for now.
46         break   1, 5            // unhandled memory error exception
47 # endif
48         wsr     a0, MESAVE
49         movi    a0, _MemErrorHandler
50         jx      a0
51
52         .size   _MemErrorVector, . - _MemErrorVector
53         .text
54         .end    literal_prefix
55
56
57 # elif defined(__SPLIT__handler)
58
59 /*
60  *  Some rules and assumptions:
61  *
62  *      Anything that can interrupt this handler (e.g. NMI):
63  *              - must not lock or unlock cache lines
64  */
65
66
67 #define ICACHE_WAYWIDTH (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH)        /* LICT's "iis" */
68 #define DCACHE_WAYWIDTH (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH)        /* LDCT's "dis" */
69 /*  NOTE:  Memory ECC/parity is not supported on XLMI or on local ROMs:  */
70 #define HAVE_LOCAL_RAM  (XCHAL_NUM_DATARAM || XCHAL_NUM_INSTRAM /*|| XCHAL_NUM_URAM || XCHAL_NUM_XLMI*/)
71
72
73         //.lcomm        _MemErrorSave, 8
74         .comm   _MemErrorSave, 8, 4
75
76         .text
77         .align 4
78         .global _MemErrorHandler
79 _MemErrorHandler:
80         rsr     a0, MESR
81         bbsi.l  a0, MESR_DME_SHIFT, .L_fatal_dme
82 # if XCHAL_ICACHE_SIZE > 0 || XCHAL_DCACHE_SIZE > 0
83         bbsi.l  a0, MESR_MEMTYPE_SHIFT+1, .L_cache      // branch if error on a cache
84 # endif
85         //  Error in a local memory.
86 # if HAVE_LOCAL_RAM
87         bbsi.l  a0, MESR_ERRTYPE_SHIFT, .L_uncorrectable_local
88         //  Correctable error in a local memory (IRAM or DRAM).
89         //  (MEVADDR has all 32 bits, so XSR preserves a register:)
90         xsr     a2, MEVADDR
91         //  Note:  MEVADDR is always 4-byte aligned,
92         //  so we can just do L32I/S32I to correct the error.
93         //  However, that's not atomic, and NMI can store in between;
94         //  that's usually a problem for D rather than I, avoid the
95         //  issue using S32C1I if configured (else NMI must not write DataRAM!?!):
96 #  if (XCHAL_HAVE_S32C1I && (XCHAL_NUM_DATARAM /*|| XCHAL_NUM_URAM || XCHAL_NUM_XLMI*/))
97         bbci.l  a0, MESR_MEMTYPE_SHIFT, .L_instram      // branch if error on InstRAM
98         //  Unfortunately we need 3 registers to do S32C1I (data,addr,SCOMPARE1) so
99         //  we need to save to _MemErrorSave:
100         movi    a0, _MemErrorSave
101         s32i    a4, a0, 0       // save a4
102         l32i    a4, a2, 0       // load data (re-correct)
103         rsr     a0, SCOMPARE1   // save SCOMPARE1
104         wsr     a4, SCOMPARE1
105         s32c1i  a4, a2, 0       // store if still contains same value (else other store corrected error)
106         movi    a4, _MemErrorSave
107         wsr     a0, SCOMPARE1   // restore SCOMPARE1
108         l32i    a4, a4, 0       // restore a4
109         j       2f
110 .L_instram:
111 #  endif
112         l32i    a0, a2, 0       // load data (re-correct)
113         s32i    a0, a2, 0       // store data to correct ECC bits
114 2:      xsr     a2, MEVADDR
115 # endif /* HAVE_LOCAL_RAM */
116 .L_done:
117         rsr     a0, MESAVE
118         rfme
119
120
121         //  Weak reference:  if unresolved, links okay but with zero value:
122         .weak   _xtos_merr_hook_fatal_dme
123 .L_fatal_dme:
124         //  Fatal (unrecoverable) error, double memory exception
125         movi    a0, _xtos_merr_hook_fatal_dme
126 1:      beqz    a0, 1b          // fatal double memory error, no hook, so infinite loop
127         jx      a0              // jump to user hook, if present
128
129
130 # if HAVE_LOCAL_RAM
131         //  Weak reference:  if unresolved, links okay but with zero value:
132         .weak   _xtos_merr_hook_uncorrectable_local
133 .L_uncorrectable_local:
134         //  Fatal (unrecoverable) error in IRAM or DRAM:  parity or uncorrectable ECC error
135         movi    a0, _xtos_merr_hook_uncorrectable_local
136 1:      beqz    a0, 1b          // fatal memory error, no hook provided, so infinite loop
137         jx      a0              // jump to user hook, if present
138 # endif
139
140
141 # if XCHAL_ICACHE_SIZE > 0 || XCHAL_DCACHE_SIZE > 0
142 .L_cache:
143         //  Error in one of the caches.
144 # endif
145
146 # if XCHAL_ICACHE_SIZE > 0
147 #  if XCHAL_DCACHE_SIZE > 0
148         bbsi.l  a0, MESR_MEMTYPE_SHIFT, .L_dcache       // branch if data cache error
149 #  endif
150         //  Error in the instruction cache.
151         bbsi.l  a0, MESR_ERRTYPE_SHIFT, .L_icache_noncorr       // branch if uncorrectable
152         //  Correctable error in the instruction cache.
153         xsr     a2, MEVADDR
154         //  TODO FIXME: remove these 5 lines if waynum is in MEVADDR!? by using III if tag and IHI otherwise!?!?!?:
155 #  if XCHAL_ICACHE_WAYS > 1
156         extui   a0, a0, MESR_WAYNUM_SHIFT, 2
157         slli    a0, a0, ICACHE_WAYWIDTH
158         slli    a2, a2, 32 - ICACHE_WAYWIDTH
159         srli    a2, a2, 32 - ICACHE_WAYWIDTH
160         or      a2, a2, a0
161 #  endif
162         iii     a2, 0                   // invalidate line (whole set!) if not locked
163 #  if XCHAL_ICACHE_LINE_LOCKABLE
164         //  III has no effect if the line is locked; for that case, need to do more:
165         lict    a0, a2
166         bbci.l  a0, XCHAL_ICACHE_TAG_L_SHIFT, .L_icache_done    // branch if unlocked
167         //  Correctable error in a locked instruction cache line.
168         //  Fix both tag and one word, quicker than figuring out whether error is in tag or data:
169         sict    a0, a2                  // fix tag
170         licw    a0, a2
171         sicw    a0, a2                  // fix data word
172 #  endif
173 .L_icache_done:
174         xsr     a2, MEVADDR
175         j       .L_done
176
177 .L_icache_noncorr:
178         //  Non-correctable error in the instruction cache.
179         bbsi.l  a0, MESR_MEMTYPE_SHIFT+2, .L_icache_tag_noncorr // branch if tag error
180         //  Non-correctable error in the instruction cache data.
181         //  Just invalidate the line if we can.
182 #  if XCHAL_ICACHE_LINE_LOCKABLE
183         //  If locked, need a different fix sequence.
184         xsr     a2, MEVADDR
185
186 #   if XCHAL_ICACHE_WAYS > 1
187         //  This sequence is shorter, but does not retain original MEVADDR so
188         //  prevents subsequent use of instructions requiring a virtual address
189         //  (such as LICW, IPFL, etc):
190 //      extui   a0, a0, MESR_WAYNUM_SHIFT, 2
191 //      slli    a0, a0, ICACHE_WAYWIDTH
192 //      slli    a2, a2, 32 - ICACHE_WAYWIDTH
193 //      srli    a2, a2, 32 - ICACHE_WAYWIDTH
194 //      or      a2, a2, a0
195
196         extui   a0, a0, MESR_WAYNUM_SHIFT, 2    // id of way with mem error
197         slli    a0, a0, ICACHE_WAYWIDTH
198         xor     a0, a2, a0                      // xor corresponding bits of addr
199         extui   a0, a0, ICACHE_WAYWIDTH, 2      // take 2 xor'ed way bits
200         or      a2, a2, a0                      // save them at bottom of addr
201         slli    a0, a0, ICACHE_WAYWIDTH
202         xor     a2, a2, a0                      // and change 2 way bits of addr
203 #   endif
204         lict    a0, a2
205         bbsi.l  a0, XCHAL_ICACHE_TAG_L_SHIFT, .L_icache_locked_uncor    // branch if locked
206         //  Cache line is not locked, just invalidate:
207 #   if XCHAL_ICACHE_WAYS > 1
208         iii     a2, 0
209 #   else
210         ihi     a2, 0
211 #   endif
212         j       .L_icache_done
213
214         //  NOTE:  we don't use the LICW/SICW sequence below unless the line is locked,
215         //      otherwise the i-cache line might get replaced between LICW and SICW
216         //      (if we're not extremely careful), which would be disastrous.
217         //      Also, for locked lines, LICW/SICW is much safer than IHU/IHI/IPFL
218         //      because it doesn't leave a window where the line is unlocked;
219         //      however, if the error is non-correctable, we have no choice.
220
221 .L_icache_locked_uncor:
222         //  If locked and uncorrectable however, the only recourse is relocking.
223         //  So we need to recover the virtual address so we can do IPFL.
224         //  Note:  can't use MEPC instead of MEVADDR, because (a) it might not
225         //  point to the correct cache line, and (b) it might be completely wrong
226         //  in the case where the mem error happened e.g. during an LICW or IPFL.
227 #   if XCHAL_ICACHE_WAYS > 1
228         //  Recover virtual address in a2:
229         extui   a0, a2, 0, 2                    // get saved xor'ed bits at bottom
230         slli    a0, a0, ICACHE_WAYWIDTH         // line them up
231         xor     a2, a2, a0                      // restore original MEVADDR
232 #   endif
233         ihu     a2, 0           // unlock line
234         ihi     a2, 0           // invalidate line
235         ipfl    a2, 0           // refetch-and-lock the line
236         j       .L_icache_done
237 #  else /* LOCKABLE */
238         rsr     a0, MEVADDR
239         ihi     a0, 0           // invalidate that cache line
240         j       .L_done
241 #  endif /* LOCKABLE */
242
243 .L_icache_tag_noncorr:
244         //  Non-correctable error in the instruction cache tag.
245         //  Just invalidate the tag or the entire set.
246 #  if XCHAL_ICACHE_LINE_LOCKABLE
247         //  Note:  can't use either IIU or III, as these don't write the entire tag,
248         //  so they'll get the exception again.  So, have to use SICT.
249 #   if XCHAL_ICACHE_WAYS > 1
250         //  TODO FIXME: avoid this 8-line alternative if waynum is in MEVADDR!?:
251         xsr     a2, MEVADDR
252         extui   a0, a0, MESR_WAYNUM_SHIFT, 2
253         slli    a0, a0, ICACHE_WAYWIDTH
254         slli    a2, a2, 32 - ICACHE_WAYWIDTH
255         srli    a2, a2, 32 - ICACHE_WAYWIDTH
256         or      a2, a2, a0
257         iiu     a2, 0           // unlock line ==> also invalidates! (I-side only)
258         xsr     a2, MEVADDR
259 #   else
260         rsr     a0, MEVADDR
261         iiu     a0, 0           // unlock line ==> also invalidates! (I-side only)
262 #   endif
263         // If line was locked, can't recover lock state, need external info to recover.
264         // User can provide an assembler hook routine _xtos_merr_hook_icache_relock
265         // to relock the icache at the index in a2:
266         //      - any number of lines might still be locked at that index,
267         //        including all of them
268         //      - no stack is provided, a0 must be used as starting point to
269         //        load a save area and saved registers as necessary
270         //      - unless routine just does ret (i.e. does not modify any
271         //        register, only possible if it does nothing), it needs to
272         //        return by restoring all registers it modified, ending with:
273         //              rsr     a0, MESAVE
274         //              rfme
275         //  CAVEAT EMPTOR:  this hook mechanism is subject to change.
276         .weak   _xtos_merr_hook_icache_relock   // if unresolved, links with zero value
277         movi    a0, _xtos_merr_hook_icache_relock
278 1:      beqz    a0, 1b          // if no hook to recover lock state on icache tag mem error, loop forever
279         callx0  a0              // invoke user hook to relock i-cache (index in MEVADDR)
280 #  else
281         rsr     a0, MEVADDR
282         iii     a0, 0           // invalidate entire set
283 #  endif
284         j       .L_done
285 # endif /* have ICACHE */
286
287
288 # if XCHAL_DCACHE_SIZE > 0
289 #  if XCHAL_ICACHE_SIZE > 0
290 .L_dcache:
291 #  endif
292         //  Error in the data cache.
293 #  if XCHAL_DCACHE_IS_WRITEBACK || XCHAL_DCACHE_LINE_LOCKABLE
294         bbsi.l  a0, MESR_ERRTYPE_SHIFT, .L_dcache_noncorr       // branch if uncorrectable
295         //  Uncorrectable error on a writeback dcache might be unrecoverable:
296 #  endif
297         bbsi.l  a0, MESR_MEMTYPE_SHIFT+2, .L_dcache_tag         // branch if tag error
298         //  Error in the data cache data (correctable, or non-correctable in writethru+unlockable cache).
299         //  MEVADDR always a real vaddr here; might point to cache-isolate mode area though.
300 #  if XCHAL_DCACHE_LINE_LOCKABLE
301         //  Correctable error on lockable dcache data.
302         //  If locked, need to refetch the line (or load/store its contents, which is less safe):
303         xsr     a2, MEVADDR
304 #   if XCHAL_DCACHE_WAYS > 1
305         //  Need some extra computation to get the correct dcache way's tag:
306         movi    a0, _MemErrorSave
307         s32i    a4, a0, 0       // save a4
308         s32i    a5, a0, 4       // save a5
309         rsr     a4, MESR
310         extui   a4, a4, MESR_WAYNUM_SHIFT, 2
311         slli    a4, a4, DCACHE_WAYWIDTH
312         slli    a5, a2, 32 - DCACHE_WAYWIDTH
313         srli    a5, a5, 32 - DCACHE_WAYWIDTH
314         add     a4, a4, a5
315         mov     a5, a0
316         ldct    a0, a4
317         l32i    a4, a5, 0       // restore a4
318         l32i    a5, a5, 4       // restore a5
319 #   else
320         ldct    a0, a2
321 #   endif
322         //  FIXME:  if castout, a2 is a physical address! doesn't work with any address translation.
323 #   if 0 /* translation */
324         movi    a4, _xtos_vmap_vaddr    // FIXME: do we need two variables for full MMU?
325 1:      beqz    a4, 1b          // if no vaddr to use, loop forever (FIXME: caxlt: could assume V==P)
326         rdtlb1  a5, a4          // save current contents
327         ... clear lower bits of a4 ...
328         xx = some function of a2
329         wdtlb   xx, a4
330         a2 = virtual address, i.e. some function of a2 and a4 ...
331         ... do the sequence below ...
332         ...
333         wdtlb   a5, a4          // restore TLB entry
334 #   endif
335         //  NOTE:  the following sequence leaves the line temporarily unlocked, if locked.
336         //  We assume NMI handlers don't lock lines or rely on their being locked.
337         //  We could have used "l32i a0,a2,0; s32i a0,a2,0" but that's not atomic on the data.
338         dhu     a2, 0           // unlock the cache line, if locked
339         dhwbi   a2, 0           // writeback and invalidate cache line
340         bbci.l  a0, XCHAL_DCACHE_TAG_L_SHIFT, 1f
341         dpfl    a2, 0           // re-prefetch-and-lock the cache line
342 1:      xsr     a2, MEVADDR
343 #  else /* LOCKABLE */
344         //  Error in unlockable data cache data (correctable, or non-correctable in writethru cache).
345         rsr     a0, MEVADDR
346         //  USELESS NOTE:  if writethru dcache and NMI handlers don't store to this, we could use DHI instead:
347         //  FIXME:  if castout, a0 is a physical address! doesn't work with any address translation.
348         dhwbi   a0, 0           // writeback (if correctable) and invalidate that cache line
349 #  endif /* LOCKABLE */
350         j       .L_done
351
352 .L_dcache_tag:
353         //  Error in data cache tag (correctable, or non-correctable in writethru+unlockable cache).
354         //  MEVADDR only contains cache index here (not waynum), don't expect a vaddr (the ISA
355         //  says upper bits are undefined; actual hw does put a vaddr, but in future might not).
356         //  Whether or not correctable, just invalidate the particular way's line:
357         xsr     a2, MEVADDR
358         //  NOTE: could remove these 5 lines if hw were designed with waynum in MEVADDR (but is not):
359 #  if XCHAL_DCACHE_WAYS > 1
360         extui   a0, a0, MESR_WAYNUM_SHIFT, 2
361         slli    a0, a0, DCACHE_WAYWIDTH
362         slli    a2, a2, 32 - DCACHE_WAYWIDTH
363         srli    a2, a2, 32 - DCACHE_WAYWIDTH
364         or      a2, a2, a0
365 #  endif
366 #  if XCHAL_DCACHE_LINE_LOCKABLE
367         ldct    a0, a2          // invalidate and unlock that cache tag
368         bbci.l  a0, XCHAL_DCACHE_TAG_L_SHIFT, 1f        // branch if not locked
369         sdct    a0, a2          // if locked, this safely writes whole tag
370 #  endif
371 1:      diwbi   a2, 0           // writeback (if correctable) and invalidate the line
372         xsr     a2, MEVADDR
373         j       .L_done
374
375
376
377 #  if XCHAL_DCACHE_IS_WRITEBACK || XCHAL_DCACHE_LINE_LOCKABLE
378 .L_dcache_noncorr:
379         //  Uncorrectable error on a (writeback and/or lockable) data cache.
380 #   if XCHAL_DCACHE_IS_WRITEBACK
381         //  On tag errors we don't know whether the line is dirty, so this is unrecoverable:
382         bbsi.l  a0, MESR_MEMTYPE_SHIFT+2, .L_uncorrectable_dtag // branch if tag error
383         //  Castouts are by definition dirty, uncorrectable errors on these are unrecoverable:
384         bbsi.l  a0, MESR_ACCTYPE_SHIFT, .L_uncorrectable_dirty  // branch if castout
385         //  Note: could still be an error on dirty dcache data, also unrecoverable.
386 #   else
387         bbsi.l  a0, MESR_MEMTYPE_SHIFT+2, .L_dcache_tag_noncorr // branch if tag error
388 #   endif
389         //  Uncorrectable error in dcache data.
390         //  May be dirty or locked, so get tag to find out.
391         xsr     a2, MEVADDR
392 #   if XCHAL_DCACHE_WAYS > 1
393         extui   a0, a0, MESR_WAYNUM_SHIFT, 2    // id of way with mem error
394         slli    a0, a0, DCACHE_WAYWIDTH
395         xor     a0, a2, a0                      // xor corresponding bits of addr
396         extui   a0, a0, DCACHE_WAYWIDTH, 2      // take 2 xor'ed way bits
397         or      a2, a2, a0                      // save them at bottom of addr
398         slli    a0, a0, DCACHE_WAYWIDTH
399         xor     a2, a2, a0                      // and change 2 way bits of addr
400 #   endif
401         ldct    a0, a2                  // get dcache tag
402 #   if XCHAL_DCACHE_IS_WRITEBACK
403         bbsi.l  a0, XCHAL_DCACHE_TAG_D_SHIFT, .L_uncorrectable_dirty_2  // branch if dirty
404 #   endif
405         //  Data cache line is clean.
406 #   if XCHAL_DCACHE_LINE_LOCKABLE
407         bbsi.l  a0, XCHAL_DCACHE_TAG_L_SHIFT, .L_dcache_nc_locked
408 #   endif
409         //  Data cache line is clean and unlocked.  Just invalidate it.
410         //  FIXME:  any stores to this line by an NMI handler will be lost.
411         //      On the other hand, if we use DHWBI, any stores by an NMI handler
412         //      that don't happen to fix the error result in an unrecoverable castout.
413         //      
414 #   if XCHAL_ICACHE_WAYS > 1
415         //  Recover virtual address in a2:
416         extui   a0, a2, 0, 2                    // get saved xor'ed bits at bottom
417         slli    a0, a0, ICACHE_WAYWIDTH         // line them up
418         xor     a2, a2, a0                      // restore original MEVADDR
419 #   endif
420         dhi     a2, 0           // invalidate that data cache line
421         xsr     a2, MEVADDR
422         j       .L_done
423
424 #   if XCHAL_DCACHE_LINE_LOCKABLE
425 .L_dcache_nc_locked:
426 #    if XCHAL_ICACHE_WAYS > 1
427         //  Recover virtual address in a2:
428         extui   a0, a2, 0, 2                    // get saved xor'ed bits at bottom
429         slli    a0, a0, ICACHE_WAYWIDTH         // line them up
430         xor     a2, a2, a0                      // restore original MEVADDR
431 #    endif
432         //  Unlock, invalidate, and relock it:
433         dhu     a2, 0           // unlock that data cache line
434         dhi     a2, 0           // invalidate that data cache line
435         dpfl    a2, 0           // prefetch-and-lock the line again
436         xsr     a2, MEVADDR
437         j       .L_done
438 #   endif
439
440 #   if XCHAL_DCACHE_IS_WRITEBACK
441         //  Weak reference:  if unresolved, links okay but with zero value:
442         .weak   _xtos_merr_hook_uncor_dtag
443 .L_uncorrectable_dtag:
444         //  Fatal (unrecoverable) error in dcache tag (maybe dirty):  parity or uncorrectable ECC error
445         movi    a0, _xtos_merr_hook_uncor_dtag
446 1:      beqz    a0, 1b          // fatal non-corr dcache tag, no hook, so infinite loop
447         jx      a0              // jump to user hook, if present
448
449         //  Weak reference:  if unresolved, links okay but with zero value:
450         .weak   _xtos_merr_hook_uncor_dirty
451 .L_uncorrectable_dirty_2:
452         xsr     a2, MEVADDR
453 .L_uncorrectable_dirty:
454         //  Fatal (unrecoverable) error, parity or non-correctable ECC error on dirty cache data
455         movi    a0, _xtos_merr_hook_uncor_dirty
456 1:      beqz    a0, 1b          // fatal non-corr dirty cache line, no hook, so infinite loop
457         jx      a0              // jump to user hook, if present
458 #   else
459 .L_dcache_tag_noncorr:
460         //  Uncorrectable error on a lockable writethru data cache tag.
461         //  We have to invalidate the line, but that way we lose the lock bit.
462         //  Provide a hook to relock if necessary (using knowledge outside this module
463         //  about what needs to be locked).  See _xtos_merr_hook_icache_relock for details.
464         //  CAVEAT EMPTOR:  this hook mechanism is subject to change.
465         .weak   _xtos_merr_hook_dcache_relock   // if unresolved, links with zero value
466         movi    a0, _xtos_merr_hook_dcache_relock
467 1:      beqz    a0, 1b          // if no hook to recover lock state on dcache tag mem error, loop forever
468         callx0  a0              // invoke user hook to relock d-cache (index in MEVADDR)
469         j       .L_done
470 #   endif
471
472 #  endif /* DCACHE IS WRITEBACK || LINE_LOCKABLE */
473
474 # endif /* have DCACHE */
475
476         .size   _MemErrorHandler, . - _MemErrorHandler
477
478
479
480 # endif /* splitting */
481 #endif /* XCHAL_HAVE_MEM_ECC_PARITY */
482