/** * Inject errors using the hardware fault injection functionality, and write * random data and read it back using the indicated location. * * @param InstancePtr is a pointer to the XBram instance to * be worked on. * @param The Addr is the indicated memory location to use * @param The Index1 is the bit location of the first injected error * @param The Index2 is the bit location of the second injected error * @param The ActualData is filled in with expected data for checking * @param The ActualEcc is filled in with expected ECC for checking * * @return None * * @note None. * ******************************************************************************/ static void InjectErrors(XBram * InstancePtr, u32 Addr, int Index1, int Index2, u32 *ActualData, u32 *ActualEcc) { u32 InjectedData = 0; u32 InjectedEcc = 0; u32 RandomData = PrngData(&PrngResult); if (Index1 < 32) { InjectedData = 1 << Index1; } else { InjectedEcc = 1 << (Index1 - 32); } if (Index2 < 32) { InjectedData |= (1 << Index2); } else { InjectedEcc |= 1 << (Index2 - 32); } WR(FI_D_0_OFFSET, InjectedData); WR(FI_ECC_0_OFFSET, InjectedEcc); XBram_Out32(Addr, RandomData); (void) XBram_In32(Addr); *ActualData = InjectedData ^ RandomData; *ActualEcc = InjectedEcc ^ CalculateEcc(RandomData); }
/** * * This function ensures that ECC in the BRAM is initialized if no hardware * initialization is available. The ECC bits are initialized by reading and * writing data in the memory. This code is not optimized to only read data * in initialized sections of the BRAM. * * @param ConfigPtr is a reference to a structure containing information * about a specific BRAM device. * @param EffectiveAddr is the device base address in the virtual memory * address space. * * @return * None * * @note None. * *****************************************************************************/ void InitializeECC(XBram_Config *ConfigPtr, u32 EffectiveAddr) { u32 Addr; volatile u32 Data; if (ConfigPtr->EccPresent && ConfigPtr->EccOnOffRegister && ConfigPtr->EccOnOffResetValue == 0 && ConfigPtr->WriteAccess != 0) { for (Addr = ConfigPtr->MemBaseAddress; Addr < ConfigPtr->MemHighAddress; Addr+=4) { Data = XBram_In32(Addr); XBram_Out32(Addr, Data); } XBram_WriteReg(EffectiveAddr, XBRAM_ECC_ON_OFF_OFFSET, 1); } }
/** * Inject errors using the hardware fault injection functionality, and write * random data and read it back using the indicated location. * * @param InstancePtr is a pointer to the XBram instance to * be worked on. * @param The Addr is the indicated memory location to use * @param The Index1 is the bit location of the first injected error * @param The Index2 is the bit location of the second injected error * @param The Width is the data byte width * @param The ActualData is filled in with expected data for checking * @param The ActualEcc is filled in with expected ECC for checking * * @return None * * @note None. * ******************************************************************************/ static void InjectErrors(XBram * InstancePtr, u32 Addr, int Index1, int Index2, int Width, u32 *ActualData, u32 *ActualEcc) { u32 InjectedData = 0; u32 InjectedEcc = 0; u32 RandomData = PrngData(&PrngResult); if (Index1 < 32) { InjectedData = 1 << Index1; } else { InjectedEcc = 1 << (Index1 - 32); } if (Index2 < 32) { InjectedData |= (1 << Index2); } else { InjectedEcc |= 1 << (Index2 - 32); } WR(FI_D_0_OFFSET, InjectedData); WR(FI_ECC_0_OFFSET, InjectedEcc); XBram_Out32(Addr, RandomData); Xil_DCacheFlushRange(Addr, 4); switch (Width) { case 1: /* Byte - Write to do Read-Modify-Write */ XBram_Out8(Addr, PrngData(&PrngResult) & 0xFF); break; case 2: /* Halfword - Write to do Read-Modify-Write */ XBram_Out16(Addr, PrngData(&PrngResult) & 0xFFFF); break; case 4: /* Word - Read */ (void) XBram_In32(Addr); break; } *ActualData = InjectedData ^ RandomData; *ActualEcc = InjectedEcc ^ CalculateEcc(RandomData); }
/** * Run a self-test on the driver/device. Unless fault injection is implemented * in hardware, this function only does a minimal test in which available * registers (if any) are written and read. * * With fault injection, all possible single-bit and double-bit errors are * injected, and checked to the extent possible, given the implemented hardware. * * @param InstancePtr is a pointer to the XBram instance. * * @return XST_SUCCESS unless fault injection is implemented and an * injected fault is not correctly detected. * * If the BRAM device is not present in the * hardware a bus error could be generated. Other indicators of a * bus error, such as registers in bridges or buses, may be * necessary to determine if this function caused a bus error. * * @note None. * ******************************************************************************/ int XBram_SelfTest(XBram *InstancePtr) { Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); if (InstancePtr->Config.CtrlBaseAddress == 0) return (XST_SUCCESS); /* * Only 32-bit data width is supported as of yet. 64-bit and 128-bit * widths will be supported in future. */ if (InstancePtr->Config.DataWidth != 32) return (XST_SUCCESS); /* * Read from the implemented readable registers in the hardware device. */ if (InstancePtr->Config.CorrectableFailingRegisters) { (void) RD(CE_FFA_0_OFFSET); (void) RD(CE_FFD_0_OFFSET); (void) RD(CE_FFE_0_OFFSET); } if (InstancePtr->Config.UncorrectableFailingRegisters) { (void) RD(UE_FFA_0_OFFSET); (void) RD(UE_FFD_0_OFFSET); (void) RD(UE_FFE_0_OFFSET); } /* * Write and read the implemented read/write registers in the hardware * device. */ if (InstancePtr->Config.EccStatusInterruptPresent) { WR(ECC_EN_IRQ_OFFSET, 0); if (RD(ECC_EN_IRQ_OFFSET) != 0) { return (XST_FAILURE); } } if (InstancePtr->Config.CorrectableCounterBits > 0) { u32 Value; /* Calculate counter max value */ if (InstancePtr->Config.CorrectableCounterBits == 32) { Value = 0xFFFFFFFF; } else { Value = (1 << InstancePtr->Config.CorrectableCounterBits) - 1; } WR(CE_CNT_OFFSET, 0xFFFFFFFF); if (RD(CE_CNT_OFFSET) != Value) { return (XST_FAILURE); } WR(CE_CNT_OFFSET, 0); if (RD(CE_CNT_OFFSET) != 0) { return (XST_FAILURE); } } /* * If fault injection is implemented, inject all possible single-bit * and double-bit errors, and check all observable effects. */ if (InstancePtr->Config.FaultInjectionPresent && InstancePtr->Config.WriteAccess != 0) { const u32 Addr[2] = {InstancePtr->Config.MemBaseAddress & 0xfffffffc, InstancePtr->Config.MemHighAddress & 0xfffffffc }; u32 SavedWords[2]; u32 ActualData; u32 ActualEcc; u32 CounterValue; u32 CounterMax; int WordIndex = 0; int Result = XST_SUCCESS; int Index1; int Index2; PrngResult = 42; /* Random seed */ /* Save two words in BRAM used for test */ SavedWords[0] = XBram_In32(Addr[0]); SavedWords[1] = XBram_In32(Addr[1]); /* Calculate counter max value */ if (InstancePtr->Config.CorrectableCounterBits == 32) { CounterMax = 0xFFFFFFFF; } else { CounterMax =(1 << InstancePtr->Config.CorrectableCounterBits) - 1; } /* Inject and check all single bit errors */ for (Index1 = 0; Index1 < TOTAL_BITS; Index1++) { /* Save counter value */ if (InstancePtr->Config.CorrectableCounterBits > 0) { CounterValue = RD(CE_CNT_OFFSET); } /* Inject single bit error */ InjectErrors(InstancePtr, Addr[WordIndex], Index1, Index1, &ActualData, &ActualEcc); /* Check that CE is set */ if (InstancePtr->Config.EccStatusInterruptPresent) { CHECK(ECC_STATUS_OFFSET, XBRAM_IR_CE_MASK, Result); } /* Check that address, data, ECC are correct */ if (InstancePtr->Config.CorrectableFailingRegisters) { CHECK(CE_FFA_0_OFFSET, Addr[WordIndex], Result); #if 0 /* * The following 2 registers are not implemented * in the current version of the axi_bram_ctrl. * This is a common driver for axi_bram_ctrl and * lmb_bram_if_cntlr. */ CHECK(CE_FFD_0_OFFSET, ActualData, Result); CHECK(CE_FFE_0_OFFSET, ActualEcc, Result); #endif } /* Check that counter has incremented */ if (InstancePtr->Config.CorrectableCounterBits > 0 && CounterValue < CounterMax) { CHECK(CE_CNT_OFFSET, CounterValue + 1, Result); } /* Restore correct data in the used word */ XBram_Out32(Addr[WordIndex], SavedWords[WordIndex]); /* Clear status register */ if (InstancePtr->Config.EccStatusInterruptPresent) { WR(ECC_STATUS_OFFSET, XBRAM_IR_ALL_MASK); } /* Switch to the other word */ WordIndex = WordIndex ^ 1; if (Result != XST_SUCCESS) break; } if (Result != XST_SUCCESS) { return XST_FAILURE; } for (Index1 = 0; Index1 < TOTAL_BITS; Index1++) { for (Index2 = 0; Index2 < TOTAL_BITS; Index2++) { if (Index1 != Index2) { /* Inject double bit error */ InjectErrors(InstancePtr, Addr[WordIndex], Index1, Index2, &ActualData, &ActualEcc); /* Check that UE is set */ if (InstancePtr->Config. EccStatusInterruptPresent) { CHECK(ECC_STATUS_OFFSET, XBRAM_IR_UE_MASK, Result); } /* Check that address, data, ECC are correct */ if (InstancePtr->Config. UncorrectableFailingRegisters) { CHECK(UE_FFA_0_OFFSET, Addr[WordIndex], Result); CHECK(UE_FFD_0_OFFSET, ActualData, Result); CHECK(UE_FFE_0_OFFSET, ActualEcc, Result); } /* Restore correct data in the used word */ XBram_Out32(Addr[WordIndex], SavedWords[WordIndex]); /* Clear status register */ if (InstancePtr->Config. EccStatusInterruptPresent) { WR(ECC_STATUS_OFFSET, XBRAM_IR_ALL_MASK); } /* Switch to the other word */ WordIndex = WordIndex ^ 1; } if (Result != XST_SUCCESS) break; } if (Result != XST_SUCCESS) break; } /* Check saturation of correctable error counter */ if (InstancePtr->Config.CorrectableCounterBits > 0 && Result == XST_SUCCESS) { WR(CE_CNT_OFFSET, CounterMax); InjectErrors(InstancePtr, Addr[WordIndex], 0, 0, &ActualData, &ActualEcc); CHECK(CE_CNT_OFFSET, CounterMax, Result); } /* Restore the two words used for test */ XBram_Out32(Addr[0], SavedWords[0]); XBram_Out32(Addr[1], SavedWords[1]); /* Clear the Status Register. */ if (InstancePtr->Config.EccStatusInterruptPresent) { WR(ECC_STATUS_OFFSET, XBRAM_IR_ALL_MASK); } /* Set Correctable Counter to zero */ if (InstancePtr->Config.CorrectableCounterBits > 0) { WR(CE_CNT_OFFSET, 0); } return (Result); } return (XST_SUCCESS); }