summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthew Raybuck <matthew.raybuck@ibm.com>2019-05-03 08:32:02 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2019-05-09 10:42:22 -0500
commit7d1cedd447b62cf0a61e249ec691b0a384711996 (patch)
treefe161b3b024a798272320f1e002d6e4545703043 /src
parente929912354d61206c2dbfe43a3d1db46072056fe (diff)
downloadtalos-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.H1
-rw-r--r--src/usr/vpd/ocmb_spd.C367
-rw-r--r--src/usr/vpd/spd.C20
-rwxr-xr-xsrc/usr/vpd/spd.H20
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
OpenPOWER on IntegriCloud