diff options
author | Matthew Raybuck <matthew.raybuck@ibm.com> | 2019-05-03 08:32:02 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2019-05-09 10:42:22 -0500 |
commit | 7d1cedd447b62cf0a61e249ec691b0a384711996 (patch) | |
tree | fe161b3b024a798272320f1e002d6e4545703043 /src | |
parent | e929912354d61206c2dbfe43a3d1db46072056fe (diff) | |
download | talos-hostboot-7d1cedd447b62cf0a61e249ec691b0a384711996.tar.gz talos-hostboot-7d1cedd447b62cf0a61e249ec691b0a384711996.zip |
Add keyword support for OCMB SPD reads
Currently the only supported keyword was ENTIRE_SPD for OCMB chips. This
commit adds support for all of the common keywords (modSpec NA and DDIMM) for
DDRx DIMMs and new keywords for OCMB_MODULE_PART_NUMBER and
OCMB_MODULE_SERIAL_NUMBER.
Change-Id: Ib29fb6153e47e56b24a1e7f51c8cbf33e6a48d73
RTC:203788
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/76922
Reviewed-by: Matt Derksen <mderkse1@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: Michael Baiocchi <mbaiocch@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/include/usr/vpd/vpdreasoncodes.H | 1 | ||||
-rw-r--r-- | src/usr/vpd/ocmb_spd.C | 367 | ||||
-rw-r--r-- | src/usr/vpd/spd.C | 20 | ||||
-rwxr-xr-x | src/usr/vpd/spd.H | 20 |
4 files changed, 342 insertions, 66 deletions
diff --git a/src/include/usr/vpd/vpdreasoncodes.H b/src/include/usr/vpd/vpdreasoncodes.H index 8a201c422..e4336c9f8 100644 --- a/src/include/usr/vpd/vpdreasoncodes.H +++ b/src/include/usr/vpd/vpdreasoncodes.H @@ -99,6 +99,7 @@ enum vpdModuleId // OCMB SPD VPD_OCMB_GET_SPD = 0x90, + VPD_OCMB_SPD_PERFORM_OP = 0x91, }; diff --git a/src/usr/vpd/ocmb_spd.C b/src/usr/vpd/ocmb_spd.C index c4f8137cc..4e0899c91 100644 --- a/src/usr/vpd/ocmb_spd.C +++ b/src/usr/vpd/ocmb_spd.C @@ -28,8 +28,17 @@ #include <errl/errlentry.H> #include <vpd/vpdreasoncodes.H> +#include "spd.H" +#include "errlud_vpd.H" + extern trace_desc_t * g_trac_spd; +//#define TRACSSCOMP(args...) TRACFCOMP(args) +#define TRACSSCOMP(args...) + +// Namespace alias for targeting +namespace T = TARGETING; + namespace SPD { @@ -54,17 +63,39 @@ namespace SPD * NOTE: ONLY ENTIRE_SPD READ SUPPORTED CURRENTLY */ errlHndl_t ocmbSPDPerformOp(DeviceFW::OperationType i_opType, - TARGETING::Target* i_target, - void* io_buffer, - size_t& io_buflen, - int64_t i_accessType, - va_list i_args); + T::TargetHandle_t i_target, + void* io_buffer, + size_t& io_buflen, + int64_t i_accessType, + va_list i_args); + +/** + * @param This function is a wrapper for reading the correct keyword. + * + * @param[in] i_target The target DDIMM to access. + * + * @param[in] i_byteAddr The offset into the JEDEC SPD layout. + * + * @param[in] i_numbytes Number of bytes to read. + * + * @param[out] o_data The data buffer that will return the data read. + * + * @param[in] i_location The SPD source (PNOR/SEEPROM). + * + * @return errlHndl_t nullptr if successful, otherwise a pointer to the + * error log. + */ +errlHndl_t ocmbFetchData(T::TargetHandle_t i_target, + uint64_t i_byteAddr, + size_t i_numBytes, + void* o_data, + EEPROM::EEPROM_SOURCE i_location); // Register the perform Op with the routing code for OCMBs. -DEVICE_REGISTER_ROUTE( DeviceFW::READ, - DeviceFW::SPD, - TARGETING::TYPE_OCMB_CHIP, - ocmbSPDPerformOp ); +DEVICE_REGISTER_ROUTE(DeviceFW::READ, + DeviceFW::SPD, + T::TYPE_OCMB_CHIP, + ocmbSPDPerformOp); /** * @brief Read keyword from SPD @@ -72,37 +103,83 @@ DEVICE_REGISTER_ROUTE( DeviceFW::READ, * Currently used to detect I2C_MUTEX and OCMB_CHIP targets * * @param[in] i_target OCMB target to read data from - * @param[in] i_keyword keyword from spdenums.H to read * @param[in/out] io_buffer databuffer SPD will be written to - * @param[in] i_buflen length of the given data buffer + * @param[in/out] io_buflen length of the given data buffer + * @param[in] i_keyword keyword from spdenums.H to read + * @param[in] i_memType The memory type of this target. * * @pre io_buffer and i_target must be non-null * @pre currenlty only supported value for i_keyword is ENTIRE_SPD * * @return errlHndl_t */ -errlHndl_t ocmbGetSPD(const TARGETING::Target* i_target, - const uint64_t & i_keyword, - void* const io_buffer, - const size_t& i_buflen) +errlHndl_t ocmbGetSPD(T::TargetHandle_t i_target, + void* const io_buffer, + size_t& io_buflen, + const uint64_t & i_keyword, + const uint8_t i_memType) { errlHndl_t l_errl = nullptr; - TRACFCOMP( g_trac_spd, - ENTER_MRK"ocmbGetSPD()" ); + TRACFCOMP(g_trac_spd, + ENTER_MRK"ocmbGetSPD()"); - // If any of these asserts fail it is a SW error - assert(io_buffer != nullptr, "io_buffer is nullptr in ocmbGetSPD"); assert(i_target != nullptr, "i_target is nullptr in ocmbGetSPD"); - assert(i_buflen >= SPD::OCMB_SPD_EFD_COMBINED_SIZE, "Buffer must be at least 2 KB in ocmbGetSPD"); do { - if(i_keyword != ENTIRE_SPD) + const KeywordData* entry = nullptr; + l_errl = getKeywordEntry(i_keyword, + i_memType, + i_target, + entry); + if (l_errl) + { + break; + } + + // Check to be sure entry is not nullptr. + if (entry == nullptr) { - TRACFCOMP( g_trac_spd, - "ocmbGetSPD() only entire SPD currently supported, 0x%X is not supported", - i_keyword); + TRACFCOMP(g_trac_spd, + ERR_MRK"KeywordData entry pointer is nullptr!"); + + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid VPD::VPD_OCMB_GET_SPD + * @reasoncode VPD::VPD_NULL_ENTRY + * @userdata1[00:31] Buffer Size + * @userdata1[32:63] Memory Type + * @userdata2[00:31] SPD Keyword + * @userdata2[32:63] Target HUID + * @devdesc SPD is not valid for this part + * @custdesc A problem occurred during the IPL + * of the system. + */ + l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + VPD::VPD_OCMB_GET_SPD, + VPD::VPD_NULL_ENTRY, + TWO_UINT32_TO_UINT64(io_buflen, + i_memType), + TWO_UINT32_TO_UINT64(i_keyword, + T::get_huid(i_target)), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + + l_errl->collectTrace( "SPD", 256); + + break; + } + + // For now only support DDIMM, NA keywords with offset less than 128, + // and the ENTIRE_SPD keyword. + if ( ((entry->modSpec != DDIMM) + && (entry->modSpec == NA && entry->offset >= 0x80)) + && (i_keyword != ENTIRE_SPD)) + { + TRACFCOMP(g_trac_spd, + "ocmbGetSPD() keyword 0x%X is not supported", + i_keyword); /*@ * @errortype * @moduleid VPD::VPD_OCMB_GET_SPD @@ -113,44 +190,244 @@ errlHndl_t ocmbGetSPD(const TARGETING::Target* i_target, * @custdesc Firmware error during system IPL */ l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, - VPD::VPD_OCMB_GET_SPD, - VPD::VPD_NOT_SUPPORTED, - i_keyword, - i_target->getAttr<TARGETING::ATTR_HUID>(), - ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + VPD::VPD_OCMB_GET_SPD, + VPD::VPD_NOT_SUPPORTED, + i_keyword, + i_target->getAttr<TARGETING::ATTR_HUID>(), + ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + break; + } + + // For ENTIRE_SPD, we must read OCMB SPD and EFD combined size. + size_t dataSize = entry->length; + if (i_keyword == ENTIRE_SPD) + { + assert(((io_buflen >= OCMB_SPD_EFD_COMBINED_SIZE) + || (io_buffer == nullptr)), + "Buffer must be at least 2 KB in ocmbGetSPD for ENTIRE_SPD"); + dataSize = OCMB_SPD_EFD_COMBINED_SIZE; + } + + // Support passing in nullptr buffer to return VPD field size. + if (io_buffer == nullptr) + { + io_buflen = dataSize; break; + } + l_errl = spdCheckSize(io_buflen, + dataSize, + i_keyword); + + if (l_errl != nullptr) + { + break; } - size_t l_spdReadBufferLen = SPD::OCMB_SPD_EFD_COMBINED_SIZE; - l_errl = DeviceFW::deviceOp(DeviceFW::READ, - const_cast<TARGETING::Target*>(i_target), - io_buffer, - l_spdReadBufferLen, - DEVICE_EEPROM_ADDRESS(EEPROM::VPD_PRIMARY, - 0, - EEPROM::AUTOSELECT) - ); + l_errl = ocmbFetchData(i_target, + entry->offset, + dataSize, + io_buffer, + EEPROM::AUTOSELECT); + if (l_errl != nullptr) + { + break; + } - }while(0); + // Return the size read. + io_buflen = dataSize; + + } while(0); return l_errl; } +// ------------------------------------------------------------------ +// ocmbFetchData +// ------------------------------------------------------------------ +errlHndl_t ocmbFetchData(T::TargetHandle_t i_target, + uint64_t i_byteAddr, + size_t i_numBytes, + void* o_data, + EEPROM::EEPROM_SOURCE i_location) +{ + errlHndl_t err = nullptr; + + TRACSSCOMP(g_trac_spd, + ENTER_MRK"ocmbFetchData()" ); + + do + { + // Get the data + err = DeviceFW::deviceOp(DeviceFW::READ, + i_target, + o_data, + i_numBytes, + DEVICE_EEPROM_ADDRESS(EEPROM::VPD_PRIMARY, + i_byteAddr, + i_location)); + if( err ) + { + TRACFCOMP(g_trac_spd, + ERR_MRK"ocmbFetchData(): failing out of deviceOp"); + break; + } + + } while(0); + + TRACSSCOMP(g_trac_spd, + EXIT_MRK"ocmbFetchData(): returning %s errors", + ((err != nullptr) ? "with" : "with no") ); + + return err; +} + +// ------------------------------------------------------------------ +// isValidOcmbDimmType +// ------------------------------------------------------------------ +bool isValidOcmbDimmType(const uint8_t i_dimmType) +{ + return ((SPD_DDR4_TYPE == i_dimmType )); +} + +// ------------------------------------------------------------------ +// getMemType +// ------------------------------------------------------------------ +errlHndl_t getMemType(uint8_t& o_memType, + T::TargetHandle_t i_target) +{ + errlHndl_t err = nullptr; + + err = ocmbFetchData(i_target, + MEM_TYPE_ADDR, + MEM_TYPE_SZ, + &o_memType, + EEPROM::AUTOSELECT); + + TRACSSCOMP(g_trac_spd, + EXIT_MRK"SPD::getMemType() - MemType: 0x%02x, Error: %s", + o_memType, + ((err != nullptr) ? "Yes" : "No")); + + return err; +} + // See above for details errlHndl_t ocmbSPDPerformOp(DeviceFW::OperationType i_opType, - TARGETING::Target* i_target, + T::TargetHandle_t i_target, void* io_buffer, size_t& io_buflen, int64_t i_accessType, va_list i_args) { - errlHndl_t l_errl = nullptr; - const uint64_t l_keyword = va_arg(i_args, uint64_t); - l_errl = ocmbGetSPD(i_target, l_keyword, io_buffer, io_buflen); - return l_errl; -} + errlHndl_t errl = nullptr; + const uint64_t keyword = va_arg(i_args, uint64_t); + + TRACSSCOMP(g_trac_spd, + ENTER_MRK"ocmbSPDPerformOP(), io_buflen: %d, keyword: 0x%04x", + io_buflen, keyword ); + + do + { + // Read the Basic Memory Type + uint8_t memType(MEM_TYPE_INVALID); + errl = getMemType(memType, i_target); + + if( errl ) + { + break; + } + + TRACSSCOMP(g_trac_spd, + INFO_MRK"Mem Type: %04x", + memType); + + // Check the Basic Memory Type + if (isValidOcmbDimmType(memType)) + { + // If the user wanted the Basic memory type, return this now. + if(BASIC_MEMORY_TYPE == keyword) + { + io_buflen = MEM_TYPE_SZ; + if (io_buffer != nullptr) + { + memcpy(io_buffer, &memType, io_buflen); + } + break; + } + + // Read the keyword value + errl = ocmbGetSPD(i_target, + io_buffer, + io_buflen, + keyword, + memType); + + if( errl ) + { + break; + } + } + else + { + TRACFCOMP(g_trac_spd, + ERR_MRK"Invalid Basic Memory Type (0x%04x), " + "target huid = 0x%x", + memType, + T::get_huid(i_target)); + + /*@ + * @errlortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid VPD::VPD_OCMB_SPD_PERFORM_OP + * @reasoncode VPD::VPD_INVALID_BASIC_MEMORY_TYPE + * @userdata1 Basic Memory Type (Byte 2) + * @userdata2 Keyword Requested + * @devdesc Invalid Basic Memory Type + */ + errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + VPD::VPD_OCMB_SPD_PERFORM_OP, + VPD::VPD_INVALID_BASIC_MEMORY_TYPE, + memType, + keyword); + + // User could have installed a bad/unsupported dimm + errl->addHwCallout(i_target, + HWAS::SRCI_PRIORITY_HIGH, + HWAS::DECONFIG, + HWAS::GARD_NULL); + + errl->addProcedureCallout(HWAS::EPUB_PRC_HB_CODE, + HWAS::SRCI_PRIORITY_LOW); + + errl->addProcedureCallout(HWAS::EPUB_PRC_SP_CODE, + HWAS::SRCI_PRIORITY_LOW); + + errl->collectTrace("SPD", 256); + + break; + } + } while(0); + + // If there is an error, add parameter info to log + if ( errl != nullptr ) + { + VPD::UdVpdParms(i_target, + io_buflen, + 0, + keyword, + true) // read + .addToLog(errl); + } + TRACSSCOMP(g_trac_spd, + EXIT_MRK"ocmbSPDPerformOP(): returning %s errors", + (errl ? "with" : "with no") ); + + return errl; } + + +} // End of SPD namespace diff --git a/src/usr/vpd/spd.C b/src/usr/vpd/spd.C index 34bc37cec..bd54bc35b 100644 --- a/src/usr/vpd/spd.C +++ b/src/usr/vpd/spd.C @@ -173,26 +173,6 @@ errlHndl_t getModType ( modSpecTypes_t & o_modType, VPD::vpdCmdTarget i_location ); /** - * @brief This function will scan the table and return the entry - * corresponding to the keyword being requested. - * - * @param[in] i_keyword - The keyword being requested. - * - * @param[in] i_memType - The memory type of the target. - * - * @param[in] i_target - Target (only used for callouts) - * - * @param[out] o_entry - The table entry corresponding to the keyword. - * - * @return errlHndl_t - NULL if successful, otherwise a pointer to - * the error log. - */ -errlHndl_t getKeywordEntry ( VPD::vpdKeyword i_keyword, - uint64_t i_memType, - TARGETING::Target * i_target, - const KeywordData *& o_entry ); - -/** * @brief This function will set the size of SPD for the given target based on * the DIMM type. * diff --git a/src/usr/vpd/spd.H b/src/usr/vpd/spd.H index edf7d74c7..c3cb7b038 100755 --- a/src/usr/vpd/spd.H +++ b/src/usr/vpd/spd.H @@ -391,7 +391,25 @@ errlHndl_t dimmPresenceDetect( DeviceFW::OperationType i_opType, size_t & io_buflen, int64_t i_accessType, va_list i_args ); - +/** + * @brief This function will scan the table and return the entry + * corresponding to the keyword being requested. + * + * @param[in] i_keyword - The keyword being requested. + * + * @param[in] i_memType - The memory type of the target. + * + * @param[in] i_target - Target (only used for callouts) + * + * @param[out] o_entry - The table entry corresponding to the keyword. + * + * @return errlHndl_t - NULL if successful, otherwise a pointer to + * the error log. + */ +errlHndl_t getKeywordEntry(VPD::vpdKeyword i_keyword, + uint64_t i_memType, + TARGETING::Target* i_target, + const KeywordData* &o_entry ); /** * @brief This function is used to check the parameters in the SPD data that * indicate which module specific keywords are valid, and then check that |