diff options
Diffstat (limited to 'src/usr/vpd/ocmb_spd.C')
-rw-r--r-- | src/usr/vpd/ocmb_spd.C | 368 |
1 files changed, 298 insertions, 70 deletions
diff --git a/src/usr/vpd/ocmb_spd.C b/src/usr/vpd/ocmb_spd.C index c4f8137cc..2767efca7 100644 --- a/src/usr/vpd/ocmb_spd.C +++ b/src/usr/vpd/ocmb_spd.C @@ -28,16 +28,24 @@ #include <errl/errlentry.H> #include <vpd/vpdreasoncodes.H> +#include "ocmb_spd.H" +#include "spd.H" +#include "errlud_vpd.H" +#include <vpd/vpd_if.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 { /** * @brief Handle SPD READ deviceOp to OCMB_CHIP targets - * This function performs read operations on OCMBs by in turn performing - * an EEPROM deviceOp on this target, reading the first 2 KB of the OCMB's - * Primary VPD eeprom and returning it via a buffer * * @param[in] i_opType Operation type, see driverif.H * @param[in] i_target MMIO target @@ -50,107 +58,327 @@ namespace SPD * In this function, there is one argument, * the l_keyword, so far we only support ENTIRE_SPD * @return errlHndl_t - * - * 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); // 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 - * - * 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 - * - * @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* io_buffer, + size_t& io_buflen, + const VPD::vpdKeyword i_keyword, + const uint8_t i_memType, + EEPROM::EEPROM_SOURCE i_location) { errlHndl_t l_errl = nullptr; - 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 != nullptr) + { + 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 - * @moduleid VPD::VPD_OCMB_GET_SPD - * @reasoncode VPD::VPD_NOT_SUPPORTED - * @userdata1 Keyword Enum - * @userdata2 Target huid - * @devdesc Attempted to lookup SPD keyword not supported - * @custdesc Firmware error during system IPL + * @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_NOT_SUPPORTED, - i_keyword, - i_target->getAttr<TARGETING::ATTR_HUID>(), - ERRORLOG::ErrlEntry::ADD_SW_CALLOUT); + 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; + } + + // Only allow keywords supported by DDIMM + l_errl = checkModSpecificKeyword(*entry, + i_memType, + i_target, + VPD::SEEPROM); + if (l_errl != nullptr) + { + break; + } + + if (entry->isSpecialCase) + { + l_errl = spdSpecialCases(*entry, + io_buffer, + i_target, + i_memType, + VPD::SEEPROM); + if (l_errl != nullptr) + { + break; + } + } + + // Support passing in nullptr buffer to return VPD field size. + if (io_buffer == nullptr) + { + io_buflen = entry->length; + 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 = spdCheckSize(io_buflen, + entry->length, + i_keyword); - }while(0); + if (l_errl != nullptr) + { + break; + } + + l_errl = ocmbFetchData(i_target, + entry->offset, + entry->length, + io_buffer, + i_location); + + if (l_errl != nullptr) + { + break; + } + + // Return the size read. + io_buflen = entry->length; + + } 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()" + " i_byteAddr = 0x%x i_numBytes = %d i_location = 0x%x", + i_byteAddr, i_numBytes, i_location); + + 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, + EEPROM::EEPROM_SOURCE i_location) +{ + errlHndl_t err = nullptr; + + err = ocmbFetchData(i_target, + MEM_TYPE_ADDR, + MEM_TYPE_SZ, + &o_memType, + i_location); + + 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, EEPROM::AUTOSELECT); + + 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, + EEPROM::AUTOSELECT); + + 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[00:31] Basic Memory Type (Byte 2) + * @userdata1[32:63] Target HUID + * @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, + TWO_UINT32_TO_UINT64(memType, + T::get_huid(i_target)), + 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 |