summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTsung Yeung <tyeung@us.ibm.com>2018-12-20 10:39:39 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2019-02-12 10:50:42 -0600
commitb2027cd8b704587be6ce4dd14327e6730f9d519b (patch)
treebf1b0206440c5105e46db51bb1a837ac71290ce9 /src
parent95bbfc78a463c06cd06204ee8cb1b904ec864565 (diff)
downloadblackbird-hostboot-b2027cd8b704587be6ce4dd14327e6730f9d519b.tar.gz
blackbird-hostboot-b2027cd8b704587be6ce4dd14327e6730f9d519b.zip
Disable NVDIMM Trigger Before Draminit and Deassert DDR_RESETn During MPIPL
- Per the JEDEC spec, DDR_RESETn is masked from the DRAM when the NVDIMM is armed. This could cause the training to fail if the trigger is not disabled before training. Two scenarios where this can happen are warm reboot and cold boot before the backup power module can deplete the charge - Deassert DDR_RESETn in MPIPL before triggering the restore. - Fix the config flag to enable NVDIMM code Change-Id: I9d25c2f653fc54d379f0dbab49218f5b59a407a0 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/70035 Reviewed-by: Matt Derksen <mderkse1@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-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> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/build/configs/fsprelease.config1
-rw-r--r--src/include/usr/isteps/istep13list.H5
-rw-r--r--src/include/usr/isteps/istep14list.H6
-rw-r--r--src/include/usr/isteps/istep21list.H5
-rw-r--r--src/include/usr/isteps/nvdimm/nvdimm.H20
-rw-r--r--src/include/usr/vpd/spdenums.H5
-rw-r--r--src/usr/isteps/istep13/call_mss_draminit.C20
-rw-r--r--src/usr/isteps/istep14/call_mss_power_cleanup.C198
-rw-r--r--src/usr/isteps/nvdimm/nvdimm.C568
-rw-r--r--src/usr/isteps/nvdimm/nvdimm.H300
-rw-r--r--src/usr/isteps/nvdimm/runtime/nvdimm_rt.C136
-rw-r--r--src/usr/isteps/pm/runtime/rt_pm.C2
-rwxr-xr-xsrc/usr/vpd/spdDDR4.H3
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 },
OpenPOWER on IntegriCloud