/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/usr/sbe/sbe_update.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2013,2016 */ /* [+] Google Inc. */ /* [+] 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 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sbe_update.H" #include "sbe_resolve_sides.H" // fapi support #include #include //Procedures #include #include #include #include #include #include // ---------------------------------------------- // Trace definitions // ---------------------------------------------- trace_desc_t* g_trac_sbe = NULL; TRAC_INIT( & g_trac_sbe, SBE_COMP_NAME, 4*KILOBYTE ); // ------------------------ // Macros for unit testing //#define TRACUCOMP(args...) TRACFCOMP(args) #define TRACUCOMP(args...) // ---------------------------------------- // Global Variables for MBOX Ipl Query static bool g_mbox_query_done = false; static bool g_mbox_query_result = false; static bool g_istep_mode = false; static bool g_update_both_sides = false; using namespace ERRORLOG; using namespace TARGETING; namespace SBE { errlHndl_t updateProcessorSbeSeeproms(sbeUpdateCheckType i_check_type) { errlHndl_t err = NULL; errlHndl_t err_cleanup = NULL; sbeTargetState_t sbeState; std::vector sbeStates_vector; bool l_cleanupVmmSpace = false; bool l_restartNeeded = false; TRACUCOMP( g_trac_sbe, ENTER_MRK"updateProcessorSbeSeeproms(): i_check_type=%d", i_check_type); do{ #ifdef CONFIG_NO_SBE_UPDATES TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms() - " "SBE updates not configured"); break; #endif #ifdef CONFIG_SBE_UPDATE_SEQUENTIAL // Check if FSP-services are enabled and if we're running in simics if ( !INITSERVICE::spBaseServicesEnabled() && !Util::isSimicsRunning() ) { assert (false, "resolveProcessorSbeSeeproms() - " "SBE_UPDATE_SEQUENTIAL mode, but FSP-services are not " "enabled - Invalid Configuration"); } // else - continue on #endif // Get Target Service, and the system target. TargetService& tS = targetService(); TARGETING::Target* sys = NULL; (void) tS.getTopLevelTarget( sys ); assert(sys, "updateProcessorSbeSeeproms() system target is NULL"); /*****************************************************************/ /* Skip Update if MNFG_FLAG_FSP_UPDATE_SBE_IMAGE is set */ /* AND there is a FSP present */ /*****************************************************************/ ATTR_MNFG_FLAGS_type mnfg_flags = sys->getAttr(); if ( (mnfg_flags & MNFG_FLAG_FSP_UPDATE_SBE_IMAGE) && INITSERVICE::spBaseServicesEnabled() // true => FSP present ) { TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update skipped due to " "FSP present and MNFG_FLAG_FSP_UPDATE_SBE_IMAGE " "(0x%.16X) is set in MNFG Flags 0x%.16X", MNFG_FLAG_FSP_UPDATE_SBE_IMAGE, mnfg_flags); break; } // For a future check, determine if in istep mode and FSP is present if ( sys->getAttr() && // true => istep mode INITSERVICE::spBaseServicesEnabled() ) // true => FSP present { g_istep_mode = true; } if (mnfg_flags & MNFG_FLAG_UPDATE_BOTH_SIDES_OF_SBE) { TRACFCOMP(g_trac_sbe, INFO_MRK"Update Both Sides of SBE Flag Indicated."); bool l_isGoldenSide=true; errlHndl_t l_err = isGoldenSide(l_isGoldenSide); if(l_err) { TRACFCOMP(g_trac_sbe, ERR_MRK"updateProcessorSbeSeeproms::isGoldenSide " "returned an error, RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); errlCommit( l_err, SBE_COMP_ID ); l_isGoldenSide = true; } if (l_isGoldenSide) { g_update_both_sides = false; TRACFCOMP(g_trac_sbe, INFO_MRK"Boot on Golden Side - Ignoring Update " "both sides of SBE Flag"); } else { g_update_both_sides = true; } } //Make sure procedure constants keep within expected range. assert((FIXED_SEEPROM_WORK_SPACE <= VMM_SBE_UPDATE_SIZE/2), "updateProcessorSbeSeeproms() FIXED_SEEPROM_WORK_SPACE " "too large"); assert((MAX_RING_BUF_SIZE <= VMM_SBE_UPDATE_SIZE/4), "updateProcessorSbeSeeproms() MAX_RING_BUF_SIZE too " "large"); // reset global variables for MBOX Ipl Query g_mbox_query_done = false; g_mbox_query_result = false; // Create VMM space for p9_xip_customize() procedure err = createSbeImageVmmSpace(); if (err) { TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): " "createSbeImageVmmSpace() Failed. ", "rc=0x%.4X", err->reasonCode() ); break; } else { // Make sure cleanup gets called l_cleanupVmmSpace = true; } /*****************************************************************/ /* Iterate over all the functional processors and do for each: */ /* 1) Check their SBE State (PNOR, MVPD, SEEPROMs, etc), */ /* 2) Determine the Necessary Update */ /* 3) Perform Update Action */ /*****************************************************************/ TARGETING::TargetHandleList procList; TARGETING::getAllChips(procList, TARGETING::TYPE_PROC, true); // true: return functional targets if( ( 0 == procList.size() ) || ( NULL == procList[0] ) ) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateProcessorSbeSeeproms() - " "No functional processors Found!" ); break; } // Get the Master Proc Chip Target for comparisons later TARGETING::Target* masterProcChipTargetHandle = NULL; err = tS.queryMasterProcChipTargetHandle( masterProcChipTargetHandle); if (err) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateProcessorSbeSeeproms() - " "queryMasterProcChipTargetHandle returned error. " "Commit here and continue. Check below against " "masterProcChipTargetHandle=NULL is ok, " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); errlCommit( err, SBE_COMP_ID ); err = NULL; } for(uint32_t i=0; ireasonCode(), TARGETING::get_huid(sbeState.target)); // Don't break - handle error at the end of the loop } // Continue if we're just doing the nest freq check and don't // have a mismatch if ( ( i_check_type == SBE_UPDATE_ONLY_CHECK_NEST_FREQ ) && ( sbeState.seeprom_0_ver_Nest_Freq_Mismatch == false ) && ( sbeState.seeprom_1_ver_Nest_Freq_Mismatch == false ) ) { TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): " "Only looking for Nest Freq Mismatch and " "none found for Target UID=0x%X", TARGETING::get_huid(sbeState.target)); sbeState.update_actions = CLEAR_ACTIONS; } /**********************************************/ /* Determine update actions for this target */ /**********************************************/ // Skip if we got an error collecting SBE Info State else if ( err == NULL ) { err = getTargetUpdateActions(sbeState); if (err) { TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): " "getTargetUpdateActions() Failed " "rc=0x%.4X, Target UID=0x%X", err->reasonCode(), TARGETING::get_huid(sbeState.target)); // Don't break - handle error at the end of the loop, } } /**********************************************/ /* Perform Update Actions For This Target */ /**********************************************/ if ((err == NULL) && (sbeState.update_actions & DO_UPDATE)) { err = performUpdateActions(sbeState); if (err) { TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): " "performUpdateActions() Failed " "rc=0x%.4X, Target UID=0x%X", err->reasonCode(), TARGETING::get_huid(sbeState.target)); // Don't break - handle error at the end of the loop, } else { // Target updated without failure, so set IPL_RESTART // flag, if necessary if (sbeState.update_actions & IPL_RESTART) { l_restartNeeded = true; } } } if ( err ) { // Something failed for this target. // Save error information sbeState.err_plid = err->plid(); sbeState.err_eid = err->eid(); sbeState.err_rc = err->reasonCode(); // Commit the error here and move on to the next target, // or if no targets left, will just continue the IPL TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): " "Committing Error Log rc=0x%.4X eid=0x%.8X " "plid=0x%.8X for Target UID=0x%X, but " "continuing procedure", sbeState.err_rc, sbeState.err_eid, sbeState.err_plid, TARGETING::get_huid(sbeState.target)); errlCommit( err, SBE_COMP_ID ); } // Push this sbeState onto the vector sbeStates_vector.push_back(sbeState); } //end of Target for loop collecting each target's SBE State /**************************************************************/ /* Perform System Operation */ /**************************************************************/ // Restart IPL if SBE Update requires it if ( l_restartNeeded == true ) { TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): Restart " "Needed (%d). Calling preReIplCheck()", l_restartNeeded); err = preReIplCheck(sbeStates_vector); if ( err ) { // Something failed on the check. Commit the error here // and continue with the Re-IPL Request TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): " "Committing Error Log rc=0x%.4X from " "preReIplCheck(), but doing Re-IPL", err->reasonCode()); errlCommit( err, SBE_COMP_ID ); } #ifdef CONFIG_BMC_IPMI err = sbePreRebootIpmiCalls(); if (err) { TRACFCOMP( g_trac_sbe,ERR_MRK"sbePreRebootIpmiCalls " "failed"); break; } #endif #ifdef CONFIG_CONSOLE CONSOLE::displayf(SBE_COMP_NAME, "System Rebooting To " "Perform SBE Update\n"); CONSOLE::flush(); #endif #ifndef CONFIG_BMC_IPMI TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): Calling " "INITSERVICE::doShutdown() with " "SBE_UPDATE_REQUEST_REIPL = 0x%X", SBE_UPDATE_REQUEST_REIPL ); INITSERVICE::doShutdown(SBE_UPDATE_REQUEST_REIPL); #endif } /************************************************************/ /* Deconfigure any Processors that have a Version different */ /* from the Master Processor's Version */ /************************************************************/ // skip if we're only checking for NEST_FREQ mismatch if ( i_check_type != SBE_UPDATE_ONLY_CHECK_NEST_FREQ ) { err = masterVersionCompare(sbeStates_vector); if ( err ) { // Something failed on the check TRACFCOMP( g_trac_sbe, INFO_MRK"updateProcessorSbeSeeproms(): Call to " "masterVersionCompare() failed rc=0x%.4X", err->reasonCode()); } } }while(0); // Cleanup VMM Workspace if ( l_cleanupVmmSpace == true ) { err_cleanup = cleanupSbeImageVmmSpace(); if ( err_cleanup != NULL ) { if ( err != NULL ) { // 2 error logs, so commit the cleanup log here TRACFCOMP( g_trac_sbe, ERR_MRK"updateProcessorSbeSeeproms(): Previous " "error (rc=0x%X) before cleanupSbeImageVmmSpace" "() failed. Committing cleanup error (rc=0x%X) " "and returning original error", err->reasonCode(), err_cleanup->reasonCode() ); errlCommit( err_cleanup, SBE_COMP_ID ); } else { // no previous error, so returning cleanup error TRACFCOMP( g_trac_sbe, ERR_MRK"updateProcessorSbeSeeproms(): " "cleanupSbeImageVmmSpace() failed.", "rc=0x%.4X", err_cleanup->reasonCode() ); err = err_cleanup; } } } TRACUCOMP( g_trac_sbe, EXIT_MRK"updateProcessorSbeSeeproms()" ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t findSBEInPnor(TARGETING::Target* i_target, void*& o_imgPtr, size_t& o_imgSize, sbe_image_version_t* o_version) { errlHndl_t err = NULL; PNOR::SectionInfo_t pnorInfo; sbeToc_t* sbeToc = NULL; uint8_t ec = 0; PNOR::SectionId pnorSectionId = PNOR::INVALID_SECTION; void* hdr_Ptr = NULL; o_imgPtr = NULL; o_imgSize = 0; TRACDCOMP( g_trac_sbe, ENTER_MRK"findSBEInPnor()" ); do{ // Get the correct PNOR Section Id if ( i_target->getAttr() == TYPE_PROC ) { pnorSectionId = PNOR::SBE_IPL; } else if ( i_target->getAttr() == TYPE_MEMBUF ) { pnorSectionId = PNOR::CENTAUR_SBE; } else { // Unsupported target type was passed in TRACFCOMP( g_trac_sbe, ERR_MRK"findSBEInPnor: Unsupported " "target type was passed in: uid=0x%X, type=0x%X", TARGETING::get_huid(i_target), i_target->getAttr()); /*@ * @errortype * @moduleid SBE_FIND_IN_PNOR * @reasoncode SBE_INVALID_INPUT * @userdata1 Target Unit Id * @userdata2 Target Type * @devdesc Unsupported Target Type passed in * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_FIND_IN_PNOR, SBE_INVALID_INPUT, TARGETING::get_huid(i_target), i_target->getAttr()); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } // Get SBE PNOR section info from PNOR RP err = getSectionInfo( pnorSectionId, pnorInfo ); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"findSBEInPnor: Error calling " "getSectionInfo() rc=0x%.4X", err->reasonCode() ); break; } TRACUCOMP( g_trac_sbe, INFO_MRK"findSBEInPnor: UID=0x%X, sectionId=0x%X. " "pnor vaddr = 0x%.16X", TARGETING::get_huid(i_target), pnorSectionId, pnorInfo.vaddr); sbeToc = reinterpret_cast( pnorInfo.vaddr ); if (sbeToc->eyeCatch != SBETOC_EYECATCH) { //The SBE partition does not have the proper eyecatcher TRACFCOMP( g_trac_sbe, ERR_MRK"findSBEInPnor: SBE partition " "does not have the proper eyecatcher: was: 0x%X, " "should be: 0x%X", sbeToc->eyeCatch, SBETOC_EYECATCH ); TRACFBIN( g_trac_sbe, "sbeToc", sbeToc, sizeof(sbeToc_t)); /*@ * @errortype * @moduleid SBE_FIND_IN_PNOR * @reasoncode SBE_INVALID_EYECATCHER * @userdata1 SBE TOC EYE-CATCHER * @userdata2 Expected EYE-CATCHER * @devdesc Unsupported EYE-CATCHER found in TOC * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_FIND_IN_PNOR, SBE_INVALID_EYECATCHER, sbeToc->eyeCatch, SBETOC_EYECATCH); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_SP_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } else { //Check the TOC Version if( SUPPORTED_TOC_VER != sbeToc->tocVersion) { TRACFCOMP( g_trac_sbe, ERR_MRK"findSBEInPnor: Unsupported " "SBE TOC Version in SBE Partition" ); TRACFBIN( g_trac_sbe, "sbeToc", sbeToc, sizeof(sbeToc_t)); /*@ * @errortype * @moduleid SBE_FIND_IN_PNOR * @reasoncode SBE_UNSUPPORTED_TOC * @userdata1[0:31] CHIP EC * @userdata1[32:63] Expected TOC Version * @userdata2[0:31] SBE TOC Version * @userdata2[32:63] SBE TOC EyeCatch * @devdesc SBE partition contains unsupported version * of Table of Contents * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_FIND_IN_PNOR, SBE_UNSUPPORTED_TOC, TWO_UINT32_TO_UINT64(ec, SUPPORTED_TOC_VER), TWO_UINT32_TO_UINT64(sbeToc->tocVersion, sbeToc->eyeCatch)); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_SP_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } //Walk the TOC and find our current EC ec = i_target->getAttr(); for(uint32_t i=0; i(ec) == sbeToc->entries[i].ec) { // EC found in TOC uint64_t offset = pnorInfo.vaddr + static_cast(sbeToc->entries[i].offset); hdr_Ptr = reinterpret_cast( offset ); o_imgSize = sbeToc->entries[i].size; TRACUCOMP( g_trac_sbe, INFO_MRK"findSBEInPnor: Found " "EC Image: ec=0x%.2X offset=0x%.16X, i=%d " "size=0x%X", ec, offset, i, o_imgSize ); break; } } } if(NULL == hdr_Ptr) { //if we get here, it's an error TRACFCOMP( g_trac_sbe,ERR_MRK"findSBEInPnor:SBE Image not " "located, ec=0x%.2X",ec ); TRACFBIN( g_trac_sbe, "sbeToc", sbeToc, sizeof(sbeToc_t)); /*@ * @errortype * @moduleid SBE_FIND_IN_PNOR * @reasoncode SBE_EC_NOT_FOUND * @userdata1[0:31] CHIP EC * @userdata1[32:63] PNOR Section ID * @userdata2[0:31] SBE TOC Version * @userdata2[32:63] SBE TOC EyeCatch * @devdesc SBE image for current chip EC was not found * in PNOR * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_FIND_IN_PNOR, SBE_EC_NOT_FOUND, TWO_UINT32_TO_UINT64(ec, pnorSectionId), TWO_UINT32_TO_UINT64(sbeToc->tocVersion, sbeToc->eyeCatch)); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_SP_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } // The SBE Image for the corresponding EC was found, check if // it includes a SBE Header if (pnorInfo.sha512perEC) { TRACFCOMP(g_trac_sbe,INFO_MRK"findSBEInPnor: sha512perEC " "Found in %s", pnorInfo.name); // Advance PNOR pointer 4k to move it past header page to the // start of the non-customized SBE image o_imgPtr = reinterpret_cast (reinterpret_cast(hdr_Ptr)+0x1000); } if(NULL != o_version) { err = readPNORVersion(hdr_Ptr, *o_version); if(err) { break; } } }while(0); TRACDCOMP( g_trac_sbe, EXIT_MRK"findSBEInPnor(): o_imgPtr=%p, o_imgSize=0x%X", o_imgPtr, o_imgSize ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t findHBBLInPnor(void*& o_imgPtr, size_t& o_imgSize) { errlHndl_t err = NULL; PNOR::SectionInfo_t pnorInfo; hbblEndData_t* hbblEndData = NULL; PNOR::SectionId pnorSectionId = PNOR::HB_BOOTLOADER; o_imgPtr = NULL; o_imgSize = 0; TRACDCOMP( g_trac_sbe, ENTER_MRK"findHBBLInPnor()" ); do{ // Get SBE PNOR section info from PNOR RP err = getSectionInfo( pnorSectionId, pnorInfo ); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"findHBBLInPnor: Error calling " "getSectionInfo() rc=0x%.4X", err->reasonCode() ); break; } TRACUCOMP( g_trac_sbe, INFO_MRK"findHBBLInPnor: sectionId=0x%X. " "pnor vaddr = 0x%.16X", pnorSectionId, pnorInfo.vaddr); // Look for HBBL end data on 16-byte boundary start at offset 0x2C00 // Note: Code takes up at least the first 0x2C00 bytes of the HBBL // image, so start at that offset to search for this data. uint64_t hbblAbsoluteEnd = pnorInfo.vaddr + pnorInfo.size; uint64_t hbblAddr = pnorInfo.vaddr + 0x2C00; while( hbblAddr < hbblAbsoluteEnd ) { hbblEndData = reinterpret_cast(hbblAddr); if( HBBL_END_EYECATCHER == hbblEndData->eyecatcher ) { TRACUCOMP( g_trac_sbe, INFO_MRK"findHBBLInPnor: hbblEndData = %p, " "hbblEndData.address = 0x%.16X", hbblEndData, hbblEndData->address); break; } hbblAddr += sizeof(hbblEndData_t); } if( hbblAddr >= hbblAbsoluteEnd ) { //The HBBL partition does not have the HBBL end data TRACFCOMP( g_trac_sbe, ERR_MRK"findHBBLInPnor: HBBL partition " "does not have the HBBL end data" ); /*@ * @errortype * @moduleid HBBL_FIND_IN_PNOR * @reasoncode HBBL_END_DATA_NOT_FOUND * @userdata1 HBBL PNOR Section Address * @userdata2 HBBL PNOR Section Size * @devdesc HBBL partition did not have end data * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, HBBL_FIND_IN_PNOR, HBBL_END_DATA_NOT_FOUND, pnorInfo.vaddr, pnorInfo.size); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_SP_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } o_imgPtr = reinterpret_cast( pnorInfo.vaddr ); o_imgSize = hbblEndData->address - HBBL_START_ADDRESS; }while(0); TRACDCOMP( g_trac_sbe, EXIT_MRK"findHBBLInPnor(): o_imgPtr=%p, o_imgSize=0x%X", o_imgPtr, o_imgSize ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t appendHbblToSbe(void* i_section, uint32_t i_section_size, void* i_image, uint32_t& io_image_size) { errlHndl_t err = NULL; TRACUCOMP( g_trac_sbe, ENTER_MRK"appendHbblToSbe(): i_section=%p, " "i_section_size=0x%X, i_image=%p, " "io_image_size=0x%X", i_section, i_section_size, i_image, io_image_size); do{ // Invoke p9_xip_section_append to append HBBL image to SBE image FAPI_INVOKE_HWP( err, p9_xip_section_append, i_section, i_section_size, P9_XIP_SECTION_SBE_HBBL, i_image, io_image_size ); // Check for error if(err) { TRACUCOMP( g_trac_sbe, "appendHbblToSbe(): " "p9_xip_section_append failed, rc=0x%X", err->reasonCode() ); // exit loop break; } }while(0); TRACUCOMP( g_trac_sbe, EXIT_MRK"appendHbblToSbe(): i_image=%p, " "io_image_size=0x%X, RC=0x%X", i_image, io_image_size, ERRL_GETRC_SAFE(err) ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t ringOvd(void *io_imgPtr, uint32_t & io_ovdImgSize) { errlHndl_t l_err = nullptr; PNOR::SectionInfo_t l_pnorRingOvd; do { l_err = PNOR::getSectionInfo(PNOR::RINGOVD, l_pnorRingOvd); if(l_err) { TRACFCOMP( g_trac_sbe, ERR_MRK"ringOvd():Error trying to read RINGOVD " "from PNOR!"); io_ovdImgSize = 0; break; } if(l_pnorRingOvd.size == 0) { TRACFCOMP( g_trac_sbe, INFO_MRK"ringOvd(): No RINGOVD section in PNOR"); io_ovdImgSize = 0; break; } TRACDBIN( g_trac_sbe, "ringOvd():100 bytes of RINGOVD section", (void *)l_pnorRingOvd.vaddr,100); // If first 8 bytes are just FF's then we know there's no override if((*(static_cast((void *)l_pnorRingOvd.vaddr))) == 0xFFFFFFFFFFFFFFFF) { TRACFCOMP( g_trac_sbe, INFO_MRK"ringOvd():No overrides in RINGOVD section " "found"); io_ovdImgSize = 0; break; } TRACFCOMP( g_trac_sbe, INFO_MRK"ringOvd():Valid overrides, applying them"); // Hard coded value, pass in 2KB max uint32_t RING_OVD_SIZE = 0x800; FAPI_INVOKE_HWP(l_err,p9_xip_section_append, (void *)l_pnorRingOvd.vaddr, RING_OVD_SIZE, P9_XIP_SECTION_SBE_OVERRIDES, io_imgPtr, io_ovdImgSize); if ( l_err ) { TRACFCOMP( g_trac_sbe, ERR_MRK"ringOvd(): FAPI_EXEC_HWP(" "p9_xip_section_append) failed, PLID=0x%x", l_err->plid()); l_err->collectTrace(SBE_COMP_NAME, 256); io_ovdImgSize = 0; break; } }while(0); return l_err; } ///////////////////////////////////////////////////////////////////// errlHndl_t procCustomizeSbeImg(TARGETING::Target* i_target, void* i_sbeImgPtr, size_t i_maxImgSize, void* io_imgPtr, size_t& o_actImgSize) { errlHndl_t err = NULL; uint32_t tmpImgSize = static_cast(i_maxImgSize); uint32_t coreMask = 0x00FFFFFF; // Bits(8:31) = EC00:EC23 size_t maxCores = P9_MAX_EC_PER_PROC; uint32_t coreCount = 0; uint32_t procIOMask = 0; bool procedure_success = false; TRACUCOMP( g_trac_sbe, ENTER_MRK"procCustomizeSbeImg(): uid=0x%X, i_sbeImgPtr= " "%p, maxS=0x%X, io_imgPtr=%p", TARGETING::get_huid(i_target), i_sbeImgPtr, i_maxImgSize, io_imgPtr); do{ // cast OUR type of target to a FAPI type of target. const fapi2::Target l_fapiTarg(i_target); // The p9_xip_customize() procedure tries to include as much core // information as possible, but is limited by SBE Image size // constraints. // First, maximize core mask for the target // Then loop on the procedure call, where the loop is designed to // remove the number of cores passed into p9_xip_customize() until // an image can be created successfully. // Maximize Core mask for this target err = selectBestCores(i_target, maxCores, coreMask); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"procCustomizeSbeImg() - " "selectBestCores() failed rc=0x%X. " "MaxCores=0x%.8X. HUID=0x%X. Aborting " "Customization of SBE Image", err->reasonCode(), maxCores, TARGETING::get_huid(i_target)); break; } // Get Target Service // System target check done earlier, so no assert check necessary TargetService& tS = targetService(); TARGETING::Target* sys = NULL; (void) tS.getTopLevelTarget( sys ); // setup loop parameters coreCount = __builtin_popcount(coreMask); uint32_t min_cores = sys->getAttr(); min_cores *= (is_fused_mode()) ? 2 : 1; // double minimum for fused while( coreCount >= min_cores ) { // copy customized SBE image to destination memcpy ( io_imgPtr, i_sbeImgPtr, tmpImgSize); procIOMask = coreMask; uint8_t l_ringSectionBuf[MAX_SEEPROM_IMAGE_SIZE]; uint32_t l_ringSectionBufSize = MAX_SEEPROM_IMAGE_SIZE; FAPI_INVOKE_HWP( err, p9_xip_customize, l_fapiTarg, io_imgPtr, //image in/out tmpImgSize, (void*)l_ringSectionBuf, l_ringSectionBufSize, SYSPHASE_HB_SBE, MODEBUILD_IPL, (void*)RING_BUF1_VADDR, (uint32_t)MAX_RING_BUF_SIZE, (void*)RING_BUF2_VADDR, (uint32_t)MAX_RING_BUF_SIZE, procIOMask ); // Bits(8:31) = EC00:EC23 // Check for no error if ( NULL == err ) { // Check if we have a valid ring override section and // append it in if so uint32_t l_ovdImgSize = static_cast(i_maxImgSize); err = ringOvd(io_imgPtr,l_ovdImgSize); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"procCustomizeSbeImg(): " "Error in call to ringOvd!"); break; } // If it's larger then the original size then we added some // overrides if(l_ovdImgSize > tmpImgSize) { // We added an override so adjust tmpImgSize TRACFCOMP( g_trac_sbe, INFO_MRK"procCustomizeSbeImg(): We added some " "ring overrides, initial image size:%u " "new image size:%u", tmpImgSize, l_ovdImgSize); tmpImgSize = l_ovdImgSize; } // Procedure was successful procedure_success = true; o_actImgSize = static_cast(tmpImgSize); TRACUCOMP( g_trac_sbe, "procCustomizeSbeImg(): " "p9_xip_customize success=%d, procIOMask=0x%X " "o_actImgSize=0x%X", procedure_success, procIOMask, o_actImgSize); // exit inner loop break; } // Check if p9_xip_customize returned a different core mask else if ( procIOMask != coreMask ) { // A different core mask is returned from p9_xip_customize // when the cores sent in couldn't fit, but possibly // a different procIOMask would work TRACFCOMP( g_trac_sbe, ERR_MRK"procCustomizeSbeImg(): FAPI_EXEC_HWP(" "p9_xip_customize) returned rc=0x%X, " "XIPC_IMAGE_WOULD_OVERFLOW-Retry " "MaxCores=0x%.8X. HUID=0x%X. coreMask=0x%.8X, " "procIOMask=0x%.8X. coreCount=%d", ERRL_GETRC_SAFE(err), maxCores, TARGETING::get_huid(i_target), coreMask, procIOMask, coreCount); // Setup for next loop - update coreMask err = selectBestCores(i_target, --coreCount, coreMask); if ( err ) { TRACFCOMP(g_trac_sbe, ERR_MRK"procCustomizeSbeImg() - " "selectBestCores() failed rc=0x%X. " "coreCount=0x%.8X. HUID=0x%X. Aborting " "Customization of SBE Image", err->reasonCode(), coreCount, TARGETING::get_huid(i_target)); // break from inner while loop break; } TRACFCOMP( g_trac_sbe, "procCustomizeSbeImg(): for " "next loop: coreMask=0x%.8X, coreCount=%d", coreMask, coreCount); // Check if loop will execute again // Clean up some data if it will if( coreCount >= min_cores ) { // Reset size and clear image buffer tmpImgSize = static_cast(i_maxImgSize); memset ( io_imgPtr, 0, tmpImgSize); } // No break - keep looping } else { // Unexpected return code - create err and fail TRACFCOMP( g_trac_sbe, ERR_MRK"procCustomizeSbeImg(): FAPI_EXEC_HWP(" "p9_xip_customize) failed with rc=0x%X, " "MaxCores=0x%X. HUID=0x%X. coreMask=0x%.8X, " "procIOMask=0x%.8X. coreCount=%d. Create " "err and break loop", ERRL_GETRC_SAFE(err), maxCores, TARGETING::get_huid(i_target), coreMask, procIOMask, coreCount); ERRORLOG::ErrlUserDetailsTarget(i_target, "Proc Target") .addToLog(err); err->collectTrace(SBE_COMP_NAME, 256); // break from inner while loop break; } } // end of inner while loop if(err) { // There was a previous error, so break here break; } if ( procedure_success == false ) { // No err, but exit from while loop before successful TRACFCOMP( g_trac_sbe, ERR_MRK"procCustomizeSbeImg() - " "Failure to successfully complete p9_xip_customize()" ". HUID=0x%X, rc=0x%X, coreCount=%d, coreMask=0x%.8X" " procIOMask=0x%.8X, maxCores=0x%X, min_cores=0x%X", TARGETING::get_huid(i_target), ERRL_GETRC_SAFE(err), coreCount, coreMask, procIOMask, maxCores, min_cores); /*@ * @errortype * @moduleid SBE_CUSTOMIZE_IMG * @reasoncode SBE_P9_XIP_CUSTOMIZE_UNSUCCESSFUL * @userdata1[0:31] procIOMask in/out parameter * @userdata1[32:63] rc of procedure * @userdata2[0:31] coreMask of target * @userdata2[32:63] coreCount - updated on the loops * @devdesc Unsuccessful in creating Customized SBE Image * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_CUSTOMIZE_IMG, SBE_P9_XIP_CUSTOMIZE_UNSUCCESSFUL, TWO_UINT32_TO_UINT64(procIOMask, ERRL_GETRC_SAFE(err)), TWO_UINT32_TO_UINT64(coreMask, coreCount)); ErrlUserDetailsTarget(i_target ).addToLog(err); err->collectTrace("FAPI", 256); err->collectTrace(SBE_COMP_NAME, 256); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); } }while(0); TRACUCOMP( g_trac_sbe, EXIT_MRK"procCustomizeSbeImg(): io_imgPtr=%p, " "o_actImgSize=0x%X, RC=0x%X, procedure_success=%d", io_imgPtr, o_actImgSize, ERRL_GETRC_SAFE(err), procedure_success ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t selectBestCores(TARGETING::Target* i_target, size_t i_maxCores, uint32_t& o_coreMask) { TRACUCOMP( g_trac_sbe, ENTER_MRK"selectBestCores(i_maxCores=0x%.8X)", i_maxCores); errlHndl_t err = NULL; const uint32_t chipUnitMask = 0x00800000; // Bits(8:31) = EC00:EC23 uint32_t manGuardEcs = 0x00000000; uint32_t remainingEcs = 0x00000000; uint32_t coreCount = 0; uint32_t deconfigByEid = 0; o_coreMask = 0x00000000; do{ // Special case: if i_maxCores == 0 don't loop through cores if (unlikely(i_maxCores == 0 )) { break; } // find all CORE chiplets of the proc TARGETING::TargetHandleList l_coreTargetList; TARGETING::getChildAffinityTargetsByState( l_coreTargetList, i_target, CLASS_UNIT, TYPE_CORE, UTIL_FILTER_PRESENT); //Sort through cores for( const auto & l_core_target: l_coreTargetList ) { uint8_t chipUnit = l_core_target-> getAttr(); if(l_core_target-> getAttr().functional) { o_coreMask |= (chipUnitMask >> chipUnit); coreCount++; } else { //If non-functional due to FCO or Manual gard, //add it to list of cores to include if //more are needed deconfigByEid = l_core_target-> getAttr(). deconfiguredByEid; if( // FCO (deconfigByEid == HWAS::DeconfigGard::DECONFIGURED_BY_FIELD_CORE_OVERRIDE) || // Manual GARD (deconfigByEid == HWAS::DeconfigGard::DECONFIGURED_BY_MANUAL_GARD) ) { manGuardEcs |= (chipUnitMask >> chipUnit); } // Add it to the 'remaining' list in case // more are needed else { remainingEcs |= (chipUnitMask >> chipUnit); } } } // end core target loop if(coreCount == i_maxCores) { //We've found the exact amount, break out of function break; } else if(coreCount > i_maxCores) { //We have too many, so need to trim o_coreMask = trimBitMask(o_coreMask, i_maxCores); break; } else { // We need to add 'other' cores TRACUCOMP( g_trac_sbe,INFO_MRK"selectBestCores: non-functional " "cores needed for bit mask: coreCount=%d, " "i_maxCores=%d, o_coreMask=0x%.8X, " "manGuardEcs=0x%.8X, remainingEcs=0x%.8X", coreCount, i_maxCores, o_coreMask, manGuardEcs, remainingEcs ); } // Add more 'good' cores. manGuardEcs = trimBitMask(manGuardEcs, i_maxCores-coreCount); o_coreMask |= manGuardEcs; coreCount = __builtin_popcount(o_coreMask); TRACUCOMP( g_trac_sbe,INFO_MRK"selectBestCores: trimBitMask " "manGuardEcs=0x%.8X", manGuardEcs); if(coreCount >= i_maxCores) { //We've found enough, break out of function break; } // If we still need more, add 'remaining' cores // Get Target Service // System target check done earlier, so no assert check necessary TargetService& tS = targetService(); TARGETING::Target* sys = NULL; (void) tS.getTopLevelTarget( sys ); uint32_t min_cores = sys->getAttr(); min_cores *= (is_fused_mode()) ? 2 : 1; // double minimum for fused if ( coreCount < min_cores ) { remainingEcs = trimBitMask(remainingEcs, min_cores-coreCount); o_coreMask |= remainingEcs; TRACUCOMP( g_trac_sbe,INFO_MRK"selectBestCores: trimBitMask " "remainingEcs=0x%.8X, min_cores=%d", remainingEcs, min_cores); } }while(0); TRACUCOMP( g_trac_sbe, EXIT_MRK"selectBestCores(o_coreMask=0x%.8X)", o_coreMask); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t getSetMVPDVersion(TARGETING::Target* i_target, opType_t i_op, mvpdSbKeyword_t& io_sb_keyword) { errlHndl_t err = NULL; size_t vpdSize = 0; TRACUCOMP( g_trac_sbe, ENTER_MRK"getSetMVPDVersion(i_op=%d)", i_op ); do{ // Read SB Keyword which contains SBE version and dirty bit // information // Note: First read with NULL for o_buffer sets vpdSize to the // correct length err = deviceRead( i_target, NULL, vpdSize, DEVICE_MVPD_ADDRESS( MVPD::CP00, MVPD::SB ) ); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSetMVPDVersion() - MVPD " "failure getting SB keywordw size HUID=0x%.8X", TARGETING::get_huid(i_target)); break; } if(vpdSize != MVPD_SB_RECORD_SIZE) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSetMVPDVersion() - MVPD SB " "keyword wrong length HUID=0x%.8X, length=0x%.2X, " "expected=0x%.2x", TARGETING::get_huid(i_target), vpdSize, MVPD_SB_RECORD_SIZE); /*@ * @errortype * @moduleid SBE_GETSET_MVPD_VERSION * @reasoncode SBE_MVPD_LEN_INVALID * @userdata1 Discovered VPD Size * @userdata2 Expected VPD Size * @devdesc SB Keyword in MVPD has invalid size * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_GETSET_MVPD_VERSION, SBE_MVPD_LEN_INVALID, TO_UINT64(vpdSize), TO_UINT64(MVPD_SB_RECORD_SIZE)); ErrlUserDetailsTarget(i_target ).addToLog(err); err->collectTrace(SBE_COMP_NAME, 256); err->addProcedureCallout( HWAS::EPUB_PRC_SP_CODE, HWAS::SRCI_PRIORITY_HIGH ); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_MED ); break; } if(i_op == MVPDOP_READ) { err = deviceRead( i_target, reinterpret_cast( &io_sb_keyword ), vpdSize, DEVICE_MVPD_ADDRESS( MVPD::CP00, MVPD::SB ) ); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSetMVPDVersion() - MVPD " "failure reading SB keyword data HUID=0x%.8X", TARGETING::get_huid(i_target)); break; } TRACDBIN(g_trac_sbe, "MVPD:SB:r", &io_sb_keyword, vpdSize); } else //write { TRACDBIN(g_trac_sbe, "MVPD:SB:w", &io_sb_keyword, vpdSize); err = deviceWrite( i_target, reinterpret_cast( &io_sb_keyword ), vpdSize, DEVICE_MVPD_ADDRESS( MVPD::CP00, MVPD::SB ) ); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSetMVPDVersion() - MVPD " "failure writing SB keyword data HUID=0x%.8X", TARGETING::get_huid(i_target)); break; } } }while(0); TRACUCOMP( g_trac_sbe, EXIT_MRK"getSetMVPDVersion()" ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t readPNORVersion(void*& i_pnorImgHdrPtr, sbe_image_version_t& o_version) { errlHndl_t err = NULL; TRACDCOMP( g_trac_sbe, ENTER_MRK"readPNORVersion()" ); do{ // @todo RTC 34080 - support Secure Boot Header //For Non-secure systems, version is prefixed with //'VERSION\0' in ASCII in the 4k header. The official //protocol is to scan for VERSION, then grab the value //that follows. char* tmpPtr = static_cast(i_pnorImgHdrPtr); //Last reasonable offset is (Version size + //size of eyecatcher) bytes from end of Page. char* endPtr = tmpPtr +(4*KILOBYTE) - sizeof(sbe_image_version_t&) - sizeof(NONSECURE_VER_EYECATCH); // Increment pointer sizeof(uint64_t) because eyecatcher // must be 8-byte aligned for(; tmpPtr(tmpPtr)) == NONSECURE_VER_EYECATCH) { //increment 8 more bytes and break out tmpPtr+=sizeof(uint64_t); break; } } if(tmpPtr < endPtr) { memcpy(reinterpret_cast( &o_version ), tmpPtr, sizeof(o_version)); } else { TRACFCOMP( g_trac_sbe, ERR_MRK"readPNORVersion() - VERSION not found in SBE image in PNOR"); /*@ * @errortype * @moduleid SBE_READ_PNOR_VERSION * @reasoncode SBE_VERSION_NOT_FOUND * @userdata1 Not Used * @userdata2 Not Used * @devdesc Image Version not found in PNOR * SBE image. * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_READ_PNOR_VERSION, SBE_VERSION_NOT_FOUND, 0, 0); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_SP_CODE, HWAS::SRCI_PRIORITY_HIGH ); } }while(0); TRACDCOMP( g_trac_sbe, EXIT_MRK"readPNORVersion()" ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t getSbeBootSeeprom(TARGETING::Target* i_target, sbeSeepromSide_t& o_bootSide) { TRACFCOMP( g_trac_sbe, ENTER_MRK"getSbeBootSeeprom()" ); errlHndl_t err = NULL; uint64_t scomData = 0x0; o_bootSide = SBE_SEEPROM0; do{ TARGETING::Target * l_target=i_target; #if defined(CONFIG_SBE_UPDATE_INDEPENDENT) || \ defined(CONFIG_SBE_UPDATE_SIMULTANEOUS) // Get the Master Proc Chip Target for comparisons later TARGETING::Target* masterProcChipTargetHandle = NULL; TargetService& tS = targetService(); err = tS.queryMasterProcChipTargetHandle( masterProcChipTargetHandle); if ( i_target != masterProcChipTargetHandle ) { l_target=masterProcChipTargetHandle; TRACFCOMP( g_trac_sbe, INFO_MRK"getSbeBootSeeprom() " "using master proc to read SBE_VITAL_REG: " "i_target=0x%.8x, target=0x%.8x ", TARGETING::get_huid(i_target), TARGETING::get_huid(l_target)); } #endif // Read PERV_SB_CS_SCOM 0x00050008 size_t op_size = sizeof(scomData); err = deviceRead( l_target, &scomData, op_size, DEVICE_SCOM_ADDRESS(PERV_SB_CS_SCOM) ); if( err ) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeBootSeeprom() -Error " "reading SB CS SCOM (0x%.8X) from Target :" "HUID=0x%.8X, RC=0x%X, PLID=0x%lX", PERV_SB_CS_SCOM, // 0x00050008 TARGETING::get_huid(l_target), ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } if(scomData & SBE_BOOT_SELECT_MASK) { o_bootSide = SBE_SEEPROM1; } }while(0); TRACFCOMP( g_trac_sbe, EXIT_MRK"getSbeBootSeeprom(): o_bootSide=0x%X (reg=0x%X, " "tgt=0x%X)", o_bootSide, scomData, TARGETING::get_huid(i_target) ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t getSbeInfoState(sbeTargetState_t& io_sbeState, sbeUpdateCheckType& i_check_type) { TRACUCOMP( g_trac_sbe, ENTER_MRK"getSbeInfoState(): HUID=0x%.8X", TARGETING::get_huid(io_sbeState.target)); errlHndl_t err = NULL; bool skip_customization = false; void *sbeHbblImgPtr = NULL; do{ /************************************************************/ /* Set Target Properties (target_is_master previously set) */ /************************************************************/ io_sbeState.ec = io_sbeState.target->getAttr(); /*******************************************/ /* Get SEEPROM A SBE Version Information */ /*******************************************/ err = getSeepromSideVersion(io_sbeState.target, EEPROM::SBE_PRIMARY, io_sbeState.seeprom_0_ver, io_sbeState.seeprom_0_ver_ECC_fail); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - Error " "getting SBE Information from SEEPROM A (0x%X), " "RC=0x%X, PLID=0x%lX", EEPROM::SBE_PRIMARY, ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } TRACDBIN(g_trac_sbe, "getSbeInfoState-spA", &(io_sbeState.seeprom_0_ver), sizeof(sbeSeepromVersionInfo_t)); /*******************************************/ /* Get SEEPROM B SBE Version Information */ /*******************************************/ err = getSeepromSideVersion(io_sbeState.target, EEPROM::SBE_BACKUP, io_sbeState.seeprom_1_ver, io_sbeState.seeprom_1_ver_ECC_fail); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - Error " "getting SBE Information from SEEPROM B (0x%X), " "RC=0x%X, PLID=0x%lX", EEPROM::SBE_BACKUP, ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } TRACDBIN(g_trac_sbe, "getSbeInfoState-spB", &(io_sbeState.seeprom_1_ver), sizeof(sbeSeepromVersionInfo_t)); // Check NEST_FREQ settings err = checkNestFreqSettings(io_sbeState); if (err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - " "Error returned from checkNestFreqSettings(), " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } else if ((i_check_type == SBE_UPDATE_ONLY_CHECK_NEST_FREQ) && (io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch == false) && (io_sbeState.seeprom_1_ver_Nest_Freq_Mismatch == false)) { TRACFCOMP( g_trac_sbe, INFO_MRK"getSbeInfoState(): " "Only looking for Nest Freq Mismatch and " "none found for Target UID=0x%X. Skipping " "SBE customization", TARGETING::get_huid(io_sbeState.target)); // Skipping SBE customization, but still need other info like // MVPD in the case another processor requires a re-IPL skip_customization = true; } /*******************************************/ /* Get PNOR SBE Version Information */ /*******************************************/ void* sbePnorPtr = NULL; size_t sbePnorImageSize = 0; sbe_image_version_t tmp_pnorVersion; err = findSBEInPnor(io_sbeState.target, sbePnorPtr, sbePnorImageSize, &tmp_pnorVersion); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - " "Error getting SBE Version from PNOR, " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } else { TRACFCOMP( g_trac_sbe, "getSbeInfoState() - " "sbePnorPtr=%p, sbePnorImageSize=0x%08X (%d)", sbePnorPtr, sbePnorImageSize, sbePnorImageSize); } // copy tmp_pnorVersion to the main structure memcpy ( &io_sbeState.pnorVersion, &tmp_pnorVersion, sizeof(tmp_pnorVersion)); /*******************************************/ /* Get PNOR HBBL Information */ /*******************************************/ void* hbblPnorPtr = NULL; size_t hbblPnorImageSize = 0; size_t hbblCachelineSize = 0; err = findHBBLInPnor(hbblPnorPtr, hbblPnorImageSize); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - " "Error getting HBBL Version from PNOR, " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } else { TRACFCOMP( g_trac_sbe, "getSbeInfoState() - " "hbblPnorPtr=%p, hbblPnorImageSize=0x%08X (%d)", hbblPnorPtr, hbblPnorImageSize, hbblPnorImageSize); } hbblCachelineSize = ALIGN_X(hbblPnorImageSize, CACHELINE_SIZE); TRACUCOMP( g_trac_sbe, "getSbeInfoState() - HBBL: " "maxSize=0x%X, actSize=0x%X, cachelineSize=0x%X", HBBL_MAX_SIZE, hbblPnorImageSize, hbblCachelineSize); /*******************************************/ /* Append HBBL Image from PNOR to SBE */ /* Image from PNOR */ /*******************************************/ uint32_t sbeHbblImgSize = static_cast(sbePnorImageSize + hbblCachelineSize); // copy SBE image from PNOR to memory sbeHbblImgPtr = malloc(sbeHbblImgSize); memcpy ( sbeHbblImgPtr, sbePnorPtr, sbePnorImageSize); err = appendHbblToSbe(hbblPnorPtr, // HBBL Image to append hbblCachelineSize, // Size of HBBL Image sbeHbblImgPtr, // SBE, HBBL Image sbeHbblImgSize); // Available/used if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - " "Error from procAppendHbblToSbe(), " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } /*******************************************/ /* Customize SBE/HBBL Image and */ /* Calculate CRC of the image */ /*******************************************/ size_t sbeImgSize = 0; if ( skip_customization == false ) { err = procCustomizeSbeImg(io_sbeState.target, sbeHbblImgPtr, //SBE, HBBL in memory FIXED_SEEPROM_WORK_SPACE, //max size reinterpret_cast (SBE_IMG_VADDR), //destination sbeImgSize); } if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - " "Error from procCustomizeSbeImg(), " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } io_sbeState.customizedImage_size = sbeImgSize; io_sbeState.customizedImage_crc = Util::crc32_calc(reinterpret_cast (SBE_IMG_VADDR), sbeImgSize) ; TRACUCOMP( g_trac_sbe, "getSbeInfoState() - procCustomizeSbeImg(): " "maxSize=0x%X, actSize=0x%X, crc=0x%X", FIXED_SEEPROM_WORK_SPACE, sbeImgSize, io_sbeState.customizedImage_crc); /*******************************************/ /* Get MVPD SBE Version Information */ /*******************************************/ err = getSetMVPDVersion(io_sbeState.target, MVPDOP_READ, io_sbeState.mvpdSbKeyword); if(err) { //If MVPD is bad, commit the error and move to the next proc TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - " "Error reading version from MVPD, " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } // Determine Permanent Side from flag in MVPD if(SEEPROM_0_PERMANENT_VALUE == (io_sbeState.mvpdSbKeyword.flags & PERMANENT_FLAG_MASK)) { io_sbeState.permanent_seeprom_side = SBE_SEEPROM0; } else // Side 1 must be permanent { io_sbeState.permanent_seeprom_side = SBE_SEEPROM1; } /***********************************************/ /* Determine which SEEPROM System Booted On */ /***********************************************/ //Get Current (boot) Side sbeSeepromSide_t tmp_cur_side = SBE_SEEPROM_INVALID; err = getSbeBootSeeprom(io_sbeState.target, tmp_cur_side); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - " "Error returned from getSbeBootSeeprom(), " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } io_sbeState.cur_seeprom_side = tmp_cur_side; if (io_sbeState.cur_seeprom_side == SBE_SEEPROM0) { io_sbeState.alt_seeprom_side = SBE_SEEPROM1; } else if ( io_sbeState.cur_seeprom_side == SBE_SEEPROM1) { io_sbeState.alt_seeprom_side = SBE_SEEPROM0; } else { TRACFCOMP( g_trac_sbe, ERR_MRK"getSbeInfoState() - Error: " "Unexpected cur_seeprom_side value = 0x%X, ", io_sbeState.cur_seeprom_side); /*@ * @errortype * @moduleid SBE_GET_TARGET_INFO_STATE * @reasoncode SBE_INVALID_SEEPROM_SIDE * @userdata1 Temporary Current Side * @userdata2 SBE State Current Side * @devdesc Invalid Boot SEEPROM Side Found */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_GET_TARGET_INFO_STATE, SBE_INVALID_SEEPROM_SIDE, tmp_cur_side, io_sbeState.cur_seeprom_side); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } TRACUCOMP( g_trac_sbe,"getSbeInfoState() - cur=0x%X, alt=0x%X", io_sbeState.cur_seeprom_side, io_sbeState.alt_seeprom_side); }while(0); free(sbeHbblImgPtr); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t getSeepromSideVersion(TARGETING::Target* i_target, EEPROM::eeprom_chip_types_t i_seepromSide, sbeSeepromVersionInfo_t& o_info, bool& o_seeprom_ver_ECC_fail) { TRACUCOMP( g_trac_sbe, ENTER_MRK"getSeepromSideVersion(): HUID=0x%.8X, side:%d", TARGETING::get_huid(i_target), i_seepromSide); errlHndl_t err = NULL; PNOR::ECC::eccStatus eccStatus = PNOR::ECC::CLEAN; o_seeprom_ver_ECC_fail = false; // Set these variables to the read out the max struct size // Supported version 1 is a subset of supported version 2 size_t sbeInfoSize = sizeof(sbeSeepromVersionInfo_t); size_t sbeInfoSize_ECC = (sbeInfoSize*9)/8; uint8_t * tmp_data_ECC = static_cast( malloc(sbeInfoSize_ECC)); do{ /***********************************************/ /* Read SBE Version SBE Version Information */ /***********************************************/ // Clear Buffer memset( tmp_data_ECC, 0, sbeInfoSize_ECC ); //Read SBE Versions err = deviceRead( i_target, tmp_data_ECC, sbeInfoSize_ECC, DEVICE_EEPROM_ADDRESS( i_seepromSide, SBE_VERSION_SEEPROM_ADDRESS)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSeepromSideVersion() - " "Error reading SBE Version from Seeprom 0x%X, " "HUID=0x%.8X, RC=0x%X, PLID=0x%lX", i_seepromSide, TARGETING::get_huid(i_target), ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } TRACDBIN(g_trac_sbe, "getSeepromSideVersion() - tmp_data_ECC", tmp_data_ECC, sbeInfoSize_ECC); // Clear destination memset( &o_info, 0, sizeof(o_info) ); // Initially only look at the first 8-Bytes which should include // the struct version value // Remove ECC eccStatus = removeECC(tmp_data_ECC, reinterpret_cast(&o_info), 8, SBE_VERSION_SEEPROM_ADDRESS, SBE_SEEPROM_SIZE); TRACUCOMP( g_trac_sbe, "getSeepromSideVersion(): First 8-Bytes: " "eccStatus=%d, version=0x%X, data_crc=0x%X", eccStatus, o_info.struct_version, o_info.data_crc); if ( STRUCT_VERSION_CHECK(o_info.struct_version) ) { // Supported Versions - set size variable to remove ECC sbeInfoSize = SBE_SEEPROM_STRUCT_SIZES[o_info.struct_version]; sbeInfoSize_ECC = (sbeInfoSize*9)/8; } else { // Unsupported versions - ignoring any ECC errors TRACFCOMP( g_trac_sbe, "getSeepromSideVersion(): Unsupported " "Struct Version=0x%X, ignoring any eccStatus=%d", o_info.struct_version, eccStatus); break; } // Remove ECC for full SBE Version struct eccStatus = PNOR::ECC::CLEAN; eccStatus = removeECC(tmp_data_ECC, reinterpret_cast(&o_info), sbeInfoSize, SBE_VERSION_SEEPROM_ADDRESS, SBE_SEEPROM_SIZE); TRACFCOMP( g_trac_sbe, "getSeepromSideVersion(): eccStatus=%d, " "sizeof o_info/sI=%d, sI_ECC=%d, origin golden=%i", eccStatus, sbeInfoSize, sbeInfoSize_ECC, o_info.origin); // Handle Uncorrectable ECC - no error log: // clear data and set o_seeprom_ver_ECC_fail=true if ( eccStatus == PNOR::ECC::UNCORRECTABLE ) { TRACFCOMP( g_trac_sbe, ERR_MRK"getSeepromSideVersion() - ECC " "ERROR: Handled. eccStatus=%d, side=%d, sizeof " "o_info/sI=%d, sI_ECC=%d", eccStatus, i_seepromSide, sbeInfoSize, sbeInfoSize_ECC); memset( &o_info, 0, sizeof(o_info)); o_seeprom_ver_ECC_fail = true; TRACUCOMP( g_trac_sbe, "getSeepromSideVersion(): clearing out " "version data (o_info) for side %d and returning " "o_seeprom_ver_ECC_fail as true (%d)", i_seepromSide, o_seeprom_ver_ECC_fail); } TRACDBIN(g_trac_sbe, "getSeepromSideVersion: data (no ECC)", &o_info, sizeof(o_info)); }while(0); // Free allocated memory free(tmp_data_ECC); TRACUCOMP( g_trac_sbe, EXIT_MRK"getSeepromSideVersion: o_seeprom_ver_ECC_fail=%d", o_seeprom_ver_ECC_fail ); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t updateSeepromSide(sbeTargetState_t& io_sbeState) { TRACUCOMP( g_trac_sbe, ENTER_MRK"updateSeepromSide(): HUID=0x%.8X, side=%d", TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update); errlHndl_t err = NULL; int64_t rc = 0; int64_t rc_readBack_ECC_memcmp = 0; PNOR::ECC::eccStatus eccStatus = PNOR::ECC::CLEAN; // This struct is always 8-byte aligned size_t sbeInfoSize = sizeof(sbeSeepromVersionInfo_t); size_t sbeInfoSize_ECC = (sbeInfoSize*9)/8; // Buffers for reading/writing SBE Version Information uint8_t * sbeInfo_data = static_cast( malloc(sbeInfoSize)); uint8_t * sbeInfo_data_ECC = static_cast( malloc(sbeInfoSize_ECC)); uint8_t * sbeInfo_data_readBack = static_cast( malloc(sbeInfoSize)); uint8_t * sbeInfo_data_ECC_readBack = static_cast( malloc(sbeInfoSize_ECC)); do{ /*************************************************************/ /* Write Invalid SBE Version Information */ /* -- This is done to prevent confusion if there is a fail */ /* when updating the Version or Image after this */ /*************************************************************/ // Create Invalid Version struct (which is always 8-byte aligned) uint8_t* sbeInfoEnd = sbeInfo_data + sbeInfoSize; for (uint64_t* p = reinterpret_cast(sbeInfo_data); p < reinterpret_cast(sbeInfoEnd); p++) { *p = SBE_SEEPROM_STRUCT_INVALID; } // Inject ECC to Data memset( sbeInfo_data_ECC, 0, sbeInfoSize_ECC); injectECC(sbeInfo_data, sbeInfoSize, SBE_VERSION_SEEPROM_ADDRESS, SBE_SEEPROM_SIZE, sbeInfo_data_ECC); TRACDBIN( g_trac_sbe, "updateSeepromSide: Invalid Info", sbeInfo_data, sbeInfoSize); TRACDBIN( g_trac_sbe, "updateSeepromSide: Invalid Info ECC", sbeInfo_data_ECC, sbeInfoSize_ECC); err = deviceWrite( io_sbeState.target, sbeInfo_data_ECC, sbeInfoSize_ECC, DEVICE_EEPROM_ADDRESS( io_sbeState.seeprom_side_to_update, SBE_VERSION_SEEPROM_ADDRESS)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide() - Error " "Writing SBE Version Info: HUID=0x%.8X, side=%d, " "RC=0x%X, PLID=0x%lX", TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update, ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } // In an effort to avoid an infinite loop of updates, if there // was an ECC error when reading this SBE Version Information // while collecting data, read back this data to ensure there // isn't a permanent ECC error on the SEEPROM if ( io_sbeState.new_readBack_check == true ) { // Read Back Version Information err = deviceRead( io_sbeState.target, sbeInfo_data_ECC_readBack, sbeInfoSize_ECC, DEVICE_EEPROM_ADDRESS( io_sbeState.seeprom_side_to_update, SBE_VERSION_SEEPROM_ADDRESS)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide() - Error " "Reading Back SBE Version Info: HUID=0x%.8X, " "side=%d, RC=0x%X, PLID=0x%lX", TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update, ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } // Compare ECC data rc_readBack_ECC_memcmp = memcmp( sbeInfo_data_ECC, sbeInfo_data_ECC_readBack, sbeInfoSize_ECC); // Remove ECC eccStatus = removeECC( sbeInfo_data_ECC_readBack, sbeInfo_data_readBack, sbeInfoSize, SBE_VERSION_SEEPROM_ADDRESS, SBE_SEEPROM_SIZE); TRACUCOMP( g_trac_sbe, "updateSeepromSide(): eccStatus=%d, " "sizeof sI=%d, sI_ECC=%d, rc_ECC=%d", eccStatus, sbeInfoSize, sbeInfoSize_ECC, rc_readBack_ECC_memcmp); // Fail if uncorrectable ECC or any data miscompare if ( ( eccStatus == PNOR::ECC::UNCORRECTABLE ) || ( rc_readBack_ECC_memcmp != 0 ) ) { // There is an ECC issue with this SEEPROM TRACFCOMP( g_trac_sbe,ERR_MRK"updateSeepromSide() - ECC " "ERROR or Data Miscimpare On SBE Version Read " "Back: eccStatus=%d, rc_ECC=%d, " "sI=%d, sI_ECC=%d, HUID=0x%.8X, side=%d", eccStatus, rc_readBack_ECC_memcmp, sbeInfoSize, sbeInfoSize_ECC, TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update); TRACFBIN( g_trac_sbe, "updateSeepromSide: readback_wECC", sbeInfo_data_ECC_readBack, sbeInfoSize_ECC); /*@ * @errortype * @moduleid SBE_GET_SEEPROM_INFO * @reasoncode SBE_ECC_FAIL * @userdata1[0:15] ECC Status * @userdata1[16:31] SEEPROM Side * @userdata1[32:47] RC on Data Compare with ECC * @userdata1[48:63] * @userdata2[0:31] Size - No Ecc * @userdata2[32:63] Size - ECC * @devdesc ECC or Data Miscompare Fail Reading Back * SBE Verion Information */ err = new ErrlEntry(ERRL_SEV_PREDICTIVE, SBE_UPDATE_SEEPROMS, SBE_ECC_FAIL, FOUR_UINT16_TO_UINT64( eccStatus, io_sbeState.seeprom_side_to_update, rc_readBack_ECC_memcmp, 0x0), TWO_UINT32_TO_UINT64(sbeInfoSize, sbeInfoSize_ECC)); err->collectTrace(SBE_COMP_NAME); err->addPartCallout( io_sbeState.target, HWAS::SBE_SEEPROM_PART_TYPE, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); ErrlUserDetailsTarget(io_sbeState.target).addToLog(err); break; } } /*******************************************/ /* Update SBE with Customized Image */ /*******************************************/ // The Customized Image For This Target Still Resides In // The SBE Update VMM Space: SBE_IMG_VADDR = VMM_VADDR_SBE_UPDATE // Inject ECC // clear out back half of page block to use as temp space // for ECC injected SBE Image. rc = mm_remove_pages(RELEASE, reinterpret_cast(SBE_ECC_IMG_VADDR), SBE_ECC_IMG_MAX_SIZE); if( rc ) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide() - Error " "from mm_remove_pages : rc=%d, HUID=0x%.8X, " "ECC_VADDR=0x%.16X, eccSize=0x%.8X.", rc, TARGETING::get_huid(io_sbeState.target), SBE_ECC_IMG_VADDR, SBE_ECC_IMG_MAX_SIZE ); /*@ * @errortype * @moduleid SBE_UPDATE_SEEPROMS * @reasoncode SBE_REMOVE_PAGES_FOR_EC * @userdata1 Requested Address * @userdata2 rc from mm_remove_pages * @devdesc updateProcessorSbeSeeproms> mm_remove_pages * RELEASE failed * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_UPDATE_SEEPROMS, SBE_REMOVE_PAGES_FOR_EC, TO_UINT64(SBE_ECC_IMG_VADDR), TO_UINT64(rc)); //Target isn't directly related to fail, but could be useful // to see how far we got before failing. ErrlUserDetailsTarget(io_sbeState.target ).addToLog(err); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } //align size, calculate ECC size size_t sbeImgSize = ALIGN_8(io_sbeState.customizedImage_size); size_t sbeEccImgSize = setECCSize(sbeImgSize); // Check if assert below will fail and values should be traced if(sbeEccImgSize > SBE_ECC_IMG_MAX_SIZE) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide(): assert " "values eccSize=0x%.8X <= ECC_MAX_SIZE=0x%.8X", sbeEccImgSize, SBE_ECC_IMG_MAX_SIZE ); } assert(sbeEccImgSize <= SBE_ECC_IMG_MAX_SIZE, "updateSeepromSide() SBE Image with ECC too large"); TRACUCOMP( g_trac_sbe, INFO_MRK"updateSeepromSide(): " "SBE_VADDR=0x%.16X, ECC_VADDR=0x%.16X, size=0x%.8X, " "eccSize=0x%.8X, UPDATE_END=0x%.16X, UPDATE_SIZE=0x%.8X", SBE_IMG_VADDR, SBE_ECC_IMG_VADDR, sbeImgSize, sbeEccImgSize, VMM_VADDR_SBE_UPDATE_END, VMM_SBE_UPDATE_SIZE ); injectECC(reinterpret_cast(SBE_IMG_VADDR), sbeImgSize, SBE_IMAGE_SEEPROM_ADDRESS, SBE_SEEPROM_SIZE, reinterpret_cast(SBE_ECC_IMG_VADDR)); TRACDBIN(g_trac_sbe,"updateSeepromSide()-start of IMG - no ECC", reinterpret_cast(SBE_IMG_VADDR), 0x80); TRACDBIN(g_trac_sbe,"updateSeepromSide()-start of IMG - ECC", reinterpret_cast(SBE_ECC_IMG_VADDR), 0x80); //Write new data to seeprom TRACFCOMP( g_trac_sbe, INFO_MRK"updateSeepromSide(): Write New " "SBE Image for Target 0x%X to Seeprom %d", TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update ); //Write image to indicated side err = deviceWrite(io_sbeState.target, reinterpret_cast(SBE_ECC_IMG_VADDR), sbeEccImgSize, DEVICE_EEPROM_ADDRESS( io_sbeState.seeprom_side_to_update, SBE_IMAGE_SEEPROM_ADDRESS)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide() - Error " "writing new SBE image to size=%d. HUID=0x%.8X." "SBE_VADDR=0x%.16X, ECC_VADDR=0x%.16X, size=0x%.8X, " "eccSize=0x%.8X, EEPROM offset=0x%X, " "RC=0x%X, PLID=0x%lX", io_sbeState.seeprom_side_to_update, TARGETING::get_huid(io_sbeState.target), SBE_IMG_VADDR, SBE_ECC_IMG_VADDR, sbeImgSize, sbeEccImgSize, SBE_IMAGE_SEEPROM_ADDRESS, ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } /*******************************************/ /* Update SBE Version Information */ /*******************************************/ // The new version has already been created memcpy(sbeInfo_data, &io_sbeState.new_seeprom_ver, sbeInfoSize); // Inject ECC to Data memset( sbeInfo_data_ECC, 0, sbeInfoSize_ECC); injectECC(sbeInfo_data, sbeInfoSize, SBE_VERSION_SEEPROM_ADDRESS, SBE_SEEPROM_SIZE, sbeInfo_data_ECC); TRACDBIN( g_trac_sbe, "updateSeepromSide: Info", sbeInfo_data, sbeInfoSize); TRACDBIN( g_trac_sbe, "updateSeepromSide: Info ECC", sbeInfo_data_ECC, sbeInfoSize_ECC); err = deviceWrite( io_sbeState.target, sbeInfo_data_ECC, sbeInfoSize_ECC, DEVICE_EEPROM_ADDRESS( io_sbeState.seeprom_side_to_update, SBE_VERSION_SEEPROM_ADDRESS)); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"updateSeepromSide() - Error " "Writing SBE Version Info: HUID=0x%.8X, side=%d, " "RC=0x%X, PLID=0x%lX", TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update, ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); break; } // Successful update if we get here, so update internal code // structure with the new version information memcpy( io_sbeState.seeprom_side_to_update == EEPROM::SBE_PRIMARY ? &io_sbeState.seeprom_0_ver : &io_sbeState.seeprom_1_ver, &io_sbeState.new_seeprom_ver, sbeInfoSize ); }while(0); // Free allocated memory free( sbeInfo_data ); free( sbeInfo_data_ECC); free( sbeInfo_data_readBack ); free( sbeInfo_data_ECC_readBack ); #ifdef CONFIG_SBE_UPDATE_SIMULTANEOUS // If no error, recursively call this function for the other SEEPROM if ( ( err == NULL ) && ( io_sbeState.seeprom_side_to_update == EEPROM::SBE_PRIMARY ) ) { io_sbeState.seeprom_side_to_update = EEPROM::SBE_BACKUP; TRACFCOMP( g_trac_sbe, "updateSeepromSide(): Recursively calling itself: " "HUID=0x%.8X, side=%d", TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update); err = updateSeepromSide(io_sbeState); } #endif #ifdef CONFIG_SBE_UPDATE_INDEPENDENT //If MFG flag is set to indicate update both side of SBE //Update both sides of SBE - even in indepent mode if (g_update_both_sides) { // If no error, recursively call this function for the other SEEPROM if ( ( err == NULL ) && ( io_sbeState.seeprom_side_to_update == EEPROM::SBE_PRIMARY ) ) { io_sbeState.seeprom_side_to_update = EEPROM::SBE_BACKUP; TRACFCOMP( g_trac_sbe, "UPDATE_BOTH_SIDES_OF_SBE MNFG Flag indicated, will update both sides" ); TRACFCOMP( g_trac_sbe, "updateSeepromSide(): Recursively calling itself: " "HUID=0x%.8X, side=%d", TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update); err = updateSeepromSide(io_sbeState); } } #endif return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t getTargetUpdateActions(sbeTargetState_t& io_sbeState) { TRACUCOMP( g_trac_sbe, ENTER_MRK"getTargetUpdateActions(): HUID=0x%.8X", TARGETING::get_huid(io_sbeState.target)); errlHndl_t err = NULL; bool seeprom_0_isDirty = false; bool seeprom_1_isDirty = false; bool current_side_isDirty = false; bool alt_side_isDirty = false; bool pnor_check_dirty = false; bool crc_check_dirty = false; bool isSimics_check = false; TARGETING::Target * l_sys = nullptr; do{ /**************************************************************/ /* Compare SEEPROM 0 with PNOR and Customized Image CRC -- */ /* -- dirty or clean? */ /**************************************************************/ // Check PNOR and SEEPROM 0 Version if ( 0 != memcmp(&(io_sbeState.pnorVersion), &(io_sbeState.seeprom_0_ver.image_version), SBE_IMAGE_VERSION_SIZE) ) { pnor_check_dirty = true; } // Check CRC and SEEPROM 0 CRC if ( io_sbeState.customizedImage_crc != io_sbeState.seeprom_0_ver.data_crc ) { crc_check_dirty = true; } // Check if in simics if ( ( io_sbeState.seeprom_0_ver.struct_version == STRUCT_VERSION_SIMICS ) && ( Util::isSimicsRunning() ) ) { isSimics_check = true; } if ( ( pnor_check_dirty || crc_check_dirty || io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch ) && !isSimics_check ) { seeprom_0_isDirty = true; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: Seeprom0 " "dirty: pnor=%d, crc=%d (custom=0x%X/s0=0x%X), " "nest_freq=%d, isSimics=%d", TARGETING::get_huid(io_sbeState.target), pnor_check_dirty, crc_check_dirty, io_sbeState.customizedImage_crc, io_sbeState.seeprom_0_ver.data_crc, io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch, isSimics_check); } else { TRACUCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: Seeprom0 " "flagged as clean: pnor=%d, crc=%d " "(custom=0x%X/s0=0x%X), nest_freq=%d, isSimics=%d", TARGETING::get_huid(io_sbeState.target), pnor_check_dirty, crc_check_dirty, io_sbeState.customizedImage_crc, io_sbeState.seeprom_0_ver.data_crc, io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch, isSimics_check); } /**************************************************************/ /* Compare SEEPROM 1 with PNOR and Customized Image CRC -- */ /* -- dirty or clean? */ /**************************************************************/ // reset dirty variables pnor_check_dirty = false; crc_check_dirty = false; isSimics_check = false; // Check PNOR and SEEPROM 1 Version if ( 0 != memcmp(&(io_sbeState.pnorVersion), &(io_sbeState.seeprom_1_ver.image_version), SBE_IMAGE_VERSION_SIZE) ) { pnor_check_dirty = true; } // Check CRC and SEEPROM 1 CRC if ( io_sbeState.customizedImage_crc != io_sbeState.seeprom_1_ver.data_crc ) { crc_check_dirty = true; } // Check if in simics if ( ( io_sbeState.seeprom_1_ver.struct_version == STRUCT_VERSION_SIMICS ) && ( Util::isSimicsRunning() ) ) { isSimics_check = true; } if ( (pnor_check_dirty || crc_check_dirty || io_sbeState.seeprom_1_ver_Nest_Freq_Mismatch ) && !isSimics_check ) { seeprom_1_isDirty = true; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: Seeprom1 " "dirty: pnor=%d, crc=%d (custom=0x%X/s1=0x%X), " "nest_freq=%d, isSimics=%d", TARGETING::get_huid(io_sbeState.target), pnor_check_dirty, crc_check_dirty, io_sbeState.customizedImage_crc, io_sbeState.seeprom_1_ver.data_crc, io_sbeState.seeprom_1_ver_Nest_Freq_Mismatch, isSimics_check); } else { TRACUCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: Seeprom1 " "flagged as clean: pnor=%d, crc=%d " "(custom=0x%X/s1=0x%X), nest_freq=%d, isSimics=%d", TARGETING::get_huid(io_sbeState.target), pnor_check_dirty, crc_check_dirty, io_sbeState.customizedImage_crc, io_sbeState.seeprom_1_ver.data_crc, io_sbeState.seeprom_1_ver_Nest_Freq_Mismatch, isSimics_check); } // Extra information for unit testing if ( seeprom_0_isDirty || seeprom_1_isDirty ) { TRACFBIN( g_trac_sbe, "PNOR Version", &(io_sbeState.pnorVersion), 16 ) ; TRACFBIN( g_trac_sbe, "Seeprom0: Image Version", &(io_sbeState.seeprom_0_ver.image_version), 16 ) ; TRACFBIN( g_trac_sbe, "Seeprom1: Image Version", &(io_sbeState.seeprom_1_ver.image_version), 16 ) ; TRACFBIN( g_trac_sbe, "MVPD SB", &(io_sbeState.mvpdSbKeyword), sizeof(mvpdSbKeyword_t)); } /**************************************************************/ /* Determine what side to update */ /**************************************************************/ // Set cur and alt isDirty values if( io_sbeState.cur_seeprom_side == SBE_SEEPROM0 ) { current_side_isDirty = seeprom_0_isDirty; alt_side_isDirty = seeprom_1_isDirty; io_sbeState.cur_seeprom_ver_Nest_Freq_Mismatch = io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch; } else { current_side_isDirty = seeprom_1_isDirty; alt_side_isDirty = seeprom_0_isDirty; io_sbeState.cur_seeprom_ver_Nest_Freq_Mismatch = io_sbeState.seeprom_1_ver_Nest_Freq_Mismatch; } // Set system_situation - bits defined in sbe_update.H uint8_t system_situation = 0x00; // Bit 0: current_side is permanent (0) or temp (1) // -- defaulted to 0 (cur=perm) above if ( io_sbeState.cur_seeprom_side != io_sbeState.permanent_seeprom_side ) { system_situation |= SITUATION_CUR_IS_TEMP; } // Bit 1: current_side clean (0) or dirty (1) // -- defaulted to 0 (clean) above if ( current_side_isDirty ) { system_situation |= SITUATION_CUR_IS_DIRTY; } // Bit 2: alt_side is clean (0) or dirty (1) if ( alt_side_isDirty ) { system_situation |= SITUATION_ALT_IS_DIRTY; } // Call function to update actions err = decisionTreeForUpdates(io_sbeState, system_situation); if ( err ) { break; } TRACUCOMP( g_trac_sbe, "getTargetUpdateActions() - system_situation" "= 0x%.2X, actions=0x%.8X, Update EEPROM=0x%X", system_situation, io_sbeState.update_actions, io_sbeState.seeprom_side_to_update); /**************************************************************/ /* Setup new SBE Image Version Info, if necessary */ /**************************************************************/ if ( ( io_sbeState.update_actions & UPDATE_SBE ) || ( io_sbeState.update_actions & UPDATE_NEST_FREQ ) ) { memset(&(io_sbeState.new_seeprom_ver), 0x0, sizeof(sbeSeepromVersionInfo_t)); // the above memset also has the side effect of setting the // origin field to WORKING_SIDE which is the default io_sbeState.new_seeprom_ver.struct_version = STRUCT_VERSION_LATEST; memcpy( &(io_sbeState.new_seeprom_ver.image_version), &(io_sbeState.pnorVersion), SBE_IMAGE_VERSION_SIZE); memcpy( &(io_sbeState.new_seeprom_ver.data_crc), &(io_sbeState.customizedImage_crc), sizeof(io_sbeState.new_seeprom_ver.data_crc)); if ( io_sbeState.update_actions & UPDATE_SBE ) { TARGETING::targetService().getTopLevelTarget( l_sys ); io_sbeState.new_seeprom_ver.nest_freq_mhz = l_sys->getAttr(); } else { // UPDATE_NEST_FREQ: set the nest freq to what the // current SBE Seeprom booted from io_sbeState.new_seeprom_ver.nest_freq_mhz = io_sbeState.mproc_nest_freq_mhz; } // If there was an ECC fail on either SEEPROM, do a read-back // Check when writing this information to the SEEPROM io_sbeState.new_readBack_check = ( io_sbeState.seeprom_0_ver_ECC_fail || io_sbeState.seeprom_1_ver_ECC_fail); TRACDBIN( g_trac_sbe, "getTargetUpdateActions() - New SBE Version Info", &(io_sbeState.new_seeprom_ver), sizeof(sbeSeepromVersionInfo_t)); } /**************************************************************/ /* Update MVPD Struct to write back, if necessary */ /**************************************************************/ if ( io_sbeState.update_actions & UPDATE_MVPD ) { // Note: mvpdSbKeyword.flags updated in decisionTreeForUpdates() if ( io_sbeState.seeprom_side_to_update == EEPROM::SBE_PRIMARY ) { memcpy(&(io_sbeState.mvpdSbKeyword.seeprom_0_data_crc), &(io_sbeState.customizedImage_crc), sizeof(io_sbeState.mvpdSbKeyword.seeprom_0_data_crc)); memcpy(&(io_sbeState.mvpdSbKeyword.seeprom_0_short_version), &(io_sbeState.pnorVersion), SBE_MVPD_SHORT_IMAGE_VERSION_SIZE); } else // EEPROM::SBE_Backup { memcpy(&(io_sbeState.mvpdSbKeyword.seeprom_1_data_crc), &(io_sbeState.customizedImage_crc), sizeof(io_sbeState.mvpdSbKeyword.seeprom_1_data_crc)); memcpy(&(io_sbeState.mvpdSbKeyword.seeprom_1_short_version), &(io_sbeState.pnorVersion), SBE_MVPD_SHORT_IMAGE_VERSION_SIZE); } } }while(0); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t decisionTreeForUpdates(sbeTargetState_t& io_sbeState, uint8_t i_system_situation) { errlHndl_t err = NULL; uint32_t l_actions = CLEAR_ACTIONS; io_sbeState.update_actions = CLEAR_ACTIONS; io_sbeState.seeprom_side_to_update = EEPROM::LAST_CHIP_TYPE; do{ // To be safe, we're only look at the bits defined in sbe_update.H i_system_situation &= SITUATION_ALL_BITS_MASK; #ifdef CONFIG_SBE_UPDATE_INDEPENDENT //Check if MFG flag set to indicate both sides should be updated if (g_update_both_sides) { decisionTreeForUpdatesSimultaneous(l_actions, io_sbeState, i_system_situation); } else { // The 2 SBE SEEPROMs are independent of each other // Determine if PNOR is 1- or 2-sided and if the current // Seeprom is pointing at PNOR's GOLDEN side PNOR::SideId tmp_side = PNOR::WORKING; PNOR::SideInfo_t pnor_side_info; err = PNOR::getSideInfo (tmp_side, pnor_side_info); if ( err ) { TRACFCOMP( g_trac_sbe, ERR_MRK "SBE Update() - Error returned from " "PNOR::getSideInfo() rc=0x%.4X, Target UID=0x%X", err->reasonCode(), TARGETING::get_huid(io_sbeState.target)); break; } TRACUCOMP( g_trac_sbe,INFO_MRK"SBE Update tgt=0x%X: PNOR Info: " "side-%c, sideId=0x%X, isGolden=%d, hasOtherSide=%d", TARGETING::get_huid(io_sbeState.target), pnor_side_info.side, pnor_side_info.id, pnor_side_info.isGolden, pnor_side_info.hasOtherSide); if ( pnor_side_info.isGolden == true ) { // Check for NEST_FREQ mismatch if ( ( io_sbeState.target_is_master == true ) && ( io_sbeState.cur_seeprom_ver_Nest_Freq_Mismatch == true ) ) { l_actions |= DO_UPDATE; l_actions |= UPDATE_NEST_FREQ; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "Booting Master Proc READ_ONLY SEEPROM pointing at " "PNOR's GOLDEN side and NEST_FREQ mismatch. Update " "NEST_FREQ. Continue IPL. " "(sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); } else { // Nothing to do (covered in istep 6 function) l_actions = CLEAR_ACTIONS; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "Booting READ_ONLY SEEPROM pointing at PNOR's " "GOLDEN side. No updates for cur side=%d. Continue " "IPL. (sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); } } else if ( ( pnor_side_info.hasOtherSide == false ) && ( io_sbeState.cur_seeprom_side == READ_ONLY_SEEPROM ) ) { // Check for NEST_FREQ mismatch if ( ( io_sbeState.target_is_master == true ) && ( io_sbeState.cur_seeprom_ver_Nest_Freq_Mismatch == true ) ) { l_actions |= DO_UPDATE; l_actions |= UPDATE_NEST_FREQ; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "Treating cur of Master Proc like READ_ONLY SBE " "SEEPROM and NEST_FREQ mismatch. Update " "NEST_FREQ. Continue IPL. " "(sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); } else { // Even though current seeprom is not pointing at PNOR's // GOLDEN side, treat like READ_ONLY if booting from // READ_ONLY seeprom and PNOR does not have another side // - No Update (ie, Palmetto configuration) l_actions = CLEAR_ACTIONS; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "Treating cur like READ_ONLY SBE SEEPROM. " "No updates for cur side=%d. Continue IPL. " "(sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); } } else // proceed to update this side { // proceed to update this side TRACUCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "NOT Booting READ_ONLY SEEPROM. Check for update" " on cur side=%d ", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side); // Check for clean vs. dirty only on cur side if ( i_system_situation & SITUATION_CUR_IS_DIRTY ) { // Update cur side and re-ipl l_actions |= IPL_RESTART; l_actions |= DO_UPDATE; l_actions |= UPDATE_SBE; //even though flags byte not updated l_actions |= UPDATE_MVPD; // Set Update side to cur io_sbeState.seeprom_side_to_update = ( io_sbeState.cur_seeprom_side == SBE_SEEPROM0 ) ? EEPROM::SBE_PRIMARY : EEPROM::SBE_BACKUP; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "cur side (%d) dirty. Update cur. Re-IPL. " "(sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); } else { // Cur side clean - No Updates - Continue IPL l_actions = CLEAR_ACTIONS; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "cur side (%d) clean-no updates. " "Continue IPL. (sit=0x%.2X, act=0x%.8X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions); } } } #elif CONFIG_SBE_UPDATE_SIMULTANEOUS decisionTreeForUpdatesSimultaneous(l_actions, io_sbeState, i_system_situation); #elif CONFIG_SBE_UPDATE_SEQUENTIAL // Updating the SEEPROMs 1-at-a-time switch ( i_system_situation ) { /////////////////////////////////////////////////////////////////// case ( SITUATION_CUR_IS_TEMP | SITUATION_CUR_IS_DIRTY | SITUATION_ALT_IS_DIRTY ) : // 0xE0: cur=temp, cur=dirty, alt=dirty // Treat like 0xC0 // not sure why we booted off of temp /////////////////////////////////////////////////////////////////// case ( SITUATION_CUR_IS_TEMP | SITUATION_CUR_IS_DIRTY | SITUATION_ALT_IS_CLEAN ) : // 0xC0: cur=temp, cur=dirty, alt=clean // Bad path: we shouldn't be booting to dirty side // Update Alt and re-IPL to it // Update MVPD flag: make cur=perm (because we know it // works a bit) l_actions |= IPL_RESTART; l_actions |= DO_UPDATE; l_actions |= UPDATE_MVPD; l_actions |= UPDATE_SBE; // Set Update side to alt io_sbeState.seeprom_side_to_update = ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? EEPROM::SBE_PRIMARY : EEPROM::SBE_BACKUP ; // Update MVPD PERMANENT flag: make cur=perm ( io_sbeState.cur_seeprom_side == SBE_SEEPROM0 ) ? // clear bit 0 io_sbeState.mvpdSbKeyword.flags &= ~PERMANENT_FLAG_MASK : //set bit 0 io_sbeState.mvpdSbKeyword.flags |= PERMANENT_FLAG_MASK; // Update MVPD RE-IPL SEEPROM flag: re-IPL on ALT: ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? // clear bit 1 io_sbeState.mvpdSbKeyword.flags &= ~REIPL_SEEPROM_MASK : //set bit 1 io_sbeState.mvpdSbKeyword.flags |= REIPL_SEEPROM_MASK; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "cur=temp/dirty(%d). Update alt. Re-IPL. " "Update MVPD flag " "(sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); break; /////////////////////////////////////////////////////////////////// case ( SITUATION_CUR_IS_TEMP | SITUATION_CUR_IS_CLEAN | SITUATION_ALT_IS_DIRTY ) : // 0xA0: cur=temp, cur=clean, alt=dirty // Common 2nd step of Code Update path // Update Alt and Continue IPL // Update MVPD flag: make cur=perm l_actions |= DO_UPDATE; l_actions |= UPDATE_MVPD; l_actions |= UPDATE_SBE; // Set Update side to alt io_sbeState.seeprom_side_to_update = ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? EEPROM::SBE_PRIMARY : EEPROM::SBE_BACKUP ; // MVPD flag Update // Update MVPD flag make cur=perm ( io_sbeState.cur_seeprom_side == SBE_SEEPROM0 ) ? // clear bit 0 io_sbeState.mvpdSbKeyword.flags &= ~PERMANENT_FLAG_MASK : // set bit 0 io_sbeState.mvpdSbKeyword.flags |= PERMANENT_FLAG_MASK; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "cur=temp/clean(%d), alt=dirty. " "Update alt. Continue IPL. Update MVPD flag." "(sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); break; /////////////////////////////////////////////////////////////////// case ( SITUATION_CUR_IS_TEMP | SITUATION_CUR_IS_CLEAN | SITUATION_ALT_IS_CLEAN ) : // 0x80: cur=temp, cur=clean, alt=clean // Both sides are clean, // Not sure why cur=temp, but do nothing l_actions = CLEAR_ACTIONS; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "Both sides clean-no updates. cur was temp(%d). " "Continue IPL. (sit=0x%.2X, act=0x%.8X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions); break; /////////////////////////////////////////////////////////////////// case ( SITUATION_CUR_IS_PERM | SITUATION_CUR_IS_DIRTY | SITUATION_ALT_IS_DIRTY ) : // 0x60: cur=perm, cur=dirty, alt=dirty // Common situation: likely first step of code update // Update alt and re-ipl l_actions |= IPL_RESTART; l_actions |= DO_UPDATE; l_actions |= UPDATE_MVPD; l_actions |= UPDATE_SBE; // Set Update side to alt io_sbeState.seeprom_side_to_update = ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? EEPROM::SBE_PRIMARY : EEPROM::SBE_BACKUP ; // Update MVPD RE-IPL SEEPROM flag: re-IPL on ALT: ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? // clear bit 1 io_sbeState.mvpdSbKeyword.flags &= ~REIPL_SEEPROM_MASK : // set bit 1 io_sbeState.mvpdSbKeyword.flags |= REIPL_SEEPROM_MASK; // If istep mode, re-IPL bit won't be checked, so also // change perm flag to boot off of alt on next IPL if ( g_istep_mode ) { // Update MVPD PERMANENT flag: make alt=perm (io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? // clear bit 0 io_sbeState.mvpdSbKeyword.flags &= ~PERMANENT_FLAG_MASK : //set bit 0 io_sbeState.mvpdSbKeyword.flags |= PERMANENT_FLAG_MASK; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "istep mode: update alt to perm, (sit=" "0x%.2X)", TARGETING::get_huid(io_sbeState.target), i_system_situation); } TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "cur=perm/dirty(%d), alt=dirty. Update alt. re-" "IPL. (sit=0x%.2X, act=0x%.8X, flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); break; /////////////////////////////////////////////////////////////////// case ( SITUATION_CUR_IS_PERM | SITUATION_CUR_IS_DIRTY | SITUATION_ALT_IS_CLEAN ) : // 0x40: cur=perm, cur=dirty, alt=clean // Ask FSP if we just re-IPLed due to our request. // If Yes: Working PERM side is out-of-sync, so callout // SBE code, but continue IPL on dirty image // If Not: Update alt and re-IPL if ( isIplFromReIplRequest() ) { l_actions = CLEAR_ACTIONS; TRACFCOMP(g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "cur=perm/dirty(%d), alt=clean. On our Re-" "IPL. Call-out SBE code but Continue IPL. " "(sit=0x%.2X, act=0x%.8X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions); /*@ * @errortype * @moduleid SBE_DECISION_TREE * @reasoncode SBE_PERM_SIDE_DIRTY_BAD_PATH * @userdata1 System Situation * @userdata2 Update Actions * @devdesc Bad Path in decisionUpdateTree: * cur=PERM/DIRTY * @custdesc A problem occurred while updating * processor boot code. */ err = new ErrlEntry(ERRL_SEV_RECOVERED, SBE_DECISION_TREE, SBE_PERM_SIDE_DIRTY_BAD_PATH, TO_UINT64(i_system_situation), TO_UINT64(l_actions)); // Target isn't directly related to fail, but could be // useful to see how far we got before failing. ErrlUserDetailsTarget(io_sbeState.target ).addToLog(err); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } else { // Update alt and re-ipl l_actions |= IPL_RESTART; l_actions |= DO_UPDATE; l_actions |= UPDATE_MVPD; l_actions |= UPDATE_SBE; // Set Update side to alt io_sbeState.seeprom_side_to_update = ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? EEPROM::SBE_PRIMARY : EEPROM::SBE_BACKUP ; // Update MVPD RE-IPL SEEPROM flag: re-IPL on ALT: ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? // clear bit 1 io_sbeState.mvpdSbKeyword.flags &= ~REIPL_SEEPROM_MASK : // set bit 1 io_sbeState.mvpdSbKeyword.flags |= REIPL_SEEPROM_MASK; TRACFCOMP(g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "cur=perm/dirty(%d), alt=clean. Not our Re-" "IPL. Update alt and MVPD. re-IPL. " "(sit=0x%.2X, act=0x%.8X, flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions, io_sbeState.mvpdSbKeyword.flags); break; } /////////////////////////////////////////////////////////////////// case ( SITUATION_CUR_IS_PERM | SITUATION_CUR_IS_CLEAN | SITUATION_ALT_IS_DIRTY ) : // 0x20: cur=perm, cur=clean, alt=dirty // Not sure why alt is dirty, but update alt and // continue IPL l_actions |= DO_UPDATE; l_actions |= UPDATE_SBE; // Set Update side to alt io_sbeState.seeprom_side_to_update = ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? EEPROM::SBE_PRIMARY : EEPROM::SBE_BACKUP ; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "cur=perm/clean(%d), alt=dirty. " "Update alt. Continue IPL. " "(sit=0x%.2X, act=0x%.8X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions); break; /////////////////////////////////////////////////////////////////// case ( SITUATION_CUR_IS_PERM | SITUATION_CUR_IS_CLEAN | SITUATION_ALT_IS_CLEAN ) : // 0x0: cur=perm, cur=clean, alt=clean // Both sides are clean - no updates // Continue IPL l_actions = CLEAR_ACTIONS; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "Both sides clean-no updates. cur was perm(%d). " "Continue IPL. (sit=0x%.2X, act=0x%.8X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, l_actions); break; /////////////////////////////////////////////////////////////////// default: l_actions = UNSUPPORTED_SITUATION; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "Unsupported Scenario. Just Continue IPL. " "(sit=0x%.2X, act=0x%.8X, cur=%d)", TARGETING::get_huid(io_sbeState.target), i_system_situation, l_actions, io_sbeState.cur_seeprom_side); break; } /////////////////////////////////////////////////////////////////// // End of i_system_situation switch statement /////////////////////////////////////////////////////////////////// #endif // Set actions io_sbeState.update_actions = static_cast (l_actions); TRACUCOMP( g_trac_sbe, "decisionTreeForUpdates() Tgt=0x%X: " "i_system_situation=0x%.2X, actions=0x%.8X, " "Update EEPROM=0x%X, flags=0x%X, cur=%d", TARGETING::get_huid(io_sbeState.target), i_system_situation, io_sbeState.update_actions, io_sbeState.seeprom_side_to_update, io_sbeState.mvpdSbKeyword.flags, io_sbeState.cur_seeprom_side); }while(0); return err; } ///////////////////////////////////////////////////////////////////// void decisionTreeForUpdatesSimultaneous(uint32_t& io_actions, sbeTargetState_t& io_sbeState, uint8_t& i_system_situation ) { // Updates both SEEPROMs if either side is dirty if ( ( i_system_situation & SITUATION_CUR_IS_DIRTY ) || ( i_system_situation & SITUATION_ALT_IS_DIRTY ) ) { // At least one of the sides is dirty // Update both sides and re-IPL // Update MVPD flag: make cur=perm (because we know it // works a bit) io_actions |= IPL_RESTART; io_actions |= DO_UPDATE; io_actions |= UPDATE_MVPD; io_actions |= UPDATE_SBE; // Set update side to Primary here, but both sides // will be updated io_sbeState.seeprom_side_to_update = EEPROM::SBE_PRIMARY; // Update MVPD PERMANENT flag: make cur=perm ( io_sbeState.cur_seeprom_side == SBE_SEEPROM0 ) ? // clear bit 0 io_sbeState.mvpdSbKeyword.flags &= ~PERMANENT_FLAG_MASK : //set bit 0 io_sbeState.mvpdSbKeyword.flags |= PERMANENT_FLAG_MASK; // Update MVPD RE-IPL SEEPROM flag: re-IPL on ALT: ( io_sbeState.alt_seeprom_side == SBE_SEEPROM0 ) ? // clear bit 1 io_sbeState.mvpdSbKeyword.flags &= ~REIPL_SEEPROM_MASK : //set bit 1 io_sbeState.mvpdSbKeyword.flags |= REIPL_SEEPROM_MASK; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "At least one side dirty. cur side=%d. Update " "alt. Re-IPL. Update MVPD flag " "(sit=0x%.2X, act=0x%.8X flags=0x%.2X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, io_actions, io_sbeState.mvpdSbKeyword.flags); } else { // Both sides are clean - no updates // Continue IPL io_actions = CLEAR_ACTIONS; TRACFCOMP( g_trac_sbe, INFO_MRK"SBE Update tgt=0x%X: " "Both sides clean-no updates. cur side=%d. " "Continue IPL. (sit=0x%.2X, act=0x%.8X)", TARGETING::get_huid(io_sbeState.target), io_sbeState.cur_seeprom_side, i_system_situation, io_actions); } } ///////////////////////////////////////////////////////////////////// void setNestFreqAttributes(uint32_t i_nestFreq) { INITSERVICE::SPLESS::MboxScratch4_t l_scratch4; uint32_t l_i2cBusDiv = 0; // Call targeting function to update NEST_FREQ TargetService& tS = targetService(); TARGETING::Target * l_sys = nullptr; TARGETING::Target * l_masterProc = nullptr; (void) tS.getTopLevelTarget( l_sys ); assert( l_sys, "setNestFreqAttributes() system target is NULL"); (void) tS.masterProcChipTargetHandle( l_masterProc ); assert( l_masterProc, "setNestFreqAttributes() " "Master Proc target is NULL"); // Get the i2c bus divisor TARGETING::ATTR_MASTER_MBOX_SCRATCH_type l_scratchRegs; assert(l_sys->tryGetAttr (l_scratchRegs), "setNestFreqAttributes() failed to get MASTER_MBOX_SCRATCH"); l_scratch4.data32 = l_scratchRegs[INITSERVICE::SPLESS::SCRATCH_4]; // The Nest PLL Bucket ID ranges 1-5. Subtract 1 for zero-based indexing l_i2cBusDiv = NEST_PLL_FREQ_I2CDIV_LIST[l_scratch4.nestPllBucket-1]; TRACFCOMP(g_trac_sbe, "setNestFreqAttributes(): " "UPDATE_NEST_FREQ to %d ", i_nestFreq); TARGETING::setFrequencyAttributes(l_sys, i_nestFreq, l_i2cBusDiv ); } ///////////////////////////////////////////////////////////////////// errlHndl_t performUpdateActions(sbeTargetState_t& io_sbeState) { TRACUCOMP( g_trac_sbe, ENTER_MRK"performUpdateActions(): HUID=0x%.8X, " "updateActions=0x%.8X", TARGETING::get_huid(io_sbeState.target), io_sbeState.update_actions); errlHndl_t err = NULL; errlHndl_t err_info = NULL; uint32_t l_actions = io_sbeState.update_actions; do{ /**************************************************************/ /* Update SEEPROM, if necessary */ /**************************************************************/ if (l_actions & UPDATE_SBE) { #ifdef CONFIG_SBE_UPDATE_SIMULTANEOUS io_sbeState.seeprom_side_to_update = EEPROM::SBE_PRIMARY; #endif #ifdef CONFIG_SBE_UPDATE_INDEPENDENT if (g_update_both_sides) { TRACFCOMP( g_trac_sbe, "UPDATE_BOTH_SIDES_OF_SBE MNFG Flag indicated, will update both sides" ); io_sbeState.seeprom_side_to_update = EEPROM::SBE_PRIMARY; } #endif err = updateSeepromSide(io_sbeState); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"performUpdateActions() - " "updateProcessorSbeSeeproms() failed. " "HUID=0x%.8X.", TARGETING::get_huid(io_sbeState.target)); break; } l_actions |= SBE_UPDATE_COMPLETE; } /**************************************************************/ /* Update MVPD, if necessary */ /**************************************************************/ if (l_actions & UPDATE_MVPD) { err = getSetMVPDVersion(io_sbeState.target, MVPDOP_WRITE, io_sbeState.mvpdSbKeyword); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"performUpdateActions() - " "Error Updating MVPD with new SBE Image Info " "HUID=0x%.8X, rc=0x%.4x. Skipping SBE Update. " "(actions=0x%.8X)", TARGETING::get_huid(io_sbeState.target), err->reasonCode(), l_actions ); break; } l_actions |= MVPD_UPDATE_COMPLETE; } /**************************************************************/ /* Create Info Error Log of successful operation */ /**************************************************************/ #ifndef CONFIG_SBE_UPDATE_SIMULTANEOUS TRACFCOMP( g_trac_sbe,INFO_MRK"performUpdateActions(): Successful " "SBE Update of HUID=0x%.8X SEEPROM %d", TARGETING::get_huid(io_sbeState.target), io_sbeState.seeprom_side_to_update); #else TRACFCOMP( g_trac_sbe,INFO_MRK"performUpdateActions(): Successful " "SBE Update of HUID=0x%.8X - Both SEEPROMs", TARGETING::get_huid(io_sbeState.target)); #endif /*@ * @errortype * @moduleid SBE_PERFORM_UPDATE_ACTIONS * @reasoncode SBE_INFO_LOG * @userdata1[0:31] Update Actions Enum * @userdata1[32:63] Customized Data CRC * @userdata2[0:31] Original SEEPROM 0 CRC * @userdata2[32:63] Original SEEPROM 1 CRC * @devdesc Successful Update of SBE SEEPROM * SBE Verion Information */ err_info = new ErrlEntry(ERRL_SEV_INFORMATIONAL, SBE_PERFORM_UPDATE_ACTIONS, SBE_INFO_LOG, TWO_UINT32_TO_UINT64( l_actions, io_sbeState.customizedImage_crc), TWO_UINT32_TO_UINT64( io_sbeState.seeprom_0_ver.data_crc, io_sbeState.seeprom_1_ver.data_crc)); // Add general data sections to capture MVPD SB Keyword and // the new SBE SEEPROM Version structure err_info->addFFDC( SBE_COMP_ID, &(io_sbeState.mvpdSbKeyword), sizeof(io_sbeState.mvpdSbKeyword), 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge err_info->addFFDC( SBE_COMP_ID, &(io_sbeState.new_seeprom_ver), sizeof(io_sbeState.new_seeprom_ver), 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge err_info->collectTrace(SBE_COMP_NAME, KILOBYTE); ErrlUserDetailsTarget(io_sbeState.target, "SBE Target Updated") .addToLog(err_info); errlCommit( err_info, SBE_COMP_ID ); /**************************************************************/ }while(0); io_sbeState.update_actions = static_cast (l_actions); TRACUCOMP( g_trac_sbe, EXIT_MRK"performUpdateActions(): HUID=0x%.8X, " "updateActions=0x%.8X", TARGETING::get_huid(io_sbeState.target), io_sbeState.update_actions); return err; } ///////////////////////////////////////////////////////////////////// uint32_t trimBitMask(uint32_t i_mask, size_t i_maxBits) { TRACDCOMP( g_trac_sbe, ENTER_MRK"trimBitMask(i_mask=0x%.8X, i_maxBits=0x%.8X)", i_mask, i_maxBits); uint32_t retMask = i_mask; while(__builtin_popcount(retMask) > static_cast(i_maxBits)) { retMask ^= (0x80000000 >> static_cast(__builtin_clz(retMask))); } TRACDCOMP( g_trac_sbe, EXIT_MRK"trimBitMask(): retMask=0x%.8X", retMask); return retMask; } ///////////////////////////////////////////////////////////////////// errlHndl_t createSbeImageVmmSpace(void) { TRACDCOMP( g_trac_sbe, ENTER_MRK"createSbeImageVmmSpace"); int64_t rc = 0; errlHndl_t err = NULL; do{ //Make sure procedure constants keep within expected range. assert((FIXED_SEEPROM_WORK_SPACE <= VMM_SBE_UPDATE_SIZE/2), "createSbeImageVmmSpace() FIXED_SEEPROM_WORK_SPACE too large"); assert((MAX_RING_BUF_SIZE <= VMM_SBE_UPDATE_SIZE/4), "createSbeImageVmmSpace() MAX_RING_BUF_SIZE too large"); // Create a memory block to serve as XIP Customize scratch space // NOTE: using mm_alloc_block since this code is running before we // have mainstore and we must have contiguous blocks of memory for // the customize procedure to use. rc = mm_alloc_block( NULL, reinterpret_cast (VMM_VADDR_SBE_UPDATE), VMM_SBE_UPDATE_SIZE); if(rc == -EALREADY) { //-EALREADY inidciates the block is already mapped // so just ignore rc = 0; } if( rc ) { TRACFCOMP( g_trac_sbe, ERR_MRK"createSbeImageVmmSpace() - " "Error from mm_alloc_block : rc=%d", rc ); /*@ * @errortype * @moduleid SBE_CREATE_TEST_SPACE * @reasoncode SBE_ALLOC_BLOCK_FAIL * @userdata1 Requested Address * @userdata2 rc from mm_alloc_block * @devdesc updateProcessorSbeSeeproms> Error * from mm_alloc_block * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_CREATE_TEST_SPACE, SBE_ALLOC_BLOCK_FAIL, TO_UINT64(VMM_VADDR_SBE_UPDATE), TO_UINT64(rc)); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } rc = mm_set_permission(reinterpret_cast (VMM_VADDR_SBE_UPDATE), VMM_SBE_UPDATE_SIZE, WRITABLE | ALLOCATE_FROM_ZERO ); if( rc ) { TRACFCOMP( g_trac_sbe, ERR_MRK"createSbeImageVmmSpace() - Error from mm_set_permission : rc=%d", rc ); /*@ * @errortype * @moduleid SBE_CREATE_TEST_SPACE * @reasoncode SBE_SET_PERMISSION_FAIL * @userdata1 Requested Address * @userdata2 rc from mm_set_permission * @devdesc updateProcessorSbeSeeproms> Error from * mm_set_permission on creation * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_CREATE_TEST_SPACE, SBE_SET_PERMISSION_FAIL, TO_UINT64(VMM_VADDR_SBE_UPDATE), TO_UINT64(rc)); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } }while(0); TRACDCOMP( g_trac_sbe, EXIT_MRK"createSbeImageVmmSpace() - rc =0x%X", rc); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t cleanupSbeImageVmmSpace(void) { TRACDCOMP( g_trac_sbe, ENTER_MRK"cleanupSbeImageVmmSpace"); errlHndl_t err = NULL; int64_t rc = 0; do{ //release all pages in page block rc = mm_remove_pages(RELEASE, reinterpret_cast (VMM_VADDR_SBE_UPDATE), VMM_SBE_UPDATE_SIZE); if( rc ) { TRACFCOMP( g_trac_sbe, ERR_MRK"cleanupSbeImageVmmSpace() - " "Error from mm_remove_pages : rc=%d", rc ); /*@ * @errortype * @moduleid SBE_CLEANUP_TEST_SPACE * @reasoncode SBE_REMOVE_PAGES_FAIL * @userdata1 Requested Address * @userdata2 rc from mm_remove_pages * @devdesc updateProcessorSbeSeeproms> mm_remove_pages * RELEASE failed * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_CLEANUP_TEST_SPACE, SBE_REMOVE_PAGES_FAIL, TO_UINT64(VMM_VADDR_SBE_UPDATE), TO_UINT64(rc)); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } // Set permissions back to "no_access" rc = mm_set_permission(reinterpret_cast (VMM_VADDR_SBE_UPDATE), VMM_SBE_UPDATE_SIZE, NO_ACCESS | ALLOCATE_FROM_ZERO ); if( rc ) { TRACFCOMP( g_trac_sbe, ERR_MRK"cleanupSbeImageVmmSpace() - " "Error from mm_set_permission : rc=%d", rc ); /*@ * @errortype * @moduleid SBE_CLEANUP_TEST_SPACE * @reasoncode SBE_SET_PERMISSION_FAIL * @userdata1 Requested Address * @userdata2 rc from mm_set_permission * @devdesc updateProcessorSbeSeeproms> Error from * mm_set_permission on cleanup * @custdesc A problem occurred while updating processor * boot code. */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_CLEANUP_TEST_SPACE, SBE_SET_PERMISSION_FAIL, TO_UINT64(VMM_VADDR_SBE_UPDATE), TO_UINT64(rc)); err->collectTrace(SBE_COMP_NAME); err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, HWAS::SRCI_PRIORITY_HIGH ); break; } }while(0); TRACDCOMP( g_trac_sbe, EXIT_MRK"cleanupSbeImageVmmSpace() - rc =0x%X", rc); return err; } ///////////////////////////////////////////////////////////////////// bool isIplFromReIplRequest(void) { TRACDCOMP( g_trac_sbe, ENTER_MRK"isIplFromReIplRequest"); bool o_reIplRequest = false; errlHndl_t err = NULL; msg_t * msg = msg_allocate(); do{ /***********************************************/ /* Check if MBOX Query has already been made */ /***********************************************/ if ( g_mbox_query_done == true ) { o_reIplRequest = g_mbox_query_result; TRACUCOMP( g_trac_sbe, "isIplFromReIplRequest: query " "previously done (%d). o_reIplRequest = %d", g_mbox_query_done, o_reIplRequest); break; } /*********************************************/ /* Check if MBOX is enabled */ /*********************************************/ bool mbox_enabled = false; TARGETING::Target * sys = NULL; TARGETING::targetService().getTopLevelTarget( sys ); TARGETING::SpFunctions spfuncs; if( sys && sys->tryGetAttr(spfuncs) && spfuncs.mailboxEnabled) { mbox_enabled = true; } /****************************************************/ /* MBOX IS NOT enabled: assume IPL not our request */ /****************************************************/ if ( mbox_enabled == false ) { o_reIplRequest = false; TRACFCOMP(g_trac_sbe, INFO_MRK"isIplFromReIplRequest(): " "MBOX not enabled, so assume not our IPL request. " "o_reIplRequest=%d", o_reIplRequest); break; } /*********************************************/ /* MBOX enabled, send message */ /*********************************************/ msg->type = MSG_IPL_DUE_TO_SBE_UPDATE; msg->data[0] = 0x0; msg->data[1] = 0x0; msg->extra_data = NULL; err = MBOX::sendrecv(MBOX::IPL_SERVICE_QUEUE, msg); if(err) { o_reIplRequest = false; TRACFCOMP(g_trac_sbe, ERR_MRK"isIplFromReIplRequest(): " "Error sending MBOX msg. Commit error, and assume " "IPL wasn't requested from us: o_reIplRequest=%d, " "RC=0x%X, PLID=0x%lX", o_reIplRequest, ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); errlCommit(err, SBE_COMP_ID); break; } // data word 0: if non-zero: IPL is due to SBE Update Request // data word 1: if non-zero: IPL is due to an error found by the // FSP if ( msg->data[1] == 0 ) // No error from FSP side { if( msg->data[0] != 0 ) { // IPL is due to SBE Update Request o_reIplRequest = true; TRACFCOMP(g_trac_sbe, INFO_MRK"isIplFromReIplRequest(): " "MBOX retuned that it was our IPL request: " "o_reIplRequest=%d (d0=0x%X, d1=0x%X)", o_reIplRequest, msg->data[0], msg->data[1]); } else { // normal IPL o_reIplRequest = false; TRACFCOMP(g_trac_sbe, INFO_MRK"isIplFromReIplRequest(): " "MBOX returned that it was a normal IPL: " "o_reIplRequest=%d (d0=0x%X, d1=0x%X)", o_reIplRequest, msg->data[0], msg->data[1]); } } else /* Non-Zero: error from FSP side. */ { // handle error reported by FSP o_reIplRequest = false; TRACFCOMP(g_trac_sbe, INFO_MRK"isIplFromReIplRequest(): " "MBOX returned error from FSP-side, so assume not our" "IPL request: o_reIplRequest=%d (d0=0x%X, d1=0x%X)", o_reIplRequest, msg->data[0], msg->data[1]); } }while(0); /********************************************************************/ /* If check hadn't been done before, set globals for next request */ /********************************************************************/ if ( g_mbox_query_done == false ) { g_mbox_query_done = true; g_mbox_query_result = o_reIplRequest; TRACUCOMP( g_trac_sbe, "isIplFromReIplRequest: save results: " "q_done = %d, q_result = %d", g_mbox_query_done, g_mbox_query_result); } // msg cleanup msg_free(msg); msg = NULL; TRACDCOMP( g_trac_sbe, EXIT_MRK"isIplFromReIplRequest(): o_reIplRequest=%d", o_reIplRequest); return o_reIplRequest; } ///////////////////////////////////////////////////////////////////// errlHndl_t preReIplCheck(std::vector& io_sbeStates_v) { TRACDCOMP( g_trac_sbe, ENTER_MRK"preReIplCheck"); errlHndl_t err = NULL; // MVPD PERMANT and Re-IPL Seeprom flags uint8_t perm_and_reipl = 0x0; uint8_t flags_mask = (PERMANENT_FLAG_MASK | REIPL_SEEPROM_MASK); uint8_t flags_match_0 = SEEPROM_0_PERMANENT_VALUE | REIPL_SEEPROM_0_VALUE; uint8_t flags_match_1 = SEEPROM_1_PERMANENT_VALUE | REIPL_SEEPROM_1_VALUE; uint8_t flags_misMatch_A = SEEPROM_1_PERMANENT_VALUE | REIPL_SEEPROM_0_VALUE; uint8_t flags_misMatch_B = SEEPROM_0_PERMANENT_VALUE | REIPL_SEEPROM_1_VALUE; do{ /*****************************************************************/ /* Iterate over all the processors and check/update each for: */ /* 1) MVPD SB Keyword has correct flag set for the */ /* re-IPL SEEPROM */ /*****************************************************************/ for ( uint8_t i=0; i < io_sbeStates_v.size(); i++ ) { /*************************************************************/ /* If not already updated, make sure MVPD SB Keyword has */ /* correct flag set for re-IPL SEEPROM */ /*************************************************************/ if (!(io_sbeStates_v[i].update_actions & MVPD_UPDATE_COMPLETE)) { // This target has not already had its MVPD updated // Check that perm and re-IPL boot flag match perm_and_reipl = io_sbeStates_v[i].mvpdSbKeyword.flags & flags_mask; if ( ( perm_and_reipl == flags_match_0 ) || ( perm_and_reipl == flags_match_1 ) ) { TRACUCOMP(g_trac_sbe,"preReIplCheck(): no MVPD update " "required for tgt=0x%X (u_a=0x%X, flag=0x%X)", TARGETING::get_huid(io_sbeStates_v[i].target), io_sbeStates_v[i].update_actions, io_sbeStates_v[i].mvpdSbKeyword.flags); continue; } else if ( ( perm_and_reipl == flags_misMatch_A ) || ( perm_and_reipl == flags_misMatch_B ) ) { if ( perm_and_reipl == flags_misMatch_A ) { // Perm is SEEPROM 1, so set both to 1 io_sbeStates_v[i].mvpdSbKeyword.flags |= flags_match_1; } else { // Perm is SEEPROM 0, so set both to 0 io_sbeStates_v[i].mvpdSbKeyword.flags &= ~flags_mask; } TRACFCOMP(g_trac_sbe,"preReIplCheck(): MVPD update " "Requried for tgt=0x%X (u_a=0x%X, flag=0x%X)", TARGETING::get_huid(io_sbeStates_v[i].target), io_sbeStates_v[i].update_actions, io_sbeStates_v[i].mvpdSbKeyword.flags); err = getSetMVPDVersion( io_sbeStates_v[i].target, MVPDOP_WRITE, io_sbeStates_v[i].mvpdSbKeyword); if(err) { TRACFCOMP(g_trac_sbe,ERR_MRK"preReIplCheck() " "Error Updating MVPD with new flag Info: " "HUID=0x%.8X, rc=0x%.4X. Committing log " "here and continuing.", TARGETING::get_huid(io_sbeStates_v[i].target), err->reasonCode()); errlCommit( err, SBE_COMP_ID ); } // update actions field uint32_t tmp_actions = io_sbeStates_v[i].update_actions | MVPD_UPDATE_COMPLETE; io_sbeStates_v[i].update_actions = static_cast (tmp_actions); continue; } } } // end of for loop }while(0); TRACDCOMP( g_trac_sbe, EXIT_MRK"preReIplCheck()"); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t masterVersionCompare( std::vector& io_sbeStates_v) { TRACDCOMP( g_trac_sbe, ENTER_MRK"masterVersionCompare"); errlHndl_t err = NULL; uint8_t mP = UINT8_MAX; sbe_image_version_t mP_version; sbe_image_version_t * ver_ptr; do{ // If running in simics, don't do these checks if ( Util::isSimicsRunning() ) { break; } /*****************************************************************/ /* Iterate over all the processors to find Master Processor */ /*****************************************************************/ for ( uint8_t i=0; i < io_sbeStates_v.size(); i++ ) { if ( io_sbeStates_v[i].target_is_master == true ) { mP = i; // Compare against 'current' Master side in case there is // an issue with the other side if (io_sbeStates_v[i].cur_seeprom_side == SBE_SEEPROM0) { ver_ptr = &(io_sbeStates_v[i].seeprom_0_ver.image_version); } else // SBE_SEEPROM1 { ver_ptr = &(io_sbeStates_v[i].seeprom_1_ver.image_version); } memcpy(&(mP_version), ver_ptr, SBE_IMAGE_VERSION_SIZE); break; } } // Handle very unlikely case of not finding Master Processor assert( (mP != UINT8_MAX), "masterVersionCompare(): master processor not found"); /*****************************************************************/ /* Make sure that there aren't any errors associated with */ /* updating the non-master targets; otherwise you can't trust */ /* their version */ /* -- AND -- */ /* Compare 'current' Version on all processors to see if they */ /* match the 'current' version on the Master Processor */ /* */ /* NOTE: Comparison based on PNOR SBE Image and --NOT-- */ /* based on CRC (which is partly target specific) */ /* */ /* Also, there are special checks for the Master Processor */ /*****************************************************************/ // @todo RTC 107721 - Need to handle Habanero 'Golden' SEEPROM side for ( uint8_t i=0; i < io_sbeStates_v.size(); i++ ) { // Special Master Processor checks if ( i == mP ) { // Skip Master Processor check of Both SEEPROMs being identical #ifndef CONFIG_SBE_UPDATE_INDEPENDENT // Compare Versions of Both SEEPROMs to PNOR Version // Create a Predictive Error if there's an issue if ((0 != memcmp( &(io_sbeStates_v[i].pnorVersion), &(io_sbeStates_v[i].seeprom_0_ver.image_version), SBE_IMAGE_VERSION_SIZE) ) || (0 != memcmp( &(io_sbeStates_v[i].pnorVersion), &(io_sbeStates_v[i].seeprom_1_ver.image_version), SBE_IMAGE_VERSION_SIZE) ) ) { TRACFCOMP( g_trac_sbe,ERR_MRK"masterVersionCompare() - " "SBE Version Miscompare Between Master " "Target SEEPROMs (HUID=0x%.8X, current " "side=%d)", TARGETING::get_huid( io_sbeStates_v[mP].target), io_sbeStates_v[mP].cur_seeprom_side); // Trace first 8 bytes of each section // Full Version added to error log below TRACFBIN( g_trac_sbe, "PNOR Version", &(io_sbeStates_v[i].pnorVersion), 8 ) ; TRACFBIN( g_trac_sbe, "Seeprom0: Master Image Version", &(io_sbeStates_v[mP].seeprom_0_ver.image_version), 8 ) ; TRACFBIN( g_trac_sbe, "Seeprom1: Master Image Version", &(io_sbeStates_v[mP].seeprom_1_ver.image_version), 8 ) ; /*@ * @errortype * @moduleid SBE_MASTER_VERSION_COMPARE * @reasoncode SBE_MASTER_VERSION_DOWNLEVEL * @userdata1 Master Target HUID * @userdata2 Master Target Loop Index * @devdesc SBE Image Verion Miscompare with * Master Target */ err = new ErrlEntry(ERRL_SEV_PREDICTIVE, SBE_MASTER_VERSION_COMPARE, SBE_MASTER_VERSION_DOWNLEVEL, TARGETING::get_huid( io_sbeStates_v[mP].target), mP); err->collectTrace(SBE_COMP_NAME); err->addPartCallout( io_sbeStates_v[i].target, HWAS::SBE_SEEPROM_PART_TYPE, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); ErrlUserDetailsTarget(io_sbeStates_v[mP].target, "Master Target").addToLog(err); // Add general data sections to capture the // different versions err->addFFDC( SBE_COMP_ID, &(io_sbeStates_v[i].pnorVersion), SBE_IMAGE_VERSION_SIZE, 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge err->addFFDC( SBE_COMP_ID, &(io_sbeStates_v[mP].seeprom_0_ver.image_version), SBE_IMAGE_VERSION_SIZE, 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge err->addFFDC( SBE_COMP_ID, &(io_sbeStates_v[mP].seeprom_1_ver.image_version), SBE_IMAGE_VERSION_SIZE, 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge errlCommit( err, SBE_COMP_ID ); } // end of check #endif // Continue to avoid remaining non-Master Processor checks continue; } else { // Not Master, so get 'current' version if (io_sbeStates_v[i].cur_seeprom_side == SBE_SEEPROM0) { ver_ptr = &(io_sbeStates_v[i].seeprom_0_ver.image_version); } else // SBE_SEEPROM1 { ver_ptr = &(io_sbeStates_v[i].seeprom_1_ver.image_version); } } // See if there was an issue updating this target if ( io_sbeStates_v[i].err_plid != 0 ) { TRACFCOMP( g_trac_sbe,ERR_MRK"masterVersionCompare() - " "Error Associated with Updating Target " "HUID=0x%.8X: plid=0x%.8X, eid=0x%.8X, " "rc=0x%.4X. Can't trust its SBE Version", TARGETING::get_huid(io_sbeStates_v[i].target), io_sbeStates_v[i].err_plid, io_sbeStates_v[i].err_eid, io_sbeStates_v[i].err_rc); /*@ * @errortype * @moduleid SBE_MASTER_VERSION_COMPARE * @reasoncode SBE_ERROR_ON_UPDATE * @userdata1[0:31] Target HUID * @userdata1[32:63] Original Error PLID * @userdata2[0:31] Original Error EID * @userdata2[32:63] Original Error Reason Code * @devdesc Error Associated with Updating this Target */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_MASTER_VERSION_COMPARE, SBE_ERROR_ON_UPDATE, TWO_UINT32_TO_UINT64( TARGETING::get_huid( io_sbeStates_v[i].target), io_sbeStates_v[i].err_plid), TWO_UINT32_TO_UINT64( io_sbeStates_v[i].err_eid, io_sbeStates_v[i].err_rc)); // Link the 2 logs err->plid(io_sbeStates_v[i].err_plid); } // Compare 'current' version of target to 'current' version // of Master target in case Master version is down-level else if ( 0 != memcmp( &(mP_version), ver_ptr, SBE_IMAGE_VERSION_SIZE) ) { TRACFCOMP( g_trac_sbe,ERR_MRK"masterVersionCompare() - " "SBE Version Miscompare Between Master Target " "HUID=0x%.8X (side=%d) and Target HUID=0x%.8X " "(side=%d)", TARGETING::get_huid( io_sbeStates_v[mP].target), io_sbeStates_v[mP].cur_seeprom_side, TARGETING::get_huid(io_sbeStates_v[i].target), io_sbeStates_v[i].cur_seeprom_side); // Trace first 8 bytes of each section // Full Version added to error log below TRACFBIN( g_trac_sbe, "PNOR Version", &(io_sbeStates_v[i].pnorVersion), 8 ) ; TRACFBIN( g_trac_sbe, "Seeprom0: Master Image Version", &(io_sbeStates_v[mP].seeprom_0_ver.image_version), 8 ) ; TRACFBIN( g_trac_sbe, "Seeprom1: Master Image Version", &(io_sbeStates_v[mP].seeprom_1_ver.image_version), 8 ) ; TRACFBIN( g_trac_sbe, "Seeprom0: Failing Image Version", &(io_sbeStates_v[i].seeprom_0_ver.image_version), 8 ) ; TRACFBIN( g_trac_sbe, "Seeprom1: Failing Image Version", &(io_sbeStates_v[i].seeprom_1_ver.image_version), 8 ) ; /*@ * @errortype * @moduleid SBE_MASTER_VERSION_COMPARE * @reasoncode SBE_MISCOMPARE_WITH_MASTER_VERSION * @userdata1 Master Target HUID * @userdata2 Comparison Target HUID * @devdesc SBE Verion Miscompare with Master Target */ err = new ErrlEntry(ERRL_SEV_UNRECOVERABLE, SBE_MASTER_VERSION_COMPARE, SBE_MISCOMPARE_WITH_MASTER_VERSION, TARGETING::get_huid( io_sbeStates_v[mP].target), TARGETING::get_huid( io_sbeStates_v[i].target)); // Add general data sections to capture the // different versions err->addFFDC( SBE_COMP_ID, &(io_sbeStates_v[i].pnorVersion), SBE_IMAGE_VERSION_SIZE, 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge err->addFFDC( SBE_COMP_ID, &(io_sbeStates_v[mP].seeprom_0_ver.image_version), SBE_IMAGE_VERSION_SIZE, 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge err->addFFDC( SBE_COMP_ID, &(io_sbeStates_v[mP].seeprom_1_ver.image_version), SBE_IMAGE_VERSION_SIZE, 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge err->addFFDC( SBE_COMP_ID, &(io_sbeStates_v[i].seeprom_0_ver.image_version), SBE_IMAGE_VERSION_SIZE, 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge err->addFFDC( SBE_COMP_ID, &(io_sbeStates_v[i].seeprom_1_ver.image_version), SBE_IMAGE_VERSION_SIZE, 0, // Version ERRL_UDT_NOFORMAT, // parser ignores data false ); // merge } // No issues else { TRACUCOMP( g_trac_sbe, "masterVersionCompare: Successful " "Version check", i, mP); } if ( err ) { // Add FFDC and Commit the error log created here err->collectTrace(SBE_COMP_NAME); err->addPartCallout( io_sbeStates_v[i].target, HWAS::SBE_SEEPROM_PART_TYPE, HWAS::SRCI_PRIORITY_HIGH, HWAS::NO_DECONFIG, HWAS::GARD_NULL ); ErrlUserDetailsTarget(io_sbeStates_v[mP].target, "Master Target").addToLog(err); ErrlUserDetailsTarget(io_sbeStates_v[i].target, "Failing Target").addToLog(err); errlCommit( err, SBE_COMP_ID ); } } }while(0); TRACDCOMP( g_trac_sbe, EXIT_MRK"masterVersionCompare"); return err; } ///////////////////////////////////////////////////////////////////// errlHndl_t isGoldenSide( bool & o_isGolden ) { errlHndl_t l_errl = NULL; o_isGolden = false; #ifndef CONFIG_SBE_UPDATE_SEQUENTIAL do { // Get the master processor TARGETING::Target * l_masterProc = NULL; TARGETING::targetService().masterProcChipTargetHandle(l_masterProc); assert( l_masterProc != NULL ); sbeSeepromSide_t l_currentSide = SBE_SEEPROM_INVALID; // Get Seeprom side l_errl = getSbeBootSeeprom(l_masterProc, l_currentSide); if( l_errl ) { TRACFCOMP( g_trac_sbe, ERR_MRK "isGoldenSide() - Error returned " "from getSbeBootSeeprom() " "rc=0x%.4X, Target UID=0x%X", l_errl->reasonCode(), TARGETING::get_huid(l_masterProc)); break; } //Get PNOR Side PNOR::SideId l_pnorSide = PNOR::WORKING; PNOR::SideInfo_t l_sideInfo; l_errl = PNOR::getSideInfo( l_pnorSide, l_sideInfo ); if( l_errl ) { TRACFCOMP(g_trac_sbe, ERR_MRK "isGoldenSide() - Error returned " "from PNOR::getSideInfo() " "rc=0x%.4X, Target UID=0x%X", l_errl->reasonCode(), TARGETING::get_huid( l_masterProc )); break; } // SBE_SEEPROM1 by itself does not imply golden side. // cross reference sbe side with pnor side to make sure. if(( l_currentSide == SBE_SEEPROM1 ) && (( l_sideInfo.isGolden ) || (l_sideInfo.hasOtherSide == false ))) { TRACUCOMP(g_trac_sbe, INFO_MRK "sbe_update.C::isGoldenSide() - " "Booted from Golden side!"); o_isGolden = true; } }while( 0 ); #endif return l_errl; } ///////////////////////////////////////////////////////////////////// void checkSeepromNestFreq(TARGETING::Target* i_tgt, uint32_t i_default_nest_freq, uint32_t i_struct_version, uint32_t i_seeprom_nest_freq, size_t i_seeprom_num, bool & o_mismatch) { TARGETING::Target * l_sys = nullptr; TARGETING::targetService().getTopLevelTarget( l_sys ); uint32_t l_current_nest_freq = l_sys->getAttr(); TRACUCOMP( g_trac_sbe, ENTER_MRK"checkSeepromNestFreq: tgt=0x%X current_freq=%d, " "default_freq=%d, version=0x%X, i_seeprom_nest_freq=%d, " "seeprom_num=%d", TARGETING::get_huid(i_tgt), l_current_nest_freq, i_default_nest_freq, i_struct_version, i_seeprom_nest_freq, i_seeprom_num); o_mismatch = false; // Check Seeprom if ( STRUCT_VERSION_CHECK(i_struct_version) && i_seeprom_nest_freq != 0 ) { // Only version that tracks the nest freq when the image was // customized if ( l_current_nest_freq == i_seeprom_nest_freq ) { TRACUCOMP( g_trac_sbe,"checkSeepromNestFreq: tgt=0x%X: " "Seeprom%d: ver%d found and current " "nest_freq(%d) and image nest_freq(%d) match", TARGETING::get_huid(i_tgt), i_seeprom_num, i_struct_version, l_current_nest_freq, i_seeprom_nest_freq); } else { o_mismatch = true; TRACFCOMP( g_trac_sbe,"checkSeepromNestFreq: tgt=0x%X: " "Seeprom%d: ver%d found and current " "nest_freq(%d) and image nest_freq(%d) DO NOT match", TARGETING::get_huid(i_tgt), i_seeprom_num, i_struct_version, l_current_nest_freq, i_seeprom_nest_freq); } } else { // Either uninitialized, simics, corrupted, etc // Assume SBE image created with the module's default frequency if ( l_current_nest_freq == i_default_nest_freq ) { TRACUCOMP( g_trac_sbe,"checkSeepromNestFreq: tgt=0x%X: " "Seeprom%d: ver=0x%X found and current " "nest_freq(%d) and default nest_freq(%d) match", TARGETING::get_huid(i_tgt), i_seeprom_num, i_struct_version, l_current_nest_freq, i_default_nest_freq); } else { o_mismatch = true; TRACFCOMP( g_trac_sbe,"checkSeepromNestFreq: tgt=0x%X: " "Seeprom%d: ver=0x%X found and current " "nest_freq(%d) and default nest_freq(%d) " "DO NOT match. ", TARGETING::get_huid(i_tgt), i_seeprom_num, i_struct_version, l_current_nest_freq, i_default_nest_freq); } } TRACUCOMP( g_trac_sbe, EXIT_MRK"checkSeepromNestFreq: tgt=0x%X " "Seeprom%d: return o_mismatch=%d", TARGETING::get_huid(i_tgt), i_seeprom_num, o_mismatch); return; } ///////////////////////////////////////////////////////////////////// errlHndl_t getBootNestFreq( uint32_t & o_bootNestFreq ) { errlHndl_t l_err = nullptr; INITSERVICE::SPLESS::MboxScratch4_t l_scratch4; TARGETING::Target * l_masterProcTarget = NULL; TARGETING::targetService() .masterProcChipTargetHandle( l_masterProcTarget ); TARGETING::Target * l_sys = nullptr; (void) TARGETING::targetService().getTopLevelTarget( l_sys ); assert( l_sys, "getBootNestFreq() system target is NULL"); TRACFCOMP( g_trac_sbe, ENTER_MRK"Enter getBootNestFreq()"); do { TARGETING::ATTR_MASTER_MBOX_SCRATCH_type l_scratchRegs; assert(l_sys->tryGetAttr (l_scratchRegs), "getBootNestFreq() failed to get MASTER_MBOX_SCRATCH"); l_scratch4.data32 = l_scratchRegs[INITSERVICE::SPLESS::SCRATCH_4]; TRACFCOMP(g_trac_sbe, "The nest PLL bucket id is %d", l_scratch4.nestPllBucket ); size_t sizeOfPll = sizeof(NEST_PLL_FREQ_LIST)/ sizeof(NEST_PLL_FREQ_LIST[0]); assert((uint8_t)(l_scratch4.nestPllBucket-1) < (uint8_t) sizeOfPll ); // The nest PLL bucket IDs are numbered 1 - 5. Subtract 1 to // take zero-based indexing into account. o_bootNestFreq = NEST_PLL_FREQ_LIST[l_scratch4.nestPllBucket-1]; TRACFCOMP(g_trac_sbe, "getBootNestFreq::The boot frequency was %d: Bucket Id = %d", o_bootNestFreq, l_scratch4.nestPllBucket ); }while( 0 ); TRACUCOMP(g_trac_sbe,EXIT_MRK "Exit getBootNestFreq()"); return l_err; } ///////////////////////////////////////////////////////////////////// errlHndl_t checkNestFreqSettings(sbeTargetState_t& io_sbeState) { TRACFCOMP( g_trac_sbe, ENTER_MRK"checkNestFreqSettings(): HUID:0x%08X", TARGETING::get_huid(io_sbeState.target)); errlHndl_t err = NULL; uint32_t default_nest_freq = 0; do{ // Set defaults io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch = false; io_sbeState.seeprom_1_ver_Nest_Freq_Mismatch = false; // Retrieve the boot frequency we booted from err = getBootNestFreq(default_nest_freq); if( err ) { TRACFCOMP(g_trac_sbe, "There was an error getting the default boot frequency"); break; } TRACFCOMP( g_trac_sbe,"checkNestFreqSettings(): ATTR_FREQ_PB_MHZ" " Boot Frequency=%d", default_nest_freq); TRACUCOMP( g_trac_sbe,"checkNestFreqSettings(): " "seeprom0 ver=%d freq=%d seeprom1 ver=%d freq=%d", io_sbeState.seeprom_0_ver.struct_version, io_sbeState.seeprom_0_ver.nest_freq_mhz, io_sbeState.seeprom_1_ver.struct_version, io_sbeState.seeprom_1_ver.nest_freq_mhz); // Check Seeprom 0 checkSeepromNestFreq(io_sbeState.target, default_nest_freq, io_sbeState.seeprom_0_ver.struct_version, io_sbeState.seeprom_0_ver.nest_freq_mhz, 0, io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch); // Check Seeprom 1 checkSeepromNestFreq(io_sbeState.target, default_nest_freq, io_sbeState.seeprom_1_ver.struct_version, io_sbeState.seeprom_1_ver.nest_freq_mhz, 1, io_sbeState.seeprom_1_ver_Nest_Freq_Mismatch); // Set the frequency at which the master processor booted from if ( io_sbeState.target_is_master == true ) { //Get Current (boot) Side sbeSeepromSide_t tmp_cur_side = SBE_SEEPROM_INVALID; err = getSbeBootSeeprom(io_sbeState.target, tmp_cur_side); if(err) { TRACFCOMP( g_trac_sbe, ERR_MRK"checkNestFreqSettings() - " "Error returned from getSbeBootSeeprom(), " "RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(err), ERRL_GETPLID_SAFE(err)); // Assume it was default frequency for this module io_sbeState.mproc_nest_freq_mhz = default_nest_freq; break; } if (tmp_cur_side == SBE_SEEPROM0) { if ( STRUCT_VERSION_CHECK( io_sbeState.seeprom_0_ver.struct_version) && io_sbeState.seeprom_0_ver.nest_freq_mhz != 0 ) { io_sbeState.mproc_nest_freq_mhz = io_sbeState.seeprom_0_ver.nest_freq_mhz; } else { // Assume it was default frequency for this module io_sbeState.mproc_nest_freq_mhz = default_nest_freq; } } else if ( tmp_cur_side == SBE_SEEPROM1 ) { if ( STRUCT_VERSION_CHECK( io_sbeState.seeprom_1_ver.struct_version) && io_sbeState.seeprom_1_ver.nest_freq_mhz != 0 ) { io_sbeState.mproc_nest_freq_mhz = io_sbeState.seeprom_1_ver.nest_freq_mhz; } else { // Assume it was default frequency for this module io_sbeState.mproc_nest_freq_mhz = default_nest_freq; } } else { // Assume it was default frequency for this module io_sbeState.mproc_nest_freq_mhz = default_nest_freq; } } TRACUCOMP( g_trac_sbe,"checkNestFreqSettings(): s0-mismatch=%d, " "s1-mismatch=%d, mproc_nest_freq_mhz=%d", io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch, io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch, io_sbeState.mproc_nest_freq_mhz); }while(0); TRACFCOMP( g_trac_sbe, EXIT_MRK"checkNestFreqSettings"); return err; } ///////////////////////////////////////////////////////////////////// size_t setECCSize(size_t i_srcSz, const uint64_t i_offset, const uint64_t i_boundary) { // Assert that source size is a multiple of 8 assert((i_srcSz % 8) == 0); // Calculate size with ECC. but without padding size_t l_eccSz = (i_srcSz * 9) / 8; // Determine padding at each boundary size_t l_padSz = i_boundary % 9; // Calculate number of boundary crossings // Only use portion of offset beyond last boundary it crosses // Exactly reaching a boundary is not counted as a crossing uint64_t l_boundaryCrossings = (l_eccSz + (i_offset % i_boundary) - 1) / (i_boundary - l_padSz); // Calculate total padding size_t l_totalPadding = l_boundaryCrossings * l_padSz; return (l_eccSz + l_totalPadding); } ///////////////////////////////////////////////////////////////////// void injectECC(const uint8_t* i_src, size_t i_srcSz, const uint64_t i_offset, const uint64_t i_boundary, uint8_t* o_dst) { // Initialize local size variables for inject loop size_t l_completeSz = 0; size_t l_completeEccSz = 0; size_t l_padSz = i_boundary % 9; size_t l_injectSz = ((i_boundary - l_padSz - (i_offset % i_boundary)) * 8) / 9; if(l_injectSz > i_srcSz) { l_injectSz = i_srcSz; } // Loop through injection of ECC while(l_completeSz < i_srcSz) { // Assert that injection size is a multiple of 8 assert((l_injectSz % 8) == 0); // Inject ECC PNOR::ECC::injectECC(i_src + l_completeSz, l_injectSz, o_dst + l_completeEccSz); // Adjust local size variables l_completeSz += l_injectSz; l_completeEccSz += ((l_injectSz * 9) / 8); // Determine next size for ECC injection if((i_srcSz - l_completeSz) >= (((i_boundary - l_padSz) * 8) / 9)) { // Set up size to go to next device boundary l_injectSz = ((i_boundary - l_padSz) * 8) / 9; } else { // Set up size to finish ECC injection l_injectSz = i_srcSz - l_completeSz; } // Determine if ECC injection is not finished if(l_injectSz > 0) { // Pad to device boundary if some ECC injection is left memset(o_dst + l_completeEccSz, '\0', l_padSz); l_completeEccSz += l_padSz; } } // while (l_completeSz < i_srcSz) } ///////////////////////////////////////////////////////////////////// PNOR::ECC::eccStatus removeECC(uint8_t* io_src, uint8_t* o_dst, size_t i_dstSz, const uint64_t i_offset, const uint64_t i_boundary) { PNOR::ECC::eccStatus l_status = PNOR::ECC::CLEAN; // Initialize local size variables for remove loop size_t l_completeSz = 0; size_t l_completeEccSz = 0; size_t l_padSz = i_boundary % 9; size_t l_removeSz = ((i_boundary - l_padSz - (i_offset % i_boundary)) * 8) / 9; if(l_removeSz > i_dstSz) { l_removeSz = i_dstSz; } // Loop through removal of ECC while(l_completeSz < i_dstSz) { // Assert that removal size is a multiple of 8 assert((l_removeSz % 8) == 0); // remove ECC l_status = PNOR::ECC::removeECC(io_src + l_completeEccSz, o_dst + l_completeSz, l_removeSz); if (l_status == PNOR::ECC::UNCORRECTABLE) { break; } // Adjust local size variables l_completeSz += l_removeSz; l_completeEccSz += ((l_removeSz * 9) / 8); // Determine next size for ECC removal if((i_dstSz - l_completeSz) >= (((i_boundary - l_padSz) * 8) / 9)) { // Set up size to go to next device boundary l_removeSz = ((i_boundary - l_padSz) * 8) / 9; } else { // Set up size to finish ECC removal l_removeSz = i_dstSz - l_completeSz; } // Determine if ECC removal is not finished if(l_removeSz > 0) { // Skip pad at device boundary if some ECC removal is left l_completeEccSz += l_padSz; } } // while (l_completeSz < i_dstSz) return l_status; } ///////////////////////////////////////////////////////////////////// errlHndl_t getBootMcSyncMode( uint8_t& o_mcSyncMode ) { errlHndl_t l_err = nullptr; INITSERVICE::SPLESS::MboxScratch5_t l_scratch5; TRACFCOMP( g_trac_sbe, ENTER_MRK"Enter getBootMcSyncMode()"); do { TARGETING::Target * l_sys = nullptr; (void) TARGETING::targetService().getTopLevelTarget( l_sys ); assert( l_sys, "getBootMcSyncMode() system target is NULL"); TARGETING::ATTR_MASTER_MBOX_SCRATCH_type l_scratchRegs; assert(l_sys->tryGetAttr (l_scratchRegs), "getBootMcSyncMode() failed to get MASTER_MBOX_SCRATCH"); l_scratch5.data32 = l_scratchRegs[INITSERVICE::SPLESS::SCRATCH_5]; TRACFCOMP(g_trac_sbe, "The MC Sync Bit is %d", l_scratch5.mcSyncMode ); o_mcSyncMode = l_scratch5.mcSyncMode; } while( 0 ); TRACUCOMP(g_trac_sbe,EXIT_MRK "Exit getBootMcSyncMode()"); return l_err; } } //end SBE Namespace