]> git.sur5r.net Git - freertos/blob
a812c329924b09b99191a1180b55757b4f18db62
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2011 - 2014 Xilinx, Inc.  All rights reserved.
4 *
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:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
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.
18 *
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
25 * SOFTWARE.
26 *
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.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 * @file xbram_selftest.c
35 *
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.
40 * Temp change
41 *
42 * @note
43 *
44 * None
45 *
46 * <pre>
47 * MODIFICATION HISTORY:
48 *
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
60 *                      for CR 635655
61 *                      Updated to check CorrectableFailingDataRegs in the case
62 *                      of LMB BRAM.
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)
66 * </pre>
67 *****************************************************************************/
68
69 /***************************** Include Files ********************************/
70 #include "xbram.h"
71 #include "xil_cache.h"
72 /************************** Constant Definitions ****************************/
73 #define TOTAL_BITS      39
74
75 /**************************** Type Definitions ******************************/
76
77 /***************** Macros (Inline Functions) Definitions ********************/
78 #define RD(reg)         XBram_ReadReg(InstancePtr->Config.CtrlBaseAddress, \
79                                         XBRAM_ ## reg)
80 #define WR(reg, data)   XBram_WriteReg(InstancePtr->Config.CtrlBaseAddress, \
81                                                 XBRAM_ ## reg, data)
82
83 #define CHECK(reg, data, result) if (result!=XST_SUCCESS || RD(reg)!=data) \
84                                                 result = XST_FAILURE;
85
86 /************************** Variable Definitions ****************************/
87 static u32 PrngResult;
88
89 /************************** Function Prototypes *****************************/
90 static inline u32 PrngData(u32 *PrngResult);
91
92 static inline u32 CalculateEcc(u32 Data);
93
94 static void InjectErrors(XBram * InstancePtr, u32 Addr,
95                          int Index1, int Index2, int Width,
96                          u32 *ActualData, u32 *ActualEcc);
97
98
99 /*****************************************************************************/
100 /**
101 * Generate a pseudo random number.
102 *
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.
106 *
107 * @return       The generated pseudo random number
108 *
109 * @note         None.
110 *
111 ******************************************************************************/
112 static inline u32 PrngData(u32 *PrngResult)
113 {
114         *PrngResult = *PrngResult * 0x77D15E25 + 0x3617C161;
115         return *PrngResult;
116 }
117
118
119 /*****************************************************************************/
120 /**
121 * Calculate ECC from Data.
122 *
123 * @param        The Data Value
124 *
125 * @return       The calculated ECC
126 *
127 * @note         None.
128 *
129 ******************************************************************************/
130 static inline u32 CalculateEcc(u32 Data)
131 {
132         unsigned char c[7], d[32];
133         u32 Result = 0;
134         int Index;
135
136         for (Index = 0; Index < 32; Index++) {
137                 d[31 - Index] = Data & 1;
138                 Data = Data >> 1;
139         }
140
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] ^
143                 d[28] ^ d[30];
144
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] ^
147                 d[28] ^ d[31];
148
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] ^
151                 d[30] ^ d[31];
152
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];
155
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];
158
159         c[5] = d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31];
160
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];
166
167         for (Index = 0; Index < 7; Index++) {
168                 Result = Result << 1;
169                 Result |= c[Index] & 1;
170         }
171
172         return Result;
173 }
174
175 /*****************************************************************************/
176 /**
177 * Get the expected actual data read in case of uncorrectable errors.
178 *
179 * @param        The injected data value including errors (if any)
180 * @param        The syndrome (calculated ecc ^ actual ecc read)
181 *
182 * @return       The actual data value read
183 *
184 * @note         None.
185 *
186 ******************************************************************************/
187 static inline u32 UncorrectableData(u32 Data, u8 Syndrome)
188 {
189         switch (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;
194
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;
200
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;
206
207                 case 0x31: return Data ^ 0x10000000;
208                 case 0x35: return Data ^ 0x00004000;
209                 case 0x39: return Data ^ 0x00200000;
210                 case 0x3d: return Data ^ 0x00000040;
211         }
212         return Data;
213 }
214
215 /*****************************************************************************/
216 /**
217 * Inject errors using the hardware fault injection functionality, and write
218 * random data and read it back using the indicated location.
219 *
220 * @param        InstancePtr is a pointer to the XBram instance to
221 *               be worked on.
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
228 *
229 * @return       None
230 *
231 * @note         None.
232 *
233 ******************************************************************************/
234 static void InjectErrors(XBram * InstancePtr, u32 Addr,
235                          int Index1, int Index2, int Width,
236                          u32 *ActualData, u32 *ActualEcc)
237 {
238         u32 InjectedData = 0;
239         u32 InjectedEcc = 0;
240         u32 RandomData = PrngData(&PrngResult);
241
242         if (Index1 < 32) {
243                 InjectedData = 1 << Index1;
244         } else {
245                 InjectedEcc = 1 << (Index1 - 32);
246         }
247
248         if (Index2 < 32) {
249                 InjectedData |= (1 << Index2);
250         } else {
251                 InjectedEcc |= 1 << (Index2 - 32);
252         }
253
254         WR(FI_D_0_OFFSET, InjectedData);
255         WR(FI_ECC_0_OFFSET, InjectedEcc);
256
257         XBram_Out32(Addr, RandomData);
258         Xil_DCacheFlushRange(Addr, 4);
259         switch (Width) {
260                 case 1: /* Byte - Write to do Read-Modify-Write */
261                         XBram_Out8(Addr, PrngData(&PrngResult) & 0xFF);
262                         break;
263                 case 2: /* Halfword - Write to do Read-Modify-Write */
264                         XBram_Out16(Addr, PrngData(&PrngResult) & 0xFFFF);
265                         break;
266                 case 4: /* Word - Read */
267                         (void) XBram_In32(Addr);
268                         break;
269         }
270         *ActualData = InjectedData ^ RandomData;
271         *ActualEcc  = InjectedEcc ^ CalculateEcc(RandomData);
272 }
273
274
275 /*****************************************************************************/
276 /**
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.
280 *
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.
283 *
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.
288 *
289 * @return
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.
294 *               .
295 *
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.
300 *
301 * @note         None.
302 *
303 ******************************************************************************/
304 int XBram_SelfTest(XBram *InstancePtr, u8 IntMask)
305 {
306         Xil_AssertNonvoid(InstancePtr != NULL);
307         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
308
309
310
311         if (InstancePtr->Config.EccPresent == 0) {
312                 return (XST_SUCCESS);
313         }
314
315         if (InstancePtr->Config.CtrlBaseAddress == 0) {
316                 return (XST_SUCCESS);
317         }
318
319         /*
320          * Only 32-bit data width is supported as of yet. 64-bit and 128-bit
321          * widths will be supported in future.
322          */
323         if (InstancePtr->Config.DataWidth != 32)
324                 return (XST_SUCCESS);
325
326         /*
327          * Read from the implemented readable registers in the hardware device.
328          */
329         if (InstancePtr->Config.CorrectableFailingRegisters) {
330                 (void) RD(CE_FFA_0_OFFSET);
331         }
332         if (InstancePtr->Config.CorrectableFailingDataRegs) {
333                 (void) RD(CE_FFD_0_OFFSET);
334                 (void) RD(CE_FFE_0_OFFSET);
335         }
336         if (InstancePtr->Config.UncorrectableFailingRegisters) {
337                 (void) RD(UE_FFA_0_OFFSET);
338         }
339         if (InstancePtr->Config.UncorrectableFailingDataRegs) {
340                 (void) RD(UE_FFD_0_OFFSET);
341                 (void) RD(UE_FFE_0_OFFSET);
342         }
343
344         /*
345          * Write and read the implemented read/write registers in the hardware
346          * device.
347          */
348         if (InstancePtr->Config.EccStatusInterruptPresent) {
349                 WR(ECC_EN_IRQ_OFFSET, 0);
350                 if (RD(ECC_EN_IRQ_OFFSET) != 0) {
351                         return (XST_FAILURE);
352                 }
353         }
354
355         if (InstancePtr->Config.CorrectableCounterBits > 0) {
356                 u32 Value;
357
358                 /* Calculate counter max value */
359                 if (InstancePtr->Config.CorrectableCounterBits == 32) {
360                         Value = 0xFFFFFFFF;
361                 } else {
362                         Value = (1 <<
363                                 InstancePtr->Config.CorrectableCounterBits) - 1;
364                  }
365
366                 WR(CE_CNT_OFFSET, Value);
367                 if (RD(CE_CNT_OFFSET) != Value) {
368                         return (XST_FAILURE);
369                 }
370
371                 WR(CE_CNT_OFFSET, 0);
372                 if (RD(CE_CNT_OFFSET) != 0) {
373                         return (XST_FAILURE);
374                 }
375         }
376
377         /*
378          * If fault injection is implemented, inject all possible single-bit
379          * and double-bit errors, and check all observable effects.
380          */
381         if (InstancePtr->Config.FaultInjectionPresent &&
382             InstancePtr->Config.WriteAccess != 0) {
383
384             const u32 Addr[2] = {InstancePtr->Config.MemBaseAddress &
385                                         0xfffffffc,
386                                  InstancePtr->Config.MemHighAddress &
387                                         0xfffffffc};
388             u32 SavedWords[2];
389             u32 ActualData;
390             u32 ActualEcc;
391             u32 CounterValue = 0;
392             u32 CounterMax;
393             int WordIndex = 0;
394             int Result = XST_SUCCESS;
395             int Index1;
396             int Index2;
397             int Width;
398
399             PrngResult = 42; /* Random seed */
400
401             /* Save two words in BRAM used for test */
402             SavedWords[0] = XBram_In32(Addr[0]);
403             SavedWords[1] = XBram_In32(Addr[1]);
404
405             for (Width = 1; Width <= 4; Width <<= 1) {
406                 /* Calculate counter max value */
407                 if (InstancePtr->Config.CorrectableCounterBits == 32) {
408                         CounterMax = 0xFFFFFFFF;
409                 } else {
410                         CounterMax =(1 <<
411                                 InstancePtr->Config.CorrectableCounterBits) - 1;
412                 }
413
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);
419                         }
420
421                         /* Inject single bit error */
422                         InjectErrors(InstancePtr, Addr[WordIndex], Index1,
423                                      Index1, Width, &ActualData, &ActualEcc);
424
425                         /* Check that CE is set */
426                         if (InstancePtr->Config.EccStatusInterruptPresent) {
427                                 CHECK(ECC_STATUS_OFFSET,
428                                         XBRAM_IR_CE_MASK, Result);
429                         }
430
431                         /* Check that address, data, ECC are correct */
432                         if (InstancePtr->Config.CorrectableFailingRegisters) {
433                                 CHECK(CE_FFA_0_OFFSET, Addr[WordIndex], Result);
434                         }
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);
439                         }
440
441                         /* Check that counter has incremented */
442                         if (InstancePtr->Config.CorrectableCounterBits > 0 &&
443                                 CounterValue < CounterMax) {
444                                         CHECK(CE_CNT_OFFSET,
445                                         CounterValue + 1, Result);
446                         }
447
448                         /* Restore correct data in the used word */
449                         XBram_Out32(Addr[WordIndex], SavedWords[WordIndex]);
450
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);
457                         }
458
459                         /* Switch to the other word */
460                         WordIndex = WordIndex ^ 1;
461
462                         if (Result != XST_SUCCESS) break;
463
464                 }
465
466                 if (Result != XST_SUCCESS) {
467                         return XST_FAILURE;
468                 }
469
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,
475                                         Addr[WordIndex],
476                                                 Index1, Index2, Width,
477                                                 &ActualData,
478                                                 &ActualEcc);
479
480                                 /* Check that UE is set */
481                                 if (InstancePtr->Config.
482                                     EccStatusInterruptPresent) {
483                                         CHECK(ECC_STATUS_OFFSET,
484                                         XBRAM_IR_UE_MASK,
485                                         Result);
486                                 }
487
488                                 /* Check that address, data, ECC are correct */
489                                 if (InstancePtr->Config.
490                                     UncorrectableFailingRegisters) {
491                                         CHECK(UE_FFA_0_OFFSET, Addr[WordIndex],
492                                                         Result);
493                                         CHECK(UE_FFD_0_OFFSET,
494                                                 ActualData, Result);
495                                         CHECK(UE_FFE_0_OFFSET, ActualEcc,
496                                                 Result);
497                                         }
498
499                                 /* Restore correct data in the used word */
500                                 XBram_Out32(Addr[WordIndex],
501                                                 SavedWords[WordIndex]);
502
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,
509                                                 XBRAM_IR_ALL_MASK);
510                                         WR(ECC_EN_IRQ_OFFSET, 0);
511                                 }
512
513                                 /* Switch to the other word */
514                                 WordIndex = WordIndex ^ 1;
515                             }
516                                 if (Result != XST_SUCCESS) break;
517                         }
518                         if (Result != XST_SUCCESS) break;
519                 }
520
521                 /* Check saturation of correctable error counter */
522                 if (InstancePtr->Config.CorrectableCounterBits > 0 &&
523                         Result == XST_SUCCESS) {
524
525                                 WR(CE_CNT_OFFSET, CounterMax);
526
527                                 InjectErrors(InstancePtr, Addr[WordIndex], 0, 0,
528                                         4, &ActualData, &ActualEcc);
529
530                                 CHECK(CE_CNT_OFFSET, CounterMax, Result);
531                 }
532
533                 /* Restore the two words used for test */
534                 XBram_Out32(Addr[0], SavedWords[0]);
535                 XBram_Out32(Addr[1], SavedWords[1]);
536
537                 /* Clear the Status Register. */
538                 if (InstancePtr->Config.EccStatusInterruptPresent) {
539                         WR(ECC_STATUS_OFFSET, XBRAM_IR_ALL_MASK);
540                 }
541
542                 /* Set Correctable Counter to zero */
543                 if (InstancePtr->Config.CorrectableCounterBits > 0) {
544                         WR(CE_CNT_OFFSET, 0);
545                 }
546
547                 if (Result != XST_SUCCESS) break;
548
549             } /* Width loop */
550
551             return (Result);
552         }
553
554         return (XST_SUCCESS);
555 }
556