diff options
author | Matt Derksen <mderkse1@us.ibm.com> | 2019-01-15 10:48:31 -0600 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2019-01-24 13:12:08 -0600 |
commit | cb35695328fbc1cb6764f048a8dbb3e81faba1e9 (patch) | |
tree | ea9cce42514a9f000c687545ab5f417842df04af /src | |
parent | 9de9d8f7c5b5c73247dc69925a594fcd07ce060c (diff) | |
download | talos-hostboot-cb35695328fbc1cb6764f048a8dbb3e81faba1e9.tar.gz talos-hostboot-cb35695328fbc1cb6764f048a8dbb3e81faba1e9.zip |
Inform PHYP of NVDIMM protection by OCC
The OCC is responsible for detecting the EPOW signal
and triggering the save operation on the NVDIMM.
Therefore, if the OCC is not running we are unprotected
from a poweroff event. PHYP needs to inform the LPARs
using the NV (non-volatile) memory of this state so they
can behave accordingly.
HBRT is responsible for telling PHYP when we get into this state.
There are two ways we can detect this state:
a) HBRT explicitly puts the PM complex into reset
b) PRD detects a specific FIR bit
The message should include this data:
- what state we are in (protected or unprotected)
- which processor is affected
Work for this story will include:
- Definition of the new message
- Creating a utility function to send the message
- Calling utility function to send 'unprotected' message
inside of all pm reset paths at runtime
Change-Id: Ib015d001d47883a247faedabedb0705ba0f1b215
RTC:201181
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/68870
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: TSUNG K. YEUNG <tyeung@us.ibm.com>
Reviewed-by: Roland Veloz <rveloz@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
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, |