summaryrefslogtreecommitdiffstats
path: root/src/usr
diff options
context:
space:
mode:
authorMatt Derksen <mderkse1@us.ibm.com>2018-12-10 16:38:11 -0600
committerDaniel M. Crowell <dcrowell@us.ibm.com>2019-02-28 10:24:21 -0600
commit37e67698be56632c6505990dc3375136494d2a67 (patch)
treea23967962c1e31f9a2a8b7430fff1b10232241b2 /src/usr
parent80cea86add7ba742181cd272b16e10185b5e9a4d (diff)
downloadtalos-hostboot-37e67698be56632c6505990dc3375136494d2a67.tar.gz
talos-hostboot-37e67698be56632c6505990dc3375136494d2a67.zip
Framework for NVDIMM update
This includes framework to update the firmware running on the NV controller. The controller requires 12V power to update, so this function in inside hostboot. Change-Id: I0733d83ff6ba2fc3f026d49c72784b1295bd3eed RTC:201197 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/69879 Reviewed-by: Roland Veloz <rveloz@us.ibm.com> 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: FSP CI Jenkins <fsp-CI-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/usr')
-rw-r--r--src/usr/isteps/istep20/call_host_load_payload.C13
-rw-r--r--src/usr/isteps/istep20/call_nvdimm_update.C76
-rw-r--r--src/usr/isteps/istep20/call_nvdimm_update.H38
-rw-r--r--src/usr/isteps/istep20/makefile1
-rw-r--r--src/usr/isteps/nvdimm/nvdimm.mk10
-rw-r--r--src/usr/isteps/nvdimm/nvdimm_update.C544
-rw-r--r--src/usr/isteps/nvdimm/nvdimm_update.H278
-rw-r--r--src/usr/targeting/common/util.C24
-rwxr-xr-xsrc/usr/vpd/spdDDR4.H4
9 files changed, 978 insertions, 10 deletions
diff --git a/src/usr/isteps/istep20/call_host_load_payload.C b/src/usr/isteps/istep20/call_host_load_payload.C
index 6251eaf80..26dab532b 100644
--- a/src/usr/isteps/istep20/call_host_load_payload.C
+++ b/src/usr/isteps/istep20/call_host_load_payload.C
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* Contributors Listed Below - COPYRIGHT 2016,2019 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -40,6 +40,11 @@
#include <xz/xz.h>
#include <config.h>
+#ifdef CONFIG_NVDIMM
+#include "call_nvdimm_update.H"
+#endif
+
+
using namespace ERRORLOG;
using namespace ISTEP;
using namespace ISTEP_ERROR;
@@ -129,6 +134,12 @@ void* call_host_load_payload (void *io_pArgs)
}
}
+#ifdef CONFIG_NVDIMM
+ // Update the NVDIMM controller code, if necessary
+ // Need to do this after LIDs are accessible
+ NVDIMM_UPDATE::call_nvdimm_update();
+#endif
+
}while(0);
return l_err;
diff --git a/src/usr/isteps/istep20/call_nvdimm_update.C b/src/usr/isteps/istep20/call_nvdimm_update.C
new file mode 100644
index 000000000..7a1817faf
--- /dev/null
+++ b/src/usr/isteps/istep20/call_nvdimm_update.C
@@ -0,0 +1,76 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/isteps/istep20/call_nvdimm_update.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2018 */
+/* [+] 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 */
+#include <trace/interface.H>
+#include <errl/errlentry.H>
+#include <initservice/isteps_trace.H>
+#include <targeting/common/commontargeting.H>
+#include <targeting/common/utilFilter.H>
+
+// NVDIMM support
+#include <isteps/nvdimm/nvdimm.H>
+
+#include "call_nvdimm_update.H"
+
+namespace NVDIMM_UPDATE
+{
+
+/**
+ * @brief This function updates the NVDIMM firmware code
+ */
+void call_nvdimm_update()
+{
+ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,ENTER_MRK"call_nvdimm_update()");
+
+ TARGETING::TargetHandleList l_nvdimmTargetList;
+ TARGETING::TargetHandleList l_procList;
+ TARGETING::getAllChips(l_procList, TARGETING::TYPE_PROC, false);
+
+ // grab the NVDIMMs under each processor and add to overall list
+ for (auto l_proc : l_procList)
+ {
+ TARGETING::TargetHandleList tmpList =
+ TARGETING::getProcNVDIMMs(l_proc);
+ l_nvdimmTargetList.insert(l_nvdimmTargetList.end(),
+ tmpList.begin(), tmpList.end());
+ }
+
+ // Run the nvdimm update function if the list is not empty
+ if ( !l_nvdimmTargetList.empty() )
+ {
+ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
+ "call_nvdimm_update(): found %d nvdimms to check for update",
+ l_nvdimmTargetList.size());
+ bool updateWorked = NVDIMM::nvdimm_update(l_nvdimmTargetList);
+ if (!updateWorked)
+ {
+ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
+ "call_nvdimm_update(): nvdimm update failed");
+ }
+ }
+
+ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,EXIT_MRK"call_nvdimm_update()");
+}
+
+};
diff --git a/src/usr/isteps/istep20/call_nvdimm_update.H b/src/usr/isteps/istep20/call_nvdimm_update.H
new file mode 100644
index 000000000..70922f3d8
--- /dev/null
+++ b/src/usr/isteps/istep20/call_nvdimm_update.H
@@ -0,0 +1,38 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/isteps/istep20/call_nvdimm_update.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2018 */
+/* [+] 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 */
+#ifndef __CALL_NVDIMM_UPDATE_H
+#define __CALL_NVDIMM_UPDATE_H
+
+namespace NVDIMM_UPDATE
+{
+ /**
+ * @brief This function updates the NVDIMM firmware code
+ * Will locate functional NVDIMMs and update their
+ * nv controller code if necessary.
+ */
+ void call_nvdimm_update();
+}
+
+#endif
diff --git a/src/usr/isteps/istep20/makefile b/src/usr/isteps/istep20/makefile
index f98bb7e9b..5a656bd3b 100644
--- a/src/usr/isteps/istep20/makefile
+++ b/src/usr/isteps/istep20/makefile
@@ -26,5 +26,6 @@ ROOTPATH = ../../../..
MODULE = istep20
OBJS += call_host_load_payload.o
+OBJS += $(if $(CONFIG_NVDIMM),call_nvdimm_update.o,)
include ${ROOTPATH}/config.mk
diff --git a/src/usr/isteps/nvdimm/nvdimm.mk b/src/usr/isteps/nvdimm/nvdimm.mk
index cf5ec4fe6..397b27814 100644
--- a/src/usr/isteps/nvdimm/nvdimm.mk
+++ b/src/usr/isteps/nvdimm/nvdimm.mk
@@ -22,6 +22,9 @@
# permissions and limitations under the License.
#
# IBM_PROLOG_END_TAG
+# nvdimmm.mk should only be called when CONFIG_NVDIMM is set
+# Called by src/makefile with the condition that CONFIG_NVDIMM is defined
+
PROCEDURE_PATH = ${ROOTPATH}/src/import/chips/p9/procedures
#Add all the extra include paths
@@ -45,4 +48,11 @@ OBJS += nvdimm.o
OBJS += nvdimmdd.o
OBJS += errlud_nvdimm.o
+ifneq (${HOSTBOOT_RUNTIME},1)
+
+# code update path for NVDIMMs (not at RUNTIME)
+OBJS += nvdimm_update.o
+
+endif
+
VPATH += ${PROCEDURE_PATH}/hwp/memory/lib/dimm/ddr4/
diff --git a/src/usr/isteps/nvdimm/nvdimm_update.C b/src/usr/isteps/nvdimm/nvdimm_update.C
new file mode 100644
index 000000000..a3191cb53
--- /dev/null
+++ b/src/usr/isteps/nvdimm/nvdimm_update.C
@@ -0,0 +1,544 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/isteps/nvdimm/nvdimm_update.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2018 */
+/* [+] 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 */
+#include "nvdimm_update.H"
+#include "nvdimm.H"
+#include <isteps/nvdimm/nvdimm.H>
+#include <isteps/nvdimm/nvdimmreasoncodes.H>
+
+#include <errl/errlmanager.H>
+#include <devicefw/userif.H>
+#include <vpd/spdenums.H>
+
+// Easy macro replace for unit testing
+// #define TRACUCOMP(args...) TRACFCOMP(args)
+#define TRACUCOMP(args...)
+
+namespace NVDIMM
+{
+//////////////////////////////////////////////////////////////////////////////
+// Helper Inline functions
+//////////////////////////////////////////////////////////////////////////////
+/**
+ * @brief Inline function to collect NVDIMM traces and
+ * make sure error is logged at least as PREDICTIVE
+ */
+inline void commitPredictiveNvdimmError(errlHndl_t & io_err)
+{
+ io_err->collectTrace(NVDIMM_COMP_NAME, 256);
+ if ( io_err->sev() < ERRORLOG::ERRL_SEV_PREDICTIVE )
+ {
+ io_err->setSev( ERRORLOG::ERRL_SEV_PREDICTIVE );
+ }
+ ERRORLOG::errlCommit(io_err, NVDIMM_COMP_ID);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// NVDIMM LID Image
+///////////////////////////////////////////////////////////////////////////////
+NvdimmLidImage::NvdimmLidImage(Util::LidId i_lidId, errlHndl_t& io_errHdl)
+{
+ iv_lidImage = nullptr;
+ iv_lidImageSize = 0;
+ iv_ImageLoaded = false;
+
+ iv_lidMgr = new UtilLidMgr(i_lidId);
+ io_errHdl = loadImage();
+}
+
+NvdimmLidImage::~NvdimmLidImage()
+{
+ errlHndl_t l_err = unloadImage();
+ if (l_err)
+ {
+ ERRORLOG::errlCommit(l_err, NVDIMM_COMP_ID);
+ }
+}
+
+uint32_t NvdimmLidImage::getType()
+{
+ uint32_t o_type = INVALID_TYPE;
+
+ if (iv_lidImageSize >= sizeof(nvdimm_image_header_t))
+ {
+ nvdimm_image_header_t * pLid = reinterpret_cast<nvdimm_image_header_t*>
+ (iv_lidImage);
+ o_type = (uint32_t)pLid->module_mnfg_id_code << 16;
+ o_type |= (uint32_t)pLid->module_product_id;
+ }
+ return o_type;
+}
+
+uint16_t NvdimmLidImage::getVersion()
+{
+ uint16_t o_version = INVALID_VERSION;
+
+ if (iv_lidImageSize >= sizeof(nvdimm_image_header_t))
+ {
+ nvdimm_image_header_t * pLid = reinterpret_cast<nvdimm_image_header_t*>
+ (iv_lidImage);
+ o_version = pLid->controller_firmware_revision;
+ }
+ return o_version;
+}
+
+void * NvdimmLidImage::getFlashImage()
+{
+ void * o_image_ptr = nullptr;
+ if (iv_lidImageSize > sizeof(nvdimm_image_header_t))
+ {
+ nvdimm_image_header_t * pLid = reinterpret_cast<nvdimm_image_header_t*>
+ (iv_lidImage);
+
+ // make sure we don't point outside of lid memory
+ // nvdimm flash image starts after the header and digital signature
+ if ((sizeof(nvdimm_image_header_t) +
+ le16toh(pLid->SMART_digital_signature_size)) < iv_lidImageSize)
+ {
+ o_image_ptr = reinterpret_cast<uint8_t*>(iv_lidImage) +
+ sizeof(nvdimm_image_header_t) +
+ le16toh(pLid->SMART_digital_signature_size);
+ }
+ }
+ return o_image_ptr;
+}
+
+size_t NvdimmLidImage::getFlashImageSize()
+{
+ uint32_t o_flash_size = 0;
+ if (iv_lidImageSize > sizeof(nvdimm_image_header_t))
+ {
+ nvdimm_image_header_t * pLid = reinterpret_cast<nvdimm_image_header_t*>
+ (iv_lidImage);
+ o_flash_size = le32toh(pLid->firmware_image_size);
+ o_flash_size -= sizeof(nvdimm_image_header_t);
+
+ // safety check so we don't access past lid's memory size
+ if ((o_flash_size + sizeof(nvdimm_image_header_t) +
+ le16toh(pLid->SMART_digital_signature_size)) > iv_lidImageSize)
+ {
+ TRACFCOMP(g_trac_nvdimm,
+ ERR_MRK"getFlashImageSize(): %ld flash size + %ld header + "
+ "%ld digital signature is greater than %ld overall lid size",
+ o_flash_size, sizeof(nvdimm_image_header_t),
+ le16toh(pLid->SMART_digital_signature_size),
+ iv_lidImageSize);
+ // flash image size is outside of lid memory bounds so don't return
+ // a valid flash size
+ o_flash_size = 0;
+ }
+ }
+ return o_flash_size;
+}
+
+bool NvdimmLidImage::isImageLoaded()
+{
+ return iv_ImageLoaded;
+}
+///////////////////////////////////////////////////
+// Private member functions for NvdimmLidImage
+///////////////////////////////////////////////////
+errlHndl_t NvdimmLidImage::loadImage()
+{
+ errlHndl_t l_err = nullptr;
+ if (!iv_ImageLoaded && (iv_lidMgr != nullptr))
+ {
+ // @todo RTC 205015 -- need to use secure load
+ // iv_lidImage will point to memory allocated
+ // and controlled by iv_lidMgr
+ l_err = iv_lidMgr->getStoredLidImage(iv_lidImage, iv_lidImageSize);
+ if (l_err == nullptr)
+ {
+ // image successfully loaded into memory
+ iv_ImageLoaded = true;
+ }
+ }
+ return l_err;
+}
+
+errlHndl_t NvdimmLidImage::unloadImage()
+{
+ errlHndl_t l_err = nullptr;
+ if (iv_ImageLoaded && (iv_lidMgr != nullptr))
+ {
+ // use lidMgr to delete allocated memory for this lid
+ l_err = iv_lidMgr->releaseLidImage();
+ iv_lidImage = nullptr;
+ iv_lidImageSize = 0;
+ iv_ImageLoaded = false;
+ }
+ return l_err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// NVDIMM Installed Image
+///////////////////////////////////////////////////////////////////////////////
+NvdimmInstalledImage::NvdimmInstalledImage(TARGETING::Target * i_nvDimm) :
+ iv_dimm(i_nvDimm), iv_version(INVALID_VERSION),
+ iv_manufacturer_id(INVALID_ID), iv_product_id(INVALID_ID)
+{
+ // initialize to invalid values
+}
+
+errlHndl_t NvdimmInstalledImage::getType(uint32_t & o_type)
+{
+ errlHndl_t l_err = nullptr;
+ do {
+ size_t l_id_size = 0; // size of id
+ if ( iv_manufacturer_id == INVALID_ID)
+ {
+ // grab values for the installed NVDIMM via SPD
+ l_id_size = sizeof(iv_manufacturer_id);
+ l_err = deviceRead(iv_dimm, &iv_manufacturer_id, l_id_size,
+ DEVICE_SPD_ADDRESS(SPD::RAW_MODULE_MANUFACTURER_ID));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm, ERR_MRK"NvdimmInstalledImage::getType()"
+ " nvdimm[%X] failed to read manufacturer ID",
+ TARGETING::get_huid(iv_dimm));
+ iv_manufacturer_id = INVALID_ID;
+ break;
+ }
+ }
+
+ if (iv_product_id == INVALID_ID)
+ {
+ // grab values for the installed NVDIMM via SPD
+ l_id_size = sizeof(iv_product_id);
+ l_err = deviceRead(iv_dimm, &iv_product_id, l_id_size,
+ DEVICE_SPD_ADDRESS(SPD::RAW_MODULE_PRODUCT_ID));
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm, ERR_MRK"NvdimmInstalledImage::getType()"
+ " nvdimm[%X] failed to read product ID",
+ TARGETING::get_huid(iv_dimm));
+ iv_product_id = INVALID_ID;
+ break;
+ }
+ }
+ } while (0);
+
+ // return the concatenated Type (this may include INVALID_IDs)
+ o_type = ((uint32_t)iv_manufacturer_id << 16) | (uint32_t)iv_product_id;
+ return l_err;
+}
+
+errlHndl_t NvdimmInstalledImage::getVersion(uint16_t & o_version)
+{
+ errlHndl_t l_err = nullptr;
+
+ do {
+ if ((iv_version == INVALID_VERSION))
+ {
+ // Return version in little-endian format
+ uint8_t l_rev1 = 0xFF;
+ uint8_t l_rev0 = 0xFF;
+
+ l_err = nvdimmReadReg(iv_dimm, SLOT1_FWREV1, l_rev1 );
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm, ERR_MRK"NvdimmInstalledImage::"
+ "getVersion() nvdimm[%X] failed to read SLOT1_FWREV1",
+ TARGETING::get_huid(iv_dimm));
+ iv_version = INVALID_VERSION;
+ break;
+ }
+ iv_version = (uint16_t)l_rev1 << 8;
+
+ l_err = nvdimmReadReg(iv_dimm, SLOT1_FWREV0, l_rev0 );
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm, ERR_MRK"NvdimmInstalledImage::"
+ "getVersion() nvdimm[%X] failed to read SLOT1_FWREV0",
+ TARGETING::get_huid(iv_dimm));
+ iv_version = INVALID_VERSION;
+ break;
+ }
+ iv_version |= (uint16_t)l_rev0;
+ }
+ } while (0);
+ o_version = iv_version;
+ return l_err;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// NVDIMMS Update Functions
+///////////////////////////////////////////////////////////////////////////////
+NvdimmsUpdate::NvdimmsUpdate(TARGETING::TargetHandleList i_nvdimmList)
+{
+ iv_nvdimmList = i_nvdimmList;
+}
+
+bool NvdimmsUpdate::runUpdate(void)
+{
+ bool o_no_error_found = true; // true if no error was found during update
+
+ errlHndl_t l_err = nullptr;
+
+ uint32_t l_installed_type = INVALID_TYPE; // current LID type installed
+ NvdimmLidImage * pCurLid = nullptr; // current LID being used for update
+
+ // These are kept to minimize lid memory loading/unloading and
+ // reported errors
+ NvdimmLidImage * pSmallLid = nullptr;
+ NvdimmLidImage * pLargeLid = nullptr;
+
+ for (auto l_nvdimm : iv_nvdimmList)
+ {
+ NvdimmInstalledImage l_installed_image(l_nvdimm);
+ l_err = l_installed_image.getType(l_installed_type);
+ if (l_err)
+ {
+ // Continue updating other dimms
+ TRACFCOMP(g_trac_nvdimm, ERR_MRK "NvdimmsUpdate::runUpdate() - "
+ "Unable to get nvdimm[0x%.8X] installed image type. "
+ "RC=0x%X, PLID=0x%.8X",
+ get_huid(l_nvdimm), ERRL_GETRC_SAFE(l_err),
+ ERRL_GETPLID_SAFE(l_err));
+ commitPredictiveNvdimmError(l_err);
+ o_no_error_found = false;
+ continue;
+ }
+
+ if (l_installed_type == JEDEC_NVDIMM_16GB_TYPE)
+ {
+ if (pSmallLid == nullptr)
+ {
+ pSmallLid = new NvdimmLidImage(Util::NVDIMM_16GB_LIDID, l_err);
+ if (l_err)
+ {
+ // Continue to try updating other dimms
+ TRACFCOMP(g_trac_nvdimm,
+ ERR_MRK "NvdimmsUpdate::runUpdate() - Unable to load "
+ "NVDIMM_16GB_LIDID(0x%X). RC=0x%X, PLID=0x%.8X",
+ Util::NVDIMM_16GB_LIDID,
+ ERRL_GETRC_SAFE(l_err),
+ ERRL_GETPLID_SAFE(l_err));
+
+ // @todo RTC 201197 - enable when valid LIDs are present
+ //commitPredictiveNvdimmError(l_err);
+ delete l_err;
+ l_err = nullptr;
+ // -------------------------------- //
+
+ o_no_error_found = false;
+ // leaving pSmallLid object so don't continuously post the
+ // same error for each NVDIMM
+ continue;
+ }
+ }
+ pCurLid = pSmallLid;
+ }
+ else if (l_installed_type == JEDEC_NVDIMM_32GB_TYPE)
+ {
+ if (pLargeLid == nullptr)
+ {
+ pLargeLid = new NvdimmLidImage(Util::NVDIMM_32GB_LIDID, l_err);
+ if (l_err)
+ {
+ // Continue to try updating other dimms
+ TRACFCOMP(g_trac_nvdimm,
+ ERR_MRK "NvdimmsUpdate::runUpdate() - Unable to load "
+ "NVDIMM_32GB_LIDID(0x%X). RC=0x%X, PLID=0x%.8X",
+ Util::NVDIMM_32GB_LIDID,
+ ERRL_GETRC_SAFE(l_err),
+ ERRL_GETPLID_SAFE(l_err));
+
+ // @todo RTC 201197 - enable when valid LIDs are present
+ //commitPredictiveNvdimmError(l_err);
+ delete l_err;
+ l_err = nullptr;
+ // -------------------------------- //
+ o_no_error_found = false;
+ // leaving pLargeLid object so don't continuously post the
+ // same error for each NVDIMM
+ continue;
+ }
+ }
+ pCurLid = pLargeLid;
+ }
+ else
+ {
+ // unknown/unsupported Type
+ TRACFCOMP(g_trac_nvdimm, "NvdimmsUpdate::runUpdate() - unknown "
+ "nvdimm[%X] installed type 0x%04X, skipping update",
+ TARGETING::get_huid(l_nvdimm), l_installed_type);
+ /*
+ *@errortype
+ *@reasoncode NVDIMM_UNSUPPORTED_NVDIMM_TYPE
+ *@moduleid NVDIMM_RUN_UPDATE
+ *@userdata1[0:31] Unsupported Type
+ *@userdata1[32:63] NVDIMM Target Huid
+ *@userdata2[0:31] Supported nvdimm type
+ *@userdata2[32:63] Other supported nvdimm type
+ *@devdesc Unable to update an unsupported NVDIMM type
+ *@custdesc NVDIMM not updated
+ */
+ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_INFORMATIONAL,
+ NVDIMM_RUN_UPDATE,
+ NVDIMM_UNSUPPORTED_NVDIMM_TYPE,
+ TWO_UINT32_TO_UINT64(
+ l_installed_type,
+ TARGETING::get_huid(l_nvdimm)),
+ TWO_UINT32_TO_UINT64(
+ JEDEC_NVDIMM_16GB_TYPE,
+ JEDEC_NVDIMM_32GB_TYPE),
+ ERRORLOG::ErrlEntry::NO_SW_CALLOUT );
+ l_err->collectTrace(NVDIMM_COMP_NAME, 256 );
+ l_err->addHwCallout( l_nvdimm, HWAS::SRCI_PRIORITY_HIGH,
+ HWAS::NO_DECONFIG, HWAS::GARD_NULL );
+ l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE,
+ HWAS::SRCI_PRIORITY_LOW );
+ ERRORLOG::errlCommit(l_err, NVDIMM_COMP_ID);
+ pCurLid = nullptr;
+ continue;
+ }
+
+ // Verify a valid LID was loaded and ready to read
+ if ((pCurLid == nullptr) || (!pCurLid->isImageLoaded()))
+ {
+ // Errors already logged, just continue to the next NVDIMM
+ continue;
+ }
+
+ bool updateNeeded = false;
+ l_err = isUpdateNeeded(updateNeeded, pCurLid, &l_installed_image);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm, ERR_MRK "NvdimmsUpdate::runUpdate() - "
+ "Unable to determine if nvdimm[%X] needs NV controller update."
+ " RC=0x%X, PLID=0x%.8X",
+ TARGETING::get_huid(l_nvdimm), ERRL_GETRC_SAFE(l_err),
+ ERRL_GETPLID_SAFE(l_err));
+ commitPredictiveNvdimmError(l_err);
+ o_no_error_found = false;
+ }
+ else if (updateNeeded)
+ {
+ // perform update for this DIMM with the current LID image
+ TRACFCOMP(g_trac_nvdimm, "NvdimmsUpdate::runUpdate() - "
+ "now update nvdimm[0x%.8X]", TARGETING::get_huid(l_nvdimm));
+
+ TRACFCOMP(g_trac_nvdimm,"Updating with flash size: 0x%08X",
+ pCurLid->getFlashImageSize());
+
+ // @todo RTC 202536 : Add update calls
+ }
+ }
+
+ if (pLargeLid)
+ {
+ delete pLargeLid;
+ }
+ if (pSmallLid)
+ {
+ delete pSmallLid;
+ }
+
+ return o_no_error_found;
+}
+
+errlHndl_t NvdimmsUpdate::isUpdateNeeded(bool & o_update_needed,
+ NvdimmLidImage * i_lid_image,
+ NvdimmInstalledImage * i_cur_image)
+{
+ o_update_needed = false; // initialize to false
+
+ errlHndl_t l_err = nullptr;
+ uint32_t lidType = INVALID_TYPE;
+ uint32_t curType = INVALID_TYPE;
+
+ do {
+ const TARGETING::Target * l_dimm = i_cur_image->getNvdimmTarget();
+
+ // check Types match (same manufacturer and product)
+ lidType = i_lid_image->getType();
+ l_err = i_cur_image->getType(curType);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm,
+ "isUpdateNeeded(): failed to find type of NVDIMM[%X]",
+ TARGETING::get_huid(l_dimm));
+ break;
+ }
+
+ if ((lidType == curType) && (lidType != INVALID_TYPE))
+ {
+ // check that versions do NOT match
+ uint16_t curVersion = INVALID_VERSION;
+ uint16_t lidVersion = i_lid_image->getVersion();
+ l_err = i_cur_image->getVersion(curVersion);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm,
+ "isUpdateNeeded(): failed to find version of NVDIMM[%X]",
+ TARGETING::get_huid(l_dimm));
+ break;
+ }
+
+
+ if (curVersion != lidVersion)
+ {
+ // verify we are updating with a good version
+ if (lidVersion != INVALID_VERSION)
+ {
+ // Found mismatched version and a valid lid update version
+ // so an update can proceed
+ o_update_needed = true;
+
+ TRACFCOMP(g_trac_nvdimm,
+ "NVDIMM[%X] code level - current: 0x%04X, new: 0x%04X",
+ TARGETING::get_huid(l_dimm),
+ le16toh(curVersion), le16toh(lidVersion));
+ }
+ else
+ {
+ TRACFCOMP(g_trac_nvdimm, "NVDIMM[%X] has invalid version",
+ TARGETING::get_huid(l_dimm));
+ }
+ }
+ else
+ {
+ TRACUCOMP(g_trac_nvdimm,
+ "Keeping current NVDIMM[%X] level: 0x%04X",
+ TARGETING::get_huid(l_dimm), le16toh(curVersion));
+ }
+ }
+ } while (0);
+
+ return l_err;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// External function to update the NVDIMMs
+////////////////////////////////////////////////////////////////////////////////
+bool nvdimm_update(TARGETING::TargetHandleList &i_nvdimmList)
+{
+ NvdimmsUpdate l_nvdimmsUpdate(i_nvdimmList);
+ return l_nvdimmsUpdate.runUpdate();
+}
+
+}; // end namespace NVDIMM
diff --git a/src/usr/isteps/nvdimm/nvdimm_update.H b/src/usr/isteps/nvdimm/nvdimm_update.H
new file mode 100644
index 000000000..6e2a137fc
--- /dev/null
+++ b/src/usr/isteps/nvdimm/nvdimm_update.H
@@ -0,0 +1,278 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/isteps/nvdimm/nvdimm_update.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2018 */
+/* [+] 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 */
+#ifndef NVDIMM_UPDATE_H
+#define NVDIMM_UPDATE_H
+
+/**
+ * @file nvdimm/nvdimm_update.H
+ *
+ * @brief Interface to support updating NVDIMM controller code
+ */
+
+#include <cstdint>
+#include <errl/errlentry.H>
+#include <util/utillidmgr.H>
+
+namespace NVDIMM
+{
+// Some invalid constants
+const uint16_t INVALID_ID = 0xFFFF;
+const uint16_t INVALID_VERSION = 0xFFFF;
+const uint32_t INVALID_TYPE = 0xFFFFFFFF;
+
+// Type is combination of manufacturer id and product id
+const uint32_t JEDEC_NVDIMM_16GB_TYPE = 0x01945377;
+const uint32_t JEDEC_NVDIMM_32GB_TYPE = 0x01945378;
+
+class NvdimmLidImage
+{
+ public:
+ /**
+ * @brief Constructor that sets access to LID information
+ * @param i_lidId - NVDIMM_16GB_LIDID or NVDIMM_32GB_LIDID
+ * @param io_errHndl - error filled in if lid not loadable
+ */
+ explicit NvdimmLidImage(Util::LidId i_lidId, errlHndl_t& io_errHdl);
+
+ /**
+ * @brief Cleanup any allocated memory holding the lid image
+ */
+ ~NvdimmLidImage();
+
+ /**
+ * @brief Grab the type of the image
+ * (The type will be in raw little-endian format)
+ * @return concated manufacturer id and product id
+ * module_mnfg_id_code (0-1) and module_product_id (2-3)
+ */
+ uint32_t getType();
+
+ /**
+ * @brief Get the firmware version of image
+ * @return o_version - version of the image in raw little-endian format
+ */
+ uint16_t getVersion();
+
+ /**
+ * @brief Get the actual NVDIMM flash image to load on the NVDIMM
+ * @return Pointer to the start of the flash image
+ */
+ void * getFlashImage();
+
+ /**
+ * @brief Get the size of the actual flash image
+ * @return Image size
+ */
+ size_t getFlashImageSize();
+
+ /**
+ * @brief Check if the image was loaded into memory
+ * @return true, if image was loaded into memory
+ */
+ bool isImageLoaded();
+
+
+ //-----------------------------------------------------------//
+ // Layout of NVDIMM lid image
+ //
+ // Keeping as struct so it can be overlayed on lid image
+ // Note: the multiple byte variables will be in little-endian
+ //-----------------------------------------------------------//
+ // Header of NVDIMM lid image
+ typedef struct nvdimm_image_header
+ {
+ // Byte 0-1
+ uint16_t module_mnfg_id_code;
+ // Byte 2-3
+ uint16_t module_product_id;
+ // Byte 4-5
+ uint16_t nv_memory_subsys_cntrlr_mnfg_id_code;
+ // Byte 6-7
+ uint16_t nv_memory_subsys_cntrlr_product_id;
+ // Byte 8
+ uint8_t module_revision_code;
+ // Byte 9
+ uint8_t nv_memory_subsys_cntrlr_revision_code;
+ // Byte 10-11
+ uint16_t controller_firmware_revision;
+ // Byte 12-13
+ uint16_t energy_source_firmware_revision;
+ // Byte 14
+ uint8_t subcomponent_firmware_revision;
+ // Byte 15
+ uint8_t rsvd_0;
+ // Byte 16-17
+ uint16_t SMART_digital_signature_size;
+ // Byte 18
+ uint8_t SMART_digital_signature;
+ // Byte 19
+ union
+ {
+ uint8_t _valid;
+ struct
+ {
+ uint8_t _subcomponent_firmware_revision:1; // bit7 in spec
+ uint8_t _energy_source_firmware_revision:1; // bit6
+ uint8_t _nv_memory_subsys_cntrlr_revision_code:1; // bit5
+ uint8_t _module_revision_code:1; // bit4
+ uint8_t _nv_memory_subsys_cntrlr_product_id:1; // bit3
+ uint8_t _nv_memory_subsys_cntrlr_mnfg_id_code:1; // bit2
+ uint8_t _module_mnfg_product_id:1; // bit1
+ uint8_t _module_mnfg_id:1; // bit0 in spec
+ } PACKED;
+ };
+
+ // Byte 20-23
+ uint32_t firmware_image_size; // Includes 32-byte header + actual fw image
+ // Byte 20 LSB, Byte 23 MSB
+ // Byte 24-25
+ uint16_t firmware_image_checksum;
+ // Byte 26-30
+ uint8_t rsvd_1[5];
+ // Byte 31
+ uint8_t firmware_image_format;
+ } nvdimm_image_header_t;
+ // After header, these two follow:
+ // Digital signature (size: SMART_digital_signature_size bytes)
+ // Actual flash firmware image
+ // (size: firmware_image_size bytes - 32-byte header)
+ //-----------------------------------------------------------//
+
+ private:
+ /**
+ * @brief Load the lid image into memory
+ */
+ errlHndl_t loadImage();
+
+ /**
+ * @brief Unload the lid image from memory
+ */
+ errlHndl_t unloadImage();
+
+ // force user to supply lid_id
+ NvdimmLidImage();
+
+ // status of whether or not the image was loaded into memory
+ bool iv_ImageLoaded;
+
+ // pointer to lid image
+ // note: memory allocated/deallocated by iv_lidMgr
+ void * iv_lidImage;
+
+ // size of lid image
+ size_t iv_lidImageSize;
+
+ // lid manager for nvdimm lid image
+ UtilLidMgr* iv_lidMgr;
+};
+
+
+class NvdimmInstalledImage
+{
+ public:
+ /**
+ * @brief Constructor to associate a target DIMM to grab info from
+ * @param i_nvDimm - NVDIMM target
+ */
+ explicit NvdimmInstalledImage(TARGETING::Target * i_nvDimm);
+
+ /**
+ * @brief Grab the type of the installed nvdimm
+ * (The type will be in raw little-endian format)
+ * @param o_type - concated manufacturer id and product id
+ * @return error if read operation fails
+ */
+ errlHndl_t getType(uint32_t & o_type);
+
+ /**
+ * @brief Grab the installed NVDIMM's version
+ * @param o_version - version of installed NVDIMM image
+ * @return error if read operation fails
+ */
+ errlHndl_t getVersion(uint16_t & o_version);
+
+ /**
+ * @brief Accessor to grab the current NVDIMM target
+ * @return NVDIMM target
+ */
+ const TARGETING::Target * getNvdimmTarget(void)
+ {
+ return iv_dimm;
+ }
+
+ private:
+ // nvdimm target
+ TARGETING::Target * iv_dimm;
+
+ // little-endian version of installed nvdimm
+ uint16_t iv_version;
+
+ // Type contains these two concatentated little-endian IDs
+ uint16_t iv_manufacturer_id;
+ uint16_t iv_product_id;
+};
+
+
+class NvdimmsUpdate
+{
+ public:
+ /**
+ * @brief Constructor that uses passed in nvdimm list
+ * @parm[in] i_nvdimmList List of NVDIMMs to update
+ */
+ explicit NvdimmsUpdate(TARGETING::TargetHandleList i_nvdimmList);
+
+ /**
+ * @brief Main function that tries to update all NVDIMMs (if needed)
+ * This function runs SPD and lid loading/unloading, so should
+ * not be called multiple times
+ * @return true if no errors reported, else false
+ */
+ bool runUpdate(void);
+
+ protected:
+ /**
+ * @brief Checks if an update is needed for an individual nvdimm
+ * @param[out] o_update_needed - true if lid image is good to
+ * update current image, else false
+ * @param[in] i_lid_image - lid image that is appropriate for nvdimm update
+ * @param[in] i_cur_image - current installed image on the nvdimm
+
+ */
+ errlHndl_t isUpdateNeeded(bool & o_update_needed,
+ NvdimmLidImage * i_lid_image,
+ NvdimmInstalledImage * i_cur_image);
+
+ private:
+ // Force user to supply NVDIMM list
+ NvdimmsUpdate();
+
+ // List of NVDIMMs installed in system
+ TARGETING::TargetHandleList iv_nvdimmList;
+
+};
+
+} // Namespace NVDIMM
+#endif
diff --git a/src/usr/targeting/common/util.C b/src/usr/targeting/common/util.C
index 71811366f..286c37b6c 100644
--- a/src/usr/targeting/common/util.C
+++ b/src/usr/targeting/common/util.C
@@ -329,19 +329,27 @@ TARGETING::TargetHandleList getProcNVDIMMs( TARGETING::Target * i_proc )
{
TargetHandleList o_nvdimmList;
- TargetHandleList l_dimmTargetList;
- getChildAffinityTargets( l_dimmTargetList, i_proc, CLASS_NA, TYPE_DIMM );
+ TARGETING::ATTR_MODEL_type l_chipModel =
+ i_proc->getAttr<TARGETING::ATTR_MODEL>();
- for (TargetHandleList::iterator it = l_dimmTargetList.begin();
- it != l_dimmTargetList.end(); ++it)
+ // NVDIMM only present on NIMBUS systems
+ if (l_chipModel == TARGETING::MODEL_NIMBUS)
{
- TARGETING::Target* l_dimm = *it;
- if (TARGETING::isNVDIMM(l_dimm))
+ TargetHandleList l_dimmTargetList;
+ getChildAffinityTargets(l_dimmTargetList, i_proc, CLASS_NA, TYPE_DIMM);
+
+ for (TargetHandleList::iterator it = l_dimmTargetList.begin();
+ it != l_dimmTargetList.end(); ++it)
{
- // Found a valid NVDIMM
- o_nvdimmList.push_back(l_dimm);
+ TARGETING::Target* l_dimm = *it;
+ if (TARGETING::isNVDIMM(l_dimm))
+ {
+ // Found a valid NVDIMM
+ o_nvdimmList.push_back(l_dimm);
+ }
}
}
+
return o_nvdimmList;
}
diff --git a/src/usr/vpd/spdDDR4.H b/src/usr/vpd/spdDDR4.H
index bf4d0dfc8..8e03a0f0d 100755
--- a/src/usr/vpd/spdDDR4.H
+++ b/src/usr/vpd/spdDDR4.H
@@ -47,7 +47,7 @@ namespace SPD
const KeywordData ddr4Data[] =
{
// ----------------------------------------------------------------------------------
- // NOTE: This list must remain an ordered list! The Keyword must be in numerical
+ // NOTE: This list must remain an ordered list! The Keyword must be in numerical
// order (values defined in spdenums.H) to allow efficient searching, a unit
// test enforces this.
// ----------------------------------------------------------------------------------
@@ -136,6 +136,8 @@ const KeywordData ddr4Data[] =
{ 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 },
+ { RAW_MODULE_PRODUCT_ID, 0xc0, 0x02, 0x00, 0x00, false, false, NA },
+ { RAW_MODULE_MANUFACTURER_ID, 0x140, 0x02, 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