diff options
author | Mike Baiocchi <baiocchi@us.ibm.com> | 2014-05-27 15:20:43 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2014-09-08 09:07:39 -0500 |
commit | c57af7db48ddc21ce693057209c2a5070f8a5b62 (patch) | |
tree | f7adc0b3ad71ea1bf78ef8883977d9cc6eb0afbc /src | |
parent | 2247727b334be86e50bd211ddecefcdbe3dcb700 (diff) | |
download | talos-hostboot-c57af7db48ddc21ce693057209c2a5070f8a5b62.tar.gz talos-hostboot-c57af7db48ddc21ce693057209c2a5070f8a5b62.zip |
Enable Test to Validate Alt Master's LPC connection to PNOR
This commit adds a new test during istep 9.2 where all possible
Alternative Master's will have their LPC connection to PNOR tested.
The test will be done by creating a unique PnorDD class and reading
out the PNOR's TOC. This commit also updates the PnorDD class to
use a non-MASTER_PROCESSOR_CHIP_TARGET_SENTINEL target.
Change-Id: I7c141b0527a6f4d0ec5a702e9961ce686dd66a48
Backport: release-fips820
RTC: 87871
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/11348
Tested-by: Jenkins Server
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/include/usr/pnor/pnor_reasoncodes.H | 3 | ||||
-rw-r--r-- | src/include/usr/pnor/pnorif.H | 8 | ||||
-rw-r--r-- | src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C | 36 | ||||
-rw-r--r-- | src/usr/pnor/HBconfig | 3 | ||||
-rw-r--r-- | src/usr/pnor/makefile | 5 | ||||
-rw-r--r-- | src/usr/pnor/pnordd.C | 202 | ||||
-rw-r--r-- | src/usr/pnor/pnordd.H | 44 | ||||
-rw-r--r-- | src/usr/pnor/pnorrp.H | 40 | ||||
-rw-r--r-- | src/usr/pnor/pnorvalid.C | 410 | ||||
-rw-r--r-- | src/usr/pnor/test/pnorddtest.H | 20 |
10 files changed, 641 insertions, 130 deletions
diff --git a/src/include/usr/pnor/pnor_reasoncodes.H b/src/include/usr/pnor/pnor_reasoncodes.H index 52721f834..6760efd40 100644 --- a/src/include/usr/pnor/pnor_reasoncodes.H +++ b/src/include/usr/pnor/pnor_reasoncodes.H @@ -56,6 +56,9 @@ namespace PNOR MOD_PNORDD_CHECKFOROPBERRORS = 0x1E, /**< pnordd.C : PnorDD::checkForErrors */ MOD_PNORDD_HANDLEECCBERROR = 0x1F, /**< pnordd.C : PnorDD::handleEccbError */ MOD_PNORDD_RESETPNOR = 0x20, /**< pnordd.C : PnorDD::resetPnor */ + MOD_PNORVALID_MAIN = 0x21, /**< pnorvalid.C : Main Function */ + MOD_PNORVALID_MAGIC = 0x22, /**< pnorvalid.C : Magic Function */ + }; enum PNORReasonCode diff --git a/src/include/usr/pnor/pnorif.H b/src/include/usr/pnor/pnorif.H index 94a9632b6..7db87e56c 100644 --- a/src/include/usr/pnor/pnorif.H +++ b/src/include/usr/pnor/pnorif.H @@ -101,6 +101,14 @@ errlHndl_t getSectionInfo( SectionId i_section, */ bool usingL3Cache(); +/** + * @brief Validate the Alternative Master Processor's LPC + * Connection to PNOR + * + * @return errlHndl_t Error log if validation failed + */ +errlHndl_t validateAltMaster( void ); + } diff --git a/src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C b/src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C index 0d430d867..90752042d 100644 --- a/src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C +++ b/src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C @@ -48,6 +48,7 @@ #include <hwpisteperror.H> #include <sbe/sbeif.H> +#include <pnor/pnorif.H> // targeting support #include <targeting/common/commontargeting.H> @@ -338,9 +339,36 @@ void* call_proc_build_smp( void *io_pArgs ) void * call_host_slave_sbe_update( void * io_pArgs ) { errlHndl_t l_errl = NULL; + IStepError l_StepError; TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_host_slave_sbe_update entry" ); + do + { + + // Call to check state of Processor SBE SEEPROMs and + // make any necessary updates + l_errl = SBE::updateProcessorSbeSeeproms(); + + if (l_errl) + { + // Create IStep error log and cross reference error that occurred + l_StepError.addErrorDetails( l_errl); + // Commit error + errlCommit( l_errl, HWPF_COMP_ID ); + break; + } + + // Call to Validate any Alternative Master's connection to PNOR + // Any error returned should not fail istep + l_errl = PNOR::validateAltMaster(); + if (l_errl) + { + // Commit error + errlCommit( l_errl, HWPF_COMP_ID ); + break; + } + #ifdef CONFIG_PCIE_HOTPLUG_CONTROLLER // Loop through all the procs in the system @@ -398,14 +426,14 @@ void * call_host_slave_sbe_update( void * io_pArgs ) #endif - // Call to check state of Processor SBE SEEPROMs and - // make any necessary updates - l_errl = SBE::updateProcessorSbeSeeproms(); + } while (0); TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_host_slave_sbe_update exit" ); - return l_errl; + // end task, returning any errorlogs to IStepDisp + return l_StepError.getErrorHandle(); + } }; // end namespace diff --git a/src/usr/pnor/HBconfig b/src/usr/pnor/HBconfig index 05640191b..e25089cef 100644 --- a/src/usr/pnor/HBconfig +++ b/src/usr/pnor/HBconfig @@ -16,5 +16,6 @@ config BMC_DOES_SFC_INIT default y help The BMC is completely responsible for initializing and configuring the - SFC before Hostboot is started. + SFC before Hostboot is started. The BMC is also responsible for doing + any repairs or recovery for the SFC. diff --git a/src/usr/pnor/makefile b/src/usr/pnor/makefile index 7a81aef19..c9a37cc3e 100644 --- a/src/usr/pnor/makefile +++ b/src/usr/pnor/makefile @@ -5,7 +5,9 @@ # # OpenPOWER HostBoot Project # -# COPYRIGHT International Business Machines Corp. 2011,2014 +# Contributors Listed Below - COPYRIGHT 2011,2014 +# [+] International Business Machines Corp. +# # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,6 +27,7 @@ MODULE = pnor OBJS += pnorrp.o OBJS += pnordd.o +OBJS += pnorvalid.o OBJS += ecc.o SUBDIRS += test.d diff --git a/src/usr/pnor/pnordd.C b/src/usr/pnor/pnordd.C index 326f14de0..52ebe997b 100644 --- a/src/usr/pnor/pnordd.C +++ b/src/usr/pnor/pnordd.C @@ -106,6 +106,11 @@ errlHndl_t ddRead(DeviceFW::OperationType i_opType, assert( reinterpret_cast<uint64_t>(io_buffer) % 4 == 0 ); assert( io_buflen % 4 == 0 ); + // The PNOR device driver interface is initialized with the + // MASTER_PROCESSOR_CHIP_TARGET_SENTINEL. Other target + // access requires a separate PnorDD class created + assert( i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL ); + // Read the flash l_err = Singleton<PnorDD>::instance().readFlash(io_buffer, io_buflen, @@ -157,13 +162,18 @@ errlHndl_t ddWrite(DeviceFW::OperationType i_opType, assert( reinterpret_cast<uint64_t>(io_buffer) % 4 == 0 ); assert( io_buflen % 4 == 0 ); + // The PNOR device driver interface is initialized with the + // MASTER_PROCESSOR_CHIP_TARGET_SENTINEL. Other target + // access requires a separate PnorDD class created + assert( i_target == TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL ); + // Write the flash l_err = Singleton<PnorDD>::instance().writeFlash(io_buffer, io_buflen, l_addr); if(l_err) { - break; + break; } }while(0); @@ -226,9 +236,9 @@ errlHndl_t PnorDD::readFlash(void* o_buffer, } //If we get here we're doing either MODEL_LPC_MEM, MODEL_REAL_CMD, or MODEL_REAL_MMIO - mutex_lock(&cv_mutex); + mutex_lock(iv_mutex_ptr); l_err = bufferedSfcRead(i_address, io_buflen, o_buffer); - mutex_unlock(&cv_mutex); + mutex_unlock(iv_mutex_ptr); if(l_err) { break;} @@ -266,11 +276,11 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer, //If we're in VPO, just do the write directly (no erases) if(0 != iv_vpoMode) { - mutex_lock(&cv_mutex); + mutex_lock(iv_mutex_ptr); l_err = bufferedSfcWrite(static_cast<uint32_t>(l_address), 8, i_buffer); - mutex_unlock(&cv_mutex); + mutex_unlock(iv_mutex_ptr); break; } @@ -323,7 +333,7 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer, //note that writestart < blkstart can never happen // write a single block of data out to flash efficiently - mutex_lock(&cv_mutex); + mutex_lock(iv_mutex_ptr); l_err = compareAndWriteBlock( cur_blkStart_addr, cur_writeStart_addr, @@ -331,7 +341,7 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer, (void*)((uint64_t)i_buffer + ((uint64_t)cur_writeStart_addr-l_address))); - mutex_unlock(&cv_mutex); + mutex_unlock(iv_mutex_ptr); if( l_err ) { break; } @@ -362,7 +372,6 @@ errlHndl_t PnorDD::writeFlash(void* i_buffer, Private/Protected Methods ********************/ mutex_t PnorDD::cv_mutex = MUTEX_INITIALIZER; -uint64_t PnorDD::iv_vpoMode = 0; // // @note fake pnor no longer needs to allow from for SLW @@ -377,8 +386,13 @@ uint64_t PnorDD::iv_vpoMode = 0; */ PnorDD::PnorDD( PnorMode_t i_mode, uint64_t i_fakeStart, - uint64_t i_fakeSize ) + uint64_t i_fakeSize, + TARGETING::Target* i_target ) : iv_mode(i_mode) +, iv_vpoMode(0) +, iv_nor_chipid(0) +, iv_hw_workaround(0) +, iv_sfcInitDone(false) , iv_ffdc_active(false) , iv_error_handled_count(0x0) , iv_error_recovery_failed(false) @@ -389,6 +403,40 @@ PnorDD::PnorDD( PnorMode_t i_mode, //Zero out erase counter memset(iv_erases, 0xff, sizeof(iv_erases)); + + // Use i_target if all of these apply + // 1) not NULL + // 2) not MASTER_PROCESSOR_CHIP_TARGET_SENTINEL + // 3) i_target does not correspond to Master processor (ie the + // same processor as MASTER_PROCESSOR_CHIP_TARGET_SENTINEL) + // otherwise, use MASTER_PROCESSOR_CHIP_TARGET_SENTINEL + // NOTE: i_target can only be used when targetting is loaded + if ( ( i_target != NULL ) && + ( i_target != TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL ) ) + { + + iv_target = i_target; + + // Check if processor is MASTER + TARGETING::ATTR_PROC_MASTER_TYPE_type type_enum = + iv_target->getAttr<TARGETING::ATTR_PROC_MASTER_TYPE>(); + + // Master target could collide and cause deadlocks with PnorDD singleton + // used for ddRead/ddWrite with MASTER_PROCESSOR_CHIP_TARGET_SENTINEL + assert( type_enum != TARGETING::PROC_MASTER_TYPE_ACTING_MASTER ); + + // Initialize and use class-specific mutex + iv_mutex_ptr = &iv_mutex; + mutex_init(iv_mutex_ptr); + TRACFCOMP(g_trac_pnor, "PnorDD::PnorDD()> Using i_target=0x%X (non-master) and iv_mutex_ptr", TARGETING::get_huid(i_target)); + + } + else + { + iv_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; + iv_mutex_ptr = &(cv_mutex); + } + //Use real PNOR for everything except VPO if(0 == iv_vpoMode) { @@ -431,6 +479,8 @@ PnorDD::PnorDD( PnorMode_t i_mode, if( (MODEL_REAL_CMD == iv_mode) || (MODEL_REAL_MMIO == iv_mode) ) { + + // @todo RTC 97493 - make sure sfcInit only gets called once per target sfcInit( ); } @@ -445,9 +495,6 @@ PnorDD::~PnorDD() } -bool PnorDD::cv_sfcInitDone = false; //Static flag to ensure we only init the SFC one time. -uint32_t PnorDD::cv_nor_chipid = 0; //Detected NOR Flash Type -uint32_t PnorDD::cv_hw_workaround = 0; //Hardware Workaround flags /** * STATIC @@ -458,7 +505,7 @@ void PnorDD::sfcInit( ) TRACFCOMP(g_trac_pnor, "PnorDD::sfcInit> iv_mode=0x%.8x", iv_mode ); errlHndl_t l_err = NULL; - mutex_lock(&cv_mutex); + mutex_lock(iv_mutex_ptr); do { #ifdef CONFIG_SFC_IS_AST2400 @@ -467,20 +514,16 @@ void PnorDD::sfcInit( ) //@todo RTC:106881 - Fix up to support erase/write later #endif //CONFIG_SFC_IS_AST2400 - if(!cv_sfcInitDone) + if(!iv_sfcInitDone) { #ifdef CONFIG_BMC_DOES_SFC_INIT // Set OPB LPCM FIR Mask - hostboot will monitor these FIR bits - //@todo (RTC:36950) - add non-master support - TARGETING::Target* scom_target = - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; size_t scom_size = sizeof(uint64_t); uint64_t fir_mask_data = OPB_LPCM_FIR_ERROR_MASK; - // Read FIR Register l_err = deviceOp( DeviceFW::WRITE, - scom_target, + iv_target, &(fir_mask_data), scom_size, DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_MASK_WO_OR_REG)); @@ -488,11 +531,11 @@ void PnorDD::sfcInit( ) //Determine NOR Flash type - triggers vendor specific workarounds //We also use the chipID in some FFDC situations. - l_err = getNORChipId(cv_nor_chipid); + l_err = getNORChipId(iv_nor_chipid); if(l_err) { break; } TRACFCOMP(g_trac_pnor, - "PnorDD::sfcInit: cv_nor_chipid=0x%.8x> ", - cv_nor_chipid ); + "PnorDD::sfcInit: iv_nor_chipid=0x%.8x> ", + iv_nor_chipid ); // Re-initialize internal erase size cached value. l_err = readRegSfc(SFC_CMD_SPACE, @@ -509,12 +552,12 @@ void PnorDD::sfcInit( ) #endif //CONFIG_BMC_DOES_SFC_INIT - cv_sfcInitDone = true; + iv_sfcInitDone = true; } }while(0); - mutex_unlock(&cv_mutex); + mutex_unlock(iv_mutex_ptr); if( l_err ) { @@ -708,13 +751,13 @@ errlHndl_t PnorDD::pollSfcOpComplete(uint64_t i_pollTime) l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORDD_POLLSFCOPCOMPLETE, PNOR::RC_LPC_ERROR, - TWO_UINT32_TO_UINT64(cv_nor_chipid, + TWO_UINT32_TO_UINT64(iv_nor_chipid, poll_time), TWO_UINT32_TO_UINT64(sfc_stat.data32,0)); // Limited in callout: no PNOR target, so calling out processor l_err->addHwCallout( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + iv_target, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); @@ -743,7 +786,7 @@ errlHndl_t PnorDD::pollSfcOpComplete(uint64_t i_pollTime) // Commit reset error as informational since we have // original error l_err TRACFCOMP(g_trac_pnor, "PnorDD::pollSfcOpComplete> Error from resetPnor() after previous error eid=0x%X. Committing resetPnor() error log eid=0x%X.", - l_err->eid(), tmp_err->eid()); + l_err->eid(), tmp_err->eid()); tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL); tmp_err->collectTrace(PNOR_COMP_NAME); tmp_err->plid(l_err->plid()); @@ -939,7 +982,7 @@ errlHndl_t PnorDD::checkForSfcErrors( ResetLevels &o_pnorResetLevel ) // Limited in callout: no PNOR target, so calling out processor l_err->addHwCallout( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + iv_target, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); @@ -972,20 +1015,14 @@ errlHndl_t PnorDD::checkForOpbErrors( ResetLevels &o_pnorResetLevel ) size_t scom_size = sizeof(uint64_t); do { - - //@todo (RTC:36950) - add non-master support - TARGETING::Target* scom_target = - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; - // Read FIR Register l_err = deviceOp( DeviceFW::READ, - scom_target, + iv_target, &(fir_data), scom_size, DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG) ); if( l_err ) { break; } - // Mask data to just the FIR bits we care about fir_reg.data64 = fir_data & OPB_LPCM_FIR_ERROR_MASK; @@ -1082,14 +1119,14 @@ errlHndl_t PnorDD::checkForOpbErrors( ResetLevels &o_pnorResetLevel ) * and/or LPCHC Status Register */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, - PNOR::MOD_PNORDD_CHECKFORSFCERRORS, + PNOR::MOD_PNORDD_CHECKFOROPBERRORS, PNOR::RC_ERROR_IN_STATUS_REG, fir_reg.data64, o_pnorResetLevel ); // Limited in callout: no PNOR target, so calling out processor l_err->addHwCallout( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + iv_target, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); @@ -1097,7 +1134,7 @@ errlHndl_t PnorDD::checkForOpbErrors( ResetLevels &o_pnorResetLevel ) // Log FIR Register Data ERRORLOG::ErrlUserDetailsLogRegister - l_eud(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL); + l_eud(iv_target); l_eud.addDataBuffer(&fir_data, scom_size, DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG)); @@ -1136,16 +1173,12 @@ void PnorDD::addFFDCRegisters(errlHndl_t & io_errl) io_errl->eid(), io_errl->plid() ); ERRORLOG::ErrlUserDetailsLogRegister - l_eud(TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL); + l_eud(iv_target); do { - // Add ECCB Status Register - TARGETING::Target* scom_target = - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; - tmp_err = deviceOp( DeviceFW::READ, - scom_target, + iv_target, &(data64), size64, DEVICE_SCOM_ADDRESS(ECCB_STAT_REG) ); @@ -1163,7 +1196,7 @@ void PnorDD::addFFDCRegisters(errlHndl_t & io_errl) // Add OPB Fir Register tmp_err = deviceOp( DeviceFW::READ, - scom_target, + iv_target, &(data64), size64, DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_REG) ); @@ -1382,13 +1415,13 @@ errlHndl_t PnorDD::micronFlagStatus(uint64_t i_pollTime) l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORDD_MICRONFLAGSTATUS, PNOR::RC_MICRON_INCOMPLETE, - TWO_UINT32_TO_UINT64(cv_nor_chipid, + TWO_UINT32_TO_UINT64(iv_nor_chipid, poll_time), TWO_UINT32_TO_UINT64(opStatus,0)); // Limited in callout: no PNOR target, so calling out processor l_err->addHwCallout( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + iv_target, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); @@ -1514,7 +1547,7 @@ errlHndl_t PnorDD::getNORChipId(uint32_t& o_chipId, if( o_chipId == MICRON_NOR_ID ) { // Assume all Micron chips have this bug - cv_hw_workaround |= HWWK_MICRON_EXT_READ; + iv_hw_workaround |= HWWK_MICRON_EXT_READ; uint32_t outdata[4]; @@ -1538,7 +1571,7 @@ errlHndl_t PnorDD::getNORChipId(uint32_t& o_chipId, { TRACFCOMP( g_trac_pnor,"PnorDD::getNORChipId> Setting Micron workaround flag"); //Set Micron workaround flag - cv_hw_workaround |= HWWK_MICRON_WRT_ERASE; + iv_hw_workaround |= HWWK_MICRON_WRT_ERASE; } @@ -1644,7 +1677,7 @@ errlHndl_t PnorDD::flushSfcBuf(uint32_t i_addr, if(l_err) { break; } //check for special Micron Flag Status reg - if(cv_hw_workaround & HWWK_MICRON_WRT_ERASE) + if(iv_hw_workaround & HWWK_MICRON_WRT_ERASE) { l_err = micronFlagStatus(); if(l_err) { break; } @@ -1901,10 +1934,6 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, do { - //@todo (RTC:36950) - add non-master support - TARGETING::Target* scom_target = - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; - // always read/write 64 bits to SCOM size_t scom_size = sizeof(uint64_t); @@ -1913,7 +1942,7 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, eccb_cmd.read_op = 1; eccb_cmd.address = i_addr; l_err = deviceOp( DeviceFW::WRITE, - scom_target, + iv_target, &(eccb_cmd.data64), scom_size, DEVICE_SCOM_ADDRESS(ECCB_CTL_REG) ); @@ -1927,7 +1956,7 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, while( poll_time < ECCB_POLL_TIME_NS ) { l_err = deviceOp( DeviceFW::READ, - scom_target, + iv_target, &(eccb_stat.data64), scom_size, DEVICE_SCOM_ADDRESS(ECCB_STAT_REG) ); @@ -1938,6 +1967,7 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, break; } + // want to start out incrementing by small numbers then get bigger // to avoid a really tight loop in an error case so we'll increase // the wait each time through @@ -1972,7 +2002,7 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, // Limited in callout: no PNOR target, so calling out processor l_err->addHwCallout( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + iv_target, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); @@ -2008,7 +2038,7 @@ errlHndl_t PnorDD::readLPC(uint32_t i_addr, { // Commit reset error since we have original error l_err TRACFCOMP(g_trac_pnor, "PnorDD::readLPC Error from resetPnor() after previous error eid=0x%X. Committing resetPnor() error log eid=0x%X.", - l_err->eid(), tmp_err->eid()); + l_err->eid(), tmp_err->eid()); tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL); tmp_err->collectTrace(PNOR_COMP_NAME); @@ -2035,10 +2065,6 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, do { - //@todo (RTC:36950) - add non-master support - TARGETING::Target* scom_target = - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; - // always read/write 64 bits to SCOM size_t scom_size = sizeof(uint64_t); @@ -2048,7 +2074,7 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, uint64_t eccb_data = static_cast<uint64_t>(i_data); eccb_data = eccb_data << 32; //left-justify my data l_err = deviceOp( DeviceFW::WRITE, - scom_target, + iv_target, &eccb_data, scom_size, DEVICE_SCOM_ADDRESS(ECCB_DATA_REG) ); @@ -2060,7 +2086,7 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, eccb_cmd.address = i_addr; TRACDCOMP(g_trac_pnor, "writeLPC> Write ECCB command register, cmd=0x%.16x", eccb_cmd.data64 ); l_err = deviceOp( DeviceFW::WRITE, - scom_target, + iv_target, &(eccb_cmd.data64), scom_size, DEVICE_SCOM_ADDRESS(ECCB_CTL_REG) ); @@ -2074,7 +2100,7 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, while( poll_time < ECCB_POLL_TIME_NS ) { l_err = deviceOp( DeviceFW::READ, - scom_target, + iv_target, &(eccb_stat.data64), scom_size, DEVICE_SCOM_ADDRESS(ECCB_STAT_REG) ); @@ -2119,7 +2145,7 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, eccb_stat.data64); // Limited in callout: no PNOR target, so calling out processor l_err->addHwCallout( - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL, + iv_target, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); @@ -2151,7 +2177,7 @@ errlHndl_t PnorDD::writeLPC(uint32_t i_addr, { // Commit reset error since we have original error l_err TRACFCOMP(g_trac_pnor, "PnorDD::writeLPC Error from resetPnor() after previous error eid=0x%X. Committing resetPnor() error log eid=0x%X.", - l_err->eid(), tmp_err->eid()); + l_err->eid(), tmp_err->eid()); tmp_err->setSev(ERRORLOG::ERRL_SEV_INFORMATIONAL); tmp_err->collectTrace(PNOR_COMP_NAME); @@ -2366,7 +2392,6 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address) // reset class variable since we're starting a new operation iv_error_recovery_failed = false; - // This do-while loop supports retries do { @@ -2404,13 +2429,13 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address) break; //all done } - else if(cv_nor_chipid != 0) + else if(iv_nor_chipid != 0) { // group this block together with do-while do{ - TRACDCOMP(g_trac_pnor, "PnorDD::eraseFlash> Erasing flash for cv_nor_chipid=0x%.8x, iv_mode=0x%.8x", - cv_nor_chipid, iv_mode); + TRACDCOMP(g_trac_pnor, "PnorDD::eraseFlash> Erasing flash for iv_nor_chipid=0x%.8x, iv_mode=0x%.8x", + iv_nor_chipid, iv_mode); //Write erase address to ADR reg l_err = writeRegSfc(SFC_CMD_SPACE, @@ -2434,7 +2459,7 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address) if(l_err) { break; } //check for special Micron Flag Status reg - if(cv_hw_workaround & HWWK_MICRON_WRT_ERASE) + if(iv_hw_workaround & HWWK_MICRON_WRT_ERASE) { l_err = micronFlagStatus(); if(l_err) { break; } @@ -2445,8 +2470,8 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address) } else { - TRACFCOMP(g_trac_pnor,"PnorDD::eraseFlash> Erase not supported for cv_nor_chipid=%d", - cv_nor_chipid ); + TRACFCOMP(g_trac_pnor,"PnorDD::eraseFlash> Erase not supported for iv_nor_chipid=%d", + iv_nor_chipid ); /*@ * @errortype @@ -2460,7 +2485,7 @@ errlHndl_t PnorDD::eraseFlash(uint32_t i_address) ERRORLOG::ERRL_SEV_UNRECOVERABLE, PNOR::MOD_PNORDD_ERASEFLASH, PNOR::RC_UNSUPPORTED_OPERATION, - static_cast<uint64_t>(cv_nor_chipid), + static_cast<uint64_t>(iv_nor_chipid), i_address, true /*Add HB SW Callout*/ ); l_err->collectTrace(PNOR_COMP_NAME); @@ -2493,7 +2518,7 @@ errlHndl_t PnorDD::readRegFlash( SfcCustomReg_t i_cmd, { //Do a read of flash address zero to workaround // a micron bug with extended reads - if( (HWWK_MICRON_EXT_READ & cv_hw_workaround) + if( (HWWK_MICRON_EXT_READ & iv_hw_workaround) && (i_cmd.length > 4) ) { l_err = loadSfcBuf( 0, 1 ); @@ -2628,11 +2653,6 @@ errlHndl_t PnorDD::resetPnor( ResetLevels i_pnorResetLevel ) do { - // Setup common scom target - //@todo (RTC:36950) - add non-master support - TARGETING::Target* scom_target = - TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL; - // always read/write 64 bits to SCOM uint64_t scom_data_64 = 0x0; size_t scom_size = sizeof(uint64_t); @@ -2665,7 +2685,7 @@ errlHndl_t PnorDD::resetPnor( ResetLevels i_pnorResetLevel ) TRACFCOMP(g_trac_pnor, "PnorDD::resetPnor> Writing ECCB_RESET_REG to reset ECCB FW Logic"); scom_data_64 = 0x0; l_err = deviceOp( DeviceFW::WRITE, - scom_target, + iv_target, &(scom_data_64), scom_size, DEVICE_SCOM_ADDRESS(ECCB_RESET_REG) ); @@ -2705,7 +2725,7 @@ errlHndl_t PnorDD::resetPnor( ResetLevels i_pnorResetLevel ) scom_data_64 = ~(OPB_LPCM_FIR_ERROR_MASK); l_err = deviceOp( DeviceFW::WRITE, - scom_target, + iv_target, &(scom_data_64), scom_size, DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_WOX_AND_REG) ); @@ -2730,8 +2750,8 @@ errlHndl_t PnorDD::resetPnor( ResetLevels i_pnorResetLevel ) scom_data_64 = ~(OPB_LPCM_FIR_ERROR_MASK); l_err = deviceOp( DeviceFW::WRITE, - scom_target, - &(scom_data_64), + iv_target, + &(scom_data_64), scom_size, DEVICE_SCOM_ADDRESS(OPB_LPCM_FIR_WOX_AND_REG) ); @@ -2878,7 +2898,7 @@ errlHndl_t PnorDD::reinitializeSfc( void ) do { -#ifdef PNORDD_FSPATTACHED +#ifdef CONFIG_BMC_DOES_SFC_INIT TRACFCOMP( g_trac_pnor, ERR_MRK"PnorDD::reinitializeSfc> Need to Re-Initialize SFC. Calling doShutdown(PNOR::RC_REINITIALIZE_SFC)"); @@ -2892,7 +2912,7 @@ errlHndl_t PnorDD::reinitializeSfc( void ) // Clear member variable in case we don't successfully // reinitialize PNOR - cv_sfcInitDone = false; + iv_sfcInitDone = false; l_err = writeRegSfc(SFC_CMD_SPACE, SFC_REG_OADRNB, @@ -2922,12 +2942,12 @@ errlHndl_t PnorDD::reinitializeSfc( void ) //Determine NOR Flash type - triggers vendor specific workarounds //We also use the chipID in some FFDC situations. - l_err = getNORChipId(cv_nor_chipid); + l_err = getNORChipId(iv_nor_chipid); if(l_err) { break; } TRACFCOMP(g_trac_pnor, - "PnorDD::reinitializeSfc> cv_nor_chipid=0x%.8x> ", - cv_nor_chipid ); + "PnorDD::reinitializeSfc> iv_nor_chipid=0x%.8x> ", + iv_nor_chipid ); l_err = readRegSfc(SFC_CMD_SPACE, SFC_REG_ERASMS, @@ -2935,7 +2955,7 @@ errlHndl_t PnorDD::reinitializeSfc( void ) if(l_err) { break; } // Good path if you made it here: reset class variable - cv_sfcInitDone = true; + iv_sfcInitDone = true; #endif diff --git a/src/usr/pnor/pnordd.H b/src/usr/pnor/pnordd.H index 93d03d117..25915b294 100644 --- a/src/usr/pnor/pnordd.H +++ b/src/usr/pnor/pnordd.H @@ -99,10 +99,17 @@ class PnorDD /** * @brief Constructor + * + * @parm i_mode o_buffer Buffer to read data into + * @parm i_fakeStart Input: Number of bytes to read, + * @parm i_fakeSize Output: Number of bytes actually read + * @parm i_target Processor Target connected to PNOR + * NOTE: i_target can only be used when targetting is loaded */ PnorDD( PnorMode_t i_mode = MODEL_UNKNOWN, uint64_t i_fakeStart = 0, - uint64_t i_fakeSize = 0); + uint64_t i_fakeSize = 0, + TARGETING::Target* i_target = NULL ); /** @@ -335,7 +342,6 @@ class PnorDD SfcStatReg_t() : data32(0) {}; }; - /** * @brief LPC Slave Registers * These are offsets within the LPC Slave Register Space @@ -659,6 +665,7 @@ class PnorDD errlHndl_t writeLPC(uint32_t i_addr, uint32_t i_data); + /** * @brief Erase a block of flash * @@ -903,11 +910,24 @@ class PnorDD // NOTE: The layout of the variables in this class must be maintained // along with the offsets in the debug framework. + /** + * @brief Global Mutex to prevent concurrent PNOR accesses to Master Proc + * This needs to be static so we can mutex across multiple + * instances of PnorDD + */ + static mutex_t cv_mutex; + /** - * @brief Mutex to prevent concurrent PNOR accesses - * This needs to be static so we can mutex across multiple instances of PnorDD + * @brief Class Mutex used to prevent concurrent PNOR accesses */ - static mutex_t cv_mutex; + mutex_t iv_mutex; + + /** + * @brief Mutex pointer to either class-specific or global mutex to prevent + * concurrent PNOR accesses. + * Each class uses a mutex; some share the static cv_mutex + */ + mutex_t* iv_mutex_ptr; /** * @brief Track PNOR erases for wear monitoring @@ -924,7 +944,7 @@ class PnorDD /** * @brief Flag to drive special behavior in VPO. */ - static uint64_t iv_vpoMode; + uint64_t iv_vpoMode; /** * @brief describes the erase block size, set based on NOR chip type @@ -936,19 +956,19 @@ class PnorDD * @brief CHIP ID or the NOR chip attached to SFC. * */ - static uint32_t cv_nor_chipid; + uint32_t iv_nor_chipid; /** * @brief Hardware workarounds * */ - static uint32_t cv_hw_workaround; + uint32_t iv_hw_workaround; /** * @brief indicates if SFC initialization has been performed. * */ - static bool cv_sfcInitDone; + bool iv_sfcInitDone; /** * @brief Start of Fake PNOR address range.. @@ -986,6 +1006,12 @@ class PnorDD */ bool iv_reset_active; + /** + * @brief Processor Target used to access PNOR device + * + */ + TARGETING::Target* iv_target; + // Needed for testcases friend class PnorDdTest; diff --git a/src/usr/pnor/pnorrp.H b/src/usr/pnor/pnorrp.H index 6c8c5b416..38043f875 100644 --- a/src/usr/pnor/pnorrp.H +++ b/src/usr/pnor/pnorrp.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2011,2014 */ +/* Contributors Listed Below - COPYRIGHT 2011,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -31,6 +33,25 @@ #include <vmmconst.h> #include <map> +namespace PNOR +{ + + /** + * @brief Creates a 4-byte Cyclic Redundancy Check (CRC) on the data + * provided. The last iteration of the for-loop includes the ffs + * checksum itself. Therefore if the 4-byte CRC created matches + * the ffs checksum, the resulting CRC will be 0 + * + * @param[in] ptr Pointer to the data + * + * @param[in] size Size of the data + * + * @return uint32_t return 4-byte CRC, 0 if checksums match + */ + uint32_t pnor_ffs_checksum(void* data, size_t size); + +}; //namespace PNOR + /** * PNOR Resource Provider */ @@ -55,20 +76,6 @@ class PnorRP errlHndl_t getSectionInfo( PNOR::SectionId i_section, PNOR::SectionInfo_t& o_info ); - /** - * @brief Creates a 4-byte Cyclic Redundancy Check (CRC) on the data - * provided. The last iteration of the for-loop includes the ffs - * checksum itself. Therefore if the 4-byte CRC created matches - * the ffs checksum, the resulting CRC will be 0 - * - * @param[in] ptr Pointer to the data - * - * @param[in] size Size of the data - * - * @return uint32_t return 4-byte CRC, 0 if checksums match - */ - uint32_t pnor_ffs_checksum(void* data, size_t size); - protected: /** * @brief Constructor @@ -254,6 +261,9 @@ class PnorRP friend class PnorRpTest; friend class PnorDdTest; + // allow this function to use constant(s) + friend errlHndl_t PNOR::validateAltMaster( void ); + /** * @brief Static instance function for testcase only */ diff --git a/src/usr/pnor/pnorvalid.C b/src/usr/pnor/pnorvalid.C new file mode 100644 index 000000000..22232729d --- /dev/null +++ b/src/usr/pnor/pnorvalid.C @@ -0,0 +1,410 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/pnor/pnorvalid.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file pnorvalid.C + * + * @brief Implements PNOR::validateAltMaster(), which Validates + * the Alternative Master Processor's connection to PNOR + */ + +/*****************************************************************************/ +// I n c l u d e s +/*****************************************************************************/ +#include <trace/interface.H> +#include <devicefw/driverif.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <errl/errludlogregister.H> +#include <targeting/common/targetservice.H> +#include <targeting/common/utilFilter.H> +#include <attributeenums.H> +#include "ffs.h" +#include "common/ffs_hb.H" +#include "pnorrp.H" +#include "pnordd.H" +#include <pnor/pnorif.H> +#include <pnor/pnor_reasoncodes.H> + + +// Used for creating an Invalid TOC ("PNOR") +#define PNORVALID_FAKE_MAGIC 0x504E4F52 + +extern trace_desc_t* g_trac_pnor; + +namespace PNOR +{ + +/** + * @brief Validate the MAGIC field in the TOC + * + * @parm i_pnordd PNOR Device Driver Object of Alt Master + * @parm i_ffs_hdr FFS Header to check + * @parm i_toc0_offset Offset Address of TOC + * @parm i_attempt_write If invalid MAGIC, rewrite TOC if true + * (createEmptyTOC gets called) + * + * @return errlHndl_t Error log if validation failed + */ +errlHndl_t validateMagic(PnorDD* i_pnordd, + ffs_hdr* i_ffs_hdr, + uint64_t i_toc0_offset, + bool i_attempt_write); + +/** + * @brief Create an Invalid TOC on Alt Master's PNOR + * + * @parm i_pnordd PNOR Device Driver Object of Alt Master + * @parm i_ffs_hdr FFS Header to check + * @parm i_toc0_offset Offset Address of TOC + * + * @return errlHndl_t Error log if validation failed + */ +errlHndl_t createInvalidTOC(PnorDD* i_pnordd, + ffs_hdr* i_ffs_hdr, + uint64_t i_toc0_offset); + +/** + * @brief Validate the Alternative Master Processor's LPC connection to PNOR + * + * @return errlHndl_t Error log if validation failed + */ + +errlHndl_t validateAltMaster( void ) +{ + errlHndl_t l_err = NULL; + + PnorDD* pnordd = NULL; + + // When reading PNOR TOC assume a single page and no ECC + uint8_t* tocBuffer = new uint8_t[PAGESIZE]; + size_t read_size = PAGESIZE; + const uint64_t toc0_offset = PnorRP::TOC_0_OFFSET; + + do{ + + // Get list of all processors + TARGETING::TargetHandleList procList; + TARGETING::getAllChips(procList, + TARGETING::TYPE_PROC, + true); // true: return functional targets + + if( ( 0 == procList.size() ) || + ( NULL == procList[0] ) ) + { + TRACFCOMP( g_trac_pnor, INFO_MRK"PNOR::validateAltMaster()> No functional processors Found! Validation skipped" ); + break; + } + + // Loop through all processors + for(uint32_t i=0; i<procList.size(); i++) + { + // Check if processor is MASTER_CANDIDATE + TARGETING::ATTR_PROC_MASTER_TYPE_type type_enum = + procList[i]->getAttr<TARGETING::ATTR_PROC_MASTER_TYPE>(); + + if ( type_enum != TARGETING::PROC_MASTER_TYPE_MASTER_CANDIDATE ) + { + TRACDCOMP( g_trac_pnor, INFO_MRK"PNOR::validateAltMaster> Skipping Processor 0x%X (PROC_MASTER_TYPE=%d)", + TARGETING::get_huid(procList[i]), type_enum); + continue; + } + + TRACFCOMP( g_trac_pnor, INFO_MRK"PNOR::validateAltMaster> Validating Processor 0x%X (PROC_MASTER_TYPE=%d)", + TARGETING::get_huid(procList[i]), type_enum); + + // Create and initialize custom PNOR DD class for this target + if ( pnordd ) + { + delete pnordd; + pnordd = NULL; + } + pnordd = new PnorDD(PnorDD::MODEL_REAL_MMIO, 0, 0, procList[i]); + + // Read Flash + l_err = pnordd->readFlash(tocBuffer, read_size, + PnorRP::TOC_0_OFFSET); + if ( l_err ) + { + // Commit Error Log, but continue the test + TRACFCOMP( g_trac_pnor, INFO_MRK"PNOR::validateAltMaster> readFlash fail for 0x%X. eid=0x%X, rc=0x%X. Committing log and Continuing", + TARGETING::get_huid(procList[i]), l_err->eid(), + l_err->reasonCode()); + + l_err->collectTrace(PNOR_COMP_NAME); + + // if there was an error, commit here and then proceed to + // the next processor + errlCommit(l_err,PNOR_COMP_ID); + continue; + } + + // Set the header pointer + ffs_hdr* l_ffs_hdr = (ffs_hdr*) tocBuffer; + + // Recursive function to check FFS/TOC Magic and possibly write + // new TOC if necessary + l_err = validateMagic(pnordd, + l_ffs_hdr, + toc0_offset, + true); // true->write TOC if necessary + + if ( l_err ) + { + // Commit Error Log, but continue the test + TRACFCOMP( g_trac_pnor, INFO_MRK"PNOR::validateAltMaster> validateMagic fail for 0x%X. eid=0x%X, rc=0x%X. Committing log and Continuing", + TARGETING::get_huid(procList[i]), l_err->eid(), + l_err->reasonCode()); + + // Limited in callout: no PNOR target, so calling out processor + l_err->addHwCallout( + procList[i], + HWAS::SRCI_PRIORITY_HIGH, + HWAS::NO_DECONFIG, + HWAS::GARD_NULL ); + + + l_err->collectTrace(PNOR_COMP_NAME); + + // if there was an error, commit here and then proceed to + // the next processor + errlCommit(l_err,PNOR_COMP_ID); + continue; + } + + + // Now check ffs entry checksum (0 if checksums match) + if( pnor_ffs_checksum(l_ffs_hdr, FFS_HDR_SIZE) != 0) + { + //@TODO - RTC:90780 - May need to handle this differently in + // SP-less config + TRACFCOMP(g_trac_pnor, "PNOR::validateAltMaster> pnor_ffs_checksum header checksums do not match on target 0x%X. Create and commit error log then continue the test", + TARGETING::get_huid(procList[i])); + + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORVALID_MAIN + * @reasoncode PNOR::RC_PARTITION_TABLE_INVALID + * @userdata1 Master Candidate Processor Target + * @userdata2 <unused> + * @devdesc PNOR::validateAltMaster> Fail verifying FFS + * Header on Master Candidate PNOR TOC0 + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORVALID_MAIN, + PNOR::RC_PARTITION_TABLE_INVALID, + TARGETING::get_huid(procList[i]), + 0); + + // Limited in callout: no PNOR target, so calling out processor + l_err->addHwCallout( + procList[i], + HWAS::SRCI_PRIORITY_HIGH, + HWAS::NO_DECONFIG, + HWAS::GARD_NULL ); + + + TRACFBIN(g_trac_pnor, "tocBuffer", tocBuffer, 0x20); + + l_err->collectTrace(PNOR_COMP_NAME); + errlCommit(l_err,PNOR_COMP_ID); + continue; + } + else + { + TRACFCOMP(g_trac_pnor, "PNOR::validateAltMaster> Successful validation of Alt-Master 0x%X", + TARGETING::get_huid(procList[i])); + } + + } // end of processor 'for' loop + + + }while(0); + + // Delete PNOR DD class and memory buffer + if ( pnordd ) + { + delete pnordd; + pnordd = NULL; + } + + if(tocBuffer != NULL) + { + delete[] tocBuffer; + tocBuffer = NULL; + } + + return l_err; +} + + + +/** + * @brief Validate the MAGIC field in the TOC + */ +errlHndl_t validateMagic(PnorDD* i_pnordd, + ffs_hdr* i_ffs_hdr, + uint64_t i_toc0_offset, + bool i_attempt_write) +{ + errlHndl_t l_err = NULL; + + do{ + + /* Checking FFS Header MAGIC to make sure it looks valid */ + if ( ( i_ffs_hdr->magic != FFS_MAGIC ) && + ( i_ffs_hdr->magic != PNORVALID_FAKE_MAGIC ) ) + { + TRACFCOMP(g_trac_pnor, "PNOR::validateMagic> Invalid magic number in FFS header: 0x%.4X", + i_ffs_hdr->magic); + + TRACFBIN(g_trac_pnor, "PNOR::validateMagic> i_ffs_hdr", + i_ffs_hdr, FFS_HDR_SIZE); + + // Check if we should attempt to write empty TOC + if ( i_attempt_write == true ) + { + // Write Invalid TOC with a specific 'MAGIC' marker + l_err = createInvalidTOC(i_pnordd, i_ffs_hdr, i_toc0_offset); + if ( l_err ) + { + TRACFCOMP(g_trac_pnor, "PNOR::validateMagic> createInvalidTOC returned error: eid=0x%X, rc=0x%X", + l_err->eid(), l_err->reasonCode()); + break; + } + else + { + // Writing TOC successful, so recursively call this function + l_err = validateMagic(i_pnordd, + i_ffs_hdr, + i_toc0_offset, + false); // false->don't write TOC + if ( l_err ) + { + + TRACFCOMP(g_trac_pnor, "PNOR::validateMagic> After successful createEmptyTOC, validateMagic returned error: eid=0x%X, rc=0x%X", + l_err->eid(), l_err->reasonCode()); + break; + } + } + } + else + { + + //@TODO - RTC:90780 - May need to handle this differently in + // SP-less config + TRACFCOMP(g_trac_pnor, "PNOR::validateMagic> MAGIC number header still incorrect after writing empty TOC"); + + /*@ + * @errortype + * @moduleid PNOR::MOD_PNORVALID_MAGIC + * @reasoncode PNOR::RC_PARTITION_TABLE_INVALID + * @userdata1 Magic Number read + * @userdata2 <unused> + * @devdesc PNOR::validateMagic> Fail verifying FFS Magic + * Number in Header on Master + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + PNOR::MOD_PNORVALID_MAGIC, + PNOR::RC_PARTITION_TABLE_INVALID, + i_ffs_hdr->magic, + 0); + + TRACFBIN(g_trac_pnor, "i_ffs_hdr", i_ffs_hdr, FFS_HDR_SIZE); + + // HW Callout handled by caller + break; + } + } + + }while(0); + + + return l_err; +} + +/** + * @brief Create an Invalid TOC on Alt Master's PNOR + */ +errlHndl_t createInvalidTOC(PnorDD* i_pnordd, + ffs_hdr* i_ffs_hdr, + uint64_t i_toc0_offset) +{ + errlHndl_t l_err = NULL; + + // When reading PNOR TOC assume a single page and no ECC + size_t toc_size = PAGESIZE; + + do{ + // Create FFS Header of Empty TOC with Invalid MAGIC field + ffs_hdr l_hdr; + + // Clear the struct and only set (invalid) MAGIC and checksum fields + // - Thus HWSV will recognize this TOC needs to be updated + memset(&(l_hdr), 0, FFS_HDR_SIZE); + l_hdr.magic = PNORVALID_FAKE_MAGIC; + l_hdr.checksum = pnor_ffs_checksum(&(l_hdr), FFS_HDR_SIZE_CSUM); + + // Re-use previously defined io_ffs_hdr memory space + memset(i_ffs_hdr, 0, toc_size); + memcpy(i_ffs_hdr, &(l_hdr), FFS_HDR_SIZE); + + TRACFBIN(g_trac_pnor, "PNOR::createInvalidTOC> New FFS Header", + i_ffs_hdr, FFS_HDR_SIZE); + + + // Write TOC to PNOR + l_err = i_pnordd->writeFlash(i_ffs_hdr, toc_size, + i_toc0_offset); + if ( l_err ) + { + TRACFCOMP( g_trac_pnor, INFO_MRK"PNOR::createInvalidTOC> writeFlash fail: eid=0x%X, rc=0x%X", + l_err->eid(), l_err->reasonCode()); + + TRACFBIN(g_trac_pnor, "EMPTY TOC", i_ffs_hdr, 0x20); + break; + } + + // Read Back TOC from PNOR (reset toc_size and i_ffs_hdr to be safe) + toc_size = PAGESIZE; + memset(i_ffs_hdr, 0, toc_size); + l_err = i_pnordd->readFlash(i_ffs_hdr, toc_size, + i_toc0_offset); + if ( l_err ) + { + TRACFCOMP( g_trac_pnor, INFO_MRK"PNOR::createInvalidTOC> readFlash fail: eid=0x%X, rc=0x%X", + l_err->eid(), l_err->reasonCode()); + + } + + + }while(0); + + return l_err; +} + +}; //namespace PNOR + diff --git a/src/usr/pnor/test/pnorddtest.H b/src/usr/pnor/test/pnorddtest.H index 652ed0597..d762875b0 100644 --- a/src/usr/pnor/test/pnorddtest.H +++ b/src/usr/pnor/test/pnorddtest.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2011,2014 */ +/* Contributors Listed Below - COPYRIGHT 2011,2014 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -996,7 +998,7 @@ class PnorDdTest : public CxxTest::TestSuite sfc_cmd.opcode = PnorDD::SFC_OP_INVALID; sfc_cmd.length = 0; - mutex_lock(&(pnordd->cv_mutex)); + mutex_lock(pnordd->iv_mutex_ptr); l_err = pnordd->writeRegSfc(PnorDD::SFC_CMD_SPACE, PnorDD::SFC_REG_CMD, sfc_cmd.data32); @@ -1007,16 +1009,16 @@ class PnorDdTest : public CxxTest::TestSuite fails++; // Unlock mutex for Error Log to be commited - mutex_unlock(&(pnordd->cv_mutex)); + mutex_unlock(pnordd->iv_mutex_ptr); errlCommit(l_err,PNOR_COMP_ID); // Lock mutex for next operation - mutex_lock(&(pnordd->cv_mutex)); + mutex_lock(pnordd->iv_mutex_ptr); } // Poll for complete status without waiting l_err = pnordd->pollSfcOpComplete(); - mutex_unlock(&(pnordd->cv_mutex)); + mutex_unlock(pnordd->iv_mutex_ptr); total++; if ( l_err == NULL ) @@ -1037,7 +1039,7 @@ class PnorDdTest : public CxxTest::TestSuite sfc_cmd.opcode = PnorDD::SFC_OP_CHIPID; sfc_cmd.length = 0; - mutex_lock(&(pnordd->cv_mutex)); + mutex_lock(pnordd->iv_mutex_ptr); l_err = pnordd->writeRegSfc(PnorDD::SFC_CMD_SPACE, PnorDD::SFC_REG_CMD, sfc_cmd.data32); @@ -1049,11 +1051,11 @@ class PnorDdTest : public CxxTest::TestSuite fails++; // Unlock mutex for Error Log to be commited - mutex_unlock(&(pnordd->cv_mutex)); + mutex_unlock(pnordd->iv_mutex_ptr); errlCommit(l_err,PNOR_COMP_ID); // Lock mutex for next operation - mutex_lock(&(pnordd->cv_mutex)); + mutex_lock(pnordd->iv_mutex_ptr); } // Poll for complete status without waiting @@ -1076,7 +1078,7 @@ class PnorDdTest : public CxxTest::TestSuite /* before continuing */ /*******************************************************/ l_err = pnordd->pollSfcOpComplete(); - mutex_unlock(&(pnordd->cv_mutex)); + mutex_unlock(pnordd->iv_mutex_ptr); total++; if (l_err) |