/******************************************************************************* NAME $RCSfile: memSDRAM.c,v $ SUMMARY Memory Diagnostics for Crystal Beach DMA units VERSION $Revision: 1.24 $ UPDATE DATE $Date: 2010/05/28 06:39:50 $ PROGRAMMER $Author: small $ Copyright 2009 LSI Corporation. All Rights Reserved. DESCRIPTION: Contains the diagnostic functions for the register test and the interrupt test. MODIFICATION: 2010-01-13: Jim Tu REFERENCE: *******************************************************************************/ /*** INCLUDES ***/ #include #include //#include #include #include #include #include "commTypes.h" #include "commMEC.h" #include "commRpt.h" #include "commPattern.h" #include "commPRand.h" #include "commDebug.h" #include "dmaLib.h" #include "memLib.h" /*** CONSTANT DEFINATIONS ***/ #define MEM_RAM_DIAG_BYTEENABLES_TESTBYTES 8 //test bytes used in Byte_Enables algorithm #define MEM_TEST_FORWARD TRUE #define MEM_MARCH_FORWARD_CYCLE TRUE #define MEM_MARCH_BACKWORD_CYCLE FALSE /*** EXTERNAL REFERENCES ***/ extern UINT64 gMemDiagStartAddr; extern UINT64 gMemDiagRegionSize; extern UINT64 gMemDiagTOLMAddr; extern UINT64 gMemDiagTOHMAddr; extern UINT64 gMemDiagTSEGAddr; extern UINT64 gMemDiagTSEGSize; extern MEM_CHAN_CFG sysMemConfig[MEM_CONFIG_MAX_CHAN]; extern const UINT32 imcDevFuncTrans[4]; extern VOID memWriteIMCReg(UINT32 idxFunc, INT32 addrReg, INT32 length, UINT32 val); extern VOID memReadIMCReg(UINT32 idxFunc, INT32 addrReg, INT32 length, UINT32 *val); extern UINT32 memReadCMCICnt(VOID); /*** FORWARE REFERENCES ***/ LOCAL BOOLEAN memReadVerifyWriteRegion(MEM_CMD* pCmd); LOCAL BOOLEAN memWriteRegion(MEM_CMD* pCmd); LOCAL BOOLEAN memWriteRegionByDMA(MEM_CMD* pCmd); LOCAL BOOLEAN memVerifyRegion(MEM_CMD* pCmd); LOCAL VOID memDiagECC(MEM_ADDR* pMemAddr, UINT64 testPhyAddr, BYTE errorType); LOCAL VOID memECCShow(VOID); /*** GLOBAL DATA ***/ UINT8 gMCUEccErrIntCount; BOOLEAN gMCUErrIsrHadServiced; UINT32 gDimmEccCountUpbound = 1; /*** LOCAL DATA ***/ /* Each Channel just implement one Dimm, so the MC_COR_ECC_CNT_0, MC_COR_ECC_CNT_2, MC_COR_ECC_CNT_4 will be used, Jay */ const UINT32 mcECCCnt[4] = { MEM_IMC_COR_ECC_CNT_0, MEM_IMC_COR_ECC_CNT_1, MEM_IMC_COR_ECC_CNT_2 }; static UINT32 eccSingleBitErrorMask[] = { 0x00000001, 0x00000100, 0x00010000, 0x01000000}; static UINT32 eccMultiBitErrorMask[] = { 0x00010001, 0x00100010, 0x01000100, 0x10001000}; const UINT8 mcDIL[MEM_CONFIG_MAX_CHAN] ={1,0,0}; const UINT8 mcTIL[MEM_CONFIG_MAX_CHAN] ={0,1,2}; /*** PROCEDURES ***/ /******************************************************************************* * PROCEDURE * * NAME: memDataLinesTest * SUMMARY: This procedure will test the data bus of the SDRAM * SCOPE: public * * DESCRIPTION: This test will write the data line pattern to memeory and read to verify * * RETURNS: * * NOTES: * */ PUBLIC VOID memDataLinesTest(UINT64 startAddr) { VOID* pTestBase; // The pointer of the base address of this test UINT64* pTestAddr; // The pointer of the testing address UINT32 idx; // The index of data line pattern UINT32 rptProcess; // The reported progress counter UINT32 curProcess; // The current progress counter /* print new patterns that user modifies */ printk("\n"); if(gMemDLPatternCnt == 1) printk("The pattern is 0x%x\n",gMemDLPattern[0]); else{ printk("The patterns are : \n"); for(idx=0 ;idx < gMemDLPatternCnt ;idx++) { printk("Pattern no.%u = 0x%x\n",idx+1,gMemDLPattern[idx]); } } printk("\n"); M_INIT_TEST_BASE(startAddr); M_MEM_RESET_PROGRESS(curProcess, rptProcess); //Get the virtual start address pTestBase = ioremap(startAddr, gMemDLPatternCnt * sizeof(UINT64)); if(pTestBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_DATALINES, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return; } //Write patterns to memory pTestAddr = (UINT64 *)pTestBase; for(idx = 0; idx < gMemDLPatternCnt; idx++) { *pTestAddr = (((UINT64)gMemDLPattern[idx] << 32) | gMemDLPattern[idx]); pTestAddr++; } M_MEM_REPORT_PROGRESS("Memory Data Line Test", curProcess, rptProcess, MEM_HALF_PROGRESS_UINT); pTestAddr = (UINT64 *)pTestBase; //Read the writed contern from memory and verify with patterns for(idx = 0; idx < gMemDLPatternCnt; idx++) { if(*pTestAddr != (((UINT64)gMemDLPattern[idx] << 32) | gMemDLPattern[idx])) { //Report Error commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_DATALINES, MEM_DIAG_ERROR_CODE_BAD_DL, MEM_DIAG_ERROR_MSG_BAD_DL, gMemDiagStartAddr + ((UINT64)pTestAddr - (UINT64)pTestBase), (((UINT64)gMemDLPattern[idx] << 32) | gMemDLPattern[idx]), *pTestAddr, DG_MEMORY_LL_FORMAT); } *pTestAddr = 0; pTestAddr++; } iounmap(pTestBase); M_MEM_REPORT_PROGRESS("Memory Data Line Test", curProcess, rptProcess, MEM_COMPLETE_PROGRESS_UINT); } /******************************************************************************* * PROCEDURE * * NAME: memAddressLinesTest * SUMMARY: This procedure will test the address bus of the SDRAM * SCOPE: public * * DESCRIPTION: This test will write the address value to the order 2 address location and read to verify * * RETURNS: * * NOTES: * */ PUBLIC VOID memAddressLinesTest(UINT64 startAddr, UINT64 sizeTest) { UINT8* pTestAddr; // The pointer of the testing address UINT8* pSubTestAddr; // The pointer of the testing address in the subset test UINT8 AddrLineMask; // The number of bits of the address line UINT64 addrOffset; // The offset to the testing address UINT64 addrSubOffset; // The offset to the testing address UINT8 idxTest; // The index of the test UINT8 idxSubTest; // The index of the subset test UINT32 rptProcess; // The reported progress counter UINT32 curProcess; // The current progress counter M_INIT_TEST_BASE(startAddr); M_INIT_TEST_REGION(startAddr, sizeTest); M_MEM_RESET_PROGRESS(curProcess, rptProcess); AddrLineMask = (startAddr + sizeTest) - 1; idxTest = 0; for(addrOffset = 0; ((startAddr + addrOffset) & AddrLineMask) != 0; addrOffset<<=1) { //Get the virtual start address pTestAddr = (UINT8 *)ioremap(startAddr + addrOffset, sizeof(UINT8)); if(pTestAddr == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ADDRESSLINES, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return; } //Write the address value to memory *pTestAddr = idxTest; idxTest++; //Free the virtual address space iounmap((VOID *)pTestAddr); //Move to the next testing memory location } M_MEM_REPORT_PROGRESS("Memory Address Line Test", curProcess, rptProcess, MEM_FIFTH_PROGRESS_UINT); idxTest = 0; for(addrOffset = 0; ((startAddr + addrOffset) & AddrLineMask) != 0; addrOffset<<=1) { pTestAddr = (UINT8 *)ioremap(startAddr + addrOffset, sizeof(UINT8)); if(pTestAddr == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ADDRESSLINES, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); iounmap((VOID *)pTestAddr); return; } if(*pTestAddr != idxTest) { //Report error commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ADDRESSLINES, MEM_DIAG_ERROR_CODE_BAD_AL, MEM_DIAG_ERROR_MSG_BAD_AL, gMemDiagStartAddr + addrOffset, idxTest, *pTestAddr, DG_MEMORY_LL_FORMAT); } *pTestAddr = (0xFF - idxTest); idxTest++; //Verify if the content on the following locations was affected idxSubTest = idxTest; for(addrSubOffset = addrOffset << 1; ((startAddr + addrSubOffset) & AddrLineMask) != 0; addrSubOffset<<=1) { //Move to the next testing location pSubTestAddr = (UINT8 *)ioremap(startAddr + addrSubOffset, sizeof(UINT8)); if(pSubTestAddr == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ADDRESSLINES, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return; } if(*pSubTestAddr != idxSubTest) { //Report error commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ADDRESSLINES, MEM_DIAG_ERROR_CODE_BAD_AL, MEM_DIAG_ERROR_MSG_BAD_AL, (INT64)gMemDiagStartAddr + addrSubOffset, (INT64)idxSubTest, (INT64)*pSubTestAddr, DG_MEMORY_LL_FORMAT); } iounmap((VOID *)pSubTestAddr); } iounmap((VOID *)pTestAddr); M_MEM_REPORT_PROGRESS("Memory Address Line Test", curProcess, rptProcess, (MEM_TOTAL_PROGRESS_UINT - MEM_FIFTH_PROGRESS_UINT) * (sizeTest / addrSubOffset)); } M_MEM_REPORT_PROGRESS("Memory Address Line Test", curProcess, rptProcess, MEM_COMPLETE_PROGRESS_UINT); } /******************************************************************************* * PROCEDURE * * NAME: memByteEnableTest * SUMMARY: This procedure will perform byte enable test on sdram * SCOPE: public * * DESCRIPTION: This test initialize two QWord memory space with the pre-defined pattern * and change the content byte by byte and verify the content of memory * * RETURNS: * * NOTES: * */ PUBLIC VOID memByteEnableTest(UINT64 startAddr) { VOID* pTestBase; // The pointer of the base address of this test volatile UINT64* pTestAddr; // The pointer of the testing address volatile UINT64* pMaskAddr; // The pointer of the mask volatile UINT8* pTestByte; // The pointer of the testing byte UINT32 totalTestQWords; // The number of QWord to be tested UINT32 idxByte; // The index of byte of the testing QWord UINT32 idxQWord; // The index of the testing QWord UINT64 testPattern; // The patter used to perform test UINT32 rptProcess; // The reported progress counter UINT32 curProcess; // The current progress counter /* print new patterns that user modifies */ printk("\n"); printk("The pattern is 0x%x\n",gMemDLPattern[0]); printk("\n"); M_INIT_TEST_BASE(startAddr); M_MEM_RESET_PROGRESS(curProcess, rptProcess); //Get the virtual start address pTestBase = ioremap(startAddr, MEM_RAM_DIAG_BYTEENABLES_TESTBYTES * 2); if(pTestBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_BYTEENABLE, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return; } pTestAddr = (UINT64 *)pTestBase; //After the test area, locate the next 64 bits memory for mask totalTestQWords = MEM_RAM_DIAG_BYTEENABLES_TESTBYTES / sizeof(UINT64); pMaskAddr = pTestAddr + totalTestQWords; testPattern = (((UINT64)gMemDLPattern[0] << 32) | gMemDLPattern[0]); //Repeat the test for each byte for(idxByte = 0; idxByte < MEM_RAM_DIAG_BYTEENABLES_TESTBYTES; idxByte++) { //Initial all test region as the given pattern for(idxQWord = 0; idxQWord < totalTestQWords; idxQWord++) { *(pTestAddr+idxQWord) = testPattern; } M_MEM_REPORT_PROGRESS("Memory Byte Enable Test", curProcess, rptProcess, MEM_QUANTER_PROGRESS_UINT / MEM_RAM_DIAG_BYTEENABLES_TESTBYTES); //Verify the pattern on all test region for(idxQWord = 0; idxQWord < totalTestQWords; idxQWord++) { if(*(pTestAddr+idxQWord) != testPattern) { //Report error commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_BYTEENABLE, MEM_DIAG_ERROR_CODE_BAD_BL, MEM_DIAG_ERROR_MSG_BAD_BL, startAddr + idxQWord * sizeof(UINT64), testPattern, *(pTestAddr+idxQWord), DG_MEMORY_LL_FORMAT); break; } } M_MEM_REPORT_PROGRESS("Memory Byte Enable Test", curProcess, rptProcess, MEM_QUANTER_PROGRESS_UINT / MEM_RAM_DIAG_BYTEENABLES_TESTBYTES); //Clear the byte monitored during this loop pTestByte = (UINT8 *)pTestAddr + idxByte; *pTestByte = 0; //Initial the mask region to all 0xFF for(idxQWord = 0; idxQWord < totalTestQWords; idxQWord++) { *(pMaskAddr+idxQWord) = 0xFFFFFFFFFFFFFFFFULL; } //Clear the byte monitored in the mask during this loop pTestByte = (UINT8 *)pMaskAddr + idxByte; *pTestByte = 0; //Verify whole test region, the only one byte has value 0x00 within the correct location for(idxQWord = 0; idxQWord < totalTestQWords; idxQWord++) { if( *(pTestAddr + idxQWord) != (testPattern & *(pMaskAddr + idxQWord)) ) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_BYTEENABLE, MEM_DIAG_ERROR_CODE_BAD_BL, MEM_DIAG_ERROR_MSG_BAD_BL, startAddr + idxQWord * sizeof(UINT64), (testPattern & *(pMaskAddr + idxQWord)), *(pTestAddr + idxQWord), DG_MEMORY_LL_FORMAT); break; } } M_MEM_REPORT_PROGRESS("Memory Byte Enable Test", curProcess, rptProcess, (MEM_TOTAL_PROGRESS_UINT - 2 * MEM_QUANTER_PROGRESS_UINT) / MEM_RAM_DIAG_BYTEENABLES_TESTBYTES); } iounmap(pTestBase); M_MEM_REPORT_PROGRESS("Memory Byte Enable Test", curProcess, rptProcess, MEM_COMPLETE_PROGRESS_UINT); } /******************************************************************************* * PROCEDURE * * NAME: memMarchCTest * SUMMARY: This procedure will perform the MarchC test on sdram * SCOPE: public * * DESCRIPTION: This test will wrire and verify memory in reverse order * * RETURNS: * * NOTES: * */ VOID memMarchCTest(UINT64 startAddr, UINT64 sizeTest, UINT8 loopTest) { UINT64 testPattern; UINT16 idxLoop; UINT32 rptProcess; // The reported progress counter UINT32 curProcess; // The current progress counter MEM_CMD cmd; M_INIT_TEST_BASE(startAddr); M_INIT_TEST_REGION(startAddr, sizeTest); M_INIT_TEST_LOOP(loopTest); M_MEM_RESET_PROGRESS(curProcess, rptProcess); /* print new patterns that user modifies */ printk("\n"); if(loopTest == 1) printk("The pattern is 0x%x\n",gMemDLPattern[0]); else{ printk("The patterns are : \n"); for(idxLoop=0 ;idxLoop < 6 ;idxLoop++) { printk("Pattern no.%u = 0x%x\n",idxLoop+1,gMemDLPattern[idxLoop]); } } printk("\n"); //Show corrected ECC count memECCShow(); for(idxLoop=0; idxLoop < loopTest; idxLoop++) { testPattern = (UINT64)gMemDLPattern[idxLoop] << 32 | gMemDLPattern[idxLoop]; //Indicate the progress //Fill the test area by the first pattern's inverse cmd.testItemCode = MEM_DIAG_ITEM_CODE_MARCHC; cmd.testAddr = startAddr; cmd.testSize = sizeTest; cmd.writePattern = ~testPattern; cmd.curProgress = &curProcess; cmd.rptProgress = &rptProcess; cmd.unitProgress = MEM_FIFTH_PROGRESS_UINT / loopTest; if(!memWriteRegionByDMA(&cmd)) { return; } //The 1st march will forward go through whole memory cmd.verifyPattern = ~testPattern; cmd.writePattern = testPattern; cmd.testForward = MEM_MARCH_FORWARD_CYCLE; if(!memReadVerifyWriteRegion(&cmd)) return; //The 2nd march will forward go through whole memory cmd.verifyPattern = testPattern; cmd.writePattern = ~testPattern; cmd.testForward = MEM_MARCH_FORWARD_CYCLE; if(!memReadVerifyWriteRegion(&cmd)) return; //The 3rd march will backward go through whole memory cmd.verifyPattern = ~testPattern; cmd.writePattern = testPattern; cmd.testForward = MEM_MARCH_BACKWORD_CYCLE; if(!memReadVerifyWriteRegion(&cmd)) return; //The 4th march will backward go through whole memory cmd.verifyPattern = testPattern; cmd.writePattern = ~testPattern; cmd.testForward = MEM_MARCH_BACKWORD_CYCLE; if(!memReadVerifyWriteRegion(&cmd)) return; //The 5th mach will forward go through whole memory to verify the last written pattern cmd.verifyPattern = ~testPattern; cmd.writePattern = 0; cmd.testForward = MEM_MARCH_FORWARD_CYCLE; if(!memReadVerifyWriteRegion(&cmd)) return; } M_MEM_REPORT_PROGRESS("Memory MarchC Test", curProcess, rptProcess, MEM_COMPLETE_PROGRESS_UINT); //Show corrected ECC count memECCShow(); } /******************************************************************************* * PROCEDURE * * NAME: memWordPatternsTest * SUMMARY: This procedure will perform the Work patterns test on sdram * SCOPE: public * * DESCRIPTION: This test will write different pattern to memory and verify * * RETURNS: * * NOTES: * */ VOID memWordPatternsTest(UINT64 startAddr, UINT64 sizeTest, UINT8 loopTest) { UINT16 idxLoop; UINT16 idxTest; UINT16 idxPattern; UINT32 rptProcess; // The reported progress counter UINT32 curProcess; // The current progress counter MEM_CMD cmd; /* print new patterns that user modifies */ printk("\n"); if(gMemDWPatternCnt == 1) printk("The pattern is 0x%x\n",gMemDWPattern[0]); else{ printk("The patterns are : \n"); for(idxLoop=0 ;idxLoop < gMemDWPatternCnt ;idxLoop++) { printk("Pattern no.%u = 0x%x\n",idxLoop+1,gMemDWPattern[idxLoop]); } } printk("\n"); M_INIT_TEST_BASE(startAddr); M_INIT_TEST_REGION(startAddr, sizeTest); M_INIT_TEST_LOOP(loopTest); M_MEM_RESET_PROGRESS(curProcess, rptProcess); //Show corrected ECC count memECCShow(); for(idxLoop = 0; idxLoop < loopTest; idxLoop++) { //Write the first pattern cmd.testItemCode = MEM_DIAG_ITEM_CODE_EXTENDPATTERNS; cmd.testAddr = startAddr; cmd.testSize = sizeTest; cmd.testForward = MEM_MARCH_FORWARD_CYCLE; cmd.writePattern = (UINT64)gMemDWPattern[idxLoop%gMemDWPatternCnt] << 32 | gMemDWPattern[idxLoop%gMemDWPatternCnt]; cmd.curProgress = &curProcess; cmd.rptProgress = &rptProcess; cmd.unitProgress = (MEM_TOTAL_PROGRESS_UINT / (2 * gMemDWPatternCnt + 1)) / loopTest; if(!memWriteRegion(&cmd)) return; for(idxTest = 0; idxTest < gMemDWPatternCnt; idxTest++) { idxPattern = (idxLoop + idxTest) % gMemDWPatternCnt; cmd.verifyPattern = (UINT64)gMemDWPattern[idxPattern] << 32 | gMemDWPattern[idxPattern]; cmd.writePattern = ~cmd.verifyPattern; cmd.testForward = MEM_MARCH_FORWARD_CYCLE; cmd.unitProgress = (MEM_TOTAL_PROGRESS_UINT / (2 * gMemDWPatternCnt + 1)) / loopTest; //Verify the last written pattern and write it's inverse if(!memReadVerifyWriteRegion(&cmd)) return; cmd.verifyPattern = cmd.writePattern; idxPattern = (idxPattern + 1) % gMemDWPatternCnt; cmd.writePattern = (UINT64)gMemDWPattern[idxPattern] << 32 | gMemDWPattern[idxPattern]; if( idxPattern != idxLoop) // if this is the last pattern { cmd.writePattern = (UINT64)gMemDWPattern[idxPattern] << 32 | gMemDWPattern[idxPattern]; } else //Set the writePattern to the next one { cmd.writePattern = 0; //Clean the whole memory region } //Verify the last pattern inverse and then write the next pattern or clean if(!memReadVerifyWriteRegion(&cmd)) return; } } M_MEM_REPORT_PROGRESS("Memory Word Pattern Test", curProcess, rptProcess, MEM_COMPLETE_PROGRESS_UINT); //Show corrected ECC count memECCShow(); } /******************************************************************************* * PROCEDURE * * NAME: memDMAOperatingTest * SUMMARY: This procedure will perform the DMA operation test on sdram * SCOPE: public * * DESCRIPTION: This test will use DMA to wrie memory and verify by the processor * * RETURNS: * * NOTES: * */ VOID memDMAOperatingTest(UINT64 startAddr, UINT64 sizeTest, UINT8 loopTest) { UINT16 idxLoop; UINT32 rptProcess; // The reported progress counter UINT32 curProcess; // The current progress counter MEM_CMD cmd; /* print new patterns that user modifies */ printk("\n"); printk("The pattern is 0x%x\n",gMemDWPattern[0]); printk("\n"); M_INIT_TEST_BASE(startAddr); M_INIT_TEST_REGION(startAddr, sizeTest); M_INIT_TEST_LOOP(loopTest); M_MEM_RESET_PROGRESS(curProcess, rptProcess); //Show corrected ECC count memECCShow(); for(idxLoop=0; idxLoop < loopTest; idxLoop++) { //Use ADMA to write the pattern cmd.testItemCode = MEM_DIAG_ITEM_CODE_ADMAOPERATION; cmd.testAddr = startAddr; cmd.testSize = sizeTest; cmd.writePattern = gMemDWPattern[idxLoop%gMemDWPatternCnt]; cmd.curProgress = &curProcess; cmd.rptProgress = &rptProcess; cmd.unitProgress = MEM_DMA_OPER_PROGRESS_UINT / loopTest; if(!memWriteRegionByDMA(&cmd)) return; //Verify the given pattern cmd.verifyPattern = (UINT64)gMemDWPattern[idxLoop%gMemDWPatternCnt] << 32 | gMemDWPattern[idxLoop%gMemDWPatternCnt]; cmd.testForward = MEM_MARCH_FORWARD_CYCLE; cmd.unitProgress = MEM_DMA_OPER_PROGRESS_UINT / loopTest; if(!memVerifyRegion(&cmd)) return; } M_MEM_REPORT_PROGRESS("Memory DMA Operation Test", curProcess, rptProcess, MEM_COMPLETE_PROGRESS_UINT); //Show corrected ECC count memECCShow(); } /******************************************************************************* * PROCEDURE * * NAME: memDMAOperatingTest * SUMMARY: This procedure will perform the pseudo random test on sdram * SCOPE: public * * DESCRIPTION: This test will use the pattern generated by pseudo random generator and verify * * RETURNS: * * NOTES: * */ VOID memPRandPatternsTest(UINT64 startAddr, UINT64 sizeTest, UINT8 loopTest) { UINT64 sizeUnTest; UINT64 sizeToTest; UINT64 curTestAddr; UINT64 totalRegion; UINT64 idxRegion; UINT32 idxLoop; UINT32 rptLoop; volatile UINT64* pRegionBase; volatile UINT64* pRegionTest; UINT64 valuePRand; UINT32 rptProcess; // The reported progress counter UINT32 curProcess; // The current progress counter M_INIT_TEST_BASE(startAddr); M_INIT_TEST_REGION(startAddr, sizeTest); M_INIT_TEST_LOOP(loopTest); M_MEM_RESET_PROGRESS(curProcess, rptProcess); //Show corrected ECC count memECCShow(); //Calculate how many MEM_RAM_IOREMAP_MAX_SIZE blocks to test //since the test_length might be bigger than the maximun limitation in ioremap totalRegion = sizeTest / MEM_RAM_IOREMAP_MAX_SIZE; sizeUnTest = sizeTest & ~(sizeof(UINT64) - 1); if((sizeTest % MEM_RAM_IOREMAP_MAX_SIZE) >= (sizeof(UINT64))) totalRegion++; rptLoop = totalRegion / (MEM_HALF_PROGRESS_UINT/loopTest); //Get the loop count for(idxLoop = 0; idxLoop < loopTest; idxLoop++) { //use the seed pattern to initialize the generator commPRNInitSeed(idxLoop); //Write pseudo-random patterns through out the tested memory region for(idxRegion = 0; idxRegion < totalRegion; idxRegion++) { //Calculate the test memory length for this test region ASSERT(sizeUnTest); if(sizeUnTest >= MEM_RAM_IOREMAP_MAX_SIZE) { sizeToTest = MEM_RAM_IOREMAP_MAX_SIZE; } else { sizeToTest = sizeUnTest; } //Calculate the starting address for this test region curTestAddr = startAddr + idxRegion * MEM_RAM_IOREMAP_MAX_SIZE; if ((gMemDiagTSEGAddr > 0) && (gMemDiagTSEGSize > 0) && ((curTestAddr + sizeToTest) >= gMemDiagTSEGAddr) && (curTestAddr < (gMemDiagTSEGAddr + gMemDiagTSEGSize))) { printk("Skip TSG zone %LX\n", curTestAddr); sizeUnTest-=sizeToTest; if(rptLoop-- == 0) { M_MEM_REPORT_PROGRESS("Memory Pseudo Random Pattern Test", curProcess, rptProcess, 1); rptLoop = totalRegion / (MEM_HALF_PROGRESS_UINT/loopTest); } continue; } if(curTestAddr >= gMemDiagTOLMAddr) { curTestAddr = MEM_JF_CORE_REG_TOHMH_START + curTestAddr - gMemDiagTOLMAddr; ASSERT(curTestAddr < gMemDiagTOHMAddr); } pRegionBase = (UINT64*)ioremap(curTestAddr, sizeToTest); if(pRegionBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_PSEUDORANDOMPATTERNS, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); break; } pRegionTest = pRegionBase; while((UINT64)pRegionTest < ((UINT64)pRegionBase + sizeToTest)) { *pRegionTest = commPRNGen64(); pRegionTest++; } iounmap((VOID *)pRegionBase); sizeUnTest-=sizeToTest; if(rptLoop-- == 0) { M_MEM_REPORT_PROGRESS("Memory Pseudo Random Pattern Test", curProcess, rptProcess, 1); rptLoop = totalRegion / (MEM_HALF_PROGRESS_UINT/loopTest); } } //use the seed pattern to initialize the generator commPRNSetCurrentSeed(idxLoop); sizeUnTest = sizeTest & ~(sizeof(UINT64) - 1); //Verify content of the whole tested memory region for(idxRegion = 0; idxRegion < totalRegion; idxRegion++) { //Calculate the test memory length for this test region ASSERT(sizeUnTest); if(sizeUnTest >= MEM_RAM_IOREMAP_MAX_SIZE) { sizeToTest = MEM_RAM_IOREMAP_MAX_SIZE; } else { sizeToTest = sizeUnTest; } //Calculate the starting address for this test region curTestAddr = startAddr + idxRegion * MEM_RAM_IOREMAP_MAX_SIZE; if ((gMemDiagTSEGAddr > 0) && (gMemDiagTSEGSize > 0) && ((curTestAddr + sizeToTest) >= gMemDiagTSEGAddr) && (curTestAddr < (gMemDiagTSEGAddr + gMemDiagTSEGSize))) { printk("Skip TSG zone %LX\n", curTestAddr); sizeUnTest-=sizeToTest; if(rptLoop-- == 0) { M_MEM_REPORT_PROGRESS("Memory Pseudo Random Pattern Test", curProcess, rptProcess, 1); rptLoop = totalRegion / (MEM_HALF_PROGRESS_UINT/loopTest); } continue; } if(curTestAddr >= gMemDiagTOLMAddr) { curTestAddr = MEM_JF_CORE_REG_TOHMH_START + curTestAddr - gMemDiagTOLMAddr; ASSERT(curTestAddr < gMemDiagTOHMAddr); } pRegionBase = (UINT64 *)ioremap(curTestAddr, sizeToTest); if(pRegionBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_PSEUDORANDOMPATTERNS, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); break; } pRegionTest = pRegionBase; while((UINT64)pRegionTest < ((UINT64)pRegionBase + sizeToTest)) { valuePRand = commPRNGen64(); if(*pRegionTest != valuePRand) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_PSEUDORANDOMPATTERNS, MEM_DIAG_ERROR_CODE_DATA_VERIFY_ERR, MEM_DIAG_ERROR_MSG_DATA_VERIFY_ERR, (INT64)curTestAddr + (UINT64)pRegionTest - (UINT64)pRegionBase, (INT64)valuePRand, (INT64)*pRegionTest, DG_MEMORY_WORD_FORMAT); } pRegionTest++; } iounmap((VOID *)pRegionBase); sizeUnTest-=sizeToTest; if(rptLoop-- == 0) { M_MEM_REPORT_PROGRESS("Memory Pseudo Random Pattern Test", curProcess, rptProcess, 1); rptLoop = totalRegion / (MEM_HALF_PROGRESS_UINT/loopTest); } } } M_MEM_REPORT_PROGRESS("Memory Pseudo Random Pattern Test", curProcess, rptProcess, MEM_COMPLETE_PROGRESS_UINT); //Show corrected ECC count memECCShow(); } /******************************************************************************* * PROCEDURE * * NAME: memECCTest * SUMMARY: This procedure will perform the pseudo random test on sdram * SCOPE: public * * DESCRIPTION: This test will use the pattern generated by pseudo random generator and verify * * RETURNS: * * NOTES: * */ VOID memECCTest(UINT64 startAddr, UINT64 sizeTest) { UINT8 idxChan; UINT8 testChan; UINT8 idxDimm; UINT8 idxRank; UINT8 idxTest; UINT32 rptProcess; // The reported progress counter UINT32 curProcess; // The current progress counter UINT64 curAddr; UINT8 iLChan; UINT64 iLSize; MEM_ADDR memAddr; MEM_CHAN_CFG* pChanCfg; M_INIT_TEST_BASE(startAddr); M_INIT_TEST_REGION(startAddr, sizeTest); M_MEM_RESET_PROGRESS(curProcess, rptProcess); iLChan = 0; iLSize = 0; for(idxChan = 0; idxChan < MEM_CONFIG_MAX_CHAN; idxChan++) { if(sysMemConfig[idxChan].enableChan) { pChanCfg = &sysMemConfig[idxChan]; if(iLSize == 0) { iLSize = pChanCfg->dimmCfg[0].numRank * pChanCfg->dimmCfg[0].sizeRank; } else { if(iLSize != pChanCfg->dimmCfg[0].numRank * pChanCfg->dimmCfg[0].sizeRank) { printk("Unsupported memory configuration\n"); return; } } if(iLChan > 0 && !sysMemConfig[iLChan - 1].enableChan) { printk("Unsupported memory configuration\n"); return; } iLChan++; } else { if(iLChan == 0) { printk("Unsupported memory configuration\n"); } break; } } for(idxChan = 0; idxChan < iLChan; idxChan++) { switch(iLChan) { case 1: testChan = idxChan; break; case 2: testChan = mcDIL[idxChan]; break; case 3: testChan = mcTIL[idxChan]; break; default: printk("Unsupported interleave topology\n"); ASSERT(0); } pChanCfg = &sysMemConfig[testChan]; for(idxDimm = 0; idxDimm < MEM_CONFIG_MAX_DIMM; idxDimm++) { for(idxRank = 0; idxRank < pChanCfg->dimmCfg[idxDimm].numRank; idxRank++) { for(idxTest = 0; idxTest < MEM_DIAG_ECC_CYCLE; idxTest++) { curAddr = (pChanCfg->dimmCfg[idxDimm].sizeRank / 4) * (idxTest + 1) * iLChan * pChanCfg->dimmCfg[idxDimm].numRank; curAddr += idxRank * iLChan * MEM_CHAN_INTL_SIZE; curAddr += idxChan * MEM_CACHE_LINE_SIZE; //printk("Channel%d_Dimm%d_NumRank%d curAddr = %Lx\n",idxChan ,idxDimm ,pChanCfg->dimmCfg[idxDimm].numRank,curAddr); //Jay if(curAddr >= gMemDiagTOLMAddr) { curAddr = MEM_JF_CORE_REG_TOHMH_START + curAddr - gMemDiagTOLMAddr; if(iLChan == MEM_CONFIG_MAX_CHAN) curAddr += (MEM_CONFIG_MAX_CHAN - 1 ) * MEM_CACHE_LINE_SIZE; } if(curAddr >= gMemDiagStartAddr) { memAddr.idxChan = testChan; memAddr.idxDimm = idxDimm; memAddr.idxRank = idxRank; memAddr.totalDimm = pChanCfg->totalDimm; // printk("Channel%d, Dimm%d, Rank%d, curAddr = %Lx\n",idxChan ,idxDimm ,idxRank, curAddr); //Jay //Single-Bit ECC tet memDiagECC(&memAddr, curAddr, MEM_DIAG_CORRECTABLE_ECC); //Multi-Bit ECC test memDiagECC(&memAddr, curAddr, MEM_DIAG_NONCORRECTABLE_ECC); } } } } } } /******************************************************************************* * PROCEDURE * * NAME: memReadVerifyWriteRegion * SUMMARY: This procedure will test the data line of the SDRAM * SCOPE: local * * DESCRIPTION: This test will perform PCI register test to those registers located on * stand PCI configuration space, Device-Specific PCI Configuration Space * and PCI Express Enhanced Configuration Space. Then this test diagnose * those memory-mapping registers. * * RETURNS: * * NOTES: * */ BOOLEAN memReadVerifyWriteRegion(MEM_CMD* pCmd) { UINT64 sizeUnTest; UINT64 sizeToTest; UINT64 curTestAddr; UINT64 totalRegion; UINT64 idxRegion; UINT32 rptLoop; UINT64* pRegionBase; UINT64* pRegionTest; char* msg; //Calculate how many MEM_RAM_IOREMAP_MAX_SIZE blocks to test totalRegion = pCmd->testSize / MEM_RAM_IOREMAP_MAX_SIZE; sizeUnTest = pCmd->testSize & ~(sizeof(UINT64) - 1); if((pCmd->testSize % MEM_RAM_IOREMAP_MAX_SIZE) >= (sizeof(UINT64))) totalRegion++; rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; for(idxRegion = 0; idxRegion < totalRegion; idxRegion++) { ASSERT(sizeUnTest); if(sizeUnTest >= MEM_RAM_IOREMAP_MAX_SIZE) { sizeToTest = MEM_RAM_IOREMAP_MAX_SIZE; } else { sizeToTest = sizeUnTest; } if(pCmd->testForward) { //Calculate the address of this block curTestAddr = pCmd->testAddr + idxRegion * MEM_RAM_IOREMAP_MAX_SIZE; if (((curTestAddr + sizeToTest) >= gMemDiagTSEGAddr) && (curTestAddr < (gMemDiagTSEGAddr + gMemDiagTSEGSize))) { printk("Skip TSG zone %LX\n", curTestAddr); sizeUnTest-=sizeToTest; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } continue; } if(curTestAddr >= gMemDiagTOLMAddr) { curTestAddr = MEM_JF_CORE_REG_TOHMH_START + curTestAddr - gMemDiagTOLMAddr; ASSERT(curTestAddr < gMemDiagTOHMAddr); ASSERT(curTestAddr >= MEM_JF_CORE_REG_TOHMH_START); } pRegionBase = (UINT64 *)ioremap(curTestAddr, sizeToTest); if(pRegionBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return FALSE; } pRegionTest = pRegionBase; while((UINT64)pRegionTest < ((UINT64)pRegionBase + sizeToTest)) { ASSERT((pRegionBase + sizeToTest - pRegionTest) >= sizeof(UINT64)) ; ASSERT(((UINT64)pRegionTest % sizeof(UINT64)) == 0); if(*pRegionTest != pCmd->verifyPattern) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_DATA_VERIFY_ERR, MEM_DIAG_ERROR_MSG_DATA_VERIFY_ERR, (INT64)(curTestAddr + (UINT64)pRegionTest - (UINT64)pRegionBase), (INT64)pCmd->verifyPattern, (INT64)*pRegionTest, DG_MEMORY_LL_FORMAT); iounmap((VOID *)pRegionBase); return FALSE; } *pRegionTest = pCmd->writePattern; pRegionTest++; } ASSERT((UINT64)pRegionTest == ((UINT64)pRegionBase + sizeToTest)); } else { curTestAddr = pCmd->testAddr + sizeUnTest - sizeToTest; if (((curTestAddr + sizeToTest) >= gMemDiagTSEGAddr) && (curTestAddr < gMemDiagTSEGAddr + gMemDiagTSEGSize)) { printk("Skip TSG zone %LX\n", curTestAddr); sizeUnTest-=sizeToTest; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } continue; } if(curTestAddr >= gMemDiagTOLMAddr) { curTestAddr = MEM_JF_CORE_REG_TOHMH_START + curTestAddr - gMemDiagTOLMAddr; ASSERT(curTestAddr < gMemDiagTOHMAddr); } pRegionBase = (UINT64 *)ioremap(curTestAddr, sizeToTest); if(pRegionBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return FALSE; } pRegionTest = (UINT64 *)((UINT64)pRegionBase + sizeToTest - sizeof(UINT64)); while(pRegionTest != pRegionBase) { ASSERT(((UINT64)pRegionTest % sizeof(UINT32)) == 0); if(*pRegionTest != pCmd->verifyPattern) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_DATA_VERIFY_ERR, MEM_DIAG_ERROR_MSG_DATA_VERIFY_ERR, (INT64)(curTestAddr + (UINT64)pRegionTest - (UINT64)pRegionBase), (INT64)pCmd->verifyPattern, (INT64)*pRegionTest, DG_MEMORY_LL_FORMAT); iounmap((VOID *)pRegionBase); return FALSE; } *pRegionTest = pCmd->writePattern; pRegionTest--; } ASSERT((UINT64)pRegionTest == (UINT64)pRegionBase); } iounmap((VOID *)pRegionBase); sizeUnTest-=sizeToTest; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } } return TRUE; } /******************************************************************************* * PROCEDURE * * NAME: memMarchCTest * SUMMARY: This procedure will test the data line of the SDRAM * SCOPE: public * * DESCRIPTION: This test will perform PCI register test to those registers located on * stand PCI configuration space, Device-Specific PCI Configuration Space * and PCI Express Enhanced Configuration Space. Then this test diagnose * those memory-mapping registers. * * RETURNS: * * NOTES: * */ LOCAL BOOLEAN memWriteRegion(MEM_CMD* pCmd) { UINT64 sizeUnWrite; UINT64 sizeToWrite; UINT64 curWriteAddr; UINT64 totalRegion; UINT64 idxRegion; UINT32 rptLoop; UINT64* pRegionBase; UINT64* pRegionWrite; char *msg; //Calculate how many MEM_RAM_IOREMAP_MAX_SIZE blocks to test //since the test_length might be bigger than the maximun limitation in ioremap totalRegion = pCmd->testSize / MEM_RAM_IOREMAP_MAX_SIZE; sizeUnWrite = pCmd->testSize & ~(sizeof(UINT64) - 1); if((pCmd->testSize % MEM_RAM_IOREMAP_MAX_SIZE) >= (sizeof(UINT64))) totalRegion++; rptLoop = (totalRegion + pCmd->unitProgress - 1)/ pCmd->unitProgress; for(idxRegion = 0; idxRegion < totalRegion; idxRegion++) { //Calculate the test memory length in this block ASSERT(sizeUnWrite); if(sizeUnWrite >= MEM_RAM_IOREMAP_MAX_SIZE) { sizeToWrite = MEM_RAM_IOREMAP_MAX_SIZE; } else { sizeToWrite = sizeUnWrite; } if(pCmd->testForward) { curWriteAddr = pCmd->testAddr + idxRegion * MEM_RAM_IOREMAP_MAX_SIZE; if (((curWriteAddr + sizeToWrite) >= gMemDiagTSEGAddr) && (curWriteAddr < (gMemDiagTSEGAddr + gMemDiagTSEGSize))) { printk("Skip TSG zone %LX\n", curWriteAddr); sizeUnWrite-=sizeToWrite; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } continue; } if(curWriteAddr >= gMemDiagTOLMAddr) { curWriteAddr = MEM_JF_CORE_REG_TOHMH_START + curWriteAddr - gMemDiagTOLMAddr; ASSERT(curWriteAddr < gMemDiagTOHMAddr); } pRegionBase = (UINT64 *)ioremap(curWriteAddr, sizeToWrite); if(pRegionBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return FALSE; } pRegionWrite = pRegionBase; while((UINT64)pRegionWrite < ((UINT64)pRegionBase + sizeToWrite)) { ASSERT((pRegionBase + sizeToWrite - pRegionWrite) >= sizeof(UINT64)) ; ASSERT(((UINT64)pRegionWrite % sizeof(UINT64)) == 0); *pRegionWrite = pCmd->writePattern; pRegionWrite++; } ASSERT((UINT64)pRegionWrite == ((UINT64)pRegionBase + sizeToWrite)); } else { curWriteAddr = pCmd->testAddr + sizeUnWrite - sizeToWrite; if (((curWriteAddr + sizeToWrite) >= gMemDiagTSEGAddr) && (curWriteAddr < (gMemDiagTSEGAddr + gMemDiagTSEGSize))) { printk("Skip TSG zone %LX\n", curWriteAddr); sizeUnWrite-=sizeToWrite; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } continue; } if(curWriteAddr >= gMemDiagTOLMAddr) { curWriteAddr = MEM_JF_CORE_REG_TOHMH_START + curWriteAddr - gMemDiagTOLMAddr; ASSERT(curWriteAddr < gMemDiagTOHMAddr); } pRegionBase = (UINT64 *)ioremap(curWriteAddr, sizeToWrite); if(pRegionBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return FALSE; } pRegionWrite = (UINT64 *)((UINT64)pRegionBase + sizeToWrite - sizeof(UINT64)); while(pRegionWrite != pRegionBase) { ASSERT(((UINT64)pRegionWrite % sizeof(UINT32)) == 0); *pRegionWrite = pCmd->writePattern; pRegionWrite--; } ASSERT((UINT64)pRegionWrite == (UINT64)pRegionBase); } iounmap((VOID *)pRegionBase); sizeUnWrite-=sizeToWrite; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } } return TRUE; } /******************************************************************************* * PROCEDURE * * NAME: memWriteRegionByDMA * SUMMARY: This procedure will test the data line of the SDRAM * SCOPE: public * * DESCRIPTION: This test will perform PCI register test to those registers located on * stand PCI configuration space, Device-Specific PCI Configuration Space * and PCI Express Enhanced Configuration Space. Then this test diagnose * those memory-mapping registers. * * RETURNS: * * NOTES: * */ LOCAL BOOLEAN memWriteRegionByDMA(MEM_CMD* pCmd) { UINT64 sizeUnWrite; UINT32 sizeToWrite; UINT64 curWriteAddr; UINT64 totalRegion; UINT64 idxRegion; UINT32 rptLoop; char *msg; //Calculate how many MEM_RAM_IOREMAP_MAX_SIZE blocks to test //since the test_length might be bigger than the maximun limitation in ioremap totalRegion = pCmd->testSize / MEM_RAM_IOREMAP_MAX_SIZE; sizeUnWrite = pCmd->testSize & ~(sizeof(UINT64) - 1); if((pCmd->testSize % MEM_RAM_IOREMAP_MAX_SIZE) >= (sizeof(UINT64))) totalRegion++; rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; for(idxRegion = 0; idxRegion < totalRegion; idxRegion++) { //Calculate the test memory length in this block ASSERT(sizeUnWrite); if(sizeUnWrite >= MEM_RAM_IOREMAP_MAX_SIZE) { sizeToWrite = MEM_RAM_IOREMAP_MAX_SIZE; } else { ASSERT(sizeUnWrite < 0xFFFFFFFF); sizeToWrite = (UINT32)(sizeUnWrite & 0x00000000FFFFFFFFULL); } curWriteAddr = pCmd->testAddr + idxRegion * MEM_RAM_IOREMAP_MAX_SIZE; if (((curWriteAddr + sizeToWrite) >= gMemDiagTSEGAddr) && (curWriteAddr < (gMemDiagTSEGAddr + gMemDiagTSEGSize))) { printk("Skip TSG zone %LX\n", curWriteAddr); sizeUnWrite-=sizeToWrite; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } continue; } if(curWriteAddr >= gMemDiagTOLMAddr) { curWriteAddr = MEM_JF_CORE_REG_TOHMH_START + curWriteAddr - gMemDiagTOLMAddr; ASSERT(curWriteAddr < gMemDiagTOHMAddr); } if(!dmaMemSet(curWriteAddr, sizeToWrite, pCmd->writePattern)) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_DMA_FAILED, MEM_DIAG_ERROR_MSG_DMA_FAILED, curWriteAddr, 0, 0, DG_FORMAT_NONE); return FALSE; } if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } } return TRUE; } /******************************************************************************* * PROCEDURE * * NAME: memVerifyRegion * SUMMARY: This procedure will test the data line of the SDRAM * SCOPE: public * * DESCRIPTION: This test will perform PCI register test to those registers located on * stand PCI configuration space, Device-Specific PCI Configuration Space * and PCI Express Enhanced Configuration Space. Then this test diagnose * those memory-mapping registers. * * RETURNS: * * NOTES: * */ LOCAL BOOLEAN memVerifyRegion(MEM_CMD* pCmd) { UINT64 sizeUnVerify; UINT64 sizeToVerify; UINT64 curVerifyAddr; UINT32 totalRegion; UINT32 idxRegion; UINT32 rptLoop; UINT64* pRegionBase; UINT64* pRegionVerify; char *msg; //Calculate how many MEM_RAM_IOREMAP_MAX_SIZE blocks to test //since the test_length might be bigger than the maximun limitation in ioremap totalRegion = pCmd->testSize / MEM_RAM_IOREMAP_MAX_SIZE; sizeUnVerify = pCmd->testSize & ~(sizeof(UINT64) - 1); if((pCmd->testSize % MEM_RAM_IOREMAP_MAX_SIZE) >= (sizeof(UINT64))) totalRegion++; rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; for(idxRegion = 0; idxRegion < totalRegion; idxRegion++) { //Calculate the test memory length in this block ASSERT(sizeUnVerify); if(sizeUnVerify >= MEM_RAM_IOREMAP_MAX_SIZE) { sizeToVerify = MEM_RAM_IOREMAP_MAX_SIZE; } else { sizeToVerify = sizeUnVerify; } if(pCmd->testForward) { curVerifyAddr = pCmd->testAddr + idxRegion * MEM_RAM_IOREMAP_MAX_SIZE; if (((curVerifyAddr + sizeToVerify) >= gMemDiagTSEGAddr) && (curVerifyAddr < (gMemDiagTSEGAddr + gMemDiagTSEGSize))) { printk("Skip TSG zone %LX\n", curVerifyAddr); sizeUnVerify-=sizeToVerify; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } continue; } if(curVerifyAddr >= gMemDiagTOLMAddr) { curVerifyAddr = MEM_JF_CORE_REG_TOHMH_START + curVerifyAddr - gMemDiagTOLMAddr; ASSERT(curVerifyAddr < gMemDiagTOHMAddr); } pRegionBase = (UINT64 *)ioremap(curVerifyAddr, sizeToVerify); if(pRegionBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return FALSE; } pRegionVerify = pRegionBase; while((UINT64)pRegionVerify < ((UINT64)pRegionBase + sizeToVerify)) { ASSERT((pRegionBase + sizeToVerify - pRegionVerify) >= sizeof(UINT64)) ; ASSERT(((UINT64)pRegionVerify % sizeof(UINT64)) == 0); if(*pRegionVerify != pCmd->verifyPattern) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_DATA_VERIFY_ERR, MEM_DIAG_ERROR_MSG_DATA_VERIFY_ERR, (INT64)curVerifyAddr, (INT64)pCmd->verifyPattern, (INT64)*((UINT64 *)pRegionVerify), DG_MEMORY_LL_FORMAT); iounmap((VOID *)pRegionBase); return FALSE; } pRegionVerify++; } ASSERT((UINT64)pRegionVerify == ((UINT64)pRegionBase + sizeToVerify)); } else { curVerifyAddr = pCmd->testAddr + sizeUnVerify - sizeToVerify; if (((curVerifyAddr + sizeToVerify) >= gMemDiagTSEGAddr) && (curVerifyAddr < (gMemDiagTSEGAddr + gMemDiagTSEGSize))) { printk("Skip TSG zone %LX\n", curVerifyAddr); sizeUnVerify-=sizeToVerify; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } continue; } if(curVerifyAddr >= gMemDiagTOLMAddr) { curVerifyAddr = MEM_JF_CORE_REG_TOHMH_START + curVerifyAddr - gMemDiagTOLMAddr; ASSERT(curVerifyAddr < gMemDiagTOHMAddr); } pRegionBase = (UINT64 *)ioremap(curVerifyAddr, sizeToVerify); if(pRegionBase == NULL) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return FALSE; } pRegionVerify = (UINT64 *)((UINT64)pRegionBase + sizeToVerify - sizeof(UINT64)); while(pRegionVerify != pRegionBase) { ASSERT(((UINT64)pRegionVerify % sizeof(UINT32)) == 0); if(*pRegionVerify != pCmd->verifyPattern) { commReportError(MEC_COMP_CODE_TEMP, pCmd->testItemCode, MEM_DIAG_ERROR_CODE_DATA_VERIFY_ERR, MEM_DIAG_ERROR_MSG_DATA_VERIFY_ERR, (INT64)curVerifyAddr, (INT64)pCmd->verifyPattern, (INT64)*((UINT32 *)pRegionVerify), DG_MEMORY_WORD_FORMAT); iounmap((VOID *)pRegionBase); return FALSE; } pRegionVerify--; } ASSERT((UINT64)pRegionVerify == (UINT64)pRegionBase); } iounmap((VOID *)pRegionBase); sizeUnVerify-=sizeToVerify; if(rptLoop-- == 0) { M_SET_REPORT_STRING(pCmd->testItemCode, msg); M_MEM_REPORT_PROGRESS(msg, *pCmd->curProgress, *pCmd->rptProgress, 1); rptLoop = (totalRegion + pCmd->unitProgress - 1) / pCmd->unitProgress; } } return TRUE; } /***************************************************************************** * Function Name: DMCUECCTest * Synopsis: * Description: This function will perform DDR2 SDRAM ECC test * * Input Parameters: * testPhyAddr * errorType * * Output Parameters: * None * * Returns: * MEM_DIAG_SUCCESS * MEM_DIAG_FAILED * * Globals: * Local * ****************************************************************************/ VOID memDiagECC(MEM_ADDR* pMemAddr, UINT64 testPhyAddr, BYTE errorType){ volatile UINT64* pTestAddr; volatile UINT8* pTest; volatile UINT8* pTemp; UINT8 idxTest; UINT32 addrECC = 0; UINT32 maskECC = 0; UINT32 injectECC = 0; UINT32 memLock; UINT32 errorCntOrig = 0; UINT32 errorCMCIOrig = 0; UINT32 errorCntTest = 0; UINT8 verifyECC = 0; UINT64 DATA_TEMP[2]; unsigned long flags; STATIC DEFINE_SPINLOCK(spin_lock); /* Read the Rank on channel[A,B,C] present, Jay */ UINT32 rank_num; memReadIMCReg(MEM_IMC_CHAN0_DEVICE_ID, 0x7c, sizeof(UINT32), &rank_num); if(rank_num != 0) { // There exits at least one rank on the Channel if(rank_num == 0x03) printk("Channel 0, Rank_present 0,1 \n"); if(rank_num == 0x0f) printk("Channel 0, Rank_present 0,1,2,3 \n"); } rank_num = 0; memReadIMCReg(MEM_IMC_CHAN1_DEVICE_ID, 0x7c, sizeof(UINT32), &rank_num); if(rank_num != 0) { // There exits at least one rank on the Channel if(rank_num == 0x03) printk("Channel 1, Rank_present 0,1 \n"); if(rank_num == 0x0f) printk("Channel 1, Rank_present 0,1,2,3 \n"); } rank_num = 0; memReadIMCReg(MEM_IMC_CHAN2_DEVICE_ID, 0x7c, sizeof(UINT32), &rank_num); if(rank_num != 0) { // There exits at least one rank on the Channel if(rank_num == 0x03) printk("Channel 2, Rank_present 0,1 \n"); if(rank_num == 0x0f) printk("Channel 2, Rank_present 0,1,2,3 \n"); } // while(1); /* Read the MEMLOCK_STATUS by using pci_conf1_read function, Jay */ memReadIMCReg(0x0, 0x88, sizeof(UINT16), &memLock); if(memLock & 0x1) { printk("IMC_MEM_CFG register locked\n"); printk("MEMLOCK_STATUS 0x%x\n", memLock); return; } else if(memLock & 0x2) { /* Locked, but can unlock by user, edit the register MC_CFG_CONTROL, Jay*/ memLock = 0x2; memWriteIMCReg(0x0, 0x90, sizeof(UINT16), memLock); memReadIMCReg(0x0, 0x88, sizeof(UINT16), &memLock); if(memLock & 0x2) { printk("IMC_MEM_CFG register locked\n"); printk("MEMLOCK_STATUS 0x%x\n", memLock); return; } } pTestAddr = (UINT64 *)ioremap(testPhyAddr, sizeof(UINT64)*2); //the write operation need 2 UNIT64 space(idxTest0~7 using the same address to write), Jay if(pTestAddr == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ECCTEST, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return; } pTest = (UINT8 *)pTestAddr; //pTemp = (UINT8 *)((UINT64)pTestAddr + sizeof(UINT64)); //never using this variable in this function. Jay pTemp = 0; //Jay, just to initialize. /* Flush L1/L2 cache */ spin_lock_irqsave(&spin_lock, flags); /************************************************************/ /* set MC_CHANNEL_0_ADDR_MATCH register */ /************************************************************/ //bit 36 is represent DIMM address for 1 or 2DPC. //For 3DPC, bits 36 and 35 represent the //DIMM address and bit 34 represent the RANK address. addrECC = 0; maskECC = 0; injectECC = 0; addrECC |= pMemAddr->idxRank << MEM_DIAG_ECC_RANK_BIT_SHIFT; addrECC |= pMemAddr->idxDimm << MEM_DIAG_ECC_DIMM_BIT_SHIFT; //mask bank, col and page bit addrECC |= MEM_DIAG_ECC_ADDR_MASK; /* The idxRank is uncorrect using here, Read the Intel Page 481 MC_COR_ECC_CNT_0 for detail information, Jay */ memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[pMemAddr->idxChan], // Fixed 0430, FIX ME, THE RANK gets some miss understand,Jay sizeof(UINT32), &errorCntOrig); errorCntOrig &= 0x80008000; // Fixed 0430, FIX ME, THE RANK gets some miss understand,Jay memWriteIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[pMemAddr->idxChan], // Fixed 0430, FIX ME, THE RANK gets some miss understand,Jay sizeof(UINT32), errorCntOrig); //for (idxTest = 0; idxTest < (sizeof(UINT64)/sizeof(UINT8)); idxTest++) idxTest = 0; /* Save the default value on memory */ DATA_TEMP[0] = *pTestAddr; DATA_TEMP[1] = *(pTestAddr+1); while(idxTest < (sizeof(UINT64)/sizeof(UINT8))) //the total number must be 8 times. to using upper 32B and lower 32B ECC injection per byte. Jay { /****************************************************/ /* Clear test address and get error counter */ /****************************************************/ *pTestAddr = 0; asm volatile("clflush %0" : "+m" (*(volatile char __force *)pTestAddr)); if (errorType == MEM_DIAG_CORRECTABLE_ECC) { memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[pMemAddr->idxChan], // Fixed 0430, FIX ME, THE RANK gets some miss understand,Jay sizeof(UINT32), &errorCntOrig); //jay printk("Default errorCntOrig = %x \n",errorCntOrig); //Jay, for test 20100430 /* Check the intel System Programming Guide volume 3A, chapter 15 for MSR, and volume 3B E.3.3 Jay*/ errorCMCIOrig = memReadCMCICnt(); //This is what the lecter called "solution".. ???, Jay //jay printk("Default errorCMCIOrig = %x \n",errorCMCIOrig); //Jay, for test 20100430 } /****************************************************/ /* Setup to write bad ECC into test address */ /****************************************************/ memWriteIMCReg(imcDevFuncTrans[pMemAddr->idxChan], MEM_MC_CHANNEL_ADDR_MATCH + sizeof(UINT32), //because offset 32bit, so the addrECC is correct descript before, Jay sizeof(UINT16), addrECC); if (errorType == MEM_DIAG_CORRECTABLE_ECC) { maskECC = eccSingleBitErrorMask[idxTest % (sizeof(UINT32)/sizeof(UINT8))]; } else { maskECC = eccMultiBitErrorMask[idxTest % (sizeof(UINT32)/sizeof(UINT8))]; //imcECCenable(); } if (idxTest < (sizeof(UINT32)/sizeof(UINT8))) //FIXED for maskECC select. Jay injectECC = MEM_DIAG_ECC_ECC_INJECT_LOWER; else injectECC = MEM_DIAG_ECC_ECC_INJECT_UPPER; memWriteIMCReg(imcDevFuncTrans[pMemAddr->idxChan], MEM_MC_CHANNEL_ECC_ERROR_MASK, sizeof(UINT32), maskECC); memWriteIMCReg(imcDevFuncTrans[pMemAddr->idxChan], MEM_MC_CHANNEL_ECC_ERROR_INJECT, sizeof(UINT32), injectECC); /****************************************************/ /* Write the error into memory */ /****************************************************/ *pTestAddr = 0; // write to memory to produce the ECC check error, 64bit data, Jay asm volatile("clflush %0" : "+m" (*(volatile char __force *)pTestAddr)); //push the cache to memory wmb(); /* FIXME: workaround for coherence */ /****************************************************/ /* Turn off bad ECC generation */ /****************************************************/ spin_unlock_irqrestore(&spin_lock, flags); memWriteIMCReg(imcDevFuncTrans[pMemAddr->idxChan], MEM_MC_CHANNEL_ADDR_MATCH + sizeof(UINT32), sizeof(UINT32), 0); memWriteIMCReg(imcDevFuncTrans[pMemAddr->idxChan], MEM_MC_CHANNEL_ECC_ERROR_MASK, sizeof(UINT32), 0); memWriteIMCReg(imcDevFuncTrans[pMemAddr->idxChan], MEM_MC_CHANNEL_ECC_ERROR_INJECT, sizeof(UINT32), 0); //printk("errorCnt after write %u\n", errorCntTest & 0x7f7F); /****************************************************/ /* Cause ECC error by reading addr, delay for NMI. */ /* ECC error is caused by a DMA transfer to avoid */ /* a data abort from the XScale core. */ /****************************************************/ if (!dmaMemCopy(testPhyAddr, testPhyAddr + sizeof(UINT64), 8, TRUE)){ /* Failed to read by adma */ commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ECCTEST, MEM_DIAG_ERROR_CODE_ECC_DMA_TRANSACTION_FAIL, MEM_DIAG_ERROR_MSG_ECC_DMA_TRANSACTION_FAIL, 0, 0, 0, DG_FORMAT_NONE); } /* The error count should increase 1 after DMA copy, Jay */ memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[pMemAddr->idxChan], sizeof(UINT32), &errorCntTest); /* Just for Testing the errorCntTest, Jay*/ //Jay printk("After dmaMemCopy, the errorCntTest = %x\n",errorCntTest); //errorCMCIOrig = memReadCMCICnt(); //Jay printk("After dmaMemCopy, the errorCMCIOrig = %x\n",memReadCMCICnt()); spin_lock_irqsave(&spin_lock, flags); /* Jay for test only */ //Jay while(idxTest==7); /****************************************************/ /* Make sure ECC error occurred as expected. */ /****************************************************/ if(pMemAddr->idxRank < 2) errorCntOrig >>= 16; //move higher 16bit error count for rank2,3 to lower for compare with cmci, Jay if(pMemAddr->idxRank < 2) errorCntTest >>= 16; if(errorType == MEM_DIAG_CORRECTABLE_ECC){ /* single-bit ecc not detected */ if(((errorCntTest & 0x7f7f) == (errorCntOrig & 0x7f7f)) && (memReadCMCICnt() == errorCMCIOrig)) { if((verifyECC > MEM_DIAG_ECC_CYCLE) && ((errorCntTest & 0x7f7f) == (errorCntOrig & 0x7f7f))) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ECCTEST, MEM_DIAG_ERROR_CODE_ECC_SB_ERR_NOT_DET, MEM_DIAG_ERROR_MSG_ECC_SB_ERR_NOT_DET, 0, 0, 0, DG_FORMAT_NONE); // printk("idxTest %u addr %Lx chan %u dim %u rank %u %u/%u\n", // idxTest, testPhyAddr, pMemAddr->idxChan, pMemAddr->idxDimm, pMemAddr->idxRank, (errorCntTest & 0x7f7f), (errorCntOrig & 0x7f7f)); if(verifyECC) verifyECC = 0; idxTest++; } else { verifyECC++; // printk("S:idxTest %u addr %Lx chan %u dim %u rank %u %u/%u verify %u\n", // idxTest, testPhyAddr, pMemAddr->idxChan, pMemAddr->idxDimm, pMemAddr->idxRank, (errorCntTest & 0x7f7f), (errorCntOrig & 0x7f7f), verifyECC); } } else { if(verifyECC) verifyECC = 0; idxTest++; } } else { /* Multi-bit ecc not detected */ // ***** Remove imcECC ***** // if(!imcECCgetMCECnt()) // { // if(verifyECC > MEM_DIAG_ECC_CYCLE) // { // commReportError(MEC_COMP_CODE_TEMP, // MEM_DIAG_ITEM_CODE_ECCTEST, // MEM_DIAG_ERROR_CODE_ECC_MB_ERR_NOT_DET, // MEM_DIAG_ERROR_MSG_ECC_MB_ERR_NOT_DET, // 0, // 0, // 0, // DG_FORMAT_NONE); // // printk("idxTest %u addr %Lx chan %u dim %u rank %u %u/%u\n", // // idxTest, testPhyAddr, pMemAddr->idxChan, pMemAddr->idxDimm, pMemAddr->idxRank, (errorCntTest & 0x7f), (errorCntOrig & 0x7f)); // if(verifyECC) verifyECC = 0; // idxTest++; // } // else // { // verifyECC++; // // printk("M:idxTest %u addr %Lx chan %u dim %u rank %u %u/%u verify %u\n", // // idxTest, testPhyAddr, pMemAddr->idxChan, pMemAddr->idxDimm, pMemAddr->idxRank, (errorCntTest & 0x7f), (errorCntOrig & 0x7f), verifyECC); // } // } // else // { // if(verifyECC) verifyECC = 0; // idxTest++; // } // imcECCdisable(); // ***** Remove imcECC **** } /****************************************************/ /* Disable ECC error reporting so the tested memory */ /* can be cleared without causing any ECC errors. */ /****************************************************/ //*pTest = 0; //pTest++; } /* Load the default value back to memory */ *pTestAddr = DATA_TEMP[0]; *(pTestAddr+1) = DATA_TEMP[1]; spin_unlock_irqrestore(&spin_lock, flags); iounmap((VOID *)pTestAddr); } VOID cacheATFunc(UINT64 testPhyAddr, UINT8 idxChan, UINT8 idxDimm, UINT8 idxRank, UINT8 mode){ volatile UINT64* pTestAddr; volatile UINT8* pTest; volatile UINT8* pTemp; UINT32 addrECC = 0; UINT32 maskECC = 0; UINT32 injectECC = 0; UINT32 memLock; UINT32 errorCntOrig[3]; UINT32 errorCntTest; unsigned long flags; UINT8 idxTest1, idxTest2; UINT8 idxTest1M, idxTest2M; UINT8 idxP; UINT8 detect = 0xFF; STATIC DEFINE_SPINLOCK(spin_lock); memReadIMCReg(0x0, 0x88, sizeof(UINT16), &memLock); if(memLock & 0x1) { printk("IMC_MEM_CFG register locked\n"); printk("MEMLOCK_STATUS 0x%x\n", memLock); return; } else if(memLock & 0x2) { memLock = 0x2; memWriteIMCReg(0x0, 0x90, sizeof(UINT16), memLock); memReadIMCReg(0x0, 0x88, sizeof(UINT16), &memLock); if(memLock & 0x2) { printk("IMC_MEM_CFG register locked\n"); printk("MEMLOCK_STATUS 0x%x\n", memLock); return; } } pTestAddr = (UINT64 *)ioremap(testPhyAddr, sizeof(UINT64)*2); if(pTestAddr == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ECCTEST, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return; } pTest = (UINT8 *)pTestAddr; pTemp = (UINT8 *)((UINT64)pTestAddr + sizeof(UINT64)); /* Flush L1/L2 cache */ spin_lock_irqsave(&spin_lock, flags); /************************************************************/ /* set MC_CHANNEL_0_ADDR_MATCH register */ /************************************************************/ //bit 36 is represent DIMM address for 1 or 2DPC. //For 3DPC, bits 36 and 35 represent the //DIMM address and bit 34 represent the RANK address. addrECC = 0; maskECC = 0; injectECC = 0; addrECC |= idxRank << MEM_DIAG_ECC_RANK_BIT_SHIFT; addrECC |= idxDimm << MEM_DIAG_ECC_DIMM_BIT_SHIFT; addrECC = 0x3E0; //mask bank, col and page bit addrECC |= MEM_DIAG_ECC_ADDR_MASK; for(idxP = 0; idxP < 3; idxP++) { memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxP], sizeof(UINT16), &errorCntOrig[idxP]); errorCntOrig[idxP] &= 0x8000; memWriteIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxP], sizeof(UINT16), errorCntOrig[idxP]); memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxP], sizeof(UINT16), &errorCntOrig[idxP]); } *pTestAddr = 0; if(mode) { idxTest1M=2; idxTest2M=32; } else { idxTest1M=1; idxTest2M=1; } for (idxTest1 = 0; idxTest1 < idxTest1M; idxTest1++) { for (idxTest2 = 0; idxTest2 < idxTest2M; idxTest2++) { //idxTest1 = 0; //idxTest2 = 0; /****************************************************/ /* Setup to write bad ECC into test address */ /****************************************************/ memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ADDR_MATCH + sizeof(UINT32), sizeof(UINT16), addrECC); maskECC = 0x1 << idxTest2; injectECC = ((0x1 << idxTest1) << 1) | 0x8; //printk("maskECC:%x injectECC:%x\n", maskECC,injectECC); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ECC_ERROR_MASK, sizeof(UINT32), maskECC); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ECC_ERROR_INJECT, sizeof(UINT32), injectECC); /****************************************************/ /* Write the error into memory */ /****************************************************/ *pTest = 0; wmb(); /* FIXME: workaround for coherence */ /****************************************************/ /* Turn off bad ECC generation */ /****************************************************/ spin_unlock_irqrestore(&spin_lock, flags); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ADDR_MATCH + sizeof(UINT32), sizeof(UINT32), 0); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ECC_ERROR_MASK, sizeof(UINT32), 0); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ECC_ERROR_INJECT, sizeof(UINT32), 0); //printk("errorCnt after write %u\n", errorCntTest & 0x7F); /****************************************************/ /* Cause ECC error by reading addr, delay for NMI. */ /* ECC error is caused by a DMA transfer to avoid */ /* a data abort from the XScale core. */ /****************************************************/ *pTemp = *pTest; detect = 0xFF; for(idxP = 0; idxP < 3; idxP++) { errorCntTest = 0; memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxP], sizeof(UINT16), &errorCntTest); if((errorCntTest & 0x7fff) > (errorCntOrig[idxP] & 0x7fff)) detect = idxP; } spin_lock_irqsave(&spin_lock, flags); /****************************************************/ /* Make sure ECC error occured as expected. */ /****************************************************/ /* single-bit ecc not detected */ if(detect != 0xFF) { //printk("addr %Lx chan %u dim %u rank %u\n", // testPhyAddr, idxChan, idxDimm, idxRank); printk("addr %Lx detected ECC channel %u\n", testPhyAddr, detect); } else { printk("addr %Lx doesn't detected ECC\n", testPhyAddr); } for(idxP = 0; idxP < 3; idxP ++) { memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxP], sizeof(UINT16), &errorCntTest); printk("the MC_COR_ECC_CNT_%u = %x\n", idxP, errorCntTest); } } printk("CMCI coutner %u\n", memReadCMCICnt()); } /****************************************************/ /* Disable ECC error reporting so the tested memory */ /* can be cleared without causing any ECC errors. */ /****************************************************/ *pTest = 0; spin_unlock_irqrestore(&spin_lock, flags); iounmap((VOID *)pTestAddr); } VOID cacheLFunc(UINT64 testPhyAddr, UINT8 idxChan, UINT8 idxDimm, UINT8 idxRank){ volatile UINT64* pTestAddr; volatile UINT8* pTest; volatile UINT8* pTemp; UINT32 addrECC = 0; UINT32 maskECC = 0; UINT32 injectECC = 0; UINT32 memLock; UINT32 errorCntOrig; UINT32 errorCntTest; UINT32 errorCMCIOrig; unsigned long flags; STATIC DEFINE_SPINLOCK(spin_lock); memReadIMCReg(0x0, 0x88, sizeof(UINT16), &memLock); if(memLock & 0x1) { printk("IMC_MEM_CFG register locked\n"); printk("MEMLOCK_STATUS 0x%x\n", memLock); return; } else if(memLock & 0x2) { memLock = 0x2; memWriteIMCReg(0x0, 0x90, sizeof(UINT16), memLock); memReadIMCReg(0x0, 0x88, sizeof(UINT16), &memLock); if(memLock & 0x2) { printk("IMC_MEM_CFG register locked\n"); printk("MEMLOCK_STATUS 0x%x\n", memLock); return; } } pTestAddr = (UINT64 *)ioremap(testPhyAddr, sizeof(UINT64)*2); if(pTestAddr == NULL) { commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ECCTEST, MEM_DIAG_ERROR_CODE_IOREMAP_FAILED, MEM_DIAG_ERROR_MSG_IOREMAP_FAILED, 0, 0, 0, DG_FORMAT_NONE); return; } pTest = (UINT8 *)pTestAddr; pTemp = (UINT8 *)((UINT64)pTestAddr + sizeof(UINT64)); /* Flush L1/L2 cache */ spin_lock_irqsave(&spin_lock, flags); /************************************************************/ /* set MC_CHANNEL_0_ADDR_MATCH register */ /************************************************************/ //bit 36 is represent DIMM address for 1 or 2DPC. //For 3DPC, bits 36 and 35 represent the //DIMM address and bit 34 represent the RANK address. addrECC = 0; maskECC = 0; injectECC = 0; addrECC |= idxRank << MEM_DIAG_ECC_RANK_BIT_SHIFT; addrECC |= idxDimm << MEM_DIAG_ECC_DIMM_BIT_SHIFT; //addrECC |= 0x3E0; //mask bank, col and page bit addrECC |= MEM_DIAG_ECC_ADDR_MASK; memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxChan] + (idxRank / 2) * 0x2, sizeof(UINT16), &errorCntOrig); errorCntOrig &= 0x8000; memWriteIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxChan] + (idxRank / 2) * 0x2, sizeof(UINT16), errorCntOrig); *pTestAddr = 0; memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxChan] + (idxRank / 2) * 0x2, sizeof(UINT16), &errorCntOrig); errorCMCIOrig = memReadCMCICnt(); /****************************************************/ /* Setup to write bad ECC into test address */ /****************************************************/ memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ADDR_MATCH + sizeof(UINT32), sizeof(UINT16), addrECC); maskECC = eccSingleBitErrorMask[0]; injectECC = MEM_DIAG_ECC_ECC_INJECT_UPPER; memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ECC_ERROR_MASK, sizeof(UINT32), maskECC); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ECC_ERROR_INJECT, sizeof(UINT32), injectECC); /****************************************************/ /* Write the error into memory */ /****************************************************/ *pTest = 0; wmb(); /* FIXME: workaround for coherence */ /****************************************************/ /* Turn off bad ECC generation */ /****************************************************/ spin_unlock_irqrestore(&spin_lock, flags); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ADDR_MATCH + sizeof(UINT32), sizeof(UINT32), 0); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ECC_ERROR_MASK, sizeof(UINT32), 0); memWriteIMCReg(imcDevFuncTrans[idxChan], MEM_MC_CHANNEL_ECC_ERROR_INJECT, sizeof(UINT32), 0); //printk("errorCnt after write %u\n", errorCntTest & 0x7F); /****************************************************/ /* Cause ECC error by reading addr, delay for NMI. */ /* ECC error is caused by a DMA transfer to avoid */ /* a data abort from the XScale core. */ /****************************************************/ *pTemp = *pTest; memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxChan] + (idxRank / 2) * 0x2, sizeof(UINT16), &errorCntTest); spin_lock_irqsave(&spin_lock, flags); /****************************************************/ /* Make sure ECC error occured as expected. */ /****************************************************/ /* single-bit ecc not detected */ if((errorCntTest & 0x7f) > (errorCntOrig & 0x7f)) { printk("addr %Lx chan %u dim %u rank %u by CNT\n", testPhyAddr, idxChan, idxDimm, idxRank); } else if (memReadCMCICnt() > errorCMCIOrig) { printk("addr %Lx chan %u dim %u rank %u by CMCI\n", testPhyAddr, idxChan, idxDimm, idxRank); } #if 0 else { printk("addr %Lx chan %u dim %u rank %u %x failed\n", testPhyAddr, idxChan, idxDimm, idxRank, addrECC); for(idxP = 0; idxP < 3; idxP ++) { memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxP], sizeof(UINT16), &errorCntTest); printk("the MC_COR_ECC_CNT_%u = %x\n", idxP, errorCntTest); } } #endif /****************************************************/ /* Disable ECC error reporting so the tested memory */ /* can be cleared without causing any ECC errors. */ /****************************************************/ *pTest = 0; spin_unlock_irqrestore(&spin_lock, flags); iounmap((VOID *)pTestAddr); } VOID cacheL(UINT64 addr) { UINT8 idxChan; UINT8 idxRank; UINT16 idxTest; UINT64 curAddr; MEM_CHAN_CFG* pChanCfg; printk("gMemDiagTOLMAddr %Lx\n", gMemDiagTOLMAddr); for(idxChan = 0; idxChan < MEM_CONFIG_MAX_DIMM; idxChan++){ if(sysMemConfig[idxChan].enableChan) { pChanCfg = &sysMemConfig[idxChan]; for(idxRank = 0; idxRank < pChanCfg->dimmCfg[0].numRank; idxRank++){ for(idxTest = 0; idxTest < 0x100; idxTest++){ curAddr = addr + idxTest * 0x40; if(curAddr >= gMemDiagTOLMAddr) { curAddr = MEM_JF_CORE_REG_TOHMH_START + curAddr - gMemDiagTOLMAddr; } //Single-Bit ECC tet cacheLFunc(curAddr, idxChan, 0, idxRank); //Multi-Bit ECC test } } } } } VOID cacheT(UINT64 addr) { UINT16 idxTest; UINT64 curAddr; for(idxTest = 0; idxTest < 256; idxTest++){ curAddr = addr + idxTest * MEM_CACHE_LINE_SIZE; if(curAddr >= gMemDiagTOLMAddr) { curAddr = MEM_JF_CORE_REG_TOHMH_START + curAddr - gMemDiagTOLMAddr; //Single-Bit ECC tet //Multi-Bit ECC test } cacheATFunc(curAddr, 0, 0, 0, 0); } } VOID cacheA(UINT64 curAddr) { if(curAddr >= gMemDiagTOLMAddr) { curAddr = MEM_JF_CORE_REG_TOHMH_START + curAddr - gMemDiagTOLMAddr; //Single-Bit ECC tet //Multi-Bit ECC test } cacheATFunc(curAddr, 0, 0, 0, 1); } //2010-01-13 Jim Tu //Check corrected ECC count and print on screen VOID memECCShow(VOID) { INT32 idxChan, error; UINT32 errorCntTest; error = 0; for(idxChan = 0; idxChan < MEM_CONFIG_MAX_DIMM; idxChan++) { memReadIMCReg(MEM_IMC_CTL_DEVICE_ID + MEM_IMC_CTL_RAS_FUNC, mcECCCnt[idxChan], sizeof(UINT16), &errorCntTest); printk("[DDR3 SDRAM] Channel %d corrected ECC count: %d\n", idxChan, errorCntTest); if(errorCntTest != 0) { error++; } } if(error >= gDimmEccCountUpbound) { printk(" \n"); printk("## ## ## ##### ## ## #### ## ## ##### \n"); printk("## ## ## ## ## ### ## ## ### ## ## ## \n"); printk("## ## ## ####### ## # ## ## ## # ## ## \n"); printk("## ## ## ## ## ## ### ## ## ### ## ### \n"); printk(" ## ## ## ## ## ## #### ## ## #### # \n"); printk(" \n"); } /* commReportError(MEC_COMP_CODE_TEMP, MEM_DIAG_ITEM_CODE_ECCTEST, MEM_DIAG_ERROR_CODE_DATA_VERIFY_ERR, MEM_DIAG_ERROR_MSG_DATA_VERIFY_ERR, 0, 0, 0, DG_FORMAT_NONE); */ }