diff options
author | Prachi Gupta <pragupta@us.ibm.com> | 2014-12-10 10:12:03 -0600 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-01-29 16:38:34 -0600 |
commit | 37f68a01d02d98f995ab3f46035f1db42ac75576 (patch) | |
tree | 9fff119447e156192723e89856a6e96f65c27c7d /src/usr/pnor | |
parent | f51150123d9a0fe86c63d9681dc819cb97db7c1d (diff) | |
download | blackbird-hostboot-37f68a01d02d98f995ab3f46035f1db42ac75576.tar.gz blackbird-hostboot-37f68a01d02d98f995ab3f46035f1db42ac75576.zip |
check and fix ecc errors for a given section in PNOR
Change-Id: I99ffe4f8bca0e22c72099105ab4fe8aaf7872d8e
RTC: 100967
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/14985
Tested-by: Jenkins Server
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: STEPHEN M. CPREK <smcprek@us.ibm.com>
Reviewed-by: Brian H. Horton <brianh@linux.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/pnor')
-rw-r--r-- | src/usr/pnor/pnorrp.C | 66 | ||||
-rw-r--r-- | src/usr/pnor/pnorrp.H | 9 | ||||
-rw-r--r-- | src/usr/pnor/test/pnorrptest.H | 117 |
3 files changed, 189 insertions, 3 deletions
diff --git a/src/usr/pnor/pnorrp.C b/src/usr/pnor/pnorrp.C index 03f1a74d6..299a063f4 100644 --- a/src/usr/pnor/pnorrp.C +++ b/src/usr/pnor/pnorrp.C @@ -38,7 +38,7 @@ #include <initservice/initserviceif.H> #include "pnordd.H" #include "ffs.h" //Common header file with BuildingBlock. -#include "common/ffs_hb.H" //Hostboot definition of user data in ffs_entry struct. +#include "common/ffs_hb.H"//Hostboot definition of user data in ffs_entry struct #include <pnor/ecc.H> #include <kernel/console.H> #include <endian.h> @@ -124,6 +124,15 @@ errlHndl_t PNOR::flush( PNOR::SectionId i_section) } while (0); return l_err; } + +/** + * @brief check and fix correctable ECC for a given pnor section + */ +errlHndl_t PNOR::fixECC(PNOR::SectionId i_section) +{ + return Singleton<PnorRP>::instance().fixECC(i_section); +} + /** * STATIC * @brief Static Initializer @@ -923,3 +932,58 @@ errlHndl_t PnorRP::clearSection(PNOR::SectionId i_section) return l_errl; } + +/** + * @brief check and fix correctable ECC errors for a given section + */ +errlHndl_t PnorRP::fixECC (PNOR::SectionId i_section) +{ + errlHndl_t l_err = NULL; + uint8_t* l_buffer = new uint8_t [PAGESIZE] (); + do { + TRACFCOMP(g_trac_pnor, ENTER_MRK"PnorRP::fixECC"); + + //get info from the TOC + uint8_t* l_virtAddr = reinterpret_cast<uint8_t*> + (iv_TOC[i_section].virtAddr); + uint32_t l_size = iv_TOC[i_section].size; + bool l_ecc = iv_TOC[i_section].integrity&FFS_INTEG_ECC_PROTECT; + + if (!l_ecc) + { + TRACFCOMP(g_trac_pnor, "PnorRP::fixECC: section is not" + " ecc protected"); + /*@ + * @errortype ERRL_SEV_INFORMATIONAL + * @moduleid PNOR::MOD_PNORRP_FIXECC + * @reasoncode PNOR::RC_NON_ECC_PROTECTED_SECTION + * @userdata1 Section ID + * @userdata2 0 + * + * @devdesc Non ECC protected section is passed to fixECC + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + PNOR::MOD_PNORRP_FIXECC, + PNOR::RC_NON_ECC_PROTECTED_SECTION, + i_section, + 0,true); + break; + } + + uint32_t l_numOfPages = (l_size)/PAGESIZE; + + //loop over number of pages in a section + for (uint32_t i = 0; i < l_numOfPages; i++) + { + TRACDCOMP(g_trac_pnor, "PnorRP::fixECC: memcpy virtAddr:0x%X", + l_virtAddr); + memcpy(l_buffer, l_virtAddr, PAGESIZE); + l_virtAddr += PAGESIZE; + } + } while (0); + + delete [] l_buffer; + TRACFCOMP(g_trac_pnor, EXIT_MRK"PnorRP::fixECC"); + return l_err; +} diff --git a/src/usr/pnor/pnorrp.H b/src/usr/pnor/pnorrp.H index 9f9284290..3703afe8a 100644 --- a/src/usr/pnor/pnorrp.H +++ b/src/usr/pnor/pnorrp.H @@ -67,6 +67,15 @@ class PnorRP */ errlHndl_t clearSection(PNOR::SectionId i_section); + /** + * @brief Checks and fixes correctable ECC for a given PNOR section + * + * @param[in] i_id PNOR section to clear + * + * @return Error if fails + */ + errlHndl_t fixECC(PNOR::SectionId i_section); + protected: /** * @brief Constructor diff --git a/src/usr/pnor/test/pnorrptest.H b/src/usr/pnor/test/pnorrptest.H index 0a8bc4945..04ca72916 100644 --- a/src/usr/pnor/test/pnorrptest.H +++ b/src/usr/pnor/test/pnorrptest.H @@ -43,12 +43,11 @@ #include <devicefw/userif.H> #include <pnor/ecc.H> #include "../pnorrp.H" +#include "../pnor_common.H" #include "../ffs.h" extern trace_desc_t* g_trac_pnor; - - class PnorRpTest : public CxxTest::TestSuite { public: @@ -594,6 +593,120 @@ class PnorRpTest : public CxxTest::TestSuite //@todo - import config data from build and compare to section info + /** + * @brief PNOR RP test - fixECC + * Verify that we can detect and correct ECC for a + * given section of PNOR + */ + void test_fixECC(void) + { + errlHndl_t l_err = NULL; + size_t l_size = PNOR::PAGESIZE_PLUS_ECC; + uint8_t* l_chip_data = new uint8_t[l_size]; + uint8_t* l_goodData = new uint8_t [l_size]; + uint8_t* l_readData = new uint8_t [l_size]; + do { + TRACFCOMP(g_trac_pnor, ENTER_MRK"test_fixECC..."); + + //write ecc good data + TRACFCOMP(g_trac_pnor,"test_fixECC: write ecc good data to pnor"); + l_err = PnorRP::getInstance().clearSection(PNOR::TEST); + if (l_err) + { + TS_FAIL("PnorRpTest::test_fixECC: clearSection failed"); + ERRORLOG::errlCommit(l_err,PNOR_COMP_ID); + break; + } + + //getSectionInfo + PNOR::SectionInfo_t l_info; + l_err = PNOR::getSectionInfo(PNOR::TEST, l_info); + if (l_err) + { + TS_FAIL("PnorRpTest::test_fixECC: getSectionInfo errored"); + ERRORLOG::errlCommit(l_err,PNOR_COMP_ID); + break; + } + + // manually read the data from the PNOR device + const uint64_t l_flashAddr = l_info.flashAddr + l_size; + + l_err = deviceRead(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + l_chip_data, + l_size, + DEVICE_PNOR_ADDRESS(0, l_flashAddr)); + if(l_err) + { + TS_FAIL("PnorRpTest::test_fixECC: PNORDD" + " deviceRead() failed! Error committed."); + ERRORLOG::errlCommit(l_err,PNOR_COMP_ID); + break; + } + + //save a copy of the good data + TRACFCOMP(g_trac_pnor, "test_fixECC: making a copy of good data"); + memcpy(l_goodData, l_chip_data,l_size); + + // generate data with CEs + uint64_t l_data_ecc = 0; + uint8_t* l_chip_data_ptr = l_chip_data; + for (int i = 0; i < 9; i++) + { + memcpy( &l_data_ecc, l_chip_data_ptr, sizeof(uint64_t) ); + uint64_t l_bad_data = l_data_ecc ^ (1ul << (63 - i*5)); + memcpy( l_chip_data_ptr, &l_bad_data, sizeof(uint64_t) ); + l_chip_data_ptr += 9; + } + + // write the bad data to the chip directly + l_err = deviceWrite( + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + l_chip_data,l_size, + DEVICE_PNOR_ADDRESS(0, l_flashAddr)); + if(l_err) + { + TS_FAIL("PnorRpTest::test_fixECC: PNORDD" + " deviceWrite() failed! Error committed."); + ERRORLOG::errlCommit(l_err,PNOR_COMP_ID); + break; + } + + //fixECC of the section + l_err = PNOR::fixECC(PNOR::TEST); + if (l_err) + { + TS_FAIL("PnorRpTest::test_fixECC fixECC errored"); + ERRORLOG::errlCommit(l_err,PNOR_COMP_ID); + break; + } + + //call deviceRead to make sure ecc is corrected + l_err = deviceRead( + TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + l_readData,l_size, + DEVICE_PNOR_ADDRESS(0, l_flashAddr)); + if(l_err) + { + TS_FAIL("PnorRpTest::test_fixECC: PNORDD" + " deviceRead() failed! Error committed."); + ERRORLOG::errlCommit(l_err,PNOR_COMP_ID); + break; + } + + //compare l_readData + if (0 != memcmp(l_readData, l_goodData, l_size)) + { + TS_FAIL("PnorRpTest::test_fixECC: fixECC didn't correct CE"); + break; + } + + TRACFCOMP(g_trac_pnor, "PnorRpTest::test_fixECC finished"); + } while (0); + + delete [] l_chip_data; + delete [] l_goodData; + delete [] l_readData; + }; }; |