diff options
author | Matthew Raybuck <matthew.raybuck@ibm.com> | 2019-03-12 12:18:53 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2019-03-18 13:10:05 -0500 |
commit | d47b63700d87c88085f114b66ea02d99f19a5e62 (patch) | |
tree | 5c71bb9cd204e40a6344740f04bd0a41c880a4bf /src | |
parent | 656ba908c6f2e83c8e7323d6774709e44361443d (diff) | |
download | talos-hostboot-d47b63700d87c88085f114b66ea02d99f19a5e62.tar.gz talos-hostboot-d47b63700d87c88085f114b66ea02d99f19a5e62.zip |
Add functions to get Device Id and MFR revision from UCD
This will add the necessary functions to properly read the Device Id and
MFR revision from the UCD90* devices on a ZZ or Zeppelin system.
Change-Id: I38ffdffb62bf1c1af8941819cdbd74458308879f
RTC:205979
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/73185
Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com>
Reviewed-by: Michael Baiocchi <mbaiocch@us.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/include/usr/ucd/ucd_reasoncodes.H | 46 | ||||
-rw-r--r-- | src/usr/isteps/ucd/updateUcdFlash.C | 333 |
2 files changed, 370 insertions, 9 deletions
diff --git a/src/include/usr/ucd/ucd_reasoncodes.H b/src/include/usr/ucd/ucd_reasoncodes.H new file mode 100644 index 000000000..bfa18397f --- /dev/null +++ b/src/include/usr/ucd/ucd_reasoncodes.H @@ -0,0 +1,46 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/usr/ucd/ucd_reasoncodes.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2019 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#ifndef __UCD_REASONCODES_H +#define __UCD_REASONCODES_H + +#include <hbotcompid.H> + +namespace UCD_RC +{ + + enum UcdModuleId + { + MOD_UCD_INIT = 0x01, + }; + + enum UcdReasonCode + { + RC_DEVICE_READ_UNEXPECTED_SIZE_DEVICE_ID = UCD_COMP_ID | 0x01, + RC_DEVICE_READ_UNEXPECTED_SIZE_MFR_REVISION = UCD_COMP_ID | 0x02, + }; + +}; // namespace UCD + +#endif diff --git a/src/usr/isteps/ucd/updateUcdFlash.C b/src/usr/isteps/ucd/updateUcdFlash.C index 4e1e3b13d..1211b460b 100644 --- a/src/usr/isteps/ucd/updateUcdFlash.C +++ b/src/usr/isteps/ucd/updateUcdFlash.C @@ -25,43 +25,358 @@ #include <config.h> #include <isteps/ucd/updateUcdFlash.H> +#include <ucd/ucd_reasoncodes.H> #include <devicefw/driverif.H> + +#include <hwas/common/hwasCallout.H> + #include <targeting/common/entitypath.H> #include <targeting/common/target.H> #include <targeting/common/targetservice.H> +#include <targeting/common/utilFilter.H> + #include <errl/errlentry.H> -#include <devicefw/driverif.H> +#include <errl/errlmanager.H> +#include <errl/hberrltypes.H> + #include <trace/interface.H> #include <string.h> #include <hbotcompid.H> -#include <errl/errlmanager.H> -#include <errl/errlentry.H> namespace POWER_SEQUENCER { - -namespace TI // Texas Instruments +namespace TI { - namespace UCD // UCD Series { trace_desc_t* g_trac_ucd = nullptr; TRAC_INIT(&g_trac_ucd, UCD_COMP_NAME, 2*KILOBYTE); +class Ucd +{ +private: + + enum DEVICE_OP_LENGTH : size_t + { + MFR_REVISION_SIZE = 12, + DEVICE_ID_SIZE = 32, + }; + + enum COMMAND : uint8_t + { + // PMBUS Specificiation + MFR_REVISION = 0x9B, // Common, max 12 ASCII bytes + + // Manufacturer specific (0xD0-> 0xFD) + DEVICE_ID = 0xFD, // Common. max 32 ASCII bytes + }; + + const TARGETING::TargetHandle_t iv_pUcd; + char* iv_deviceId; + uint16_t iv_mfrRevision; + + /* + * Delete Copy Constructor + */ + Ucd(const Ucd&) = delete; + + /* + * Delete Copy Assignment + */ + Ucd& operator=(const Ucd&) = delete; + + /* + * Delete Move Constructor + */ + Ucd (Ucd&&) = delete; + + /* + * Delete Move Assignment + */ + Ucd& operator=(Ucd&&) = delete; + +public: + + /* @brief Constructor that takes a UCD target and sets up all of the + * instance variables. Will assert if a nullptr is given or if + * the given target is not of type POWER_SEQUENCER. + * + * @param[in] i_ucd A pointer to the UCD target. Must not be nullptr + * and must be of type POWER_SEQUENCER. + */ + Ucd(const TARGETING::TargetHandle_t i_ucd) + : iv_pUcd(i_ucd), iv_deviceId(nullptr), iv_mfrRevision(0) + { + assert(i_ucd != nullptr, "i_ucd must not be nullptr"); + assert(i_ucd->getAttr<TARGETING::ATTR_TYPE>() + == TARGETING::TYPE_POWER_SEQUENCER, + "i_ucd must be of type POWER_SEQUENCER"); + } + + /* @brief Destructor that cleans up the iv_deviceId instance + * variable. + * + */ + ~Ucd() + { + delete[] iv_deviceId; + iv_deviceId = nullptr; + } + + /* + * @brief Sets up the device id and mfr revision instance + * variables by performing two device reads on the UCD. + * + * @return nullptr on success. Otherwise, a error that occurred. + * + */ + errlHndl_t initialize() + { + errlHndl_t err = nullptr; + + // Wipe out the instance variables in case this function is called + // multiple times. That way if we fail during one of those attempts + // old values aren't preserved. + delete[] iv_deviceId; + iv_deviceId = nullptr; + iv_mfrRevision = 0; + + do + { + char deviceIdBuffer[DEVICE_ID_SIZE]{}; + + // Get the I2C info for this UCD. + const auto i2cInfo = iv_pUcd-> + getAttr<TARGETING::ATTR_I2C_CONTROL_INFO>(); + + TARGETING::TargetHandle_t i2cMaster = + TARGETING::targetService().toTarget(i2cInfo.i2cMasterPath); + + assert(i2cMaster != nullptr, "i2cMaster for UCD 0x%.8X was nullptr", + get_huid(iv_pUcd)); + + size_t size = sizeof(deviceIdBuffer); + + err = deviceOp(DeviceFW::READ, + i2cMaster, + deviceIdBuffer, + size, + DEVICE_I2C_SMBUS_BLOCK(i2cInfo.engine, + i2cInfo.port, + i2cInfo.devAddr, + DEVICE_ID, + i2cInfo.i2cMuxBusSelector, + &i2cInfo.i2cMuxPath) + ); + + // @TODO RTC 205982: Handle the PEC byte if it exists. + if (err) + { + TRACFCOMP(g_trac_ucd, ERR_MRK"Ucd::Initialize(): Could not " + "read DEVICE_ID from UCD " + "0x%.8X", get_huid(iv_pUcd)); + break; + } + + // Verify that the buffer is the size the we expected to get. + if (size != DEVICE_ID_SIZE) + { + TRACFCOMP(g_trac_ucd, ERR_MRK"Ucd::Initialize(): Read from " + "UCD 0x%.8X returned " + "size different than requested. " + "Actual %d, expected %d", + get_huid(iv_pUcd), + size, DEVICE_ID_SIZE); + + /*@ + * @errortype + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid UCD_RC::MOD_UCD_INIT + * @reasoncode UCD_RC::RC_DEVICE_READ_UNEXPECTED_SIZE_DEVICE_ID + * @devdesc A device read from the UCD didn't read + * the expected number of bytes. + * @custdesc A problem occurred during the IPL of the + * system: Internal Firmware Error + * @userdata1[00:31] Expected read size + * @userdata1[32:63] Actual read size + * @userdata2 HUID of the UCD + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + UCD_RC::MOD_UCD_INIT, + UCD_RC::RC_DEVICE_READ_UNEXPECTED_SIZE_DEVICE_ID, + TWO_UINT32_TO_UINT64(DEVICE_ID_SIZE, size), + get_huid(iv_pUcd) + ); + + err->addI2cDeviceCallout(i2cMaster, + i2cInfo.engine, + i2cInfo.port, + i2cInfo.devAddr, + HWAS::SRCI_PRIORITY_HIGH); + + err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_LOW); + + + break; + } + + // Verify there is a null terminator at the end of the buffer. + if (deviceIdBuffer[DEVICE_ID_SIZE-1] != '\0') + { + deviceIdBuffer[DEVICE_ID_SIZE-1] = '\0'; + } + + // Since the format of the buffer will be: Device Id|..|..|.. + // Replace the first occurence of the | symbol with null to + // exclude irrelevant info. + auto pDelimiter = strchr(deviceIdBuffer, '|'); + + if (pDelimiter != nullptr) + { + *pDelimiter = '\0'; + } + + // Copy the device id into the instance variable. + iv_deviceId = new char[strlen(deviceIdBuffer)+1](); + strcpy(iv_deviceId, deviceIdBuffer); + + TRACFCOMP(g_trac_ucd, INFO_MRK + "Ucd::Initialize(): DEVICE_ID read from UCD 0x%.8X as %s", + get_huid(iv_pUcd), + iv_deviceId); + + // This is the buffer that will be used to read the MFR Revision + // from the UCD device. + union mfrRevisionBuffer + { + // The MFR Revision represented as a value. + uint16_t value; + // The MFR Revision represented as ASCII characters excluding + // null terminator. + uint8_t str[MFR_REVISION_SIZE]; + } mfrBuf; + + size = MFR_REVISION_SIZE; + + // Read the MFR revision from the UCD device. + err = deviceOp(DeviceFW::READ, + i2cMaster, + mfrBuf.str, + size, + DEVICE_I2C_SMBUS_BLOCK(i2cInfo.engine, + i2cInfo.port, + i2cInfo.devAddr, + MFR_REVISION, + i2cInfo.i2cMuxBusSelector, + &i2cInfo.i2cMuxPath) + ); + + // @TODO RTC 205982: Need to handle the case where a bad PEC byte + // is returned + if (err) + { + TRACFCOMP(g_trac_ucd, ERR_MRK"Ucd::Initializei(): Could not " + "read MFR_REVISION from UCD 0x%.8X", + get_huid(iv_pUcd)); + break; + } + + // Verify that the buffer is the size the we expected to get. + if (size != MFR_REVISION_SIZE) + { + TRACFCOMP(g_trac_ucd, ERR_MRK"Ucd::Initialize(): Read from UCD " + "0x%.8X returned " + "size different than requested. " + "Actual %d, expected %d", + get_huid(iv_pUcd), + size, MFR_REVISION_SIZE); + + /*@ + * @errortype + * @severity ERRL_SEV_UNRECOVERABLE + * @moduleid UCD_RC::MOD_UCD_INIT + * @reasoncode UCD_RC::RC_DEVICE_READ_UNEXPECTED_SIZE_MFR_REVISION + * @devdesc A device read from the UCD didn't read + * the expected number of bytes. + * @custdesc A problem occurred during the IPL of the + * system: Internal Firmware Error + * @userdata1[00:31] Expected read size + * @userdata1[32:63] Actual read size + * @userdata2 HUID of the UCD + */ + err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + UCD_RC::MOD_UCD_INIT, + UCD_RC::RC_DEVICE_READ_UNEXPECTED_SIZE_MFR_REVISION, + TWO_UINT32_TO_UINT64(MFR_REVISION_SIZE, size), + get_huid(iv_pUcd)); + + err->addI2cDeviceCallout(i2cMaster, + i2cInfo.engine, + i2cInfo.port, + i2cInfo.devAddr, + HWAS::SRCI_PRIORITY_HIGH); + + err->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_LOW); + break; + } + + // Convert the ASCII MFR revision to unsigned int. + iv_mfrRevision = mfrBuf.value; + + TRACFCOMP(g_trac_ucd, INFO_MRK + "Ucd::Initialize(): MFR_REVISION read from UCD 0x%.8X " + "as 0x%.4X", + get_huid(iv_pUcd), + mfrBuf.value); + + } while(0); + + return err; + } + + /* + * @brief Gets the Device ID for the UCD member of this + * struct. + * + * @return A constant pointer to the device id string. + * + */ + const char* getDeviceId() const + { + return iv_deviceId; + } + + /* @brief Will get the MFR Revision for the UCD member + * of this struct. + * + * @return The ASCII MFR revision as a uint16_t. + */ + uint16_t getMfrRevision() const + { + return iv_mfrRevision; + } + +}; + + errlHndl_t updateUcdFlash( TARGETING::Target* i_pUcd, const void* i_pFlashImage) { - errlHndl_t pError=nullptr; + errlHndl_t pError = nullptr; // Stub for future additional support return pError; } -} // End namespace POWER_SEQUENCER +} // End namespace UCD } // End namespace TI -} // End namespace UCD +} // End namespace POWER_SEQUENCER |