Merge pull request #272 from aalugore/master-next
OCC firmware update to support wof
diff --git a/openpower/package/hostboot/hostboot-0004-SBE-update-support-for-adjusted-nest-freq.patch b/openpower/package/hostboot/hostboot-0004-SBE-update-support-for-adjusted-nest-freq.patch
new file mode 100644
index 0000000..b937bf0
--- /dev/null
+++ b/openpower/package/hostboot/hostboot-0004-SBE-update-support-for-adjusted-nest-freq.patch
@@ -0,0 +1,1376 @@
+From da7ff638a6ca5c5588bf8cecc00e335d8ea92c91 Mon Sep 17 00:00:00 2001
+From: Andres Lugo-Reyes <aalugore@us.ibm.com>
+Date: Mon, 24 Aug 2015 16:45:40 -0500
+Subject: [PATCH] SBE Update Support for Adjusted Nest Frequency
+
+This commit adds a check in istep 8.1 to see if the SBE Seeproms are
+programmed with the same NEST_FREQ_MHZ attribute value that the system is
+currently running at. If necessary, it will update the SBE Seeproms in this
+step which might result in a re-IPL.
+
+Change-Id: I1dca7196cd02a2704a238665b73b522c9e103936
+RTC:133406
+Depends-on:I9bba92f55f1b67ff4a15d79113f19d39272ec72d
+Backport: release-fips840
+---
+ src/include/usr/isteps/istep08list.H | 2 +
+ src/include/usr/sbe/sbeif.H | 19 +-
+ .../hwpf/hwp/activate_powerbus/activate_powerbus.C | 5 +-
+ .../edi_ei_initialization/edi_ei_initialization.C | 37 +-
+ src/usr/hwpf/hwp/slave_sbe/slave_sbe.C | 11 +-
+ src/usr/sbe/sbe_update.C | 640 ++++++++++++++++-----
+ src/usr/sbe/sbe_update.H | 57 +-
+ src/usr/sbe/test/sbeupdatetest.H | 4 +-
+ src/usr/targeting/common/genHwsvMrwXml.pl | 19 +
+ .../targeting/common/xmltohb/attribute_types.xml | 18 +
+ src/usr/targeting/common/xmltohb/target_types.xml | 12 +
+ 11 files changed, 668 insertions(+), 156 deletions(-)
+
+diff --git a/src/include/usr/isteps/istep08list.H b/src/include/usr/isteps/istep08list.H
+index 9496539..0a721c6 100644
+--- a/src/include/usr/isteps/istep08list.H
++++ b/src/include/usr/isteps/istep08list.H
+@@ -120,6 +120,8 @@ const DepModInfo g_istep08Dependancies = {
+ DEP_LIB(libnest_chiplets.so),
+ DEP_LIB(libsecure_boot.so),
+ DEP_LIB(libslave_sbe.so),
++ DEP_LIB(libsbe.so),
++ DEP_LIB(libbuild_winkle_images.so),
+ NULL
+ }
+ };
+diff --git a/src/include/usr/sbe/sbeif.H b/src/include/usr/sbe/sbeif.H
+index 9cf20c6..b00e01f 100644
+--- a/src/include/usr/sbe/sbeif.H
++++ b/src/include/usr/sbe/sbeif.H
+@@ -59,14 +59,31 @@ namespace SBE
+ size_t& o_imgSize,
+ sbe_image_version_t* o_version = NULL);
+
++ /**
++ * @enum sbeUpdateCheckType
++ *
++ * @brief Determines what types of checks are performed on the SBE Seeproms
++ * to determine if an update is necessary.
++ *
++ */
++ enum sbeUpdateCheckType
++ {
++ SBE_UPDATE_CHECK_ALL = 0x00,
++ SBE_UPDATE_ONLY_CHECK_NEST_FREQ = 0x01
++ };
+
+ /**
+ * @brief Iterates through all the functional processors and updates
+ * the SBE Image in a SEEPROM, if necessary.
+ *
++ * @param[in] i_check_type Indicates what types of checks are performed
++ * on the SBE Seeproms to determine if an update
++ * is necessary.
++ *
+ * @return errlHndl_t Error log handle on failure.
+ */
+- errlHndl_t updateProcessorSbeSeeproms();
++ errlHndl_t updateProcessorSbeSeeproms(
++ sbeUpdateCheckType i_check_type = SBE_UPDATE_CHECK_ALL);
+
+ /**
+ * @brief Iterates through all the functional processors and resolves
+diff --git a/src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C b/src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C
+index 4cb1d3a..642b539 100644
+--- a/src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C
++++ b/src/usr/hwpf/hwp/activate_powerbus/activate_powerbus.C
+@@ -347,9 +347,12 @@ void * call_host_slave_sbe_update( void * io_pArgs )
+ do
+ {
+
++ // Slave processors should now use Host I2C Access Method
++ I2C::i2cSetAccessMode( I2C::I2C_SET_ACCESS_MODE_PROC_HOST );
++
+ // Reset I2C devices before trying to access the SBE SEEPROMs
+ // Any error returned should not fail istep
+- l_errl = I2C::i2cResetActiveMasters( I2C::I2C_PROC_HOST );
++ l_errl = I2C::i2cResetActiveMasters( I2C::I2C_PROC_ALL );
+ if (l_errl)
+ {
+ // Commit error and keep going
+diff --git a/src/usr/hwpf/hwp/edi_ei_initialization/edi_ei_initialization.C b/src/usr/hwpf/hwp/edi_ei_initialization/edi_ei_initialization.C
+index ae02ad8..e1ab17d 100644
+--- a/src/usr/hwpf/hwp/edi_ei_initialization/edi_ei_initialization.C
++++ b/src/usr/hwpf/hwp/edi_ei_initialization/edi_ei_initialization.C
+@@ -5,7 +5,9 @@
+ /* */
+ /* OpenPOWER HostBoot Project */
+ /* */
+-/* COPYRIGHT International Business Machines Corp. 2012,2014 */
++/* Contributors Listed Below - COPYRIGHT 2012,2015 */
++/* [+] 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. */
+@@ -53,6 +55,8 @@
+ #include <hwas/common/deconfigGard.H>
+ #include <hwas/common/hwasCommon.H>
+
++#include <sbe/sbeif.H>
++
+ // targeting support
+ #include <targeting/common/commontargeting.H>
+ #include <targeting/common/utilFilter.H>
+@@ -102,6 +106,35 @@ void* call_fabric_erepair( void *io_pArgs )
+ errlHndl_t l_errl = NULL;
+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_fabric_erepair entry" );
+
++ do {
++
++ // Check if the system can support multiple nest frequencies
++ // and if so, see if an SBE Update is required
++ TARGETING::Target* l_sys = NULL;
++ targetService().getTopLevelTarget(l_sys);
++ assert( l_sys != NULL, "call_fabric_erepair: sys target is NULL" );
++ MRW_NEST_CAPABLE_FREQUENCIES_SYS l_mrw_nest_capable;
++ l_mrw_nest_capable =
++ l_sys->getAttr<ATTR_MRW_NEST_CAPABLE_FREQUENCIES_SYS>();
++ if ( l_mrw_nest_capable ==
++ MRW_NEST_CAPABLE_FREQUENCIES_SYS_2000_MHZ_OR_2400_MHZ )
++ {
++ // Call to check Processor SBE SEEPROM Images against NEST_FREQ_MHZ
++ // attributes and make any necessary updates
++ l_errl = SBE::updateProcessorSbeSeeproms(
++ SBE::SBE_UPDATE_ONLY_CHECK_NEST_FREQ);
++
++ if (l_errl)
++ {
++ // Create IStep error log and cross reference error that occurred
++ l_StepError.addErrorDetails( l_errl );
++ // Commit error
++ errlCommit( l_errl, HWPF_COMP_ID );
++ break;
++ }
++
++ }
++
+ std::vector<uint8_t> l_endp1_txFaillanes;
+ std::vector<uint8_t> l_endp1_rxFaillanes;
+ std::vector<uint8_t> l_endp2_txFaillanes;
+@@ -278,6 +311,8 @@ void* call_fabric_erepair( void *io_pArgs )
+ } // end for l_PbusConnections
+ } // end for MaxBusSet
+
++ } while (0);
++
+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_fabric_erepair exit" );
+
+ return l_StepError.getErrorHandle();
+diff --git a/src/usr/hwpf/hwp/slave_sbe/slave_sbe.C b/src/usr/hwpf/hwp/slave_sbe/slave_sbe.C
+index c74402d..9493144 100644
+--- a/src/usr/hwpf/hwp/slave_sbe/slave_sbe.C
++++ b/src/usr/hwpf/hwp/slave_sbe/slave_sbe.C
+@@ -194,6 +194,7 @@ void* call_host_slave_sbe_config(void *io_pArgs)
+ errlCommit( err, HWPF_COMP_ID );
+ }
+
++
+ TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
+ "call_host_slave_sbe_config exit" );
+
+@@ -616,16 +617,6 @@ void* call_proc_check_slave_sbe_seeprom_complete( void *io_pArgs )
+
+ } // endfor
+
+- // Slave processors should now use Host I2C Access Method
+- I2C::i2cSetAccessMode( I2C::I2C_SET_ACCESS_MODE_PROC_HOST );
+-
+- // Reset the Processor's I2C Masters
+- l_errl = I2C::i2cResetActiveMasters(I2C::I2C_PROC_ALL);
+- if (l_errl)
+- {
+- // Commit error
+- errlCommit( l_errl, HWPF_COMP_ID );
+- }
+
+ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
+ "call_proc_check_slave_sbe_seeprom_complete exit");
+diff --git a/src/usr/sbe/sbe_update.C b/src/usr/sbe/sbe_update.C
+index 28e42fc..1faad63 100644
+--- a/src/usr/sbe/sbe_update.C
++++ b/src/usr/sbe/sbe_update.C
+@@ -34,6 +34,7 @@
+ #include <targeting/common/predicates/predicatectm.H>
+ #include <targeting/common/utilFilter.H>
+ #include <targeting/common/targetservice.H>
++#include <targeting/common/target.H>
+ #include <util/align.H>
+ #include <util/crc32.H>
+ #include <util/misc.H>
+@@ -82,13 +83,13 @@ 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;
++static uint32_t g_current_nest_freq = 0;
+
+ using namespace ERRORLOG;
+ using namespace TARGETING;
+
+ namespace SBE
+ {
+-
+ enum {
+ SBE_IMG_VADDR = VMM_VADDR_SBE_UPDATE,
+ RING_BUF1_VADDR = FIXED_SEEPROM_WORK_SPACE + SBE_IMG_VADDR,
+@@ -100,7 +101,7 @@ namespace SBE
+ };
+
+ /////////////////////////////////////////////////////////////////////
+- errlHndl_t updateProcessorSbeSeeproms()
++ errlHndl_t updateProcessorSbeSeeproms(sbeUpdateCheckType i_check_type)
+ {
+ errlHndl_t err = NULL;
+ errlHndl_t err_cleanup = NULL;
+@@ -111,7 +112,8 @@ namespace SBE
+ bool l_restartNeeded = false;
+
+ TRACUCOMP( g_trac_sbe,
+- ENTER_MRK"updateProcessorSbeSeeproms()" );
++ ENTER_MRK"updateProcessorSbeSeeproms(): i_check_type=%d",
++ i_check_type);
+
+ do{
+
+@@ -171,6 +173,10 @@ namespace SBE
+ g_update_both_sides = true;
+ }
+
++ // Collect ATTR_NEST_FREQ_MHZ for reference later
++ g_current_nest_freq = sys->getAttr<ATTR_NEST_FREQ_MHZ>();
++
++
+ //Make sure procedure constants keep within expected range.
+ assert((FIXED_SEEPROM_WORK_SPACE <= VMM_SBE_UPDATE_SIZE/2),
+ "updateProcessorSbeSeeproms() FIXED_SEEPROM_WORK_SPACE "
+@@ -261,7 +267,8 @@ namespace SBE
+ sbeState.target_is_master = false;
+ }
+
+- err = getSbeInfoState(sbeState);
++ err = getSbeInfoState(sbeState,
++ i_check_type);
+
+ if (err)
+ {
+@@ -273,15 +280,29 @@ namespace SBE
+ 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
+- if ( err == NULL )
++ else if ( err == NULL )
+ {
+ err = getTargetUpdateActions(sbeState);
+ if (err)
+@@ -295,6 +316,7 @@ namespace SBE
+
+ // Don't break - handle error at the end of the loop,
+ }
++
+ }
+
+ /**********************************************/
+@@ -406,15 +428,19 @@ namespace SBE
+ /* Deconfigure any Processors that have a Version different */
+ /* from the Master Processor's Version */
+ /************************************************************/
+- err = masterVersionCompare(sbeStates_vector);
+-
+- if ( err )
++ // skip if we're only checking for NEST_FREQ mismatch
++ if ( i_check_type != SBE_UPDATE_ONLY_CHECK_NEST_FREQ )
+ {
+- // Something failed on the check
+- TRACFCOMP( g_trac_sbe,
+- INFO_MRK"updateProcessorSbeSeeproms(): Call to "
+- "masterVersionCompare() failed rc=0x%.4X",
+- err->reasonCode());
++ 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);
+@@ -451,7 +477,6 @@ namespace SBE
+ }
+ }
+
+-
+ TRACUCOMP( g_trac_sbe,
+ EXIT_MRK"updateProcessorSbeSeeproms()" );
+
+@@ -865,6 +890,7 @@ namespace SBE
+ }
+ } // end of while loop
+
++
+ if(err)
+ {
+ // There was a previous error, so break here
+@@ -1312,14 +1338,16 @@ namespace SBE
+ }while(0);
+
+ TRACFCOMP( g_trac_sbe,
+- EXIT_MRK"getSbeBootSeeprom(): o_bootSide=0x%X (reg=0x%X)",
+- o_bootSide, scomData );
++ 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)
++ errlHndl_t getSbeInfoState(sbeTargetState_t& io_sbeState,
++ sbeUpdateCheckType& i_check_type)
+ {
+
+ TRACUCOMP( g_trac_sbe,
+@@ -1328,6 +1356,7 @@ namespace SBE
+
+
+ errlHndl_t err = NULL;
++ bool skip_customization = false;
+
+ do{
+
+@@ -1338,6 +1367,74 @@ namespace SBE
+
+
+ /*******************************************/
++ /* 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)",
++ EEPROM::SBE_PRIMARY);
++ 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)",
++ EEPROM::SBE_BACKUP);
++ 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() ");
++ 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;
+@@ -1367,12 +1464,15 @@ namespace SBE
+ /* Calculate CRC of the image */
+ /*******************************************/
+ size_t sbeImgSize = 0;
+- err = procCustomizeSbeImg(io_sbeState.target,
++ if ( skip_customization == false )
++ {
++ err = procCustomizeSbeImg(io_sbeState.target,
+ sbePnorPtr, //SBE vaddr in PNOR
+ FIXED_SEEPROM_WORK_SPACE, //max size
+ reinterpret_cast<void*>
+ (SBE_IMG_VADDR), //destination
+ sbeImgSize);
++ }
+
+ if(err)
+ {
+@@ -1421,47 +1521,6 @@ namespace SBE
+ }
+
+
+- /*******************************************/
+- /* 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)",
+- EEPROM::SBE_PRIMARY);
+- 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)",
+- EEPROM::SBE_BACKUP);
+- break;
+- }
+-
+-
+- TRACDBIN(g_trac_sbe, "getSbeInfoState-spB",
+- &(io_sbeState.seeprom_1_ver),
+- sizeof(sbeSeepromVersionInfo_t));
+-
+ /***********************************************/
+ /* Determine which SEEPROM System Booted On */
+ /***********************************************/
+@@ -1525,7 +1584,6 @@ namespace SBE
+ 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);
+@@ -1534,22 +1592,21 @@ namespace SBE
+ PNOR::ECC::eccStatus eccStatus = PNOR::ECC::CLEAN;
+ o_seeprom_ver_ECC_fail = false;
+
+- size_t sbeInfoSize_ECC = (sizeof(sbeSeepromVersionInfo_t)*9)/8;
+- size_t sbeInfoSize_ECC_aligned = ALIGN_8(sbeInfoSize_ECC);
+-
+- // Create data buffer of larger size
+- // NOTE: EEPROM read will fill in smaller, unaligned size
++ // 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<uint8_t*>(
+- malloc(sbeInfoSize_ECC_aligned));
++ malloc(sbeInfoSize_ECC));
+
+- do{
+
+- /*******************************************/
+- /* Read SBE Version SBE Version Information */
+- /*******************************************/
++ do{
+
++ /***********************************************/
++ /* Read SBE Version SBE Version Information */
++ /***********************************************/
+ // Clear Buffer
+- memset( tmp_data_ECC, 0, sbeInfoSize_ECC_aligned );
++ memset( tmp_data_ECC, 0, sbeInfoSize_ECC );
+
+ //Read SBE Versions
+ err = deviceRead( i_target,
+@@ -1568,43 +1625,68 @@ namespace SBE
+ }
+
+ TRACDBIN(g_trac_sbe,
+- "getSeepromSideVersion()- tmp_data_ECC (not-aligned)",
++ "getSeepromSideVersion()- tmp_data_ECC",
+ tmp_data_ECC,
+ sbeInfoSize_ECC);
+
+- TRACDBIN(g_trac_sbe,
+- "getSeepromSideVersion()- tmp_data_ECC (aligned)",
+- tmp_data_ECC,
+- sbeInfoSize_ECC_aligned);
+-
+
+ // 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 = PNOR::ECC::removeECC(
+ tmp_data_ECC,
+ reinterpret_cast<uint8_t*>(&o_info),
+- sizeof(o_info));
++ 8);
++
++ 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 ( ( o_info.struct_version == 1 ) ||
++ o_info.struct_version == 2 )
++ {
++ // 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 = PNOR::ECC::removeECC(
++ tmp_data_ECC,
++ reinterpret_cast<uint8_t*>(&o_info),
++ sbeInfoSize);
+
+ TRACUCOMP( g_trac_sbe, "getSeepromSideVersion(): eccStatus=%d, "
+- "sizeof o_info=%d, sI_ECC=%d, sI_ECC_aligned=%d",
+- eccStatus, sizeof(o_info), sbeInfoSize_ECC,
+- sbeInfoSize_ECC_aligned);
++ "sizeof o_info/sI=%d, sI_ECC=%d",
++ eccStatus, sbeInfoSize, sbeInfoSize_ECC);
+
+ // Handle Uncorrectable ECC - no error log:
+ // clear data and set o_seeprom_ver_ECC_fail=true
+- // -- unless SIM version found: than just ignore
+- if ( (eccStatus == PNOR::ECC::UNCORRECTABLE) &&
+- (o_info.struct_version != SBE_SEEPROM_STRUCT_SIMICS_VERSION) )
++ if ( eccStatus == PNOR::ECC::UNCORRECTABLE )
+ {
+
+ TRACFCOMP( g_trac_sbe,ERR_MRK"getSeepromSideVersion() - ECC "
+ "ERROR: Handled. eccStatus=%d, side=%d, sizeof "
+- "o_info=%d, sI_ECC=%d, sI_ECC_aligned=%d",
+- eccStatus, i_seepromSide, sizeof(o_info),
+- sbeInfoSize_ECC, sbeInfoSize_ECC_aligned);
++ "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;
+@@ -2065,17 +2147,21 @@ namespace SBE
+ isSimics_check = true;
+ }
+
+- if ( (pnor_check_dirty || crc_check_dirty )
++ 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), "
+- "isSimics=%d",
++ "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, isSimics_check);
++ io_sbeState.seeprom_0_ver.data_crc,
++ io_sbeState.seeprom_0_ver_Nest_Freq_Mismatch,
++ isSimics_check);
+ }
+
+ /**************************************************************/
+@@ -2111,17 +2197,21 @@ namespace SBE
+ isSimics_check = true;
+ }
+
+- if ( (pnor_check_dirty || crc_check_dirty )
++ 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), "
+- "isSimics=%d",
++ "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, isSimics_check);
++ io_sbeState.seeprom_1_ver.data_crc,
++ io_sbeState.seeprom_1_ver_Nest_Freq_Mismatch,
++ isSimics_check);
+ }
+
+
+@@ -2158,11 +2248,15 @@ namespace SBE
+ {
+ 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
+@@ -2204,7 +2298,8 @@ namespace SBE
+ /**************************************************************/
+ /* Setup new SBE Image Version Info, if necessary */
+ /**************************************************************/
+- if ( io_sbeState.update_actions & UPDATE_SBE )
++ if ( ( io_sbeState.update_actions & UPDATE_SBE ) ||
++ ( io_sbeState.update_actions & UPDATE_NEST_FREQ ) )
+ {
+ memset(&(io_sbeState.new_seeprom_ver),
+ 0x0,
+@@ -2222,6 +2317,19 @@ namespace SBE
+ &(io_sbeState.customizedImage_crc),
+ sizeof(io_sbeState.new_seeprom_ver.data_crc));
+
++ if ( io_sbeState.update_actions & UPDATE_SBE )
++ {
++ io_sbeState.new_seeprom_ver.nest_freq_mhz =
++ g_current_nest_freq;
++ }
++ 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 = (
+@@ -2299,7 +2407,6 @@ namespace SBE
+ // 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);
+@@ -2322,10 +2429,30 @@ namespace SBE
+
+ if ( pnor_side_info.isGolden == true )
+ {
+- // If true, nothing to do (covered in istep 6 function)
+- l_actions = CLEAR_ACTIONS;
++ // 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: "
++ 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)",
+@@ -2333,19 +2460,38 @@ namespace SBE
+ io_sbeState.cur_seeprom_side,
+ i_system_situation, l_actions,
+ io_sbeState.mvpdSbKeyword.flags);
+- break;
++ }
+ }
+-
+ else if ( ( pnor_side_info.hasOtherSide == false ) &&
+ ( io_sbeState.cur_seeprom_side == READ_ONLY_SEEPROM ) )
+ {
+- // Even though current seeprom is not pointing at PNOR's
+- // GOLDEN side, treat like READ_ONLY if booting from
+- // READ_ONLY seeprom and and PNOR does not have another side
+- // - No Update (ie, Palmetto configuration)
+- l_actions = CLEAR_ACTIONS;
++ // 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: "
++ 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)",
+@@ -2353,7 +2499,7 @@ namespace SBE
+ io_sbeState.cur_seeprom_side,
+ i_system_situation, l_actions,
+ io_sbeState.mvpdSbKeyword.flags);
+- break;
++ }
+ }
+ else // proceed to update this side
+ {
+@@ -2363,44 +2509,43 @@ namespace SBE
+ " 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;
++ // 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 =
++ // 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) 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);
++ 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
+@@ -2835,6 +2980,32 @@ namespace SBE
+ do{
+
+ /**************************************************************/
++ /* Update NEST_FREQ, if necessary */
++ /**************************************************************/
++#ifdef CONFIG_SBE_UPDATE_INDEPENDENT
++ // This can only be set with Golden/READ-ONLY Seeprom situation
++ if (l_actions & UPDATE_NEST_FREQ)
++ {
++ // Call targeting function to update NEST_FREQ
++ TargetService& tS = targetService();
++ TARGETING::Target* sys = NULL;
++ (void) tS.getTopLevelTarget( sys );
++ assert(sys, "performUpdateActions() system target is NULL");
++
++ TRACFCOMP( g_trac_sbe, "performUpdateActions(): "
++ "UPDATE_NEST_FREQ to %d ",
++ io_sbeState.mproc_nest_freq_mhz);
++
++ TARGETING::setFrequencyAttributes(
++ sys,
++ io_sbeState.mproc_nest_freq_mhz);
++
++ // This opeation only done by itself and does not need
++ // an informational error log
++ break;
++ }
++#endif
++ /**************************************************************/
+ /* Update SEEPROM, if necessary */
+ /**************************************************************/
+ if (l_actions & UPDATE_SBE)
+@@ -3806,4 +3977,195 @@ namespace SBE
+ }
+
+
++
++/////////////////////////////////////////////////////////////////////
++ 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)
++ {
++ 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), g_current_nest_freq,
++ i_default_nest_freq, i_struct_version,
++ i_seeprom_nest_freq, i_seeprom_num);
++
++ o_mismatch = false;
++
++ // Check Seeprom
++ if ( i_struct_version == 2 )
++ {
++ // Only version that tracks the nest freq when the image was
++ // customized
++ if ( g_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,
++ g_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,
++ g_current_nest_freq, i_seeprom_nest_freq);
++ }
++ }
++
++ else
++ {
++ // Either old version (like 1), unitialized, simics, corrupted, etc
++ // Assume SBE image created with the module's default frequency
++ if ( g_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,
++ g_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,
++ g_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 checkNestFreqSettings(sbeTargetState_t& io_sbeState)
++ {
++ TRACDCOMP( g_trac_sbe,
++ ENTER_MRK"checkNestFreqSettings");
++
++ 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;
++
++ // Get DEFAULT_PROC_MODULE_NEST_FREQ_MHZ attribute
++ default_nest_freq = io_sbeState.target->getAttr<
++ TARGETING::ATTR_DEFAULT_PROC_MODULE_NEST_FREQ_MHZ>();
++
++ TRACUCOMP( g_trac_sbe,"checkNestFreqSettings(): ATTR_NEST_FREQ_MHZ "
++ "=%d, ATTR_DEFAULT_PROC_MODULE_NEST_FREQ_MHZ=%d",
++ g_current_nest_freq, default_nest_freq);
++
++ // 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()");
++
++ // 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 ( io_sbeState.seeprom_0_ver.struct_version == 2 )
++ {
++ 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 ( io_sbeState.cur_seeprom_side == SBE_SEEPROM1)
++ {
++ if ( io_sbeState.seeprom_1_ver.struct_version == 2 )
++ {
++ 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);
++
++
++ TRACDCOMP( g_trac_sbe,
++ EXIT_MRK"checkNestFreqSettings");
++
++ return err;
++
++ }
++
++
++
+ } //end SBE Namespace
+diff --git a/src/usr/sbe/sbe_update.H b/src/usr/sbe/sbe_update.H
+index 1d4b208..f13e9b1 100644
+--- a/src/usr/sbe/sbe_update.H
++++ b/src/usr/sbe/sbe_update.H
+@@ -44,9 +44,21 @@ namespace SBE
+ const size_t SBE_MVPD_SHORT_IMAGE_VERSION_SIZE = 20;
+
+ // Version of Struct stored in SEEPROM
+- const uint32_t SBE_SEEPROM_STRUCT_VERSION = 0x00000001;
++ const uint32_t SBE_SEEPROM_STRUCT_VERSION = 0x00000002;
+ const uint32_t SBE_SEEPROM_STRUCT_SIMICS_VERSION = 0x5A5A5A5A;
+
++ // Number of versions supported
++ const uint8_t SBE_SEEPROM_STRUCT_MAX_VERSIONS = 0x03;
++
++ // Size of supported versions - must be 8-byte aligned
++ const size_t SBE_SEEPROM_STRUCT_SIZES[SBE_SEEPROM_STRUCT_MAX_VERSIONS] =
++ {
++ 0, // ver0: uninitialized - no size
++ 72, // ver1: size of struct is 72 bytes
++ 80, // ver2: size of struct is 80 bytes
++ };
++
++
+ // Constant written to SBE SEEPROM version struct to invalidate the
+ // struct and the image - 'INVALID\0'
+ const uint64_t SBE_SEEPROM_STRUCT_INVALID = 0x494E56414C494400;
+@@ -126,6 +138,7 @@ namespace SBE
+ MVPD_UPDATE_COMPLETE = 0x00000008,
+ UPDATE_SBE = 0x00000010,
+ SBE_UPDATE_COMPLETE = 0x00000020,
++ UPDATE_NEST_FREQ = 0x00000100,
+ UNSUPPORTED_SITUATION = 0x80000000,
+ };
+
+@@ -138,18 +151,25 @@ namespace SBE
+ *
+ * NOTE: For ECC purposes, this must be 8-byte aligned,
+ * so pad data if necessary
+- * struct_version 1: size = 4+64+4 = 72 (aligned)
++ * struct_version 1: size = 4+4+64 = 72 (aligned)
++ * struct_version 2: size = 4+4+64+4+4 = 80 (aligned)
+ */
+ struct sbeSeepromVersionInfo_t
+ {
++ // The first 64-bits will be read out to check for struct_version
+ uint32_t struct_version;
+ uint32_t data_crc;
+ uint8_t image_version[SBE_IMAGE_VERSION_SIZE];
++
++ // New parameters for version 2: nest_freq_mhz and uin32_t/reserved
++ uint32_t nest_freq_mhz;
++ uint32_t reserved; // reserved; added for alignment
+ } PACKED;
+
+ // This line forces a compile fail if struct is NOT 8-byte-alaigned
+ CPPASSERT(0 == (sizeof(sbeSeepromVersionInfo_t) % 8));
+
++
+ /**
+ * @brief Struct of individual SBE entry in SBE and SBEC
+ * Table of Contents in PNOR partitions
+@@ -208,6 +228,11 @@ namespace SBE
+ bool seeprom_0_ver_ECC_fail;
+ bool seeprom_1_ver_ECC_fail;
+
++ bool seeprom_0_ver_Nest_Freq_Mismatch;
++ bool seeprom_1_ver_Nest_Freq_Mismatch;
++ bool cur_seeprom_ver_Nest_Freq_Mismatch;
++ uint32_t mproc_nest_freq_mhz;
++
+ sbeSeepromSide_t cur_seeprom_side; // aka 'booted' side
+ sbeSeepromSide_t alt_seeprom_side;
+ sbeSeepromSide_t permanent_seeprom_side;
+@@ -231,6 +256,10 @@ namespace SBE
+ sbeTargetState_t() :
+ target(NULL), target_is_master(false), ec(0x0),
+ seeprom_0_ver_ECC_fail(false), seeprom_1_ver_ECC_fail(false),
++ seeprom_0_ver_Nest_Freq_Mismatch(false),
++ seeprom_1_ver_Nest_Freq_Mismatch(false),
++ cur_seeprom_ver_Nest_Freq_Mismatch(false),
++ mproc_nest_freq_mhz(0x0),
+ customizedImage_size(0x0), customizedImage_crc(0x0),
+ new_readBack_check(false),
+ err_plid(0x0), err_eid(0x0), err_rc(0x0)
+@@ -248,9 +277,13 @@ namespace SBE
+ *
+ * @param[io/out] io_sbeState Struct containing SBE State of the target
+ *
++ * @param[io/out] i_check_type Determines if an early check should be run
++ * before collecting all of the information.
++ *
+ * @return errlHndl_t Error log handle on failure.
+ */
+- errlHndl_t getSbeInfoState(sbeTargetState_t& io_sbeState);
++ errlHndl_t getSbeInfoState(sbeTargetState_t& io_sbeState,
++ sbeUpdateCheckType& i_check_type);
+
+ /**
+ * @brief Analyze and Determine Update Actions for a specific target
+@@ -501,5 +534,23 @@ namespace SBE
+ size_t i_maxBits);
+
+
++ /**
++ * @brief Checks the Nest Frequency value stored in the the version struct
++ * and compares it ot the NEST_FREQ_MHZ attribute of the system
++ *
++ * @param[io/out] io_sbeState Struct containing SBE State of the target
++ * and is updated based on the situation
++ *
++ * @pre seeprom_0_ver and seeprom_1_ver have been filled in
++ *
++ * @post seeprom_0_ver_Nest_Freq_Mismatch,
++ * seeprom_1_ver_Nest_Freq_Mismatch, and nest_freq_check_complete
++ * are set.
++ *
++ * @return errlHndl_t Error log handle on failure.
++ */
++ errlHndl_t checkNestFreqSettings(sbeTargetState_t& io_sbeState);
++
++
+ } //end namespace SBE
+ #endif
+diff --git a/src/usr/sbe/test/sbeupdatetest.H b/src/usr/sbe/test/sbeupdatetest.H
+index c5a3dd5..bbdeb1e 100644
+--- a/src/usr/sbe/test/sbeupdatetest.H
++++ b/src/usr/sbe/test/sbeupdatetest.H
+@@ -444,9 +444,11 @@ class SBEUpdateTest: public CxxTest::TestSuite
+ // set bad ec just for comparison to local_ec later
+ sbeState.ec = 0xFF;
+
++ // send input part to perform all checks
++ sbeUpdateCheckType i_check_type = SBE_UPDATE_CHECK_ALL;
+
+ total++;
+- err = getSbeInfoState(sbeState);
++ err = getSbeInfoState(sbeState, i_check_type);
+ if(err)
+ {
+ fails++;
+diff --git a/src/usr/targeting/common/genHwsvMrwXml.pl b/src/usr/targeting/common/genHwsvMrwXml.pl
+index a720c44..18746cc 100755
+--- a/src/usr/targeting/common/genHwsvMrwXml.pl
++++ b/src/usr/targeting/common/genHwsvMrwXml.pl
+@@ -2352,6 +2352,25 @@ sub generate_sys
+ ";
+ }
+
++ # Tuletas can now support multiple nest frequencies
++ if ($sysname =~ /tuleta/)
++ {
++ print "
++ <attribute><id>MRW_NEST_CAPABLE_FREQUENCIES_SYS</id>
++ <default>2000_MHZ_OR_2400_MHZ</default>
++ </attribute>
++";
++ }
++ else
++ {
++ print "
++ <attribute><id>MRW_NEST_CAPABLE_FREQUENCIES_SYS</id>
++ <default>UNSUPPORTED_FREQ</default>
++ </attribute>
++";
++ }
++
++
+ if( $haveFSPs == 0 )
+ {
+ generate_apss_adc_config()
+diff --git a/src/usr/targeting/common/xmltohb/attribute_types.xml b/src/usr/targeting/common/xmltohb/attribute_types.xml
+index 22467ea..05497fd 100644
+--- a/src/usr/targeting/common/xmltohb/attribute_types.xml
++++ b/src/usr/targeting/common/xmltohb/attribute_types.xml
+@@ -16600,5 +16600,23 @@ firmware notes: Platforms should initialize this attribute to AUTO (0)</descript
+ <macro>DIRECT</macro>
+ </hwpfToHbAttrMap>
+ </attribute>
++<attribute>
++ <id>DEFAULT_PROC_MODULE_NEST_FREQ_MHZ</id>
++ <description>
++ Default Nest frequency in MHz for Processor Modules
++ Default to 2000 MHz for Murano-based Modules
++ Default to 2400 MHz for Venice- and Naples-based Modules
++ </description>
++ <simpleType>
++ <uint32_t>
++ <default>2000</default>
++ </uint32_t>
++ </simpleType>
++ <persistency>non-volatile</persistency>
++ <readable/>
++</attribute>
++
++
++
+
+ </attributes>
+diff --git a/src/usr/targeting/common/xmltohb/target_types.xml b/src/usr/targeting/common/xmltohb/target_types.xml
+index 0b45bb0..9475cc4 100644
+--- a/src/usr/targeting/common/xmltohb/target_types.xml
++++ b/src/usr/targeting/common/xmltohb/target_types.xml
+@@ -666,6 +666,10 @@
+ <id>PROC_PCIE_REFCLOCK_ENABLE</id>
+ <default>0xE0</default>
+ </attribute>
++ <attribute>
++ <id>DEFAULT_PROC_MODULE_NEST_FREQ_MHZ</id>
++ <default>2400</default>
++ </attribute>
+ </targetType>
+
+ <targetType>
+@@ -691,6 +695,10 @@
+ <id>PROC_PCIE_REFCLOCK_ENABLE</id>
+ <default>0xE0</default>
+ </attribute>
++ <attribute>
++ <id>DEFAULT_PROC_MODULE_NEST_FREQ_MHZ</id>
++ <default>2000</default>
++ </attribute>
+ </targetType>
+
+ <targetType>
+@@ -716,6 +724,10 @@
+ <id>PROC_PCIE_REFCLOCK_ENABLE</id>
+ <default>0xF0</default>
+ </attribute>
++ <attribute>
++ <id>DEFAULT_PROC_MODULE_NEST_FREQ_MHZ</id>
++ <default>2400</default>
++ </attribute>
+ </targetType>
+
+ <targetType>
+--
+1.8.2.2
+
diff --git a/openpower/package/hostboot/hostboot-0005-Function-to-set-nest-freq-based-off-dimms.patch b/openpower/package/hostboot/hostboot-0005-Function-to-set-nest-freq-based-off-dimms.patch
new file mode 100644
index 0000000..d64991a
--- /dev/null
+++ b/openpower/package/hostboot/hostboot-0005-Function-to-set-nest-freq-based-off-dimms.patch
@@ -0,0 +1,937 @@
+From 8afc07837b303e5621ba28fed8a070eba633475d Mon Sep 17 00:00:00 2001
+From: aalugore <aalugore@us.ibm.com>
+Date: Mon, 24 Aug 2015 13:42:24 -0500
+Subject: [PATCH] Function to set Nest Frequency based off DIMM memory
+ capability
+
+-Needed for 32x32GB DIMM support
+-Finds max capable frequency of system and all present DIMMs
+ and deconfigures any DIMM that cannot run at desired frequency
+-If necessary, Sets Nest Freq and triggers SBE update
+
+Change-Id: I9bba92f55f1b67ff4a15d79113f19d39272ec72d
+RTC:122884
+Depends-on:I1dca7196cd02a2704a238665b73b522c9e103936
+---
+ src/include/usr/hwpf/hwpf_reasoncodes.H | 4 +-
+ src/include/usr/isteps/istep12list.H | 4 +-
+ src/include/usr/sbe/sbeif.H | 16 +
+ src/include/usr/targeting/common/target.H | 11 +
+ src/include/util/algorithm.H | 18 +-
+ src/include/util/align.H | 17 +-
+ src/usr/hwpf/hwp/mc_config/mc_config.C | 437 ++++++++++++++++++++-
+ src/usr/hwpf/hwp/memory_attributes.xml | 12 +-
+ src/usr/hwpf/plat/fapiPlatUtil.C | 2 +-
+ src/usr/sbe/sbe_update.C | 62 +++
+ src/usr/targeting/common/target.C | 47 +++
+ .../targeting/common/xmltohb/attribute_types.xml | 10 +-
+ 12 files changed, 608 insertions(+), 32 deletions(-)
+
+diff --git a/src/include/usr/hwpf/hwpf_reasoncodes.H b/src/include/usr/hwpf/hwpf_reasoncodes.H
+index e1a00da..ea326c1 100644
+--- a/src/include/usr/hwpf/hwpf_reasoncodes.H
++++ b/src/include/usr/hwpf/hwpf_reasoncodes.H
+@@ -80,7 +80,9 @@ namespace fapi
+ MOD_PLAT_MVPD_GET_VLTG_BUCKET_ATTR = 0x26,
+ MOD_PLAT_ATTR_SVC_CEN_DQ_TO_DIMM_CONN_DQ = 0x27,
+ MOD_PLAT_ATTR_SVC_GET_MEM_ATTR_DATA = 0x28,
+-
++ MOD_GET_WOF_FREQ_UPLIFT_SELECTED = 0x29,
++ MOD_SET_NEST_FREQ = 0x2A,
++ MOD_FIND_MAX_DMI_SPD = 0x2B,
+ };
+
+ /**
+diff --git a/src/include/usr/isteps/istep12list.H b/src/include/usr/isteps/istep12list.H
+index 2e724f2..f668733 100644
+--- a/src/include/usr/isteps/istep12list.H
++++ b/src/include/usr/isteps/istep12list.H
+@@ -5,7 +5,7 @@
+ /* */
+ /* OpenPOWER HostBoot Project */
+ /* */
+-/* Contributors Listed Below - COPYRIGHT 2012,2014 */
++/* Contributors Listed Below - COPYRIGHT 2012,2015 */
+ /* [+] Google Inc. */
+ /* [+] International Business Machines Corp. */
+ /* */
+@@ -105,6 +105,8 @@ const DepModInfo g_istep12Dependancies = {
+ #ifndef CONFIG_VPO_COMPILE
+ DEP_LIB(libmc_config.so),
+ #endif
++ DEP_LIB(libsbe.so),
++ DEP_LIB(libbuild_winkle_images.so),
+ NULL
+ }
+ };
+diff --git a/src/include/usr/sbe/sbeif.H b/src/include/usr/sbe/sbeif.H
+index b00e01f..ff397ca 100644
+--- a/src/include/usr/sbe/sbeif.H
++++ b/src/include/usr/sbe/sbeif.H
+@@ -94,6 +94,22 @@ namespace SBE
+ */
+ errlHndl_t resolveProcessorSbeSeeproms();
+
++ /**
++ * @brief Determines whether we are on the Golden side or not
++ *
++ * @param[out] o_isGolden boolean, True if we are on Golden side, False
++ * otherwise.
++ *
++ * @return errlHndl_t Error log handle on failure.
++ *
++ * NOTE: -Golden Side means we booted from the Golden Seeprom pointing
++ * at the Golden side of PNOR.
++ * -Using master processor to make this determination.
++ */
++
++ errlHndl_t isGoldenSide( bool & o_isGolden );
++
++
+
+ } //end namespace SBE
+
+diff --git a/src/include/usr/targeting/common/target.H b/src/include/usr/targeting/common/target.H
+index 25e7be6..bf5b7da 100644
+--- a/src/include/usr/targeting/common/target.H
++++ b/src/include/usr/targeting/common/target.H
+@@ -672,6 +672,17 @@ const char* Target::getAttrAsString() const
+ return attrToString<A>(l_attrValue);
+ }
+
++// Function to set various frequency related attributes
++/**
++ * @brief - sets various attributes directly related to the nest frequency.
++ *
++ * @param[in] i_sys - top level system target to set attributes for
++ * @param[in] i_newNestFreq - the new nest frequency to base all the attributes
++ * off of.
++ */
++void setFrequencyAttributes(Target * i_sys, uint32_t i_newNestFreq);
++
++
+ // WARNING: The following #include imports any platform specific template
+ // specializations for getAttr and tryGetAttr
+ #include <targeting/adapters/targetadapter.H>
+diff --git a/src/include/util/algorithm.H b/src/include/util/algorithm.H
+index 54baa02..dac0f47 100644
+--- a/src/include/util/algorithm.H
++++ b/src/include/util/algorithm.H
+@@ -5,7 +5,9 @@
+ /* */
+ /* OpenPOWER HostBoot Project */
+ /* */
+-/* COPYRIGHT International Business Machines Corp. 2012,2014 */
++/* Contributors Listed Below - COPYRIGHT 2012,2015 */
++/* [+] 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. */
+@@ -52,6 +54,20 @@ namespace Util
+ static const T value = (a > b) ? a : b;
+ };
+
++ /**
++ * @brief - utility function that determines if a given number is
++ * power of 2.
++ *
++ * @param[in] i_num - given number.
++ *
++ * @return bool - True if the number is a power of 2, False otherwise.
++ */
++ template <typename T>
++ bool isPow2(T i_num)
++ {
++ return (!(i_num & (i_num-1)));
++ }
++
+ };
+ };
+ #endif
+diff --git a/src/include/util/align.H b/src/include/util/align.H
+index e0132b2..10a8369 100644
+--- a/src/include/util/align.H
++++ b/src/include/util/align.H
+@@ -51,18 +51,7 @@
+ #define ALIGN_MEGABYTE(u) (ALIGN_X(u,MEGABYTE))
+ #define ALIGN_MEGABYTE_DOWN(u) (ALIGN_DOWN_X(u,MEGABYTE))
+
+-// Returns a number that is aligned to the next highest power of 2 number of
+-// pages for the given buffer.
+-#define ALIGN_TO_NEXT_POWER_OF_TWO_PAGES(b) ({\
+- unsigned int v = ALIGN_PAGE(b)/PAGE_SIZE;\
+- v--;\
+- v |= v >> 1;\
+- v |= v >> 2;\
+- v |= v >> 4;\
+- v |= v >> 8;\
+- v |= v >> 16;\
+- v++;\
+- v * PAGE_SIZE;\
+- })
+-
++// Return a number rounded to the next power of two.
++#define ALIGN_POW2(u) ((u&(u-1)) ? 1 << (64 - __builtin_clzl(u)) : u)
++#define ALIGN_POW2_DOWN(u) (u ? 1 << (63 - __builtin_clzl(u)) : 0)
+ #endif
+diff --git a/src/usr/hwpf/hwp/mc_config/mc_config.C b/src/usr/hwpf/hwp/mc_config/mc_config.C
+index b2bc2f1..f29ee7c 100644
+--- a/src/usr/hwpf/hwp/mc_config/mc_config.C
++++ b/src/usr/hwpf/hwp/mc_config/mc_config.C
+@@ -44,16 +44,19 @@
+
+ #include <trace/interface.H>
+ #include <initservice/taskargs.H>
++#include <initservice/initserviceif.H>
+ #include <errl/errlentry.H>
+
+ #include <hwpisteperror.H>
++#include <hwpf/hwpf_reasoncodes.H>
+ #include <errl/errludtarget.H>
+
+ #include <initservice/isteps_trace.H>
+-
++#include <sbe/sbeif.H>
+ // targeting support
+ #include <targeting/common/commontargeting.H>
+ #include <targeting/common/utilFilter.H>
++#include <attributetraits.H>
+
+ // fapi support
+ #include <fapi.H>
+@@ -79,6 +82,8 @@
+ #include "mss_volt/mss_volt_dimm_count.H"
+
+ #include <config.h>
++#include <util/align.H>
++#include <util/algorithm.H>
+
+ namespace MC_CONFIG
+ {
+@@ -129,7 +134,8 @@ void set_eff_config_attrs_helper( const EFF_CONFIG_ATTRIBUTES_BASE i_base,
+ // Get Node Target
+ TARGETING::Target* sysTgt = NULL;
+ TARGETING::targetService().getTopLevelTarget(sysTgt);
+- assert(sysTgt != NULL,"System target was NULL.");
++ assert(sysTgt != NULL,"set_eff_config_attrs_helper: "
++ "System target was NULL.");
+
+ TARGETING::TargetHandleList l_nodeList;
+
+@@ -467,7 +473,8 @@ errlHndl_t setMemoryVoltageDomainOffsetVoltage()
+
+ TARGETING::Target* pSysTarget = NULL;
+ TARGETING::targetService().getTopLevelTarget(pSysTarget);
+- assert(pSysTarget != NULL,"System target was NULL.");
++ assert(pSysTarget != NULL,"setMemoryVoltageDomainOffsetVoltage: "
++ "System target was NULL.");
+
+ typename AttributeTraits< OFFSET_DISABLEMENT_ATTR >::Type
+ disableOffsetVoltage =
+@@ -717,13 +724,16 @@ void call_mss_volt_hwp (std::vector<TARGETING::ATTR_VMEM_ID_type>& i_VmemList,
+ l_membufFapiTargets.push_back( l_membuf_fapi_target );
+ }
+ }
++
++ TRACDCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ "Calling mss_volt_hwp...");
+ FAPI_INVOKE_HWP(l_err, mss_volt_hwp, l_membufFapiTargets);
+
+ // process return code.
+ if ( l_err )
+ {
+ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
+- "ERROR 0x%.8X: mss_volt_dimm_count HWP( ) ",
++ "ERROR 0x%.8X: mss_volt HWP( ) ",
+ l_err->reasonCode());
+
+ // Create IStep error log and cross reference to error that occurred
+@@ -872,7 +882,411 @@ void* call_mss_volt( void *io_pArgs )
+
+ return l_StepError.getErrorHandle();
+ }
++/**
++ * @brief - this utility function takes in the frequency in
++ * ATTR_MRW_NEST_CAPABLE_FREQUENCIES_SYS and returns the corresponding
++ * dmi bus speed from ATTR_MSS_NEST_CAPABLE_FREQUENCIES
++ *
++ * @param[in] i_freq - the input frequency
++ * @param[in/out] io_speed - the corresponding dmi bus speed
++ */
++void sysFreq_to_dmiSpeed(ATTR_MRW_NEST_CAPABLE_FREQUENCIES_SYS_type i_freq,
++ ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type & io_speed)
++{
++ switch(i_freq)
++ {
++ case TARGETING::MRW_NEST_CAPABLE_FREQUENCIES_SYS_UNSUPPORTED_FREQ:
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,"Unsupported nest freq!");
++ io_speed = 0;
++ break;
++ case TARGETING::MRW_NEST_CAPABLE_FREQUENCIES_SYS_2000_MHZ:
++ io_speed=fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_8_0G;
++ break;
++ case TARGETING::MRW_NEST_CAPABLE_FREQUENCIES_SYS_2400_MHZ:
++ io_speed=fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_9_6G;
++ break;
++ case TARGETING::MRW_NEST_CAPABLE_FREQUENCIES_SYS_2000_MHZ_OR_2400_MHZ:
++ io_speed=fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_8_0G_OR_9_6G;
++ break;
++ default:
++ io_speed = 0;
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,"Invalid nest freq!");
++ }
++}
+
++/**
++ * @brief - this utility function takes in the dmi bus speed enumeration
++ * value as described in MSS_NEST_CAPABLE_FREQUENCIES and outputs
++ * the actual corresponding nest frequency in MHz supported by the
++ * given dmi bus speed.
++ *
++ * @param[in] i_speed - the input dmi bus speed
++ * @param[in/out] io_freq - the corresponding frequency in MHz
++ *
++ */
++void dmiSpeed_to_sysFreq(ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type i_speed,
++ ATTR_NEST_FREQ_MHZ_type & io_freq)
++{
++ switch(i_speed)
++ {
++ case fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_8_0G:
++ io_freq = 2000;
++ break;
++ case fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_9_6G:
++ io_freq = 2400;
++ break;
++ default:
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, "Invalid dmi speed!");
++ io_freq = 0;
++ }
++}
++
++
++
++//
++// calloutChildDimms
++//
++void calloutChildDimms(errlHndl_t & io_errl, const TARGETING::Target * i_membuf)
++{
++ TargetHandleList l_dimmList;
++
++ // Get child dimms
++ getChildAffinityTargets( l_dimmList,
++ i_membuf,
++ CLASS_NA,
++ TYPE_DIMM );
++
++ if( !l_dimmList.empty())
++ {
++ // iterate over the DIMMs and call them out
++ TargetHandleList::iterator l_iter = l_dimmList.begin();
++
++ for(;l_iter != l_dimmList.end(); ++l_iter)
++ {
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ "Calling out DIMM Target huid = %x",
++ get_huid(*l_iter));
++
++ io_errl->addHwCallout( *l_iter,
++ HWAS::SRCI_PRIORITY_MED,
++ HWAS::DELAYED_DECONFIG,
++ HWAS::GARD_NULL );
++ }
++ }
++ else
++ {
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, "No child DIMMs found!");
++ }
++}
++
++
++// TODO RTC 135720 - Support for mixed DIMM configuration with 32GB DIMMs.
++
++/**
++ * @brief - Recursive utility function for finding the max dmi
++ * bus speed to run at based on the nest dmi bus speed
++ * and the membuf's dmi bus speed
++ *
++ * @param[in] i_iter - Iterator over the list of membufs.
++ * @param[in] i_membufs - Pointer to the list of membufs.
++ * @param[in/out] io_currentMaxSpeed - The speed to run at will be returned here
++ * @param[in] i_capableNestDmiBusSpeed - The nest capable dmi bus speed.
++ */
++void findMaxSpdAndDeconfigIncompatible(TargetHandleList::iterator i_iter,
++ TargetHandleList * i_membufs,
++ ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type & io_currentMaxSpeed,
++ ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type i_capableNestDmiBusSpeed )
++{
++ do
++ {
++ // Base Case: If we are at the end of the membuf list return
++ if(i_iter == i_membufs->end())
++ {
++ // find the left most bit of the max speed found. This bit
++ // represents the highest dmi bus speed setting we can support
++ // across the nest and all membufs and the speed we will boot with.
++ io_currentMaxSpeed = ALIGN_POW2_DOWN(io_currentMaxSpeed);
++ break;
++ }
++
++ // Get the current membuf's dmi bus speed
++ ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type l_currentMembufSpd =
++ (*i_iter)->getAttr<TARGETING::ATTR_MSS_NEST_CAPABLE_FREQUENCIES>();
++
++ // update current max speed.
++ // Max is restricted by nest capable dmi bus speed
++ if(((l_currentMembufSpd & i_capableNestDmiBusSpeed) != 0) &&
++ (l_currentMembufSpd > io_currentMaxSpeed))
++ {
++ io_currentMaxSpeed = l_currentMembufSpd;
++ }
++
++ //Save the current membuf for when we come back from recursive call.
++ TARGETING::Target * l_currentMembuf = (*i_iter);
++
++ // Recursive call to go down the list of membufs and find the max
++ // capable dmi speed across the nest and membufs.
++ findMaxSpdAndDeconfigIncompatible(++i_iter,
++ i_membufs,
++ io_currentMaxSpeed,
++ i_capableNestDmiBusSpeed );
++
++ // deconfigure any membufs with incompatible
++ // speeds on the way up the stack
++ if((l_currentMembufSpd & io_currentMaxSpeed) == 0)
++ {
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ "Deconfiguring Membuf Huid: %X, membuf speed: %d",
++ TARGETING::get_huid(l_currentMembuf),
++ l_currentMembufSpd);
++ // Membuf has incompatible frequency. Deconfigure it.
++ /*@
++ * @errortype
++ * @moduleid MOD_FIND_MAX_DMI_SPD
++ * @reasoncode RC_INVALID_FREQ
++ * @userdata1 HUID of membuf
++ * @userdata2 [0:7] membuf frequency enumeration value
++ * @userdata2 [8:15] dmi bus speed enumeration value
++ * @devdesc Invalid nest frequency found for given membuf
++ * @custdesc Invalid memory configuration
++ */
++ errlHndl_t l_err = new ERRORLOG::ErrlEntry(
++ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
++ fapi::MOD_FIND_MAX_DMI_SPD,
++ fapi::RC_INVALID_FREQ,
++ TARGETING::get_huid(l_currentMembuf),
++ TO_UINT64(TWO_UINT8_TO_UINT16
++ (l_currentMembufSpd,
++ i_capableNestDmiBusSpeed)));
++
++ l_err->addHwCallout(l_currentMembuf, HWAS::SRCI_PRIORITY_HIGH,
++ HWAS::DELAYED_DECONFIG,
++ HWAS::GARD_NULL );
++ l_err->addProcedureCallout(
++ HWAS::EPUB_PRC_MEMORY_PLUGGING_ERROR,
++ HWAS::SRCI_PRIORITY_HIGH );
++
++
++ // add hw callouts for current membuf child DIMMs
++ calloutChildDimms( l_err, l_currentMembuf );
++
++ errlCommit( l_err, HWPF_COMP_ID );
++ l_err = NULL;
++ }
++ }while( 0 );
++}
++
++
++//
++// setNestBasedOffDimms
++//
++errlHndl_t setNestBasedOffDimms()
++{
++ TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, ENTER_MRK"mc_config::setNestBasedOffDimms()");
++ errlHndl_t l_err = NULL;
++ bool l_isGoldenSide = false;
++ ATTR_MRW_NEST_CAPABLE_FREQUENCIES_SYS_type l_capableNestFreq =
++ MRW_NEST_CAPABLE_FREQUENCIES_SYS_UNSUPPORTED_FREQ;
++
++ ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type l_selectedBootSpeed =
++ fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_NONE;
++
++ ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type l_capableNestDmiBusSpeed =
++ fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_NONE;
++
++ ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type l_compatibleSpeed =
++ fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_NONE;
++
++ ATTR_NEST_FREQ_MHZ_type l_maxFreqMhz = 0;
++
++ l_isGoldenSide = false;
++
++ do
++ {
++ // First, get the systems capable nest frequency. If 0, then stick with
++ // already set nest frequency
++ TARGETING::Target * l_sys = NULL;
++ targetService().getTopLevelTarget(l_sys);
++
++ uint32_t l_currentSysNestFreq =
++ l_sys->getAttr<TARGETING::ATTR_NEST_FREQ_MHZ>();
++
++ // Check to see if we booted from the Golden side
++ l_err = SBE::isGoldenSide(l_isGoldenSide);
++
++ if(l_err)
++ {
++ // Error getting Golden side. Proceeding as if booting from safe Golden side
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ ERR_MRK"setNestBasedOffDimms::isGoldenSide returned an error");
++ errlCommit( l_err, HWPF_COMP_ID );
++ l_isGoldenSide = true;
++ }
++
++ if(!l_isGoldenSide)
++ {
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ INFO_MRK"Booting from normal side. use "
++ "MRW_NEST_CAPABLE_FREQUENCIES_SYS to calculate best freq "
++ "across membufs");
++ l_capableNestFreq = l_sys->getAttr
++ <ATTR_MRW_NEST_CAPABLE_FREQUENCIES_SYS>();
++ }
++ else
++ {
++ // We booted using the Golden Side. Use NEST_FREQ_MHZ
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ INFO_MRK"Booting from Golden Side. Use default NEST_FREQ"
++ "to calculate best freq across membufs");
++ if(l_currentSysNestFreq == 2000)
++ {
++ l_capableNestFreq =
++ TARGETING::MRW_NEST_CAPABLE_FREQUENCIES_SYS_2000_MHZ;
++ }
++ else if( l_currentSysNestFreq == 2400 )
++ {
++ l_capableNestFreq =
++ TARGETING::MRW_NEST_CAPABLE_FREQUENCIES_SYS_2400_MHZ;
++ }
++ else
++ {
++ l_capableNestFreq =
++ TARGETING::MRW_NEST_CAPABLE_FREQUENCIES_SYS_UNSUPPORTED_FREQ;
++ }
++
++ }
++
++ // convert the frequency to its corresponding dmi bus speed
++ sysFreq_to_dmiSpeed( l_capableNestFreq, l_capableNestDmiBusSpeed );
++
++ if(!l_capableNestDmiBusSpeed)
++ {
++ // Unknown frequency was given to sysFreq_to_dmiSpeed
++ // break out of function and proceed with value already in
++ // ATTR_NEST_FREQ_MHZ
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,"Invalid dmi speed. Proceeding with default value in NEST_FREQ_MHZ.");
++ break;
++ }
++
++ // Get a list of all the membufs
++ TargetHandleList l_membufs;
++ TARGETING::getAllChips(l_membufs, TYPE_MEMBUF);
++ TargetHandleList::iterator l_iter = l_membufs.begin();
++
++
++ // If the nest capable dmi bus speed can only support one setting,
++ // that speed is the speed we want to boot with.
++ // Deconfigure all membufs with incompatible speeds
++ if(Util::Algorithm::isPow2(l_capableNestDmiBusSpeed))
++ {
++ // We are forced to boot with the nest freq.
++ // Save boot freq for later.
++ l_selectedBootSpeed = l_capableNestDmiBusSpeed;
++
++
++ ATTR_MSS_NEST_CAPABLE_FREQUENCIES_type l_membufDmiBusSpeed = 0;
++ for(;l_iter != l_membufs.end(); ++l_iter )
++ {
++ l_membufDmiBusSpeed = (*l_iter)->getAttr
++ <TARGETING::ATTR_MSS_NEST_CAPABLE_FREQUENCIES>();
++
++ // if the intersection of the membuf's and nest's dmi speed
++ // is zero, the membuf is incompatible with the nest and must be
++ // deconfigured.
++ l_compatibleSpeed = l_membufDmiBusSpeed &
++ l_capableNestDmiBusSpeed;
++
++ if(l_compatibleSpeed ==
++ fapi::ENUM_ATTR_MSS_NEST_CAPABLE_FREQUENCIES_NONE )
++ {
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ "Deconfiguring Membuf Huid: %X, membuf speed: %d",
++ TARGETING::get_huid(*l_iter),
++ l_membufDmiBusSpeed);
++ // Membuf has incompatible frequency. Deconfigure it.
++ /*@
++ * @errortype
++ * @moduleid MOD_SET_NEST_FREQ
++ * @reasoncode RC_INVALID_FREQ
++ * @userdata1 HUID of membuf
++ * @userdata2 [0:7] membuf frequency enumeration value
++ * @userdata2 [8:15] dmi bus speed enumeration value
++ * @devdesc Invalid nest found for given membuf
++ * @custdesc Invalid memory configuration
++ */
++ l_err = new ERRORLOG::ErrlEntry(
++ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
++ fapi::MOD_SET_NEST_FREQ,
++ fapi::RC_INVALID_FREQ,
++ TARGETING::get_huid(*l_iter),
++ TO_UINT64(TWO_UINT8_TO_UINT16
++ (l_membufDmiBusSpeed,
++ l_capableNestDmiBusSpeed)));
++
++ l_err->addHwCallout(*l_iter, HWAS::SRCI_PRIORITY_HIGH,
++ HWAS::DELAYED_DECONFIG,
++ HWAS::GARD_NULL );
++
++
++ // add hw callouts for current membufs child DIMMs
++ calloutChildDimms( l_err, *l_iter);
++
++ errlCommit( l_err, HWPF_COMP_ID );
++ l_err = NULL;
++ continue;
++ }
++
++ } // end for-loop
++
++ }
++ else
++ {
++ // The nest supports multiple frequencies. Find the max dmi bus
++ // speed shared by the nest and at least 1 membuf and boot with that
++ // speed.
++ findMaxSpdAndDeconfigIncompatible(l_iter,
++ &l_membufs,
++ l_selectedBootSpeed,
++ l_capableNestDmiBusSpeed);
++
++ }
++
++ //Convert the selected boot speed to frequency
++ dmiSpeed_to_sysFreq(l_selectedBootSpeed, l_maxFreqMhz);
++
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ "The max supported frequency across the processor and all dimms "
++ "is %d", l_maxFreqMhz );
++
++ if( l_maxFreqMhz == l_currentSysNestFreq)
++ {
++ //do nothing. go with current Nest freq, break.
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ "Nest did not need to change. Proceeding with default NEST_FREQ");
++ break;
++ }
++ else
++ {
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ "DIMM config determined NEST_FREQ needs to be changed to %d",
++ l_maxFreqMhz );
++ //set all the attributes and trigger an sbe update
++ TARGETING::setFrequencyAttributes(l_sys, l_maxFreqMhz);
++ //trigger sbe update so we can update all the frequency attributes
++ l_err = SBE::updateProcessorSbeSeeproms(
++ SBE::SBE_UPDATE_ONLY_CHECK_NEST_FREQ);
++
++ if( l_err )
++ {
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ "Error triggering sbe update.");
++ }
++ }
++ }while( 0 );
++
++ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "setNestBasedOffDimms exit" );
++ return l_err;
++}
+ //
+ // Wrapper function to call mss_freq
+ //
+@@ -931,6 +1345,21 @@ void* call_mss_freq( void *io_pArgs )
+ }
+ } // End memBuf loop
+
++ if(! INITSERVICE::spBaseServicesEnabled() )
++ {
++ //set nest frequency based off present membufs
++ TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
++ INFO_MRK"Setting Nest Frequency based off Membuf capability.");
++ l_err = setNestBasedOffDimms();
++
++ if( l_err )
++ {
++ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
++ ERR_MRK"Error: call_mss_freq()::setNestBasedOffDimms()");
++ l_StepError.addErrorDetails(l_err);
++ }
++ }
++
+ TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_freq exit" );
+
+ return l_StepError.getErrorHandle();
+diff --git a/src/usr/hwpf/hwp/memory_attributes.xml b/src/usr/hwpf/hwp/memory_attributes.xml
+index b4059a2..df3a2ef 100644
+--- a/src/usr/hwpf/hwp/memory_attributes.xml
++++ b/src/usr/hwpf/hwp/memory_attributes.xml
+@@ -1,7 +1,7 @@
+ <!-- IBM_PROLOG_BEGIN_TAG -->
+ <!-- This is an automatically generated prolog. -->
+ <!-- -->
+-<!-- $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/centaur/working/procedures/xml/attribute_info/memory_attributes.xml,v $ -->
++<!-- $Source: src/usr/hwpf/hwp/memory_attributes.xml $ -->
+ <!-- -->
+ <!-- OpenPOWER HostBoot Project -->
+ <!-- -->
+@@ -23,7 +23,7 @@
+ <!-- -->
+ <!-- IBM_PROLOG_END_TAG -->
+ <attributes>
+-<!-- $Id: memory_attributes.xml,v 1.159 2015/09/09 18:10:53 thi Exp $ -->
++<!-- $Id: memory_attributes.xml,v 1.159AL_custom 2014/11/18 17:35:29 aalugore Exp $ -->
+ <!-- DO NOT EDIT THIS FILE DIRECTLY PLEASE UPDATE THE ODS FILE AND FOLLOW THE INSTRUCTION TAB -->
+ <!-- PLEASE SEE MARK BELLOWS (BELLOWS.IBM.COM) OR OTHERS ON MEMORY TEAM FOR HELP -->
+ <!-- *********************************************************************** -->
+@@ -108,7 +108,7 @@ Set by: PLL settings written by Dave Cadigan</description>
+ <odmChangeable/>
+ <persistRuntime/>
+ </attribute>
+-
++
+ <attribute>
+ <id>ATTR_MSS_DIMM_MFG_ID_CODE</id>
+ <targetType>TARGET_TYPE_MBA_CHIPLET</targetType>
+@@ -3051,8 +3051,8 @@ Will be set at an MBA level with one policy to be used</description>
+ <writeable/>
+ <odmVisable/>
+ <odmChangeable/>
+- <enum>8_0G = 1, 9_6G = 2</enum>
+-</attribute>
++ <enum>NONE = 0, 8_0G = 1, 9_6G = 2, 8_0G_OR_9_6G = 3</enum>
++</attribute>
+
+ <attribute>
+ <id>ATTR_MRW_STRICT_MBA_PLUG_RULE_CHECKING</id>
+@@ -3425,7 +3425,7 @@ Will be set at an MBA level with one policy to be used</description>
+ <valueType>uint32</valueType>
+ <platInit/>
+ <odmVisable/>
+-</attribute>
++</attribute>
+
+ <attribute>
+ <id>ATTR_MRW_MEM_SENSOR_CACHE_ADDR_MAP</id>
+diff --git a/src/usr/hwpf/plat/fapiPlatUtil.C b/src/usr/hwpf/plat/fapiPlatUtil.C
+index d03b670..269c36f 100644
+--- a/src/usr/hwpf/plat/fapiPlatUtil.C
++++ b/src/usr/hwpf/plat/fapiPlatUtil.C
+@@ -334,7 +334,7 @@ void* fapiPlatMalloc(size_t s)
+ {
+ if (s > PAGE_SIZE)
+ {
+- s = ALIGN_TO_NEXT_POWER_OF_TWO_PAGES(s);
++ s = PAGE_SIZE * ALIGN_POW2(ALIGN_PAGE(s) / PAGE_SIZE);
+ }
+ return malloc(s);
+ }
+diff --git a/src/usr/sbe/sbe_update.C b/src/usr/sbe/sbe_update.C
+index 1faad63..237838f 100644
+--- a/src/usr/sbe/sbe_update.C
++++ b/src/usr/sbe/sbe_update.C
+@@ -3976,6 +3976,68 @@ namespace SBE
+
+ }
+
++/////////////////////////////////////////////////////////////////////
++ 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;
++ }
+
+
+ /////////////////////////////////////////////////////////////////////
+diff --git a/src/usr/targeting/common/target.C b/src/usr/targeting/common/target.C
+index 2248283..559fd4e 100644
+--- a/src/usr/targeting/common/target.C
++++ b/src/usr/targeting/common/target.C
+@@ -645,6 +645,53 @@ bool Target::uninstallWriteAttributeCallback()
+ #undef TARG_FN
+ }
+
++
++//******************************************************************************
++// setFrequencyAttributes
++//******************************************************************************
++void setFrequencyAttributes(Target * i_sys, uint32_t i_newNestFreq)
++{
++
++ // Calculate the new value for PIB_I2C_NEST_PLL using old freq attributes.
++ uint32_t l_oldPll = i_sys->getAttr<TARGETING::ATTR_PIB_I2C_NEST_PLL>();
++ uint32_t l_oldNestFreq = i_sys->getAttr<TARGETING::ATTR_NEST_FREQ_MHZ>();
++ uint32_t l_newPll = (i_newNestFreq * l_oldPll)/l_oldNestFreq;
++
++ //NEST_FREQ
++ i_sys->setAttr<TARGETING::ATTR_NEST_FREQ_MHZ>(i_newNestFreq);
++ TRACFCOMP(g_trac_targeting,
++ "ATTR_NEST_FREQ_MHZ getting set from %d to %d",
++ l_oldNestFreq,
++ i_newNestFreq );
++
++ //FREQ_X
++ uint32_t l_freqX = i_newNestFreq * 2;
++ i_sys->setAttr<TARGETING::ATTR_FREQ_X>(l_freqX);
++ TRACFCOMP(g_trac_targeting,
++ "ATTR_FREQ_X getting set to from %d to %d",
++ l_oldNestFreq*2,
++ l_freqX );
++
++ //FREQ_PB
++ uint32_t l_freqPb = i_newNestFreq;
++ i_sys->setAttr<TARGETING::ATTR_FREQ_PB>(l_freqPb);
++ TRACFCOMP(g_trac_targeting,
++ "ATTR_FREQ_PB getting set from %d to %d",
++ l_oldNestFreq,
++ l_freqPb );
++
++ //PIB_I2C_NEST_PLL
++ i_sys->setAttr<TARGETING::ATTR_PIB_I2C_NEST_PLL>(l_newPll);
++ TRACFCOMP(g_trac_targeting,
++ "ATTR_PIB_I2C_NEST_PLL getting set from %x to %x",
++ l_oldPll,
++ l_newPll);
++
++ return;
++}
++
++
++
+ //******************************************************************************
+ // Attribute Tanks
+ //******************************************************************************
+diff --git a/src/usr/targeting/common/xmltohb/attribute_types.xml b/src/usr/targeting/common/xmltohb/attribute_types.xml
+index 05497fd..88041b4 100644
+--- a/src/usr/targeting/common/xmltohb/attribute_types.xml
++++ b/src/usr/targeting/common/xmltohb/attribute_types.xml
+@@ -2049,6 +2049,7 @@
+ <simpleType><uint32_t></uint32_t></simpleType>
+ <persistency>non-volatile</persistency>
+ <readable/>
++ <writeable/>
+ <hwpfToHbAttrMap>
+ <id>ATTR_FREQ_PB</id>
+ <macro>DIRECT</macro>
+@@ -2083,6 +2084,7 @@
+ <simpleType><uint32_t></uint32_t></simpleType>
+ <persistency>non-volatile</persistency>
+ <readable/>
++ <writeable/>
+ <hwpfToHbAttrMap>
+ <id>ATTR_FREQ_X</id>
+ <macro>DIRECT</macro>
+@@ -6103,7 +6105,7 @@ firmware notes: Used as override attribute for pstate procedure
+ <default>2000</default>
+ </uint32_t>
+ </simpleType>
+- <persistency>volatile</persistency>
++ <persistency>non-volatile</persistency>
+ <readable/>
+ <writeable/>
+ <hwpfToHbAttrMap>
+@@ -15666,7 +15668,7 @@ firmware notes: Platforms should initialize this attribute to AUTO (0)</descript
+
+ <attribute>
+ <id>MRW_VMEM_REGULATOR_POWER_LIMIT_PER_DIMM_ADJ_ENABLE</id>
+- <description>Machine Readable Workbook enablement of the HWP code to adjust
++ <description>Machine Readable Workbook enablement of the HWP code to adjust
+ the VMEM regulator power limit based on number of installed DIMMs.
+ </description>
+ <simpleType>
+@@ -15702,7 +15704,7 @@ firmware notes: Platforms should initialize this attribute to AUTO (0)</descript
+
+ <attribute>
+ <id>MRW_VMEM_REGULATOR_MEMORY_POWER_LIMIT_PER_DIMM</id>
+- <description>Machine Readable Workbook VMEM regulator power limit per CDIMM
++ <description>Machine Readable Workbook VMEM regulator power limit per CDIMM
+ assuming a full configuration. Units in cW.
+ </description>
+ <simpleType>
+@@ -15741,7 +15743,7 @@ firmware notes: Platforms should initialize this attribute to AUTO (0)</descript
+
+ <attribute>
+ <id>MRW_NEST_CAPABLE_FREQUENCIES_SYS</id>
+- <description>The NEST frequencies that the system can support. This is a bit-wise value that represents which of the possible nest frequencies are supported : 2.0GHz, 2.4GHz, or both.
++ <description>The NEST frequencies that the system can support. This is a bit-wise value that represents which of the possible nest frequencies are supported. : 2.0GHz, 2.4GHz, or both. New frequencies should be added in ascending order.
+ </description>
+ <simpleType>
+ <enumeration>
+--
+1.8.2.2
+
diff --git a/openpower/package/occ/occ.mk b/openpower/package/occ/occ.mk
index f4c56c1..f0bf819 100644
--- a/openpower/package/occ/occ.mk
+++ b/openpower/package/occ/occ.mk
@@ -4,7 +4,7 @@
#
################################################################################
-OCC_VERSION ?= 3528dc12efbb48e1141cd99016a936fc6fb1e260
+OCC_VERSION ?= 0362706b9b9eac5af36ba5b41c5d93a108ccd90d
OCC_SITE ?= $(call github,open-power,occ,$(OCC_VERSION))
OCC_LICENSE = Apache-2.0
OCC_DEPENDENCIES = host-binutils host-p8-pore-binutils