diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/runtime/interface.h | 20 | ||||
-rw-r--r-- | src/include/usr/isteps/nvdimm/nvdimm.H | 70 | ||||
-rw-r--r-- | src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H | 4 | ||||
-rw-r--r-- | src/include/usr/targeting/common/util.H | 16 | ||||
-rw-r--r-- | src/usr/isteps/nvdimm/nvdimm.C | 151 | ||||
-rw-r--r-- | src/usr/isteps/nvdimm/nvdimm.H | 13 | ||||
-rw-r--r-- | src/usr/isteps/nvdimm/runtime/makefile | 4 | ||||
-rw-r--r-- | src/usr/isteps/nvdimm/runtime/nvdimm_rt.C | 433 | ||||
-rw-r--r-- | src/usr/isteps/pm/pm_common.C | 22 | ||||
-rw-r--r-- | src/usr/isteps/pm/runtime/rt_pm.C | 40 | ||||
-rw-r--r-- | src/usr/targeting/common/util.C | 45 | ||||
-rw-r--r-- | src/usr/targeting/common/xmltohb/attribute_types.xml | 35 | ||||
-rw-r--r-- | src/usr/targeting/common/xmltohb/target_types.xml | 3 | ||||
-rwxr-xr-x | src/usr/targeting/targetservicestart.C | 9 | ||||
-rw-r--r-- | src/usr/util/runtime/rt_cmds.C | 69 | ||||
-rw-r--r-- | src/usr/util/runtime/rt_fwreq_helper.C | 60 |
16 files changed, 764 insertions, 230 deletions
diff --git a/src/include/runtime/interface.h b/src/include/runtime/interface.h index 70b6e7e1d..31f5eaddc 100644 --- a/src/include/runtime/interface.h +++ b/src/include/runtime/interface.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -98,7 +98,7 @@ enum MemoryError_t #define HBRT_RC_NEXT_OPEN_RC ((int)(0x0u - 0x1009u)) /* 0xFFFF_EFF7 */ /** End return codes for scom_read, scom_write. */ - + /** * I2C Master Description: chip, engine and port packed into @@ -551,6 +551,14 @@ typedef struct hostInterfaces HBRT_FW_MSG_HBRT_FSP_RESP = 6, HBRT_FW_MSG_TYPE_I2C_LOCK = 7, HBRT_FW_MSG_TYPE_SBE_STATE = 8, + HBRT_FW_MSG_TYPE_NVDIMM_PROTECTION = 9, + }; + + // NVDIMM protection state enum + enum + { + HBRT_FW_NVDIMM_NOT_PROTECTED = 0, + HBRT_FW_NVDIMM_PROTECTED = 1 }; struct hbrt_fw_msg // define struct hbrt_fw_msg @@ -616,6 +624,14 @@ typedef struct hostInterfaces } __attribute__ ((packed)) sbe_state; // This struct is sent from HBRT with + // io_type set to HBRT_FW_MSG_TYPE_NVDIMM_PROTECTION + struct + { + uint64_t i_procId; // processor ID of the NVDIMM with/without OCC protection + uint64_t i_state; // NVDIMM protection state enum + } __attribute__ ((packed)) nvdimm_protection_state; + + // This struct is sent from HBRT with // io_type set to HBRT_FW_MSG_HBRT_FSP_REQ or // HBRT_FW_MSG_HBRT_FSP_RESP // This struct sends/receives an MBox message to the FSP diff --git a/src/include/usr/isteps/nvdimm/nvdimm.H b/src/include/usr/isteps/nvdimm/nvdimm.H index bfe39fcd0..c1df3033e 100644 --- a/src/include/usr/isteps/nvdimm/nvdimm.H +++ b/src/include/usr/isteps/nvdimm/nvdimm.H @@ -55,26 +55,29 @@ enum void nvdimm_restore(TARGETING::TargetHandleList &i_nvdimmList); #endif + /** - * @brief This function arms the trigger to enable backup in the event - * of power loss (DDR Reset_n goes low) + * @brief This function erases image on the nvdimm target * * @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); +errlHndl_t nvdimmEraseNF(TARGETING::Target *i_nvdimm); /** - * @brief This function erases image on the nvdimm target + * @brief Set the status flag * - * @param[in] i_nvdimm - nvdimm target with NV controller + * @param[in] i_nvdimm - nvdimm target + * + * @param[in] i_status_flag - status flag to set for each nvdimm * - * @return errlHndl_t - Null if successful, otherwise a pointer to - * the error log. */ -errlHndl_t nvdimmEraseNF(TARGETING::Target *i_nvdimm); +void nvdimmSetStatusFlag(TARGETING::Target *i_nvdimm, const uint8_t i_status_flag); + + +#ifdef __HOSTBOOT_RUNTIME /** * @brief Check nvdimm error state @@ -86,14 +89,57 @@ errlHndl_t nvdimmEraseNF(TARGETING::Target *i_nvdimm); bool nvdimmInErrorState(TARGETING::Target *i_nvdimm); /** - * @brief Set the status flag + * @brief This function arms the trigger to enable backup in the event + * of power loss (DDR Reset_n goes low) * - * @param[in] i_nvdimm - nvdimm target + * @param[in] i_nvdimm - nvdimm target with NV controller * - * @param[in] i_status_flag - status flag to set for each nvdimm + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t nvdimmArmResetN(TARGETING::Target *i_nvdimm); + +/** + * @brief Arms the trigger to enable backup in the event of a power loss + * on each NVDIMM + * + * The trigger (DDR_RESETN to the DIMM) is used to tell the NVDIMM + * that we have an EPOW event, so the NV controller can backup the + * data from the DRAM to flash. This will enable the NV controller + * to react when it sees the trigger toggles. * + * @param[in] i_nvdimmTargetList : list of dimms that are NVDIMMs + * @return true if no errors logged, else false */ -void nvdimmSetStatusFlag(TARGETING::Target *i_nvdimm, const uint8_t i_status_flag); +bool nvdimmArm(TARGETING::TargetHandleList &i_nvdimmTargetList); + + +/** + * @brief NVDIMM protection state + * + * NOT_PROTECTED - default state + * PROTECTED - switches to this when armed & OCC is in control + * UNPROTECTED_BECAUSE_ERROR - PRD detected error on NV controller + * Note: error will stay with target preventing PROTECTED status + * until power is cycled again + */ +enum nvdimm_protection_t +{ + NOT_PROTECTED = 0, + PROTECTED = 1, + UNPROTECTED_BECAUSE_ERROR = 2 +}; + +/** + * @brief Notify PHYP of NVDIMM protection status + * + * @param i_target Processor with NVDIMM + * @param i_state Protection state of NVDIMM + */ +errlHndl_t notifyNvdimmProtectionChange(TARGETING::Target* i_target, + const nvdimm_protection_t i_state); +#endif + } #endif // NVDIMM_EXT_H__ diff --git a/src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H b/src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H index bde22b942..0b48e94a0 100644 --- a/src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H +++ b/src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H @@ -72,7 +72,7 @@ enum nvdimmModuleId NVDIMM_CHECK_ERASE = 0x16, NVDIMM_ARM_ERASE = 0x17, NVDIMM_CHECK_READY = 0x18, - + NOTIFY_NVDIMM_PROTECTION_CHG = 0x19, }; /** @@ -111,7 +111,7 @@ enum nvdimmReasonCode NVDIMM_ERASE_FAILED = NVDIMM_COMP_ID | 0x19, // Failure to erase NVDIMM_RESTORE_FAILED = NVDIMM_COMP_ID | 0x1A, // Failure to restore NVDIMM_NOT_READY = NVDIMM_COMP_ID | 0x1B, // NVDIMM not ready for host to access - + NVDIMM_NULL_FIRMWARE_REQUEST_PTR = NVDIMM_COMP_ID | 0x1C, // Firmware request is NULL }; enum UserDetailsTypes diff --git a/src/include/usr/targeting/common/util.H b/src/include/usr/targeting/common/util.H index 971408d16..e26e0c795 100644 --- a/src/include/usr/targeting/common/util.H +++ b/src/include/usr/targeting/common/util.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2012,2018 */ +/* Contributors Listed Below - COPYRIGHT 2012,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -38,6 +38,8 @@ namespace TARGETING { class Target; +typedef Target* TargetHandle_t; +typedef std::vector<TargetHandle_t> TargetHandleList; /** * @brief Macro which indicates whether to translate addresses or not @@ -172,6 +174,7 @@ bool orderByNodeAndPosition( Target* i_firstProc, */ uint8_t is_fused_mode( ); + /** * @brief Determine if the given dimm target is an NVDIMM * @@ -181,6 +184,15 @@ uint8_t is_fused_mode( ); */ bool isNVDIMM( TARGETING::Target * i_target ); -} +/** + * @brief Grab list of NVDIMMs under the processor + * + * @param[in] i_proc : processor under which to search for NVDIMMs + * + * @return List of DIMM targets that are NVDIMMs + */ +TARGETING::TargetHandleList getProcNVDIMMs( TARGETING::Target * i_proc ); + +} // TARGETING #endif // __TARGETING_COMMON_UTIL_H diff --git a/src/usr/isteps/nvdimm/nvdimm.C b/src/usr/isteps/nvdimm/nvdimm.C index 9d5b668c0..fdc0240a9 100644 --- a/src/usr/isteps/nvdimm/nvdimm.C +++ b/src/usr/isteps/nvdimm/nvdimm.C @@ -205,26 +205,6 @@ void nvdimmSetStatusFlag(Target *i_nvdimm, const uint8_t i_status_flag) ,TARGETING::get_huid(i_nvdimm), i_status_flag); } -/** - * @brief Check nvdimm error state - * - * @param[in] i_nvdimm - nvdimm target - * - * @return bool - true if nvdimm is in any error state, false otherwise - */ -bool nvdimmInErrorState(Target *i_nvdimm) -{ - TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmInErrorState() HUID[%X]",TARGETING::get_huid(i_nvdimm)); - - uint8_t l_statusFlag = i_nvdimm->getAttr<TARGETING::ATTR_NV_STATUS_FLAG>(); - bool l_ret = true; - - if ((l_statusFlag & NSTD_ERR) == 0) - l_ret = false; - - TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmInErrorState() HUID[%X]",TARGETING::get_huid(i_nvdimm)); - return l_ret; -} /** * @brief Check NV controller ready state @@ -447,31 +427,6 @@ errlHndl_t nvdimmPollEraseDone(Target* i_nvdimm, return l_err; } -/** - * @brief This function polls the command status register for arm completion - * (does not indicate success or fail) - * - * @param[in] i_nvdimm - nvdimm target with NV controller - * - * @param[out] o_poll - total polled time in ms - * - * @return errlHndl_t - Null if successful, otherwise a pointer to - * the error log. - */ -errlHndl_t nvdimmPollArmDone(Target* i_nvdimm, - uint32_t &o_poll) -{ - TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmPollArmDone() nvdimm[%X]", TARGETING::get_huid(i_nvdimm) ); - - errlHndl_t l_err = nullptr; - - l_err = nvdimmPollStatus ( i_nvdimm, ARM, o_poll); - - TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmPollArmDone() nvdimm[%X]", - TARGETING::get_huid(i_nvdimm)); - - return l_err; -} /** * @brief This function polls the command status register for backup power @@ -611,113 +566,7 @@ errlHndl_t nvdimmSetESPolicy(Target* i_nvdimm) } -/** - * @brief This function checks the arm status register to make sure - * the trigger has been armed to ddr_reset_n - * - * @param[in] i_nvdimm - nvdimm target with NV controller - * - * @return errlHndl_t - Null if successful, otherwise a pointer to - * the error log. - */ -errlHndl_t nvdimmCheckArmSuccess(Target *i_nvdimm) -{ - TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmCheckArmSuccess() nvdimm[%X]", - TARGETING::get_huid(i_nvdimm)); - - errlHndl_t l_err = nullptr; - uint8_t l_data = 0; - - l_err = nvdimmReadReg(i_nvdimm, ARM_STATUS, l_data); - - if (l_err) - { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmCheckArmSuccess() nvdimm[%X]" - "failed to read arm status reg!",TARGETING::get_huid(i_nvdimm)); - } - else if ((l_data & ARM_SUCCESS) != ARM_SUCCESS) - { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmCheckArmSuccess() nvdimm[%X]" - "failed to arm!",TARGETING::get_huid(i_nvdimm)); - /*@ - *@errortype - *@reasoncode NVDIMM_ARM_FAILED - *@severity ERRORLOG_SEV_PREDICTIVE - *@moduleid NVDIMM_SET_ARM - *@userdata1[0:31] Related ops (0xff = NA) - *@userdata1[32:63] Target Huid - *@userdata2 <UNUSED> - *@devdesc Encountered error arming the catastrophic save - * trigger on NVDIMM. Make sure an energy source - * is connected to the NVDIMM and the ES policy - * is set properly - *@custdesc NVDIMM encountered error arming save trigger - */ - l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_PREDICTIVE, - NVDIMM_SET_ARM, - NVDIMM_ARM_FAILED, - NVDIMM_SET_USER_DATA_1(ARM, TARGETING::get_huid(i_nvdimm)), - 0x0, - ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); - - l_err->collectTrace(NVDIMM_COMP_NAME, 256 ); - //@TODO RTC 199645 - add HW callout on dimm target - //failure to arm could mean internal NV controller error or - //even error on the battery pack. NVDIMM will lose persistency - //if failed to arm trigger - } - - TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmCheckArmSuccess() nvdimm[%X] ret[%X]", - TARGETING::get_huid(i_nvdimm), l_data); - - 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(Target *i_nvdimm) -{ - TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmArmResetN() nvdimm[%X]", - TARGETING::get_huid(i_nvdimm)); - - errlHndl_t l_err = nullptr; - - // 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); - - if (l_err) - { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmArmResetN() nvdimm[%X] error arming nvdimm!!", - TARGETING::get_huid(i_nvdimm)); - } - else - { - // 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 = nvdimmCheckArmSuccess(i_nvdimm); - } - } - - TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmArmResetN() nvdimm[%X]", - TARGETING::get_huid(i_nvdimm)); - return l_err; -} /** * @brief This function checks for valid image on the given target diff --git a/src/usr/isteps/nvdimm/nvdimm.H b/src/usr/isteps/nvdimm/nvdimm.H index f4d9e0dac..9e60d3224 100644 --- a/src/usr/isteps/nvdimm/nvdimm.H +++ b/src/usr/isteps/nvdimm/nvdimm.H @@ -149,6 +149,19 @@ errlHndl_t nvdimmReadReg(TARGETING::Target* i_nvdimm, uint8_t i_addr, uint8_t & */ errlHndl_t nvdimmWriteReg(TARGETING::Target* i_nvdimm, uint8_t i_addr, uint8_t i_data ); +/** + * @brief This function polls the status register for the given ops_id + * + * @param[in] i_nvdimm - nvdimm target with NV controller + * + * @param[in] i_ops_id - id assigned to each operation in nvdimm.H + * + * @param[out] o_poll - total polled time in ms + * + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t nvdimmPollStatus(TARGETING::Target *i_nvdimm, ops_id i_ops_id, uint32_t &o_poll); } //End NVDIMM namespace diff --git a/src/usr/isteps/nvdimm/runtime/makefile b/src/usr/isteps/nvdimm/runtime/makefile index 85433ea66..a7da50d08 100644 --- a/src/usr/isteps/nvdimm/runtime/makefile +++ b/src/usr/isteps/nvdimm/runtime/makefile @@ -27,8 +27,10 @@ HOSTBOOT_RUNTIME = 1 ROOTPATH = ../../../../.. VPATH += ../ - MODULE = nvdimm_rt include ../nvdimm.mk + +OBJS += nvdimm_rt.o + include ${ROOTPATH}/config.mk diff --git a/src/usr/isteps/nvdimm/runtime/nvdimm_rt.C b/src/usr/isteps/nvdimm/runtime/nvdimm_rt.C new file mode 100644 index 000000000..9919c9c61 --- /dev/null +++ b/src/usr/isteps/nvdimm/runtime/nvdimm_rt.C @@ -0,0 +1,433 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/nvdimm/runtime/nvdimm_rt.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2019 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/** + * @file nvdimm_rt.C + * + * @brief NVDIMM functions only needed for runtime + */ +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <util/runtime/rt_fwreq_helper.H> +#include <targeting/common/attributes.H> +#include <targeting/common/commontargeting.H> +#include <targeting/common/util.H> +#include <targeting/common/utilFilter.H> +#include <usr/runtime/rt_targeting.H> +#include <runtime/interface.h> +#include <isteps/nvdimm/nvdimmreasoncodes.H> +#include <isteps/nvdimm/nvdimm.H> // implements some of these +#include "../nvdimm.H" // for g_trac_nvdimm + +//#define TRACUCOMP(args...) TRACFCOMP(args) +#define TRACUCOMP(args...) + +namespace NVDIMM +{ + +/** +* @brief Notify PHYP of NVDIMM OCC protection status +*/ +errlHndl_t notifyNvdimmProtectionChange(TARGETING::Target* i_target, + const nvdimm_protection_t i_state) +{ + errlHndl_t l_err = nullptr; + + // default to send a not protected status + uint64_t l_nvdimm_protection_state = + hostInterfaces::HBRT_FW_NVDIMM_NOT_PROTECTED; + + TRACFCOMP( g_trac_nvdimm, ENTER_MRK + "notifyNvdimmProtectionChange: Target huid 0x%.8X, state %d", + get_huid(i_target), i_state); + do + { + TARGETING::TargetHandleList l_nvdimmTargetList = + TARGETING::getProcNVDIMMs(i_target); + + // Only send command if the processor has an NVDIMM under it + if (l_nvdimmTargetList.empty()) + { + TRACFCOMP( g_trac_nvdimm, + "notifyNvdimmProtectionChange: No NVDIMM found under processor 0x%.8X", + get_huid(i_target)); + break; + } + + TARGETING::ATTR_NVDIMM_ARMED_type l_nvdimm_armed_state = + i_target->getAttr<TARGETING::ATTR_NVDIMM_ARMED>(); + + // Only notify protected state if NVDIMM controllers are + // armed and no error was or is detected + if (i_state == NVDIMM::PROTECTED) + { + // Exit without notifying phyp if in error state + if (l_nvdimm_armed_state.error_detected) + { + // State can't go to protected after error is detected + break; + } + // check if we need to rearm the NVDIMM(s) + else if (!l_nvdimm_armed_state.armed) + { + bool nvdimms_armed = + NVDIMM::nvdimmArm(l_nvdimmTargetList); + if (nvdimms_armed) + { + // NVDIMMs are now armed and ready for backup + l_nvdimm_armed_state.armed = 1; + i_target->setAttr<TARGETING::ATTR_NVDIMM_ARMED>(l_nvdimm_armed_state); + + l_nvdimm_protection_state = hostInterfaces::HBRT_FW_NVDIMM_PROTECTED; + } + else + { + // If nvdimm arming failed, + // do NOT post that the dimms are now protected. + + // Remember this error, only try arming once + if (!l_nvdimm_armed_state.error_detected) + { + l_nvdimm_armed_state.error_detected = 1; + i_target->setAttr<TARGETING::ATTR_NVDIMM_ARMED>(l_nvdimm_armed_state); + } + + // Exit without notifying phyp of any protection change + break; + } + } + else + { + // NVDIMM already armed and no error found + l_nvdimm_protection_state = hostInterfaces::HBRT_FW_NVDIMM_PROTECTED; + } + } + else if (i_state == NVDIMM::UNPROTECTED_BECAUSE_ERROR) + { + // Remember that this NV controller has an error so + // we don't rearm this until next IPL + if (!l_nvdimm_armed_state.error_detected) + { + l_nvdimm_armed_state.error_detected = 1; + i_target->setAttr<TARGETING::ATTR_NVDIMM_ARMED>(l_nvdimm_armed_state); + } + // still notify phyp that NVDIMM is Not Protected + } + + + // Get the Proc Chip Id + RT_TARG::rtChipId_t l_chipId = 0; + + l_err = RT_TARG::getRtTarget(i_target, l_chipId); + if(l_err) + { + TRACFCOMP( g_trac_nvdimm, + ERR_MRK"notifyNvdimmProtectionChange: getRtTarget ERROR" ); + break; + } + + // send the notification msg + if ((nullptr == g_hostInterfaces) || + (nullptr == g_hostInterfaces->firmware_request)) + { + TRACFCOMP( g_trac_nvdimm, ERR_MRK"notifyNvdimmProtectionChange: " + "Hypervisor firmware_request interface not linked"); + + // need to safely convert struct type into uint32_t + union { + TARGETING::ATTR_NVDIMM_ARMED_type tNvdimmArmed; + uint32_t nvdimmArmed_int; + } armed_state_union; + armed_state_union.tNvdimmArmed = l_nvdimm_armed_state; + + /*@ + * @errortype + * @severity ERRL_SEV_PREDICTIVE + * @moduleid NOTIFY_NVDIMM_PROTECTION_CHG + * @reasoncode NVDIMM_NULL_FIRMWARE_REQUEST_PTR + * @userdata1 HUID of processor target + * @userdata2[0:31] Requested protection state + * @userdata2[32:63] Current armed state + * @devdesc Unable to inform PHYP of NVDIMM protection + * @custdesc Internal firmware error + */ + l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_PREDICTIVE, + NOTIFY_NVDIMM_PROTECTION_CHG, + NVDIMM_NULL_FIRMWARE_REQUEST_PTR, + get_huid(i_target), + TWO_UINT32_TO_UINT64( + l_nvdimm_protection_state, + armed_state_union.nvdimmArmed_int) + ); + + l_err->addProcedureCallout(HWAS::EPUB_PRC_PHYP_CODE, + HWAS::SRCI_PRIORITY_HIGH); + + break; + } + + TRACFCOMP( g_trac_nvdimm, + "notifyNvdimmProtectionChange: 0x%.8X processor NVDIMMS are " + "%s protected (current armed_state: 0x%02X)", + get_huid(i_target), + (l_nvdimm_protection_state == hostInterfaces::HBRT_FW_NVDIMM_PROTECTED)?"now":"NOT", + l_nvdimm_armed_state ); + + // Create the firmware_request request struct to send data + hostInterfaces::hbrt_fw_msg l_req_fw_msg; + memset(&l_req_fw_msg, 0, sizeof(l_req_fw_msg)); // clear it all + + // actual msg size (one type of hbrt_fw_msg) + uint64_t l_req_fw_msg_size = hostInterfaces::HBRT_FW_MSG_BASE_SIZE + + sizeof(l_req_fw_msg.nvdimm_protection_state); + + // Populate the firmware_request request struct with given data + l_req_fw_msg.io_type = + hostInterfaces::HBRT_FW_MSG_TYPE_NVDIMM_PROTECTION; + l_req_fw_msg.nvdimm_protection_state.i_procId = l_chipId; + l_req_fw_msg.nvdimm_protection_state.i_state = + l_nvdimm_protection_state; + + // Create the firmware_request response struct to receive data + hostInterfaces::hbrt_fw_msg l_resp_fw_msg; + uint64_t l_resp_fw_msg_size = sizeof(l_resp_fw_msg); + memset(&l_resp_fw_msg, 0, l_resp_fw_msg_size); + + // Make the firmware_request call + l_err = firmware_request_helper(l_req_fw_msg_size, + &l_req_fw_msg, + &l_resp_fw_msg_size, + &l_resp_fw_msg); + + } while (0); + + TRACFCOMP( g_trac_nvdimm, + EXIT_MRK "notifyNvdimmProtectionChange(%.8X, %d) - ERRL %.8X:%.4X", + get_huid(i_target), i_state, + ERRL_GETEID_SAFE(l_err), ERRL_GETRC_SAFE(l_err) ); + + 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) + * + * @param[in] i_nvdimm - nvdimm target with NV controller + * + * @param[out] o_poll - total polled time in ms + * + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t nvdimmPollArmDone(TARGETING::Target* i_nvdimm, + uint32_t &o_poll) +{ + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmPollArmDone() nvdimm[%X]", TARGETING::get_huid(i_nvdimm) ); + + errlHndl_t l_err = nullptr; + + l_err = nvdimmPollStatus ( i_nvdimm, ARM, o_poll); + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmPollArmDone() nvdimm[%X]", + TARGETING::get_huid(i_nvdimm)); + + return l_err; +} + +/** + * @brief This function checks the arm status register to make sure + * the trigger has been armed to ddr_reset_n + * + * @param[in] i_nvdimm - nvdimm target with NV controller + * + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t nvdimmCheckArmSuccess(TARGETING::Target *i_nvdimm) +{ + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmCheckArmSuccess() nvdimm[%X]", + TARGETING::get_huid(i_nvdimm)); + + errlHndl_t l_err = nullptr; + uint8_t l_data = 0; + + l_err = nvdimmReadReg(i_nvdimm, ARM_STATUS, l_data); + + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmCheckArmSuccess() nvdimm[%X]" + "failed to read arm status reg!",TARGETING::get_huid(i_nvdimm)); + } + else if ((l_data & ARM_SUCCESS) != ARM_SUCCESS) + { + + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmCheckArmSuccess() nvdimm[%X]" + "failed to arm!",TARGETING::get_huid(i_nvdimm)); + /*@ + *@errortype + *@reasoncode NVDIMM_ARM_FAILED + *@severity ERRORLOG_SEV_PREDICTIVE + *@moduleid NVDIMM_SET_ARM + *@userdata1[0:31] Related ops (0xff = NA) + *@userdata1[32:63] Target Huid + *@userdata2 <UNUSED> + *@devdesc Encountered error arming the catastrophic save + * trigger on NVDIMM. Make sure an energy source + * is connected to the NVDIMM and the ES policy + * is set properly + *@custdesc NVDIMM encountered error arming save trigger + */ + l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_PREDICTIVE, + NVDIMM_SET_ARM, + NVDIMM_ARM_FAILED, + TWO_UINT32_TO_UINT64(ARM, TARGETING::get_huid(i_nvdimm)), + 0x0, + ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); + + l_err->collectTrace(NVDIMM_COMP_NAME, 256 ); + //@TODO RTC 199645 - add HW callout on dimm target + //failure to arm could mean internal NV controller error or + //even error on the battery pack. NVDIMM will lose persistency + //if failed to arm trigger + } + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmCheckArmSuccess() nvdimm[%X] ret[%X]", + TARGETING::get_huid(i_nvdimm), l_data); + + 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) +{ + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmArmResetN() nvdimm[%X]", + TARGETING::get_huid(i_nvdimm)); + + errlHndl_t l_err = nullptr; + + // 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); + + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmArmResetN() nvdimm[%X] error arming nvdimm!!", + TARGETING::get_huid(i_nvdimm)); + } + else + { + // 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 = nvdimmCheckArmSuccess(i_nvdimm); + } + } + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmArmResetN() nvdimm[%X]", + TARGETING::get_huid(i_nvdimm)); + return l_err; +} + +/** + * @brief Check nvdimm error state + * + * @param[in] i_nvdimm - nvdimm target + * + * @return bool - true if nvdimm is in any error state, false otherwise + */ +bool nvdimmInErrorState(TARGETING::Target *i_nvdimm) +{ + TRACUCOMP(g_trac_nvdimm, ENTER_MRK"nvdimmInErrorState() HUID[%X]",TARGETING::get_huid(i_nvdimm)); + + uint8_t l_statusFlag = i_nvdimm->getAttr<TARGETING::ATTR_NV_STATUS_FLAG>(); + bool l_ret = true; + + if ((l_statusFlag & NSTD_ERR) == 0) + l_ret = false; + + TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmInErrorState() HUID[%X]",TARGETING::get_huid(i_nvdimm)); + return l_ret; +} + +} // end NVDIMM namespace diff --git a/src/usr/isteps/pm/pm_common.C b/src/usr/isteps/pm/pm_common.C index 3aef6a713..c66e75727 100644 --- a/src/usr/isteps/pm/pm_common.C +++ b/src/usr/isteps/pm/pm_common.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2016,2018 */ +/* Contributors Listed Below - COPYRIGHT 2016,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -86,6 +86,10 @@ #include <diag/prdf/prdfWriteHomerFirData.H> #endif +#if defined(__HOSTBOOT_RUNTIME) && defined(CONFIG_NVDIMM) +#include <isteps/nvdimm/nvdimm.H> // notify NVDIMM protection change +#endif + // Easy macro replace for unit testing //#define TRACUCOMP(args...) TRACFCOMP(args) #define TRACUCOMP(args...) @@ -935,6 +939,20 @@ namespace HBPM break; } +#if defined(__HOSTBOOT_RUNTIME) && defined(CONFIG_NVDIMM) + // Notify PHYP that NVDIMMs are not protected from power off event + l_errl = NVDIMM::notifyNvdimmProtectionChange(i_target, NVDIMM::NOT_PROTECTED); + if (l_errl) + { + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, + ERR_MRK"resetPMComplex: unable to notify PHYP that NVDIMM" + " is not protected for HUID=0x%.8X", get_huid(i_target) ); + + l_errl->collectTrace("ISTEPS_TRACE",256); + errlCommit(l_errl, ISTEP_COMP_ID); + } +#endif + // Reset path // p9_pm_init.C enum: PM_RESET FAPI_INVOKE_HWP( l_errl, @@ -999,7 +1017,7 @@ namespace HBPM "resetPMComplex:" "unmap, RC=0x%X" , lRc ); } - + TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, EXIT_MRK"resetPMComplex: RC=0x%X, PLID=0x%lX", ERRL_GETRC_SAFE(l_errl), ERRL_GETPLID_SAFE(l_errl) ); diff --git a/src/usr/isteps/pm/runtime/rt_pm.C b/src/usr/isteps/pm/runtime/rt_pm.C index 3e5ab8c10..9397d0e83 100644 --- a/src/usr/isteps/pm/runtime/rt_pm.C +++ b/src/usr/isteps/pm/runtime/rt_pm.C @@ -40,7 +40,6 @@ #include <runtime/rt_targeting.H> #include <runtime/runtime_reasoncodes.H> - #include <initservice/isteps_trace.H> // targeting support @@ -262,44 +261,6 @@ namespace RTPM break; } -#ifdef CONFIG_NVDIMM - //@TODO RTC 199645 - additional delay needed to ensure OCC is - // full functional - - // Only run this if PM complex started successfully - // as EPOW save trigger is done by the OCC - TARGETING::TargetHandleList l_dimmTargetList; - getChildAffinityTargets( l_dimmTargetList, proc_target, CLASS_NA, TYPE_DIMM ); - - for (auto const l_dimm : l_dimmTargetList) - { - if (TARGETING::isNVDIMM(l_dimm)) - { - // skip if the nvdimm is in error state - if (NVDIMM::nvdimmInErrorState(l_dimm)) - { - continue; - } - - l_err = NVDIMM::nvdimmArmResetN(l_dimm); - // 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_dimm, NVDIMM::NSTD_ERR_NOBKUP); - // Committing the error as we don't want the this to interrupt - // the boot. This will notifiy the user that action is needed - // on this module - l_err->setSev(ERRL_SEV_INFORMATIONAL); - l_err->collectTrace(NVDIMM_COMP_NAME,1024); - errlCommit( l_err, NVDIMM_COMP_ID ); - continue; - } - } - } -#endif } while(0); if ( l_err ) @@ -599,4 +560,3 @@ namespace RTPM registerPm g_registerPm; }; - diff --git a/src/usr/targeting/common/util.C b/src/usr/targeting/common/util.C index a5a9bb7a9..71811366f 100644 --- a/src/usr/targeting/common/util.C +++ b/src/usr/targeting/common/util.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2012,2018 */ +/* Contributors Listed Below - COPYRIGHT 2012,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -38,9 +38,6 @@ #include <targeting/common/utilFilter.H> #include <targeting/common/trace.H> -#define MCA_PER_MCS 2 -#define DIMM_PER_MCA 2 - namespace TARGETING { @@ -284,18 +281,12 @@ uint8_t is_fused_mode( ) } // end is_fused_mode -/** - * @brief Determine if the given dimm target is an NVDIMM - * - * @param[in] i_target : dimm target to check - * - * @return bool - True if the given target is an NVDIMM - */ + bool isNVDIMM( TARGETING::Target * i_target ) { // Not the most elegant way of doing it but the hybrid attributes // are at the MCS level. Need to find my way up to MCS and check - // if the dimm is hybrid + // if the dimm is hybrid TARGETING::TargetHandleList l_mcaList; getParentAffinityTargets(l_mcaList, i_target, TARGETING::CLASS_UNIT, TARGETING::TYPE_MCA); @@ -313,10 +304,17 @@ bool isNVDIMM( TARGETING::Target * i_target ) if( l_mcsList[0]->tryGetAttr<TARGETING::ATTR_EFF_HYBRID>(l_hybrid) && l_mcsList[0]->tryGetAttr<TARGETING::ATTR_EFF_HYBRID_MEMORY_TYPE>(l_hybrid_type) ) { - //Using relative position to lookup the hybrid attribute for the current dimm + //Using relative position to lookup the hybrid attribute for the current dimm TARGETING::ATTR_REL_POS_type l_dimm_rel_pos = i_target->getAttr<ATTR_REL_POS>(); TARGETING::ATTR_REL_POS_type l_mca_rel_pos = l_mcaList[0]->getAttr<ATTR_REL_POS>(); + // Verify code is not accessing outside of the array boundaries + // Check if l_dimm_rel_pos is outside of l_hybrid column boundary + assert(l_dimm_rel_pos < sizeof(l_hybrid[0])); + + // Check if l_mca_rel_pos is outside of l_hybrid row boundary + assert(l_mca_rel_pos < (sizeof(l_hybrid)/sizeof(l_hybrid[0]))); + return (l_hybrid[l_mca_rel_pos][l_dimm_rel_pos] == TARGETING::EFF_HYBRID_IS_HYBRID && l_hybrid_type[l_mca_rel_pos][l_dimm_rel_pos] == TARGETING::EFF_HYBRID_MEMORY_TYPE_NVDIMM); } @@ -326,4 +324,25 @@ bool isNVDIMM( TARGETING::Target * i_target ) return false; } + +TARGETING::TargetHandleList getProcNVDIMMs( TARGETING::Target * i_proc ) +{ + TargetHandleList o_nvdimmList; + + TargetHandleList l_dimmTargetList; + getChildAffinityTargets( l_dimmTargetList, i_proc, CLASS_NA, TYPE_DIMM ); + + for (TargetHandleList::iterator it = l_dimmTargetList.begin(); + it != l_dimmTargetList.end(); ++it) + { + TARGETING::Target* l_dimm = *it; + if (TARGETING::isNVDIMM(l_dimm)) + { + // Found a valid NVDIMM + o_nvdimmList.push_back(l_dimm); + } + } + return o_nvdimmList; +} + } // end namespace TARGETING diff --git a/src/usr/targeting/common/xmltohb/attribute_types.xml b/src/usr/targeting/common/xmltohb/attribute_types.xml index eb281a157..c31202b92 100644 --- a/src/usr/targeting/common/xmltohb/attribute_types.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types.xml @@ -4925,6 +4925,41 @@ </attribute> <attribute> + <description> + NVDIMM(s) are armed for backup incase of power loss (DDR Reset_n goes low) + This keeps track of the armed state + </description> + <persistency>volatile-zeroed</persistency> + <readable/> + <writeable/> + <complexType> + <description>Armed State</description> + <field> + <bits>1</bits> + <default>0</default> + <description>Is NVDIMM armed</description> + <name>armed</name> + <type>uint8_t</type> + </field> + <field> + <bits>1</bits> + <default>0</default> + <description>NVDIMM controller error detected</description> + <name>error_detected</name> + <type>uint8_t</type> + </field> + <field> + <bits>6</bits> + <default>0</default> + <description>Reserved for future use</description> + <name>reserved</name> + <type>uint8_t</type> + </field> + </complexType> + <id>NVDIMM_ARMED</id> + </attribute> + + <attribute> <id>NV_OPS_TIMEOUT_MSEC</id> <description> NVDIMM timeout value for 6 main operations diff --git a/src/usr/targeting/common/xmltohb/target_types.xml b/src/usr/targeting/common/xmltohb/target_types.xml index 1189f9954..197a591ae 100644 --- a/src/usr/targeting/common/xmltohb/target_types.xml +++ b/src/usr/targeting/common/xmltohb/target_types.xml @@ -538,6 +538,9 @@ <id>LOCATION_CODE</id> </attribute> <attribute> + <id>NVDIMM_ARMED</id> + </attribute> + <attribute> <default> <field> <id>reserved</id> diff --git a/src/usr/targeting/targetservicestart.C b/src/usr/targeting/targetservicestart.C index 9d318bce4..1b86a9c6b 100755 --- a/src/usr/targeting/targetservicestart.C +++ b/src/usr/targeting/targetservicestart.C @@ -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. */ /* */ @@ -584,6 +584,13 @@ static void initializeAttributes(TargetService& i_targetService, l_chip->setAttr<ATTR_HB_INITIATED_PM_RESET> (HB_INITIATED_PM_RESET_INACTIVE); + // clear the NVDIMM arming status so it gets redone when OCC is active + ATTR_NVDIMM_ARMED_type l_nvdimms_armed_state = + l_chip->getAttr<ATTR_NVDIMM_ARMED>(); + // Only force rearming (error setting should persist) + l_nvdimms_armed_state.armed = 0; + l_chip->setAttr<ATTR_NVDIMM_ARMED>(l_nvdimms_armed_state); + if (l_chip == l_pMasterProcChip) { // Need to set PROC_MASTER_TYPE to reflect the diff --git a/src/usr/util/runtime/rt_cmds.C b/src/usr/util/runtime/rt_cmds.C index bab3a85d4..c015215b5 100644 --- a/src/usr/util/runtime/rt_cmds.C +++ b/src/usr/util/runtime/rt_cmds.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2015,2018 */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -46,6 +46,9 @@ #include <scom/runtime/rt_scomif.H> // sendScomOpToFsp, // sendMultiScomReadToFsp, // switchToFspScomAccess +#ifdef CONFIG_NVDIMM +#include <isteps/nvdimm/nvdimm.H> // notify NVDIMM protection change +#endif extern char hbi_ImageId; @@ -1153,6 +1156,49 @@ void cmd_sendMultiScomReadToFSP( char* &o_output, } } +#ifdef CONFIG_NVDIMM +void cmd_nvdimm_protection_msg( char* &o_output, uint32_t i_huid, + uint32_t protection ) +{ + errlHndl_t l_err = nullptr; + o_output = new char[500]; + uint8_t l_notifyType = NVDIMM::NOT_PROTECTED; + + TARGETING::Target* l_targ{}; + l_targ = getTargetFromHUID(i_huid); + if (l_targ != NULL) + { + if (protection == 1) + { + l_notifyType = NVDIMM::PROTECTED; + l_err = notifyNvdimmProtectionChange(l_targ, NVDIMM::PROTECTED); + } + else if (protection == 2) + { + l_notifyType = NVDIMM::UNPROTECTED_BECAUSE_ERROR; + l_err = notifyNvdimmProtectionChange(l_targ, NVDIMM::UNPROTECTED_BECAUSE_ERROR); + } + else + { + l_err = notifyNvdimmProtectionChange(l_targ, NVDIMM::NOT_PROTECTED); + } + if (l_err) + { + sprintf( o_output, "Error on call to notifyNvdimmProtectionChange" + "(0x%.8X, %d), rc=0x%.8X, plid=0x%.8X", + i_huid, l_notifyType, ERRL_GETRC_SAFE(l_err), l_err->plid() ); + errlCommit(l_err, UTIL_COMP_ID); + return; + } + } + else + { + sprintf( o_output, "cmd_nvdimm_protection_msg: HUID 0x%.8X not found", + i_huid ); + return; + } +} +#endif /** * @brief Execute an arbitrary command inside Hostboot Runtime @@ -1473,6 +1519,22 @@ int hbrtCommand( int argc, "ERROR: multiScomReadToFsp <huid> <scomAddrs>"); } } +#ifdef CONFIG_NVDIMM + else if( !strcmp( argv[0], "nvdimm_protection" ) ) + { + if (argc >= 3) + { + uint32_t huid = strtou64(argv[1], NULL, 16); + uint32_t protection = strtou64( argv[2], NULL, 16); + cmd_nvdimm_protection_msg( *l_output, huid, protection ); + } + else + { + *l_output = new char[100]; + sprintf(*l_output, "ERROR: nvdimm_protection <huid> <0 or 1>"); + } + } +#endif else { *l_output = new char[50+100*12]; @@ -1509,6 +1571,11 @@ int hbrtCommand( int argc, strcat( *l_output, l_tmpstr ); sprintf( l_tmpstr, "multiScomReadToFsp <huid> <scomAddrs>\n"); strcat( *l_output, l_tmpstr ); +#ifdef CONFIG_NVDIMM + sprintf( l_tmpstr, "nvdimm_protection <huid> <0 or 1>\n"); + strcat( *l_output, l_tmpstr ); +#endif + } if( l_traceOut && (*l_output != NULL) ) diff --git a/src/usr/util/runtime/rt_fwreq_helper.C b/src/usr/util/runtime/rt_fwreq_helper.C index 40a8373e5..f94dab238 100644 --- a/src/usr/util/runtime/rt_fwreq_helper.C +++ b/src/usr/util/runtime/rt_fwreq_helper.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2018 */ +/* Contributors Listed Below - COPYRIGHT 2013,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -250,6 +250,34 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req, } break; // END case hostInterfaces::HBRT_FW_MSG_TYPE_SBE_STATE: + case hostInterfaces::HBRT_FW_MSG_TYPE_NVDIMM_PROTECTION: + { + TRACFCOMP(g_trac_runtime, + ERR_MRK"FSP is doing a reset/reload, " + "Send NVDIMM state to PHYP failed. " + "retry:%d/%d, rc:%d, procId:0x%.8X, " + "state:%d - %s", + i, + HBRT_FW_REQUEST_RETRIES, + rc, + l_req_fw_msg->sbe_state.i_procId, + l_req_fw_msg->sbe_state.i_state, + l_req_fw_msg->sbe_state.i_state? + "protected":"not protected"); + + // Pack user data 1 with Hypervisor return code and + // firmware request message type + l_userData1 = TWO_UINT32_TO_UINT64(rc, + l_req_fw_msg->io_type); + + // Pack user data 2 with processor ID of NVDIMM + // and state of the NVDIMM + l_userData2 = TWO_UINT32_TO_UINT64( + l_req_fw_msg->nvdimm_protection_state.i_procId, + l_req_fw_msg->nvdimm_protection_state.i_state); + } + break; // END case hostInterfaces::HBRT_FW_MSG_TYPE_NVDIMM_PROTECTION: + default: break; } // END switch (l_req_fw_msg->io_type) @@ -270,7 +298,8 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req, chipID * @userdata2[32:63] SCOM data (HCODE Update) || Message Type (FSP MSG) || - SBE state + SBE state || + NVDIMM protection * @devdesc The Firmware Request call failed */ l_err = new ErrlEntry(ERRL_SEV_INFORMATIONAL, @@ -439,6 +468,30 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req, } break; // END case hostInterfaces::HBRT_FW_MSG_TYPE_SBE_STATE: + case hostInterfaces::HBRT_FW_MSG_TYPE_NVDIMM_PROTECTION: + { + TRACFCOMP(g_trac_runtime, + ERR_MRK"Failed sending NVDIMM protection state to PHYP." + " rc:0x%X, procId:0x%.8X, state:%d - %s", + rc, + l_req_fw_msg->sbe_state.i_procId, + l_req_fw_msg->sbe_state.i_state, + l_req_fw_msg->sbe_state.i_state? + "protected":"not protected"); + + // Pack user data 1 with Hypervisor return code and + // firmware request message type + l_userData1 = TWO_UINT32_TO_UINT64(rc, + l_req_fw_msg->io_type); + + // Pack user data 2 with processor ID of NVDIMM + // and state of the NVDIMM + l_userData2 = TWO_UINT32_TO_UINT64( + l_req_fw_msg->nvdimm_protection_state.i_procId, + l_req_fw_msg->nvdimm_protection_state.i_state); + } + break; // END case hostInterfaces::HBRT_FW_MSG_TYPE_NVDIMM_PROTECTION: + default: break; } // END switch (l_req_fw_msg->io_type) @@ -459,7 +512,8 @@ errlHndl_t firmware_request_helper(uint64_t i_reqLen, void *i_req, chipId * @userdata2[32:63] SCOM data (HCODE Update) || Message Type (FSP MSG) || - SBE state + SBE state || + NVDIMM protection state * @devdesc The Firmware Request call failed */ l_err = new ErrlEntry(ERRL_SEV_PREDICTIVE, |