diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/build/configs/fsprelease.config | 1 | ||||
-rw-r--r-- | src/include/usr/isteps/istep13list.H | 5 | ||||
-rw-r--r-- | src/include/usr/isteps/istep14list.H | 6 | ||||
-rw-r--r-- | src/include/usr/isteps/istep21list.H | 5 | ||||
-rw-r--r-- | src/include/usr/isteps/nvdimm/nvdimm.H | 20 | ||||
-rw-r--r-- | src/include/usr/vpd/spdenums.H | 5 | ||||
-rw-r--r-- | src/usr/isteps/istep13/call_mss_draminit.C | 20 | ||||
-rw-r--r-- | src/usr/isteps/istep14/call_mss_power_cleanup.C | 198 | ||||
-rw-r--r-- | src/usr/isteps/nvdimm/nvdimm.C | 568 | ||||
-rw-r--r-- | src/usr/isteps/nvdimm/nvdimm.H | 300 | ||||
-rw-r--r-- | src/usr/isteps/nvdimm/runtime/nvdimm_rt.C | 136 | ||||
-rw-r--r-- | src/usr/isteps/pm/runtime/rt_pm.C | 2 | ||||
-rwxr-xr-x | src/usr/vpd/spdDDR4.H | 3 |
13 files changed, 881 insertions, 388 deletions
diff --git a/src/build/configs/fsprelease.config b/src/build/configs/fsprelease.config index 16310594c..ebebfdf50 100644 --- a/src/build/configs/fsprelease.config +++ b/src/build/configs/fsprelease.config @@ -12,6 +12,7 @@ unset NO_SBE_UPDATES unset BMC_BT_LPC_IPMI unset HTMGT set FSP_BUILD +set NVDIMM set CONFIG_NVDIMM diff --git a/src/include/usr/isteps/istep13list.H b/src/include/usr/isteps/istep13list.H index fd0430c6c..d4788913d 100644 --- a/src/include/usr/isteps/istep13list.H +++ b/src/include/usr/isteps/istep13list.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* Contributors Listed Below - COPYRIGHT 2012,2019 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -296,6 +296,9 @@ const DepModInfo g_istep13Dependancies = { DEP_LIB(libistep13.so), DEP_LIB(libisteps_mss.so), DEP_LIB(libcen.so), +#ifdef CONFIG_NVDIMM + DEP_LIB(libnvdimm.so), +#endif NULL } }; diff --git a/src/include/usr/isteps/istep14list.H b/src/include/usr/isteps/istep14list.H index 1a2058167..bf5b00453 100644 --- a/src/include/usr/isteps/istep14list.H +++ b/src/include/usr/isteps/istep14list.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2012,2018 */ +/* Contributors Listed Below - COPYRIGHT 2012,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -169,7 +169,11 @@ namespace INITSERVICE { ISTEPNAME(14,04,"mss_power_cleanup"), ISTEP_14::call_mss_power_cleanup, +#ifdef CONFIG_NVDIMM + { START_FN, EXT_IMAGE, MPIPL_OP | NORMAL_IPL_OP, true } +#else { START_FN, EXT_IMAGE, NORMAL_IPL_OP, true } +#endif }, { ISTEPNAME(14,05,"proc_setup_bars"), diff --git a/src/include/usr/isteps/istep21list.H b/src/include/usr/isteps/istep21list.H index 582ecf292..fabfc4be6 100644 --- a/src/include/usr/isteps/istep21list.H +++ b/src/include/usr/isteps/istep21list.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2012,2018 */ +/* Contributors Listed Below - COPYRIGHT 2012,2019 */ /* [+] Google Inc. */ /* [+] International Business Machines Corp. */ /* */ @@ -132,6 +132,9 @@ const DepModInfo g_istep21Dependancies = { #ifndef CONFIG_FSP_BUILD DEP_LIB(libnvram.so), #endif +#ifdef CONFIG_NVDIMM + DEP_LIB(libnvdimm.so), +#endif NULL } }; diff --git a/src/include/usr/isteps/nvdimm/nvdimm.H b/src/include/usr/isteps/nvdimm/nvdimm.H index c1df3033e..6f6b46541 100644 --- a/src/include/usr/isteps/nvdimm/nvdimm.H +++ b/src/include/usr/isteps/nvdimm/nvdimm.H @@ -29,7 +29,7 @@ namespace NVDIMM { -enum +enum nvdimm_err_status { NSTD_VAL_NOPRSV = 0x08, // memory valid, contents not preserved (genesis) NSTD_VAL_NOPRSV_MASK = 0xF7, @@ -41,6 +41,7 @@ enum NSTD_ERR_NOBKUP_MASK = 0xFE, NSTD_ERR = 0x03, // NSTD_ERR_NOPRSV+NSTD_ERR_NOBKUP }; + #ifndef __HOSTBOOT_RUNTIME /** * @brief Entry function to NVDIMM management @@ -76,7 +77,6 @@ errlHndl_t nvdimmEraseNF(TARGETING::Target *i_nvdimm); */ void nvdimmSetStatusFlag(TARGETING::Target *i_nvdimm, const uint8_t i_status_flag); - #ifdef __HOSTBOOT_RUNTIME /** @@ -89,15 +89,16 @@ void nvdimmSetStatusFlag(TARGETING::Target *i_nvdimm, const uint8_t i_status_fla bool nvdimmInErrorState(TARGETING::Target *i_nvdimm); /** - * @brief This function arms the trigger to enable backup in the event - * of power loss (DDR Reset_n goes low) + * @brief This function arms/disarms the trigger based on i_state * * @param[in] i_nvdimm - nvdimm target with NV controller * + * @param[in] i_state - true to arm, false to disarm + * * @return errlHndl_t - Null if successful, otherwise a pointer to * the error log. */ -errlHndl_t nvdimmArmResetN(TARGETING::Target *i_nvdimm); +errlHndl_t nvdimmChangeArmState(TARGETING::Target *i_nvdimm, bool i_state); /** * @brief Arms the trigger to enable backup in the event of a power loss @@ -113,7 +114,6 @@ errlHndl_t nvdimmArmResetN(TARGETING::Target *i_nvdimm); */ bool nvdimmArm(TARGETING::TargetHandleList &i_nvdimmTargetList); - /** * @brief NVDIMM protection state * @@ -139,6 +139,14 @@ enum nvdimm_protection_t errlHndl_t notifyNvdimmProtectionChange(TARGETING::Target* i_target, const nvdimm_protection_t i_state); #endif +/** + * @brief Entry function to NVDIMM initialization + * - Checks for ready state + * - Waits for the ongoing backup to complete + * - Disarms the trigger for draminit + * @param i_target nvdimm target + */ +void nvdimm_init(TARGETING::Target *i_nvdimm); } diff --git a/src/include/usr/vpd/spdenums.H b/src/include/usr/vpd/spdenums.H index 9decbe862..bd6418d5e 100644 --- a/src/include/usr/vpd/spdenums.H +++ b/src/include/usr/vpd/spdenums.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2016 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -142,7 +142,8 @@ enum MODULE_REVISION_CODE_DDR4 = MODULE_REVISION_CODE, DRAM_STEPPING = SPD_FIRST_NORM_KEYWORD | 0x57, MANUFACTURING_SECTION_CRC = SPD_FIRST_NORM_KEYWORD | 0x58, - SPD_LAST_NORM_KEYWORD = SPD_FIRST_NORM_KEYWORD | 0x58, + NVM_INIT_TIME = SPD_FIRST_NORM_KEYWORD | 0x59, + SPD_LAST_NORM_KEYWORD = SPD_FIRST_NORM_KEYWORD | 0x59, // ============================================================== // Module Specific Keywords (Available for both DDR3 and DDR4 DIMMs) diff --git a/src/usr/isteps/istep13/call_mss_draminit.C b/src/usr/isteps/istep13/call_mss_draminit.C index 00d69f5f3..915bc992b 100644 --- a/src/usr/isteps/istep13/call_mss_draminit.C +++ b/src/usr/isteps/istep13/call_mss_draminit.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -50,6 +50,11 @@ #include <p9_mss_draminit.H> #include <p9c_mss_draminit.H> +#ifdef CONFIG_NVDIMM +// NVDIMM support +#include <isteps/nvdimm/nvdimm.H> +#endif + using namespace ERRORLOG; using namespace ISTEP; using namespace ISTEP_ERROR; @@ -161,6 +166,19 @@ void* call_mss_draminit (void *io_pArgs) fapi2::Target<fapi2::TARGET_TYPE_MCBIST> l_fapi_mcbist_target (l_mcbist_target); + // Initialize the NVDIMMs before hitting draminit +#ifdef CONFIG_NVDIMM + TARGETING::TargetHandleList l_dimmTargetList; + getChildAffinityTargets(l_dimmTargetList, l_mcbist_target, CLASS_NA, TYPE_DIMM); + + for (const auto & l_dimm : l_dimmTargetList) + { + if (isNVDIMM(l_dimm)) + { + NVDIMM::nvdimm_init(l_dimm); + } + } +#endif FAPI_INVOKE_HWP(l_err, p9_mss_draminit, l_fapi_mcbist_target); if (l_err) diff --git a/src/usr/isteps/istep14/call_mss_power_cleanup.C b/src/usr/isteps/istep14/call_mss_power_cleanup.C index 5c27dcc67..3ca963678 100644 --- a/src/usr/isteps/istep14/call_mss_power_cleanup.C +++ b/src/usr/isteps/istep14/call_mss_power_cleanup.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2018 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -60,43 +60,50 @@ void* call_mss_power_cleanup (void *io_pArgs) TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_power_cleanup entry" ); - TARGETING::TargetHandleList l_mcbistTargetList; - getAllChiplets(l_mcbistTargetList, TYPE_MCBIST); - - for (const auto & l_target : l_mcbistTargetList) + TARGETING::Target* l_sys = nullptr; + TARGETING::targetService().getTopLevelTarget( l_sys ); + assert(l_sys, "call_mss_power_cleanup: no TopLevelTarget"); + uint8_t l_mpipl = l_sys->getAttr<ATTR_IS_MPIPL_HB>(); + if (!l_mpipl) { - // Dump current run on target - TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, - "Running mss_power_cleanup HWP on " - "target HUID %.8X", - TARGETING::get_huid(l_target)); + TARGETING::TargetHandleList l_mcbistTargetList; + getAllChiplets(l_mcbistTargetList, TYPE_MCBIST); - fapi2::Target <fapi2::TARGET_TYPE_MCBIST> l_fapi_target - (l_target); + for (const auto & l_target : l_mcbistTargetList) + { + // Dump current run on target + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, + "Running mss_power_cleanup HWP on " + "target HUID %.8X", + TARGETING::get_huid(l_target)); - // call the HWP with each fapi2::Target - FAPI_INVOKE_HWP(l_err, p9_mss_power_cleanup, l_fapi_target); + fapi2::Target <fapi2::TARGET_TYPE_MCBIST> l_fapi_target + (l_target); - if (l_err) - { - TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, - "ERROR 0x%.8X: mss_power_cleanup HWP returns error", - l_err->reasonCode()); + // call the HWP with each fapi2::Target + FAPI_INVOKE_HWP(l_err, p9_mss_power_cleanup, l_fapi_target); - // capture the target data in the elog - ErrlUserDetailsTarget(l_target).addToLog(l_err); + if (l_err) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, + "ERROR 0x%.8X: mss_power_cleanup HWP returns error", + l_err->reasonCode()); - // Create IStep error log and cross reference to error that - // occurred - l_stepError.addErrorDetails( l_err ); + // capture the target data in the elog + ErrlUserDetailsTarget(l_target).addToLog(l_err); - // Commit Error - errlCommit( l_err, HWPF_COMP_ID ); - } - else - { - TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, - "SUCCESS : mss_power_cleanup HWP( )" ); + // Create IStep error log and cross reference to error that + // occurred + l_stepError.addErrorDetails( l_err ); + + // Commit Error + errlCommit( l_err, HWPF_COMP_ID ); + } + else + { + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, + "SUCCESS : mss_power_cleanup HWP( )" ); + } } } @@ -131,76 +138,79 @@ void* call_mss_power_cleanup (void *io_pArgs) // -- Cumulus only // Get a list of all present Centaurs - TargetHandleList l_presCentaurs; - getAllChips(l_presCentaurs, TYPE_MEMBUF); - // For each present Centaur - for (TargetHandleList::const_iterator - l_cenIter = l_presCentaurs.begin(); - l_cenIter != l_presCentaurs.end(); - ++l_cenIter) + if (!l_mpipl) { - // Make a local copy of the target for ease of use - TARGETING::Target * l_pCentaur = *l_cenIter; - // Retrieve HUID of current Centaur - TARGETING::ATTR_HUID_type l_currCentaurHuid = - TARGETING::get_huid(l_pCentaur); - - // Find all present MBAs associated with this Centaur - TARGETING::TargetHandleList l_presMbas; - getChildChiplets(l_presMbas, l_pCentaur,TYPE_MBA); - - // If not at least two MBAs found - if (l_presMbas.size() < 2) + TargetHandleList l_presCentaurs; + getAllChips(l_presCentaurs, TYPE_MEMBUF); + // For each present Centaur + for (TargetHandleList::const_iterator + l_cenIter = l_presCentaurs.begin(); + l_cenIter != l_presCentaurs.end(); + ++l_cenIter) { - TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, - "Not enough MBAs found for Centaur target HUID %.8X, " - "skipping this Centaur.", - l_currCentaurHuid); - continue; - } - - // Cache current MBA HUIDs for tracing - TARGETING::ATTR_HUID_type l_currMBA0Huid = - TARGETING::get_huid(l_presMbas[0]); - TARGETING::ATTR_HUID_type l_currMBA1Huid = - TARGETING::get_huid(l_presMbas[1]); - - TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, - "Running mss_power_cleanup HWP on " - "Centaur HUID %.8X, MBA0 HUID %.8X, " - "MBA1 HUID %.8X, ", l_currCentaurHuid, - l_currMBA0Huid, l_currMBA1Huid); - - // Create FAPI Targets. - fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP> l_fapiCentaurTarget( l_pCentaur ); - fapi2::Target<fapi2::TARGET_TYPE_MBA_CHIPLET> l_fapiMba0Target( l_presMbas[0] ); - fapi2::Target<fapi2::TARGET_TYPE_MBA_CHIPLET> l_fapiMba1Target( l_presMbas[1] ); + // Make a local copy of the target for ease of use + TARGETING::Target * l_pCentaur = *l_cenIter; + // Retrieve HUID of current Centaur + TARGETING::ATTR_HUID_type l_currCentaurHuid = + TARGETING::get_huid(l_pCentaur); + + // Find all present MBAs associated with this Centaur + TARGETING::TargetHandleList l_presMbas; + getChildChiplets(l_presMbas, l_pCentaur,TYPE_MBA); + + // If not at least two MBAs found + if (l_presMbas.size() < 2) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, + "Not enough MBAs found for Centaur target HUID %.8X, " + "skipping this Centaur.", + l_currCentaurHuid); + continue; + } - // Call the HWP with each fapi::Target - FAPI_INVOKE_HWP(l_err, p9c_mss_power_cleanup, l_fapiCentaurTarget, - l_fapiMba0Target, l_fapiMba1Target); + // Cache current MBA HUIDs for tracing + TARGETING::ATTR_HUID_type l_currMBA0Huid = + TARGETING::get_huid(l_presMbas[0]); + TARGETING::ATTR_HUID_type l_currMBA1Huid = + TARGETING::get_huid(l_presMbas[1]); - if (l_err) - { - TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, - "mss_power_cleanup HWP failed to perform" - " cleanup on centaur: 0x%.8X HWP_ERROR: 0x%.8X", - l_currCentaurHuid,l_err->reasonCode()); - // Capture the target data in the error log - ErrlUserDetailsTarget(l_pCentaur).addToLog(l_err); - // Create IStep error log and cross reference error that occurred - l_stepError.addErrorDetails(l_err); - // Commit error - errlCommit(l_err, HWPF_COMP_ID); - } - else - { - // Success TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, - "Successfully ran mss_power_cleanup HWP on " + "Running mss_power_cleanup HWP on " "Centaur HUID %.8X, MBA0 HUID %.8X, " "MBA1 HUID %.8X, ", l_currCentaurHuid, - l_currMBA0Huid, l_currMBA1Huid); + l_currMBA0Huid, l_currMBA1Huid); + + // Create FAPI Targets. + fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP> l_fapiCentaurTarget( l_pCentaur ); + fapi2::Target<fapi2::TARGET_TYPE_MBA_CHIPLET> l_fapiMba0Target( l_presMbas[0] ); + fapi2::Target<fapi2::TARGET_TYPE_MBA_CHIPLET> l_fapiMba1Target( l_presMbas[1] ); + + // Call the HWP with each fapi::Target + FAPI_INVOKE_HWP(l_err, p9c_mss_power_cleanup, l_fapiCentaurTarget, + l_fapiMba0Target, l_fapiMba1Target); + + if (l_err) + { + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, + "mss_power_cleanup HWP failed to perform" + " cleanup on centaur: 0x%.8X HWP_ERROR: 0x%.8X", + l_currCentaurHuid,l_err->reasonCode()); + // Capture the target data in the error log + ErrlUserDetailsTarget(l_pCentaur).addToLog(l_err); + // Create IStep error log and cross reference error that occurred + l_stepError.addErrorDetails(l_err); + // Commit error + errlCommit(l_err, HWPF_COMP_ID); + } + else + { + // Success + TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, + "Successfully ran mss_power_cleanup HWP on " + "Centaur HUID %.8X, MBA0 HUID %.8X, " + "MBA1 HUID %.8X, ", l_currCentaurHuid, + l_currMBA0Huid, l_currMBA1Huid); + } } } TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, diff --git a/src/usr/isteps/nvdimm/nvdimm.C b/src/usr/isteps/nvdimm/nvdimm.C index fdc0240a9..b472896e5 100644 --- a/src/usr/isteps/nvdimm/nvdimm.C +++ b/src/usr/isteps/nvdimm/nvdimm.C @@ -39,6 +39,7 @@ #include <lib/mc/port.H> #include <isteps/nvdimm/nvdimmreasoncodes.H> #include <isteps/nvdimm/nvdimm.H> +#include <vpd/spdenums.H> using namespace TARGETING; using namespace DeviceFW; @@ -48,8 +49,8 @@ trace_desc_t* g_trac_nvdimm = NULL; TRAC_INIT(&g_trac_nvdimm, NVDIMM_COMP_NAME, 2*KILOBYTE); // Easy macro replace for unit testing -// #define TRACUCOMP(args...) TRACFCOMP(args) -#define TRACUCOMP(args...) +#define TRACUCOMP(args...) TRACFCOMP(args) +//#define TRACUCOMP(args...) namespace NVDIMM @@ -61,29 +62,29 @@ namespace NVDIMM #define NVDIMM_SET_USER_DATA_2_TIMEOUT(left_32_polled, right_32_timeout) \ NVDIMM_SET_USER_DATA_1(left_32_polled, right_32_timeout) +#define ADDRESS(uint16_address) \ + uint16_address & 0x00FF + +#define PAGE(uint16_address) \ + (uint16_address >> 8) & 0x000F + typedef struct ops_timeoutInfo{ const char * desc; - uint8_t page; - uint8_t offset[2]; + uint16_t offset[2]; uint8_t idx; - uint8_t status_reg_offset; + uint16_t status_reg_offset; uint8_t status_progress; } ops_timeoutInfo_t; -#ifndef __HOSTBOOT_RUNTIME -// Init flag to be used upon initial entry to initialize NV_OPS_TIMEOUT_MSEC -static bool init_nv_timeout = true; -#endif - // Table containing register info on the timeout registers for different ops constexpr ops_timeoutInfo_t timeoutInfoTable[] = { - {"SAVE", 0, {0x19, 0x18}, SAVE , NVDIMM_CMD_STATUS0, SAVE_IN_PROGRESS}, - {"RESTORE", 0, {0x1D, 0x1C}, RESTORE , NVDIMM_CMD_STATUS0, RSTR_IN_PROGRESS}, - {"ERASE", 0, {0x1F, 0x1E}, ERASE , NVDIMM_CMD_STATUS0, ERASE_IN_PROGRESS}, - {"ARM", 0, {0x21, 0x20}, ARM , NVDIMM_CMD_STATUS0, ARM_IN_PROGRESS}, - {"PAGE_SWITCH", 0, {0x1B, 0x1A}, PAGE_SWITCH, 0xff, 0xff}, - {"CHARGE", 1, {0x11, 0x10}, CHARGE , MODULE_HEALTH_STATUS1, CHARGE_IN_PROGRESS}, + {"SAVE", {CSAVE_TIMEOUT1, CSAVE_TIMEOUT0}, SAVE , NVDIMM_CMD_STATUS0, SAVE_IN_PROGRESS}, + {"RESTORE", {RESTORE_TIMEOUT1, RESTORE_TIMEOUT0}, RESTORE , NVDIMM_CMD_STATUS0, RSTR_IN_PROGRESS}, + {"ERASE", {ERASE_TIMEOUT1, ERASE_TIMEOUT0}, ERASE , NVDIMM_CMD_STATUS0, ERASE_IN_PROGRESS}, + {"ARM", {ARM_TIMEOUT1, ARM_TIMEOUT0}, ARM , NVDIMM_CMD_STATUS0, ARM_IN_PROGRESS}, + {"PAGE_SWITCH", {PAGE_SWITCH_LATENCY1, PAGE_SWITCH_LATENCY0}, PAGE_SWITCH, 0xff, 0xff}, + {"CHARGE", {ES_CHARGE_TIMEOUT1, ES_CHARGE_TIMEOUT0}, CHARGE , MODULE_HEALTH_STATUS1, CHARGE_IN_PROGRESS}, }; /** @@ -95,27 +96,63 @@ constexpr ops_timeoutInfo_t timeoutInfoTable[] = * * @param[out] o_data - returned data from read * + * @param[in] page_verify - read and verify the page associated to the given address. + * Change if needed. Default to true + * * @return errlHndl_t - Null if successful, otherwise a pointer to * the error log. */ errlHndl_t nvdimmReadReg(Target* i_nvdimm, - uint8_t i_addr, - uint8_t & o_data ) + uint16_t i_addr, + uint8_t & o_data, + const bool page_verify) { TRACUCOMP(g_trac_nvdimm, ENTER_MRK"NVDIMM Read HUID %X, addr 0x%X", TARGETING::get_huid(i_nvdimm), i_addr); errlHndl_t l_err = nullptr; size_t l_numBytes = 1; + uint8_t l_reg_addr = ADDRESS(i_addr); + uint8_t l_reg_page = PAGE(i_addr); + + do + { + // If page_verify is true, make sure the current page is set to the page + // where i_addr is in and change if needed + if (page_verify) + { + uint8_t l_data = 0; + l_err = nvdimmReadReg(i_nvdimm, OPEN_PAGE, l_data, NO_PAGE_VERIFY); - l_err = DeviceFW::deviceOp( DeviceFW::READ, - i_nvdimm, - &o_data, - l_numBytes, - DEVICE_NVDIMM_ADDRESS(i_addr)); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReadReg() nvdimm[%X] - failed to read the current page", + TARGETING::get_huid(i_nvdimm)); + break; + } - TRACUCOMP(g_trac_nvdimm, EXIT_MRK"NVDIMM Read HUID %X, addr 0x%X = %X", - TARGETING::get_huid(i_nvdimm), i_addr, o_data); + if (l_data != l_reg_page) + { + l_err = nvdimmOpenPage(i_nvdimm, l_reg_page); + + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReadReg() nvdimm[%X] - failed to verify page", + TARGETING::get_huid(i_nvdimm)); + break; + } + } + } + + l_err = DeviceFW::deviceOp( DeviceFW::READ, + i_nvdimm, + &o_data, + l_numBytes, + DEVICE_NVDIMM_ADDRESS(l_reg_addr)); + }while(0); + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"NVDIMM Read HUID %X, page 0x%X, addr 0x%X = %X", + TARGETING::get_huid(i_nvdimm), l_reg_page, l_reg_addr, o_data); return l_err; } @@ -129,28 +166,63 @@ errlHndl_t nvdimmReadReg(Target* i_nvdimm, * * @param[in] i_data - data to be written to register @ i_addr * + * @param[in] page_verify - read and verify the page associated to the given address. + * Change if needed. Default to true + * * @return errlHndl_t - Null if successful, otherwise a pointer to * the error log. */ errlHndl_t nvdimmWriteReg(Target* i_nvdimm, - uint8_t i_addr, - uint8_t i_data ) + uint16_t i_addr, + uint8_t i_data, + const bool page_verify) { + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"NVDIMM Write HUID %X, addr 0x%X = %X", + TARGETING::get_huid(i_nvdimm), i_addr, i_data); + errlHndl_t l_err = nullptr; size_t l_numBytes = 1; + uint8_t l_reg_addr = ADDRESS(i_addr); + uint8_t l_reg_page = PAGE(i_addr); - TRACUCOMP(g_trac_nvdimm, ENTER_MRK"NVDIMM Write HUID %X, addr 0x%X = %X", - TARGETING::get_huid(i_nvdimm), i_addr, i_data); + do + { + // If page_verify is true, make sure the current page is set to the page + // where i_addr is in and change if needed + if (page_verify) + { + uint8_t l_data = 0; + l_err = nvdimmReadReg(i_nvdimm, OPEN_PAGE, l_data, NO_PAGE_VERIFY); - // Need to write directly from target's EEPROM. - l_err = DeviceFW::deviceOp( DeviceFW::WRITE, - i_nvdimm, - &i_data, - l_numBytes, - DEVICE_NVDIMM_ADDRESS(i_addr)); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmWriteReg() nvdimm[%X] - failed to read the current page", + TARGETING::get_huid(i_nvdimm)); + break; + } - TRACUCOMP(g_trac_nvdimm, EXIT_MRK"NVDIMM Write HUID %X, addr 0x%X = %X", - TARGETING::get_huid(i_nvdimm), i_addr, i_data); + if (l_data != l_reg_page) + { + l_err = nvdimmOpenPage(i_nvdimm, l_reg_page); + + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmWriteReg() nvdimm[%X] - failed to verify page", + TARGETING::get_huid(i_nvdimm)); + break; + } + } + } + + l_err = DeviceFW::deviceOp( DeviceFW::WRITE, + i_nvdimm, + &i_data, + l_numBytes, + DEVICE_NVDIMM_ADDRESS(l_reg_addr)); + }while(0); + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"NVDIMM Write HUID %X, page = 0x%X, addr 0x%X = %X", + TARGETING::get_huid(i_nvdimm), l_reg_page, l_reg_addr, i_data); return l_err; } @@ -220,42 +292,82 @@ errlHndl_t nvdimmReady(Target *i_nvdimm) errlHndl_t l_err = nullptr; uint8_t l_data = 0x0; + uint8_t l_nvm_init_time = 0; + size_t l_numBytes = 1; - l_err = nvdimmReadReg(i_nvdimm, NVDIMM_READY, l_data); - - if (l_err) - { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReady() nvdimm[%X] - error getting ready status[%d]", - TARGETING::get_huid(i_nvdimm), l_data); - } - else if (l_data != NV_READY) + do { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReady() nvdimm[%X] - nvdimm not ready[%d]", - TARGETING::get_huid(i_nvdimm), l_data); - /*@ - *@errortype - *@reasoncode NVDIMM_NOT_READY - *@severity ERRORLOG_SEV_UNRECOVERABLE - *@moduleid NVDIMM_CHECK_READY - *@userdata1[0:31] Ret value from ready register - *@userdata1[32:63] Target Huid - *@userdata2 <UNUSED> - *@devdesc Failed to read ready status or NVDIMM not ready - * for host access. (userdata1 != 0xA5) - *@custdesc NVDIMM not ready - */ - l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_PREDICTIVE, - NVDIMM_POLL_STATUS, - NVDIMM_STATUS_TIMEOUT, - NVDIMM_SET_USER_DATA_1(l_data, TARGETING::get_huid(i_nvdimm)), - 0x0, - ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); + // Read the maximum NVM init time in seconds from the SPD + l_err = deviceRead(i_nvdimm, + &l_nvm_init_time, + l_numBytes, + DEVICE_SPD_ADDRESS(SPD::NVM_INIT_TIME)); - l_err->collectTrace(NVDIMM_COMP_NAME, 256 ); - //@TODO RTC 199645 - add HW callout on dimm target. - //if nvdimm is not ready for access by now, this is - //a failing indication on the NV controller - } + TRACUCOMP(g_trac_nvdimm, "nvdimmReady() HUID[%X] l_nvm_init_time = %u", + TARGETING::get_huid(i_nvdimm), l_nvm_init_time); + + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReady() nvdimm[%X] - failed to retrieve NVM_INIT_TIME from SPD", + TARGETING::get_huid(i_nvdimm)); + break; + } + + // Convert to ms for polling + uint32_t l_nvm_init_time_ms = l_nvm_init_time * MS_PER_SEC; + uint32_t l_poll = 0; + + do + { + l_err = nvdimmReadReg(i_nvdimm, NVDIMM_READY, l_data); + + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReady() nvdimm[%X] - error getting ready status[%d]", + TARGETING::get_huid(i_nvdimm), l_data); + break; + } + + if (l_data == NV_READY) + { + break; + } + + nanosleep(0, NV_READY_POLL_TIME_MS*NS_PER_MSEC); + l_poll += NV_READY_POLL_TIME_MS; + + }while(l_poll < l_nvm_init_time_ms); + + if ((l_data != NV_READY) && !l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmReady() nvdimm[%X] - nvdimm not ready[%d]", + TARGETING::get_huid(i_nvdimm), l_data); + /*@ + *@errortype + *@reasoncode NVDIMM_NOT_READY + *@severity ERRORLOG_SEV_UNRECOVERABLE + *@moduleid NVDIMM_CHECK_READY + *@userdata1[0:31] Ret value from ready register + *@userdata1[32:63] Target Huid + *@userdata2 <UNUSED> + *@devdesc Failed to read ready status or NVDIMM not ready + * for host access. (userdata1 != 0xA5) + *@custdesc NVDIMM not ready + */ + l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, + NVDIMM_CHECK_READY, + NVDIMM_NOT_READY, + NVDIMM_SET_USER_DATA_1(l_data, TARGETING::get_huid(i_nvdimm)), + 0x0, + ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); + + l_err->collectTrace(NVDIMM_COMP_NAME, 1024 ); + //@TODO RTC 199645 - add HW callout on dimm target. + //if nvdimm is not ready for access by now, this is + //a failing indication on the NV controller + } + + }while(0); TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmReady() HUID[%X] ready[%X]", TARGETING::get_huid(i_nvdimm), l_data); @@ -264,6 +376,46 @@ errlHndl_t nvdimmReady(Target *i_nvdimm) } /** + * @brief Reset the NV controller. This operation does not interfere + * with the DRAM operation but will introduce loss of protection + * if NVDIMM was armed + * + * @param[in] i_nvdimm - nvdimm target + * + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t nvdimmResetController(Target *i_nvdimm) +{ + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmResetController() HUID[%X]",TARGETING::get_huid(i_nvdimm)); + errlHndl_t l_err = nullptr; + + do + { + + l_err = nvdimmWriteReg(i_nvdimm, NVDIMM_MGT_CMD0, RESET_CONTROLLER); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmResetController() nvdimm[%X] - error reseting the controller", + TARGETING::get_huid(i_nvdimm)); + break; + } + + l_err = nvdimmReady(i_nvdimm); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmResetController() nvdimm[%X] - not ready after reset.", + TARGETING::get_huid(i_nvdimm)); + } + + }while(0); + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmResetController() HUID[%X]",TARGETING::get_huid(i_nvdimm)); + + return l_err; +} + +/** * @brief This function polls the status register for the given ops_id * * @param[in] i_nvdimm - nvdimm target with NV controller @@ -336,7 +488,7 @@ errlHndl_t nvdimmPollStatus ( Target *i_nvdimm, NVDIMM_SET_USER_DATA_2_TIMEOUT(o_poll, l_timeout), ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); - l_err->collectTrace(NVDIMM_COMP_NAME, 256 ); + l_err->collectTrace(NVDIMM_COMP_NAME, 1024 ); //@TODO RTC 199645 - add HW callout on dimm target. //may have to move the error handling to the caller //as different op could have different error severity @@ -552,7 +704,7 @@ errlHndl_t nvdimmSetESPolicy(Target* i_nvdimm) 0x0, ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); - l_err->collectTrace(NVDIMM_COMP_NAME, 256 ); + l_err->collectTrace(NVDIMM_COMP_NAME, 1024 ); //@TODO RTC 199645 - add procedure callout on backup power source. //Failure setting the energy source policy could mean error on the //battery or even the cabling @@ -565,8 +717,40 @@ errlHndl_t nvdimmSetESPolicy(Target* i_nvdimm) return l_err; } +/** + * @brief This function arms/disarms the trigger based on i_state + * + * @param[in] i_nvdimm - nvdimm target with NV controller + * + * @param[in] i_state - true to arm, false to disarm + * + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t nvdimmChangeArmState(Target *i_nvdimm, bool i_state) +{ + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmChangeArmState() nvdimm[%X]", + TARGETING::get_huid(i_nvdimm)); + errlHndl_t l_err = nullptr; + // If i_state is true, arm the nvdimm in conjunction with ATOMIC_SAVE_AND_ERASE + // feature. A separate erase command is not requred as the image will get erased + // before backup on the next catastrophic event + uint8_t l_data = i_state ? ARM_RESETN_AND_ATOMIC_SAVE_AND_ERASE : DISARM_RESETN; + + l_err = nvdimmWriteReg(i_nvdimm, ARM_CMD, l_data); + + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmChangeArmState() nvdimm[%X] error %s nvdimm!!", + TARGETING::get_huid(i_nvdimm), i_state? "arming" : "disarming"); + } + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmChangeArmState() nvdimm[%X]", + TARGETING::get_huid(i_nvdimm)); + return l_err; +} /** * @brief This function checks for valid image on the given target @@ -612,17 +796,17 @@ errlHndl_t nvdimmValidImage(Target *i_nvdimm, bool &o_imgValid) * * @param[in] i_nvdimmList - list of nvdimms * + * @param[in] i_mpipl - MPIPL mode + * * @return errlHndl_t - Null if successful, otherwise a pointer to * the error log. */ -errlHndl_t nvdimmRestore(TargetHandleList i_nvdimmList) +errlHndl_t nvdimmRestore(TargetHandleList i_nvdimmList, uint8_t &i_mpipl) { errlHndl_t l_err = nullptr; bool l_imgValid; uint8_t l_rstrValid; uint32_t l_poll = 0; - TARGETING::Target* l_sys = NULL; - targetService().getTopLevelTarget(l_sys); do { @@ -653,6 +837,25 @@ errlHndl_t nvdimmRestore(TargetHandleList i_nvdimmList) fapi2::Target<fapi2::TARGET_TYPE_MCA> l_fapi_mca(l_mcaList[0]); + // Before we do anything, check if we are in mpipl. If we are, make sure ddr_resetn + // is de-asserted before kicking off the restore + if (i_mpipl) + { + FAPI_INVOKE_HWP(l_err, mss::ddr_resetn, l_fapi_mca, HIGH); + + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmRestore() HUID[%X] i_mpipl[%u] failed to de-assert resetn!", + TARGETING::get_huid(*it), i_mpipl); + + nvdimmSetStatusFlag(*it, NSTD_ERR_NOPRSV); + //@TODO RTC 199645 - add HW callout on dimm target + //If we failed to de-assert reset_n, the dimm is pretty much useless. + //Let's not restore if that happens + break; + } + } + // Self-refresh is done at the port level FAPI_INVOKE_HWP(l_err, mss::nvdimm::self_refresh_entry, l_fapi_mca); @@ -761,7 +964,7 @@ errlHndl_t nvdimmRestore(TargetHandleList i_nvdimmList) 0x0, ERRORLOG::ErrlEntry::NO_SW_CALLOUT); - l_err->collectTrace(NVDIMM_COMP_NAME, 256 ); + l_err->collectTrace(NVDIMM_COMP_NAME, 1024 ); nvdimmSetStatusFlag(l_nvdimm, NSTD_ERR_NOPRSV); //@TODO RTC 199645 - add HW callout on dimm target //Invalid restore could be due to dram not in self-refresh @@ -861,7 +1064,7 @@ errlHndl_t nvdimmCheckEraseSuccess(Target *i_nvdimm) 0x0, ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); - l_err->collectTrace(NVDIMM_COMP_NAME, 256 ); + l_err->collectTrace(NVDIMM_COMP_NAME, 1024 ); errlCommit( l_err, NVDIMM_COMP_ID ); //@TODO RTC 199645 - add HW callout on dimm target. //failure to erase could mean internal NV controller error and/or @@ -936,7 +1139,6 @@ errlHndl_t nvdimmOpenPage(Target *i_nvdimm, bool l_success = false; uint8_t l_data; uint32_t l_poll = 0; - uint32_t l_target_timeout_values[6]; assert(i_nvdimm->tryGetAttr<TARGETING::ATTR_NV_OPS_TIMEOUT_MSEC>(l_target_timeout_values), "nvdimmOpenPage() HUID[%X], failed reading ATTR_NV_OPS_TIMEOUT_MSEC!", TARGETING::get_huid(i_nvdimm)); @@ -946,7 +1148,8 @@ errlHndl_t nvdimmOpenPage(Target *i_nvdimm, do { - l_err = nvdimmWriteReg(i_nvdimm, OPEN_PAGE, i_page); + // Open page reg is at the same address of every page + l_err = nvdimmWriteReg(i_nvdimm, OPEN_PAGE, i_page, NO_PAGE_VERIFY); if (l_err) { @@ -960,7 +1163,7 @@ errlHndl_t nvdimmOpenPage(Target *i_nvdimm, // Not using the nvdimmPollStatus since this is polled differently do { - l_err = nvdimmReadReg(i_nvdimm, OPEN_PAGE, l_data); + l_err = nvdimmReadReg(i_nvdimm, OPEN_PAGE, l_data, NO_PAGE_VERIFY); if (l_err){ break; } @@ -989,7 +1192,7 @@ errlHndl_t nvdimmOpenPage(Target *i_nvdimm, /*@ *@errortype *@reasoncode NVDIMM_OPEN_PAGE_TIMEOUT - *@severity ERRORLOG_SEV_PREDICTIVE + *@severity ERRORLOG_SEV_UNRECOVERABLE *@moduleid NVDIMM_OPEN_PAGE *@userdata1[0:31] Related ops (0xff = NA) *@userdata1[32:63] Target Huid @@ -999,7 +1202,7 @@ errlHndl_t nvdimmOpenPage(Target *i_nvdimm, *@custdesc Encountered error performing internal operaiton * on NVDIMM */ - l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_PREDICTIVE, + l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, NVDIMM_POLL_STATUS, NVDIMM_STATUS_TIMEOUT, NVDIMM_SET_USER_DATA_1(PAGE_SWITCH, TARGETING::get_huid(i_nvdimm)), @@ -1039,17 +1242,8 @@ errlHndl_t nvdimmGetTimeoutVal(Target* i_nvdimm) i_nvdimm->tryGetAttr<TARGETING::ATTR_NV_OPS_TIMEOUT_MSEC>(timeout_map); //Get the 6 main timeout values - for (uint8_t i = SAVE; i <= CHARGE; i++){ - - // Some timeout value maybe in different page - l_err = nvdimmOpenPage(i_nvdimm, timeoutInfoTable[i].page); - if (l_err) - { - TRACFCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmGetTimeoutVal() HUID[%X] " - "failing on nvdimmOpenPage()",TARGETING::get_huid(i_nvdimm)); - break; - } - + for (uint8_t i = SAVE; i <= CHARGE; i++) + { // Need to loop thru both offsets to get the full timeout value // The first offset contains the MSByte of the timeout value // with the MSB indicating ms or sec @@ -1083,7 +1277,7 @@ errlHndl_t nvdimmGetTimeoutVal(Target* i_nvdimm) timeout_map[i] = timeout_map[i] * MS_PER_SEC; } - TRACFCOMP(g_trac_nvdimm, "nvdimmGetTimeoutVal() HUID[%X], timeout_idx[%d], timeout_ms[%d]" + TRACUCOMP(g_trac_nvdimm, "nvdimmGetTimeoutVal() HUID[%X], timeout_idx[%d], timeout_ms[%d]" ,TARGETING::get_huid(i_nvdimm), timeoutInfoTable[i].idx, timeout_map[i]); } @@ -1100,73 +1294,27 @@ errlHndl_t nvdimmGetTimeoutVal(Target* i_nvdimm) #ifndef __HOSTBOOT_RUNTIME /** - * @brief Entry function to NVDIMM management + * @brief Entry function to NVDIMM restore * - Restore image from NVDIMM NAND flash to DRAM - * - Arms the backup trigger to ddr_reset_n once the restore - * is completed - * - Erase image + * - Set up the ES policy * * @param[in] i_nvdimmList - list of nvdimm targets * */ void nvdimm_restore(TargetHandleList &i_nvdimmList) { - TRACFCOMP(g_trac_nvdimm, ENTER_MRK"nvdimm_restore()"); + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimm_restore()"); errlHndl_t l_err = nullptr; + TARGETING::Target* l_sys = nullptr; + TARGETING::targetService().getTopLevelTarget( l_sys ); + assert(l_sys, "nvdimm_restore: no TopLevelTarget"); + uint8_t l_mpipl = l_sys->getAttr<ATTR_IS_MPIPL_HB>(); do { - // Typically during init the NV controller defaults the page - // to 0, but it doesn't in warmboot because the controller - // doesn't get power cycled. So, let's change it to page 0 - // anyway right at the beginning. - for (const auto & l_nvdimm : i_nvdimmList) - { - l_err = nvdimmOpenPage(l_nvdimm, ZERO); - if (l_err) - { - nvdimmSetStatusFlag(l_nvdimm, NSTD_ERR); - break; - } - - } - - if (l_err) - { - // @TODO-RTC:200275-Make logic generic for all system configs - // Because of interleaving, if one is garded the other one - // in the pair should be garded by association. So, let's - // move on since there is nothing else to do. - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_restore() - Failing open page"); - errlCommit( l_err, NVDIMM_COMP_ID ); - break; - } - - // Before proceeding, make sure the NV controller - // is in ready state. - for (const auto & l_nvdimm : i_nvdimmList) - { - l_err = nvdimmReady(l_nvdimm); - if (l_err) - { - nvdimmSetStatusFlag(l_nvdimm, NSTD_ERR); - break; - } - } - - if (l_err) - { - // If this failing right off the bat, - // something isn't quite right with - // the module - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_restore() - Failing nvdimmReady()"); - errlCommit(l_err, NVDIMM_COMP_ID); - break; - } - // Set the energy policy to device-managed // Don't think this is needed for the supercaps to start charging - // but on some devices this is needed to get the charge timeout value + // but do it anyway to get the charging going for (const auto & l_nvdimm : i_nvdimmList) { l_err = nvdimmSetESPolicy(l_nvdimm); @@ -1181,73 +1329,133 @@ void nvdimm_restore(TargetHandleList &i_nvdimmList) } } - // Get the timeout values for the major ops at init - if (init_nv_timeout){ - for (const auto & l_nvdimm : i_nvdimmList){ - l_err = nvdimmGetTimeoutVal(l_nvdimm); + if (l_mpipl) + { + // During MPIPL, make sure any in-progress save is completed before proceeding + uint32_t l_poll = 0; + for (const auto & l_nvdimm : i_nvdimmList) + { + //Check save progress + l_err = nvdimmPollBackupDone(l_nvdimm, l_poll); + if (l_err) { - nvdimmSetStatusFlag(l_nvdimm, NSTD_ERR); + //@TODO RTC 199645 - add HW callout on dimm target + //Backup is taking longer than the allotted time here. + nvdimmSetStatusFlag(l_nvdimm, NSTD_ERR_NOPRSV); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_restore() nvdimm[%X], error backing up the DRAM!", + TARGETING::get_huid(l_nvdimm)); + errlCommit(l_err, NVDIMM_COMP_ID); break; } } - init_nv_timeout = false; } + // Start the restore + l_err = nvdimmRestore(i_nvdimmList, l_mpipl); + if (l_err) { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_restore() - Failing nvdimmGetTimeoutVal()"); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_restore() - Failing nvdimmRestore()"); errlCommit( l_err, NVDIMM_COMP_ID ); break; } - // Change back to page 0 just in case, as all of the remaining - // operations will be using offsets in page 0 + // Make sure the energy source is fully charged before erasing the images + // Doing this on all the nvdimms since the ones w/o image will need + // to be fully charged before arming the trigger + uint32_t l_poll = 0; for (const auto & l_nvdimm : i_nvdimmList) { - l_err = nvdimmOpenPage(l_nvdimm, ZERO); - if (l_err) - { - nvdimmSetStatusFlag(l_nvdimm, NSTD_ERR); - break; - } + l_err = nvdimmPollESChargeStatus(l_nvdimm, l_poll); + if (l_err){ + nvdimmSetStatusFlag(l_nvdimm, NSTD_ERR_NOBKUP); + errlCommit( l_err, NVDIMM_COMP_ID ); + } } + }while(0); + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimm_restore()"); +} + +/** + * @brief NVDIMM initialization + * - Checks for ready state + * - Gathers timeout values + * - Waits for the ongoing backup to complete + * - Disarms the trigger for draminit + * + * @param[in] i_nvdimm - nvdimm target + * + */ +void nvdimm_init(Target *i_nvdimm) +{ + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimm_init() nvdimm[%X]", + TARGETING::get_huid(i_nvdimm)); + + errlHndl_t l_err = nullptr; + + do + { + l_err = nvdimmReady(i_nvdimm); + if (l_err) { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_restore() - Failing open page"); - errlCommit( l_err, NVDIMM_COMP_ID ); + nvdimmSetStatusFlag(i_nvdimm, NSTD_ERR); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_int() nvdimm[%X], controller not ready", + TARGETING::get_huid(i_nvdimm)); + errlCommit(l_err, NVDIMM_COMP_ID); break; } - // Start the restore - l_err = nvdimmRestore(i_nvdimmList); - + // Get the timeout values for the major ops at init + l_err = nvdimmGetTimeoutVal(i_nvdimm); if (l_err) { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_restore() - Failing nvdimmRestore()"); - errlCommit( l_err, NVDIMM_COMP_ID ); + nvdimmSetStatusFlag(i_nvdimm, NSTD_ERR); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_int() nvdimm[%X], error retrieving timeout values", + TARGETING::get_huid(i_nvdimm)); + errlCommit(l_err, NVDIMM_COMP_ID); break; } - // Make sure the energy source is fully charged before erasing the images - // Doing this on all the nvdimms since the ones w/o image will need - // to be fully charged before arming the trigger + //Check save progress uint32_t l_poll = 0; - for (const auto & l_nvdimm : i_nvdimmList) + l_err = nvdimmPollBackupDone(i_nvdimm, l_poll); + + if (l_err) { - l_err = nvdimmPollESChargeStatus(l_nvdimm, l_poll); + //@TODO RTC 199645 - add HW callout on dimm target + //Backup is taking longer than the allotted time here. + nvdimmSetStatusFlag(i_nvdimm, NSTD_ERR_NOPRSV); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_int() nvdimm[%X], error backing up the DRAM!", + TARGETING::get_huid(i_nvdimm)); + errlCommit(l_err, NVDIMM_COMP_ID); + break; + } - if (l_err){ - nvdimmSetStatusFlag(l_nvdimm, NSTD_ERR_NOBKUP); - errlCommit( l_err, NVDIMM_COMP_ID ); - } + // Disarm the ddr_resetn here in case it came in armed. When the nvdimm is + // armed the reset_n is masked off from the host, meaning the drams won't + // be able to get reset properly later, causing training to fail. + l_err = nvdimmChangeArmState(i_nvdimm, DISARM_TRIGGER); + + if (l_err) + { + //@TODO RTC 199645 - add HW callout on dimm target + //Failed to disarm the reset_n trigger + nvdimmSetStatusFlag(i_nvdimm, NSTD_ERR_NOPRSV); + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_init() nvdimm[%X], error disarming the nvdimm!", + TARGETING::get_huid(i_nvdimm)); + errlCommit(l_err, NVDIMM_COMP_ID); + break; } }while(0); - TRACFCOMP(g_trac_nvdimm, EXIT_MRK"nvdimm_restore()"); + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimm_init() nvdimm[%X]", + TARGETING::get_huid(i_nvdimm)); } #endif diff --git a/src/usr/isteps/nvdimm/nvdimm.H b/src/usr/isteps/nvdimm/nvdimm.H index 9e60d3224..4457424cb 100644 --- a/src/usr/isteps/nvdimm/nvdimm.H +++ b/src/usr/isteps/nvdimm/nvdimm.H @@ -41,27 +41,239 @@ extern trace_desc_t* g_trac_nvdimm; namespace NVDIMM { -//Defining necessary offsets for page0 -//Refer to BAEBI spec for details -//https://www.jedec.org/standards-documents/docs/jesd245a -enum i2cReg : uint8_t +// I2C registers for page 0-3, extracted from JEDEC BAEBI spec +// Refer to BAEBI spec for details +// https://www.jedec.org/standards-documents/docs/jesd245a +// The 2 least significant nibbles indicate the register address. +// The most significant nibble indicates the page number where the +// register belongs. +// e.g. for 0x00A, 0x0 = page number, 0x0A = register address +enum i2cReg : uint16_t { - ARM_CMD = 0x45, - ARM_STATUS = 0x6A, - NVDIMM_FUNC_CMD = 0x43, - NVDIMM_CMD_STATUS0 = 0x61, - CSAVE_INFO = 0x80, - CSAVE_STATUS = 0x64, - RESTORE_STATUS = 0x66, - SET_ES_POLICY_CMD = 0x49, - SET_ES_POLICY_STATUS = 0x70, - NVDIMM_MGT_CMD0 = 0x40, - ERASE_STATUS = 0x68, - MODULE_HEALTH = 0xA0, - MODULE_HEALTH_STATUS0 = 0xA1, - MODULE_HEALTH_STATUS1 = 0xA2, - OPEN_PAGE = 0x00, - NVDIMM_READY = 0x60, + OPEN_PAGE = 0x000, + STD_NUM_PAGES = 0x001, + VENDOR_START_PAGES = 0x002, + VENDOR_NUM_PAGES = 0x003, + HWREV = 0x004, + SPECREV = 0x006, + SLOT0_FWREV0 = 0x007, + SLOT0_FWREV1 = 0x008, + SLOT1_FWREV0 = 0x009, + SLOT1_FWREV1 = 0x00A, + SLOT0_SUBFWREV = 0x00B, + SLOT1_SUBFWREV = 0x00C, + CAPABILITIES0 = 0x010, + CAPABILITIES1 = 0x011, + ENERGY_SOURCE_POLICY = 0x014, + HOST_MAX_OPERATION_RETRY = 0x015, + CSAVE_TRIGGER_SUPPORT = 0x016, + EVENT_NOTIFICATION_SUPPORT = 0x017, + CSAVE_TIMEOUT0 = 0x018, + CSAVE_TIMEOUT1 = 0x019, + PAGE_SWITCH_LATENCY0 = 0x01A, + PAGE_SWITCH_LATENCY1 = 0x01B, + RESTORE_TIMEOUT0 = 0x01C, + RESTORE_TIMEOUT1 = 0x01D, + ERASE_TIMEOUT0 = 0x01E, + ERASE_TIMEOUT1 = 0x01F, + ARM_TIMEOUT0 = 0x020, + ARM_TIMEOUT1 = 0x021, + FIRMWARE_OPS_TIMEOUT0 = 0x022, + FIRMWARE_OPS_TIMEOUT1 = 0x023, + ABORT_CMD_TIMEOUT = 0x024, + MAX_RUNTIME_POWER0 = 0x027, + MAX_RUNTIME_POWER1 = 0x028, + CSAVE_POWER_REQ0 = 0x029, + CSAVE_POWER_REQ1 = 0x02A, + CSAVE_IDLE_POWER_REQ0 = 0x02B, + CSAVE_IDLE_POWER_REQ1 = 0x02C, + CSAVE_MIN_VOLT_REQ0 = 0x02D, + CSAVE_MIN_VOLT_REQ1 = 0x02E, + CSAVE_MAX_VOLT_REQ0 = 0x02F, + CSAVE_MAX_VOLT_REQ1 = 0x030, + VENDOR_LOG_PAGE_SIZE = 0x031, + REGION_BLOCK_SIZE = 0x032, + OPERATIONAL_UNIT_OPS_TIMEOUT0 = 0x033, + OPERATIONAL_UNIT_OPS_TIMEOUT1 = 0x034, + FACTORY_DEFAULT_TIMEOUT0 = 0x035, + FACTORY_DEFAULT_TIMEOUT1 = 0x036, + MIN_OPERATING_TEMP0 = 0x038, + MIN_OPERATING_TEMP1 = 0x039, + MAX_OPERATING_TEMP0 = 0x03A, + MAX_OPERATING_TEMP1 = 0x03B, + NVDIMM_MGT_CMD0 = 0x040, + NVDIMM_MGT_CMD1 = 0x041, + NVDIMM_FUNC_CMD = 0x043, + ARM_CMD = 0x045, + SET_EVENT_NOTIFICATION_CMD = 0x047, + SET_ES_POLICY_CMD = 0x049, + FIRMWARE_OPS_CMD = 0x04A, + OPERATIONAL_UNIT_OPS_CMD = 0x04B, + NVDIMM_READY = 0x060, + NVDIMM_CMD_STATUS0 = 0x061, + NVDIMM_CMD_STATUS1 = 0x062, + CSAVE_STATUS = 0x064, + RESTORE_STATUS = 0x066, + ERASE_STATUS = 0x068, + ARM_STATUS = 0x06A, + FACTORY_DEFAULT_STATUS = 0x06C, + SET_EVENT_NOTIFICATION_STATUS = 0x06E, + SET_ES_POLICY_STATUS = 0x070, + FIRMWARE_OPS_STATUS = 0x071, + OPERATIONAL_UNIT_OPS_STATUS = 0x072, + RESTORE_FAIL_INFO = 0x088, + OPERATIONAL_UNIT_FAIL_INFO = 0x08F, + CSAVE_INFO = 0x080, + CSAVE_FAIL_INFO0 = 0x084, + CSAVE_FAIL_INFO1 = 0x085, + NVM_LIFETIME_ERROR_THRESHOLD = 0x090, + ES_LIFETIME_ERROR_THRESHOLD = 0x091, + ES_TEMP_ERROR_HIGH_THRESHOLD0 = 0x094, + ES_TEMP_ERROR_HIGH_THRESHOLD1 = 0x095, + ES_TEMP_ERROR_LOW_THRESHOLD0 = 0x096, + ES_TEMP_ERROR_LOW_THRESHOLD1 = 0x097, + NVM_LIFETIME_WARNING_THRESHOLD = 0x098, + ES_LIFETIME_WARNING_THRESHOLD = 0x099, + ES_TEMP_WARNING_HIGH_THRESHOLD0 = 0x09C, + ES_TEMP_WARNING_HIGH_THRESHOLD1 = 0x09D, + ES_TEMP_WARNING_LOW_THRESHOLD0 = 0x09E, + ES_TEMP_WARNING_LOW_THRESHOLD1 = 0x09F, + MODULE_HEALTH = 0x0A0, + MODULE_HEALTH_STATUS0 = 0x0A1, + MODULE_HEALTH_STATUS1 = 0x0A2, + ERROR_THRESHOLD_STATUS = 0x0A5, + WARNING_THRESHOLD_STATUS = 0x0A7, + AUTO_ES_HEALTH_FREQUENCY = 0x0A9, + MODULE_OPS_CONFIG = 0x0AA, + NVM_LIFETIME = 0x0C0, + ES_HWREV = 0x104, + ES_FWREV0 = 0x106, + ES_FWREV1 = 0x107, + SLOT0_ES_FWREV0 = 0x108, + SLOT0_ES_FWREV1 = 0x109, + SLOT1_ES_FWREV0 = 0x10A, + SLOT1_ES_FWREV1 = 0x10B, + ES_CHARGE_TIMEOUT0 = 0x110, + ES_CHARGE_TIMEOUT1 = 0x111, + ES_ATTRIBUTES = 0x114, + ES_TECH = 0x115, + MIN_ES_OPERATING_TEMP0 = 0x116, + MIN_ES_OPERATING_TEMP1 = 0x117, + MAX_ES_OPERATING_TEMP0 = 0x118, + MAX_ES_OPERATING_TEMP1 = 0x119, + ES_FUNC_CMD0 = 0x130, + ES_CMD_STATUS0 = 0x150, + ES_LIFETIME = 0x170, + ES_TEMP0 = 0x171, + ES_TEMP1 = 0x172, + ES_RUNTIME0 = 0x173, + ES_RUNTIME1 = 0x174, + LAST_CSAVE_DURATION0 = 0x204, + LAST_CSAVE_DURATION1 = 0x205, + LAST_RESTORE_DURATION0 = 0x206, + LAST_RESTORE_DURATION1 = 0x207, + LAST_ERASE_DURATION0 = 0x208, + LAST_ERASE_DURATION1 = 0x209, + CSAVE_SUCCESS_COUNT0 = 0x20A, + CSAVE_SUCCESS_COUNT1 = 0x20B, + RESTORE_SUCCESS_COUNT0 = 0x20C, + RESTORE_SUCCESS_COUNT1 = 0x20D, + ERASE_SUCCESS_COUNT0 = 0x20E, + ERASE_SUCCESS_COUNT1 = 0x20F, + POWER_CYCLE_COUNT0 = 0x210, + POWER_CYCLE_COUNT1 = 0x211, + CSAVE_FAILURE_COUNT0 = 0x212, + CSAVE_FAILURE_COUNT1 = 0x213, + RESTORE_FAILURE_COUNT0 = 0x214, + RESTORE_FAILURE_COUNT1 = 0x215, + ERASE_FAILURE_COUNT0 = 0x216, + ERASE_FAILURE_COUNT1 = 0x217, + LAST_ARM_DURATION0 = 0x218, + LAST_ARM_DURATION1 = 0x219, + LAST_FACTORY_DEFAULT_DURATION0 = 0x21A, + LAST_FACTORY_DEFAULT_DURATION1 = 0x21B, + LAST_FIRMWARE_OPS_DURATION0 = 0x21C, + LAST_FIRMWARE_OPS_DURATION1 = 0x21D, + LAST_OPERATIONAL_UNIT_OPS_DURATION0 = 0x21E, + LAST_OPERATIONAL_UNIT_OPS_DURATION1 = 0x21F, + ARM_SUCCESS_COUNT0 = 0x220, + ARM_SUCCESS_COUNT1 = 0x221, + FACTORY_DEFAULT_SUCCESS_COUNT0 = 0x222, + FACTORY_DEFAULT_SUCCESS_COUNT1 = 0x223, + FIRMWARE_SUCCESS_COUNT0 = 0x224, + FIRMWARE_SUCCESS_COUNT1 = 0x225, + OPERATIONAL_UNIT_SUCCESS_COUNT0 = 0x226, + OPERATIONAL_UNIT_SUCCESS_COUNT1 = 0x227, + ARM_FAILURE_COUNT0 = 0x228, + ARM_FAILURE_COUNT1 = 0x229, + FACTORY_DEFAULT_FAILURE_COUNT0 = 0x22A, + FACTORY_DEFAULT_FAILURE_COUNT1 = 0x22B, + FIRMWARE_FAILURE_COUNT0 = 0x22C, + FIRMWARE_FAILURE_COUNT1 = 0x22D, + OPERATIONAL_UNIT_FAILURE_COUNT0 = 0x22E, + OPERATIONAL_UNIT_FAILURE_COUNT1 = 0x22F, + INJECT_OPS_FAILURES0 = 0x260, + INJECT_OPS_FAILURES1 = 0x261, + INJECT_ES_FAILURES = 0x264, + INJECT_FW_FAILURES = 0x265, + INJECT_BAD_BLOCK_CAP = 0x267, + INJECT_ERROR_TYPE = 0x268, + DRAM_ECC_ERROR_COUNT = 0x280, + DRAM_THRESHOLD_ECC_COUNT = 0x281, + HOST_MANAGED_ES_ATTRIBUTES = 0x282, + HOST_CSAVE_FAIL = 0x283, + HOST_CSAVE_WORKFLOW_FAILURE_COUNT0 = 0x284, + HOST_CSAVE_WORKFLOW_FAILURE_COUNT1 = 0x285, + TYPED_BLOCK_DATA = 0x304, + REGION_ID0 = 0x305, + REGION_ID1 = 0x306, + BLOCK_ID = 0x307, + TYPED_BLOCK_DATA_SIZE0 = 0x308, + TYPED_BLOCK_DATA_SIZE1 = 0x309, + TYPED_BLOCK_DATA_SIZE2 = 0x30A, + OPERATIONAL_UNIT_ID0 = 0x30C, + OPERATIONAL_UNIT_ID1 = 0x30D, + OPERATIONAL_UNIT_SIZE0 = 0x310, + OPERATIONAL_UNIT_SIZE1 = 0x311, + OPERATIONAL_UNIT_SIZE2 = 0x312, + OPERATIONAL_UNIT_CRC0 = 0x314, + OPERATIONAL_UNIT_CRC1 = 0x315, + FW_REGION_CRC0 = 0x340, + FW_REGION_CRC1 = 0x341, + FW_SLOT_INFO = 0x342, + TYPED_BLOCK_DATA_BYTE0 = 0x380, + TYPED_BLOCK_DATA_BYTE1 = 0x381, + TYPED_BLOCK_DATA_BYTE2 = 0x382, + TYPED_BLOCK_DATA_BYTE3 = 0x383, + TYPED_BLOCK_DATA_BYTE4 = 0x384, + TYPED_BLOCK_DATA_BYTE5 = 0x385, + TYPED_BLOCK_DATA_BYTE6 = 0x386, + TYPED_BLOCK_DATA_BYTE7 = 0x387, + TYPED_BLOCK_DATA_BYTE8 = 0x388, + TYPED_BLOCK_DATA_BYTE9 = 0x389, + TYPED_BLOCK_DATA_BYTE10 = 0x38A, + TYPED_BLOCK_DATA_BYTE11 = 0x38B, + TYPED_BLOCK_DATA_BYTE12 = 0x38C, + TYPED_BLOCK_DATA_BYTE13 = 0x38D, + TYPED_BLOCK_DATA_BYTE14 = 0x38E, + TYPED_BLOCK_DATA_BYTE15 = 0x38F, + TYPED_BLOCK_DATA_BYTE16 = 0x390, + TYPED_BLOCK_DATA_BYTE17 = 0x391, + TYPED_BLOCK_DATA_BYTE18 = 0x392, + TYPED_BLOCK_DATA_BYTE19 = 0x393, + TYPED_BLOCK_DATA_BYTE20 = 0x394, + TYPED_BLOCK_DATA_BYTE21 = 0x395, + TYPED_BLOCK_DATA_BYTE22 = 0x396, + TYPED_BLOCK_DATA_BYTE23 = 0x397, + TYPED_BLOCK_DATA_BYTE24 = 0x398, + TYPED_BLOCK_DATA_BYTE25 = 0x399, + TYPED_BLOCK_DATA_BYTE26 = 0x39A, + TYPED_BLOCK_DATA_BYTE27 = 0x39B, + TYPED_BLOCK_DATA_BYTE28 = 0x39C, + TYPED_BLOCK_DATA_BYTE29 = 0x39D, + TYPED_BLOCK_DATA_BYTE30 = 0x39E, + TYPED_BLOCK_DATA_BYTE31 = 0x39F, + TYPED_BLOCK_DATA_OFFSET = 0x3E0, }; // Up to 10 pages per BAEBI Spec, @@ -80,11 +292,13 @@ enum i2c_in_values : uint8_t { ARM_RESETN_AND_ATOMIC_SAVE_AND_ERASE = 0x84, ARM_RESETN = 0x04, + DISARM_RESETN = 0x00, ES_DEV_MANAGE = 0x01, //0x01 for device manage ERASE_IMAGE = 0x08, RESTORE_IMAGE = 0x04, RESET_CTRLR = 0x01, VALID_IMAGE = 0x01, + RESET_CONTROLLER = 0x01, }; enum i2c_out_values : uint8_t @@ -107,7 +321,8 @@ enum i2c_out_values : uint8_t enum timeout : uint32_t { OPS_POLL_TIME_MS = 5000, - PAGE_SWITCH_POLL_TIME_NS = 100, + NV_READY_POLL_TIME_MS = 1000, + PAGE_SWITCH_POLL_TIME_NS = 100, }; // Assign an id to each of the 6 major ops @@ -121,6 +336,16 @@ enum ops_id : uint8_t CHARGE, }; +enum misc +{ + NO_PAGE_VERIFY = 0, + PAGE_VERIFY = 1, + ARM_TRIGGER = 1, + DISARM_TRIGGER = 0, + LOW = 0, + HIGH = 1, +}; + /** * @brief Wrapper to call deviceOp to read the NV controller via I2C * @@ -130,10 +355,13 @@ enum ops_id : uint8_t * * @param[out] o_data - returned data from read * + * @param[in] page_verify - read and verify the page associated to the given address. + * Change if needed. Default to true + * * @return errlHndl_t - Null if successful, otherwise a pointer to * the error log. */ -errlHndl_t nvdimmReadReg(TARGETING::Target* i_nvdimm, uint8_t i_addr, uint8_t & o_data ); +errlHndl_t nvdimmReadReg(TARGETING::Target* i_nvdimm, uint16_t i_addr, uint8_t & o_data, const bool page_verify = PAGE_VERIFY); /** * @brief Wrapper to call deviceOp to write the NV controller via I2C @@ -144,10 +372,36 @@ errlHndl_t nvdimmReadReg(TARGETING::Target* i_nvdimm, uint8_t i_addr, uint8_t & * * @param[in] i_data - data to register * + * @param[in] page_verify - read and verify the page associated to the given address. + * Change if needed. Default to true + * + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t nvdimmWriteReg(TARGETING::Target* i_nvdimm, uint16_t i_addr, uint8_t i_data, const bool page_verify = PAGE_VERIFY); + +/** + * @brief Check NV controller ready state + * + * @param[in] i_nvdimm - nvdimm target + * * @return errlHndl_t - Null if successful, otherwise a pointer to * the error log. */ -errlHndl_t nvdimmWriteReg(TARGETING::Target* i_nvdimm, uint8_t i_addr, uint8_t i_data ); +errlHndl_t nvdimmReady(TARGETING::Target *i_nvdimm); + +/** + * @brief This functions opens the NV controller to the specified page + * Refer to the BAEBI to see what each page does + * + * @param[in] i_nvdimm - nvdimm target with NV controller + * + * @param[in] i_page - page number to open to + * + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log + */ +errlHndl_t nvdimmOpenPage(TARGETING::Target *i_nvdimm, uint8_t i_page); /** * @brief This function polls the status register for the given ops_id diff --git a/src/usr/isteps/nvdimm/runtime/nvdimm_rt.C b/src/usr/isteps/nvdimm/runtime/nvdimm_rt.C index 9919c9c61..e4040f546 100644 --- a/src/usr/isteps/nvdimm/runtime/nvdimm_rt.C +++ b/src/usr/isteps/nvdimm/runtime/nvdimm_rt.C @@ -231,50 +231,6 @@ errlHndl_t notifyNvdimmProtectionChange(TARGETING::Target* i_target, return l_err; } - -bool nvdimmArm(TARGETING::TargetHandleList &i_nvdimmTargetList) -{ - bool o_arm_successful = true; - - TRACFCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmArm() %d", - i_nvdimmTargetList.size()); - - errlHndl_t l_err = nullptr; - - for (auto const l_nvdimm : i_nvdimmTargetList) - { - // skip if the nvdimm is in error state - if (NVDIMM::nvdimmInErrorState(l_nvdimm)) - { - // error state means arming not successful - o_arm_successful = false; - continue; - } - - l_err = NVDIMM::nvdimmArmResetN(l_nvdimm); - // If we run into any error here we will just - // commit the error log and move on. Let the - // system continue to boot and let the user - // salvage the data - if (l_err) - { - NVDIMM::nvdimmSetStatusFlag(l_nvdimm, NVDIMM::NSTD_ERR_NOBKUP); - // Committing the error as we don't want this to interrupt - // the boot. This will notify the user that action is needed - // on this module - l_err->setSev(ERRORLOG::ERRL_SEV_PREDICTIVE); - l_err->collectTrace(NVDIMM_COMP_NAME, 1024); - errlCommit( l_err, NVDIMM_COMP_ID ); - o_arm_successful = false; - continue; - } - } - - TRACFCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmArm() returning %d", - o_arm_successful); - return o_arm_successful; -} - /** * @brief This function polls the command status register for arm completion * (does not indicate success or fail) @@ -364,49 +320,77 @@ errlHndl_t nvdimmCheckArmSuccess(TARGETING::Target *i_nvdimm) return l_err; } -/** - * @brief This function arms the trigger to enable backup in the event - * of power loss (DDR Reset_n goes low) in conjunction with - * ATOMIC_SAVE_AND_ERASE. A separate erase command is not required - * as the image will get erased immediately before backup on the - * next catastrophic event. - * - * @param[in] i_nvdimm - nvdimm target with NV controller - * - * @return errlHndl_t - Null if successful, otherwise a pointer to - * the error log. - */ -errlHndl_t nvdimmArmResetN(TARGETING::Target *i_nvdimm) +bool nvdimmArm(TARGETING::TargetHandleList &i_nvdimmTargetList) { - TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmArmResetN() nvdimm[%X]", - TARGETING::get_huid(i_nvdimm)); + bool o_arm_successful = true; - errlHndl_t l_err = nullptr; + TRACFCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmArm() %d", + i_nvdimmTargetList.size()); - // Setting ATOMIC_SAVE_AND_ERASE in conjunction with ARM_RESETN. With this, - // the content of the persistent data is not erased until immediately after - // the next catastrophic event has occurred. - l_err = nvdimmWriteReg(i_nvdimm, ARM_CMD, ARM_RESETN_AND_ATOMIC_SAVE_AND_ERASE); + errlHndl_t l_err = nullptr; - if (l_err) - { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmArmResetN() nvdimm[%X] error arming nvdimm!!", - TARGETING::get_huid(i_nvdimm)); - } - else + for (auto const l_nvdimm : i_nvdimmTargetList) { + // skip if the nvdimm is in error state + if (NVDIMM::nvdimmInErrorState(l_nvdimm)) + { + // error state means arming not successful + o_arm_successful = false; + continue; + } + + l_err = NVDIMM::nvdimmChangeArmState(l_nvdimm, ARM_TRIGGER); + // If we run into any error here we will just + // commit the error log and move on. Let the + // system continue to boot and let the user + // salvage the data + if (l_err) + { + NVDIMM::nvdimmSetStatusFlag(l_nvdimm, NVDIMM::NSTD_ERR_NOBKUP); + // Committing the error as we don't want this to interrupt + // the boot. This will notify the user that action is needed + // on this module + l_err->setSev(ERRORLOG::ERRL_SEV_PREDICTIVE); + l_err->collectTrace(NVDIMM_COMP_NAME, 1024); + errlCommit( l_err, NVDIMM_COMP_ID ); + o_arm_successful = false; + continue; + } + // Arm happens one module at a time. No need to set any offset on the counter uint32_t l_poll = 0; - l_err = nvdimmPollArmDone(i_nvdimm, l_poll); - if (!l_err) + l_err = nvdimmPollArmDone(l_nvdimm, l_poll); + if (l_err) + { + NVDIMM::nvdimmSetStatusFlag(l_nvdimm, NVDIMM::NSTD_ERR_NOBKUP); + // Committing the error as we don't want this to interrupt + // the boot. This will notify the user that action is needed + // on this module + l_err->setSev(ERRORLOG::ERRL_SEV_PREDICTIVE); + l_err->collectTrace(NVDIMM_COMP_NAME, 1024); + errlCommit( l_err, NVDIMM_COMP_ID ); + o_arm_successful = false; + continue; + } + + l_err = nvdimmCheckArmSuccess(l_nvdimm); + if (l_err) { - l_err = nvdimmCheckArmSuccess(i_nvdimm); + NVDIMM::nvdimmSetStatusFlag(l_nvdimm, NVDIMM::NSTD_ERR_NOBKUP); + // Committing the error as we don't want this to interrupt + // the boot. This will notify the user that action is needed + // on this module + l_err->setSev(ERRORLOG::ERRL_SEV_PREDICTIVE); + l_err->collectTrace(NVDIMM_COMP_NAME, 1024); + errlCommit( l_err, NVDIMM_COMP_ID ); + o_arm_successful = false; + continue; } } - TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmArmResetN() nvdimm[%X]", - TARGETING::get_huid(i_nvdimm)); - return l_err; + TRACFCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmArm() returning %d", + o_arm_successful); + return o_arm_successful; } /** diff --git a/src/usr/isteps/pm/runtime/rt_pm.C b/src/usr/isteps/pm/runtime/rt_pm.C index 9397d0e83..7ee9e0924 100644 --- a/src/usr/isteps/pm/runtime/rt_pm.C +++ b/src/usr/isteps/pm/runtime/rt_pm.C @@ -47,8 +47,6 @@ #include <targeting/common/utilFilter.H> #include <targeting/common/targetservice.H> -#include <isteps/nvdimm/nvdimm.H> - #include <scom/scomif.H> #include <scom/wakeup.H> diff --git a/src/usr/vpd/spdDDR4.H b/src/usr/vpd/spdDDR4.H index d263f9cd4..bf4d0dfc8 100755 --- a/src/usr/vpd/spdDDR4.H +++ b/src/usr/vpd/spdDDR4.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2016 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -135,6 +135,7 @@ const KeywordData ddr4Data[] = { BASE_CONFIG_CRC, 0x7f, 0x02, 0x00, 0x00, true, false, NA }, { DRAM_STEPPING, 0x160, 0x01, 0x00, 0x00, false, false, NA }, { MANUFACTURING_SECTION_CRC, 0x17f, 0x02, 0x00, 0x00, true, false, NA }, + { NVM_INIT_TIME, 0xCB, 0x01, 0x00, 0x00, false, false, NA }, // Module Specific fields supported on both DDR3 and DDR4 { MODSPEC_COM_NOM_HEIGHT_MAX, 0x80, 0x01, 0x1f, 0x00, false, false, ALL }, { MODSPEC_COM_MAX_THICK_BACK, 0x81, 0x01, 0xf0, 0x04, false, false, ALL }, |