1 /******************************************************************************
3 * Copyright (C) 2011 - 2014 Xilinx, Inc. All rights reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
31 ******************************************************************************/
32 /*****************************************************************************/
34 * @file xbram_selftest.c
36 * The implementation of the XBram driver's self test function. This SelfTest
37 * is only applicable if ECC is enabled.
38 * If ECC is not enabled then this function will return XST_SUCCESS.
39 * See xbram.h for more information about the driver.
47 * MODIFICATION HISTORY:
49 * Ver Who Date Changes
50 * ----- ---- -------- -----------------------------------------------
51 * 1.00a sa 11/24/10 First release
52 * 3.01a sa 01/13/12 Changed Selftest API from
53 * XBram_SelfTest(XBram *InstancePtr) to
54 * XBram_SelfTest(XBram *InstancePtr, u8 IntMask) and
55 * fixed a problem with interrupt generation for CR 639274
56 * Modified Selftest example to return XST_SUCCESS when
57 * ECC is not enabled and return XST_FAILURE when ECC is
58 * enabled and Control Base Address is zero (CR 636581)
59 * Modified Selftest to use correct CorrectableCounterBits
61 * Updated to check CorrectableFailingDataRegs in the case
63 * 3.02a sa 04/16/12 Added test of byte and halfword read-modify-write
64 * 3.03a bss 05/22/13 Added Xil_DCacheFlushRange in InjectErrors API to
65 * flush the Cache after writing to BRAM (CR #719011)
67 *****************************************************************************/
69 /***************************** Include Files ********************************/
71 #include "xil_cache.h"
72 /************************** Constant Definitions ****************************/
75 /**************************** Type Definitions ******************************/
77 /***************** Macros (Inline Functions) Definitions ********************/
78 #define RD(reg) XBram_ReadReg(InstancePtr->Config.CtrlBaseAddress, \
80 #define WR(reg, data) XBram_WriteReg(InstancePtr->Config.CtrlBaseAddress, \
83 #define CHECK(reg, data, result) if (result!=XST_SUCCESS || RD(reg)!=data) \
86 /************************** Variable Definitions ****************************/
87 static u32 PrngResult;
89 /************************** Function Prototypes *****************************/
90 static inline u32 PrngData(u32 *PrngResult);
92 static inline u32 CalculateEcc(u32 Data);
94 static void InjectErrors(XBram * InstancePtr, u32 Addr,
95 int Index1, int Index2, int Width,
96 u32 *ActualData, u32 *ActualEcc);
99 /*****************************************************************************/
101 * Generate a pseudo random number.
103 * @param The PrngResult is the previous random number in the pseudo
104 * random sequence, also knwon as the seed. It is modified to
105 * the calculated pseudo random number by the function.
107 * @return The generated pseudo random number
111 ******************************************************************************/
112 static inline u32 PrngData(u32 *PrngResult)
114 *PrngResult = *PrngResult * 0x77D15E25 + 0x3617C161;
119 /*****************************************************************************/
121 * Calculate ECC from Data.
123 * @param The Data Value
125 * @return The calculated ECC
129 ******************************************************************************/
130 static inline u32 CalculateEcc(u32 Data)
132 unsigned char c[7], d[32];
136 for (Index = 0; Index < 32; Index++) {
137 d[31 - Index] = Data & 1;
141 c[0] = d[0] ^ d[1] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[10] ^ d[11] ^
142 d[13] ^ d[15] ^ d[17] ^ d[19] ^ d[21] ^ d[23] ^ d[25] ^ d[26] ^
145 c[1] = d[0] ^ d[2] ^ d[3] ^ d[5] ^ d[6] ^ d[9] ^ d[10] ^ d[12] ^
146 d[13] ^ d[16] ^ d[17] ^ d[20] ^ d[21] ^ d[24] ^ d[25] ^ d[27] ^
149 c[2] = d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[14] ^
150 d[15] ^ d[16] ^ d[17] ^ d[22] ^ d[23] ^ d[24] ^ d[25] ^ d[29] ^
153 c[3] = d[4] ^ d[5] ^ d[6] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[18] ^
154 d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25];
156 c[4] = d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ d[18] ^
157 d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25];
159 c[5] = d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31];
161 c[6] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7] ^
162 d[8] ^ d[9] ^ d[10] ^ d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^
163 d[16] ^ d[17] ^ d[18] ^ d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^
164 d[24] ^ d[25] ^ d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31] ^
165 c[5] ^ c[4] ^ c[3] ^ c[2] ^ c[1] ^ c[0];
167 for (Index = 0; Index < 7; Index++) {
168 Result = Result << 1;
169 Result |= c[Index] & 1;
175 /*****************************************************************************/
177 * Get the expected actual data read in case of uncorrectable errors.
179 * @param The injected data value including errors (if any)
180 * @param The syndrome (calculated ecc ^ actual ecc read)
182 * @return The actual data value read
186 ******************************************************************************/
187 static inline u32 UncorrectableData(u32 Data, u8 Syndrome)
190 case 0x03: return Data ^ 0x00000034;
191 case 0x05: return Data ^ 0x001a2000;
192 case 0x09: return Data ^ 0x0d000000;
193 case 0x0d: return Data ^ 0x00001a00;
195 case 0x11: return Data ^ 0x60000000;
196 case 0x13: return Data ^ 0x00000003;
197 case 0x15: return Data ^ 0x00018000;
198 case 0x19: return Data ^ 0x00c00000;
199 case 0x1d: return Data ^ 0x00000180;
201 case 0x21: return Data ^ 0x80000000;
202 case 0x23: return Data ^ 0x00000008;
203 case 0x25: return Data ^ 0x00040000;
204 case 0x29: return Data ^ 0x02000000;
205 case 0x2d: return Data ^ 0x00000400;
207 case 0x31: return Data ^ 0x10000000;
208 case 0x35: return Data ^ 0x00004000;
209 case 0x39: return Data ^ 0x00200000;
210 case 0x3d: return Data ^ 0x00000040;
215 /*****************************************************************************/
217 * Inject errors using the hardware fault injection functionality, and write
218 * random data and read it back using the indicated location.
220 * @param InstancePtr is a pointer to the XBram instance to
222 * @param The Addr is the indicated memory location to use
223 * @param The Index1 is the bit location of the first injected error
224 * @param The Index2 is the bit location of the second injected error
225 * @param The Width is the data byte width
226 * @param The ActualData is filled in with expected data for checking
227 * @param The ActualEcc is filled in with expected ECC for checking
233 ******************************************************************************/
234 static void InjectErrors(XBram * InstancePtr, u32 Addr,
235 int Index1, int Index2, int Width,
236 u32 *ActualData, u32 *ActualEcc)
238 u32 InjectedData = 0;
240 u32 RandomData = PrngData(&PrngResult);
243 InjectedData = 1 << Index1;
245 InjectedEcc = 1 << (Index1 - 32);
249 InjectedData |= (1 << Index2);
251 InjectedEcc |= 1 << (Index2 - 32);
254 WR(FI_D_0_OFFSET, InjectedData);
255 WR(FI_ECC_0_OFFSET, InjectedEcc);
257 XBram_Out32(Addr, RandomData);
258 Xil_DCacheFlushRange(Addr, 4);
260 case 1: /* Byte - Write to do Read-Modify-Write */
261 XBram_Out8(Addr, PrngData(&PrngResult) & 0xFF);
263 case 2: /* Halfword - Write to do Read-Modify-Write */
264 XBram_Out16(Addr, PrngData(&PrngResult) & 0xFFFF);
266 case 4: /* Word - Read */
267 (void) XBram_In32(Addr);
270 *ActualData = InjectedData ^ RandomData;
271 *ActualEcc = InjectedEcc ^ CalculateEcc(RandomData);
275 /*****************************************************************************/
277 * Run a self-test on the driver/device. Unless fault injection is implemented
278 * in hardware, this function only does a minimal test in which available
279 * registers (if any) are written and read.
281 * With fault injection, all possible single-bit and double-bit errors are
282 * injected, and checked to the extent possible, given the implemented hardware.
284 * @param InstancePtr is a pointer to the XBram instance.
285 * @param IntMask is the interrupt mask to use. When testing
286 * with interrupts, this should be set to allow interrupt
287 * generation, otherwise it should be 0.
290 * - XST_SUCCESS if fault injection/detection is working properly OR
291 * if ECC is Not Enabled in the HW.
292 * - XST_FAILURE if the injected fault is not correctly detected or
293 * the Control Base Address is Zero when ECC is enabled.
296 * If the BRAM device is not present in the
297 * hardware a bus error could be generated. Other indicators of a
298 * bus error, such as registers in bridges or buses, may be
299 * necessary to determine if this function caused a bus error.
303 ******************************************************************************/
304 int XBram_SelfTest(XBram *InstancePtr, u8 IntMask)
306 Xil_AssertNonvoid(InstancePtr != NULL);
307 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
311 if (InstancePtr->Config.EccPresent == 0) {
312 return (XST_SUCCESS);
315 if (InstancePtr->Config.CtrlBaseAddress == 0) {
316 return (XST_SUCCESS);
320 * Only 32-bit data width is supported as of yet. 64-bit and 128-bit
321 * widths will be supported in future.
323 if (InstancePtr->Config.DataWidth != 32)
324 return (XST_SUCCESS);
327 * Read from the implemented readable registers in the hardware device.
329 if (InstancePtr->Config.CorrectableFailingRegisters) {
330 (void) RD(CE_FFA_0_OFFSET);
332 if (InstancePtr->Config.CorrectableFailingDataRegs) {
333 (void) RD(CE_FFD_0_OFFSET);
334 (void) RD(CE_FFE_0_OFFSET);
336 if (InstancePtr->Config.UncorrectableFailingRegisters) {
337 (void) RD(UE_FFA_0_OFFSET);
339 if (InstancePtr->Config.UncorrectableFailingDataRegs) {
340 (void) RD(UE_FFD_0_OFFSET);
341 (void) RD(UE_FFE_0_OFFSET);
345 * Write and read the implemented read/write registers in the hardware
348 if (InstancePtr->Config.EccStatusInterruptPresent) {
349 WR(ECC_EN_IRQ_OFFSET, 0);
350 if (RD(ECC_EN_IRQ_OFFSET) != 0) {
351 return (XST_FAILURE);
355 if (InstancePtr->Config.CorrectableCounterBits > 0) {
358 /* Calculate counter max value */
359 if (InstancePtr->Config.CorrectableCounterBits == 32) {
363 InstancePtr->Config.CorrectableCounterBits) - 1;
366 WR(CE_CNT_OFFSET, Value);
367 if (RD(CE_CNT_OFFSET) != Value) {
368 return (XST_FAILURE);
371 WR(CE_CNT_OFFSET, 0);
372 if (RD(CE_CNT_OFFSET) != 0) {
373 return (XST_FAILURE);
378 * If fault injection is implemented, inject all possible single-bit
379 * and double-bit errors, and check all observable effects.
381 if (InstancePtr->Config.FaultInjectionPresent &&
382 InstancePtr->Config.WriteAccess != 0) {
384 const u32 Addr[2] = {InstancePtr->Config.MemBaseAddress &
386 InstancePtr->Config.MemHighAddress &
391 u32 CounterValue = 0;
394 int Result = XST_SUCCESS;
399 PrngResult = 42; /* Random seed */
401 /* Save two words in BRAM used for test */
402 SavedWords[0] = XBram_In32(Addr[0]);
403 SavedWords[1] = XBram_In32(Addr[1]);
405 for (Width = 1; Width <= 4; Width <<= 1) {
406 /* Calculate counter max value */
407 if (InstancePtr->Config.CorrectableCounterBits == 32) {
408 CounterMax = 0xFFFFFFFF;
411 InstancePtr->Config.CorrectableCounterBits) - 1;
414 /* Inject and check all single bit errors */
415 for (Index1 = 0; Index1 < TOTAL_BITS; Index1++) {
416 /* Save counter value */
417 if (InstancePtr->Config.CorrectableCounterBits > 0) {
418 CounterValue = RD(CE_CNT_OFFSET);
421 /* Inject single bit error */
422 InjectErrors(InstancePtr, Addr[WordIndex], Index1,
423 Index1, Width, &ActualData, &ActualEcc);
425 /* Check that CE is set */
426 if (InstancePtr->Config.EccStatusInterruptPresent) {
427 CHECK(ECC_STATUS_OFFSET,
428 XBRAM_IR_CE_MASK, Result);
431 /* Check that address, data, ECC are correct */
432 if (InstancePtr->Config.CorrectableFailingRegisters) {
433 CHECK(CE_FFA_0_OFFSET, Addr[WordIndex], Result);
435 /* Checks are only for LMB BRAM */
436 if (InstancePtr->Config.CorrectableFailingDataRegs) {
437 CHECK(CE_FFD_0_OFFSET, ActualData, Result);
438 CHECK(CE_FFE_0_OFFSET, ActualEcc, Result);
441 /* Check that counter has incremented */
442 if (InstancePtr->Config.CorrectableCounterBits > 0 &&
443 CounterValue < CounterMax) {
445 CounterValue + 1, Result);
448 /* Restore correct data in the used word */
449 XBram_Out32(Addr[WordIndex], SavedWords[WordIndex]);
451 /* Allow interrupts to occur */
452 /* Clear status register */
453 if (InstancePtr->Config.EccStatusInterruptPresent) {
454 WR(ECC_EN_IRQ_OFFSET, IntMask);
455 WR(ECC_STATUS_OFFSET, XBRAM_IR_ALL_MASK);
456 WR(ECC_EN_IRQ_OFFSET, 0);
459 /* Switch to the other word */
460 WordIndex = WordIndex ^ 1;
462 if (Result != XST_SUCCESS) break;
466 if (Result != XST_SUCCESS) {
470 for (Index1 = 0; Index1 < TOTAL_BITS; Index1++) {
471 for (Index2 = 0; Index2 < TOTAL_BITS; Index2++) {
472 if (Index1 != Index2) {
473 /* Inject double bit error */
474 InjectErrors(InstancePtr,
476 Index1, Index2, Width,
480 /* Check that UE is set */
481 if (InstancePtr->Config.
482 EccStatusInterruptPresent) {
483 CHECK(ECC_STATUS_OFFSET,
488 /* Check that address, data, ECC are correct */
489 if (InstancePtr->Config.
490 UncorrectableFailingRegisters) {
491 CHECK(UE_FFA_0_OFFSET, Addr[WordIndex],
493 CHECK(UE_FFD_0_OFFSET,
495 CHECK(UE_FFE_0_OFFSET, ActualEcc,
499 /* Restore correct data in the used word */
500 XBram_Out32(Addr[WordIndex],
501 SavedWords[WordIndex]);
503 /* Allow interrupts to occur */
504 /* Clear status register */
505 if (InstancePtr->Config.
506 EccStatusInterruptPresent) {
507 WR(ECC_EN_IRQ_OFFSET, IntMask);
508 WR(ECC_STATUS_OFFSET,
510 WR(ECC_EN_IRQ_OFFSET, 0);
513 /* Switch to the other word */
514 WordIndex = WordIndex ^ 1;
516 if (Result != XST_SUCCESS) break;
518 if (Result != XST_SUCCESS) break;
521 /* Check saturation of correctable error counter */
522 if (InstancePtr->Config.CorrectableCounterBits > 0 &&
523 Result == XST_SUCCESS) {
525 WR(CE_CNT_OFFSET, CounterMax);
527 InjectErrors(InstancePtr, Addr[WordIndex], 0, 0,
528 4, &ActualData, &ActualEcc);
530 CHECK(CE_CNT_OFFSET, CounterMax, Result);
533 /* Restore the two words used for test */
534 XBram_Out32(Addr[0], SavedWords[0]);
535 XBram_Out32(Addr[1], SavedWords[1]);
537 /* Clear the Status Register. */
538 if (InstancePtr->Config.EccStatusInterruptPresent) {
539 WR(ECC_STATUS_OFFSET, XBRAM_IR_ALL_MASK);
542 /* Set Correctable Counter to zero */
543 if (InstancePtr->Config.CorrectableCounterBits > 0) {
544 WR(CE_CNT_OFFSET, 0);
547 if (Result != XST_SUCCESS) break;
554 return (XST_SUCCESS);