summaryrefslogtreecommitdiffstats
path: root/src/usr/pnor
diff options
context:
space:
mode:
authorPrachi Gupta <pragupta@us.ibm.com>2014-12-10 10:12:03 -0600
committerA. Patrick Williams III <iawillia@us.ibm.com>2015-01-29 16:38:34 -0600
commit37f68a01d02d98f995ab3f46035f1db42ac75576 (patch)
tree9fff119447e156192723e89856a6e96f65c27c7d /src/usr/pnor
parentf51150123d9a0fe86c63d9681dc819cb97db7c1d (diff)
downloadtalos-hostboot-37f68a01d02d98f995ab3f46035f1db42ac75576.tar.gz
talos-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.C66
-rw-r--r--src/usr/pnor/pnorrp.H9
-rw-r--r--src/usr/pnor/test/pnorrptest.H117
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;
+ };
};
OpenPOWER on IntegriCloud