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