summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthew Raybuck <matthew.raybuck@ibm.com>2019-04-17 12:53:31 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2019-05-01 09:05:04 -0500
commit5f68c549965e0cebcb557026938ba57ff0aa8ba8 (patch)
treeff7d8613a33318ac2a0f2e0f61646facd94ae575 /src
parentdecb0b6a03b108af9f5818ebd9dc7f95b3ce342b (diff)
downloadtalos-hostboot-5f68c549965e0cebcb557026938ba57ff0aa8ba8.tar.gz
talos-hostboot-5f68c549965e0cebcb557026938ba57ff0aa8ba8.zip
Gemini vs Explorer Presence Detection via SPD
Since the OCMB chip is held in reset until after presence detection the IDEC register cannot be read to differentiate between Gemini and Explorer chip types. To work around this issue, during the early part of IPL when presence detection is occurring the OCMB IDEC function will instead read the SPD and populate the necessary attributes with what is found there. That will be used to determine the difference between Gemini and Explorer until later when the OCMB IDEC register can be read from. At that point the IDEC read will be executed again and the data read from the OCMB IDEC register will be used to cross-check the data read from the SPD. Any discrepancies will be handled with predictive error logs. Change-Id: Ica664b06ff3488f48253d3ef02eff2d49c5d240d RTC: 208696 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/76108 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')
-rw-r--r--src/include/usr/hwas/common/hwas_reasoncodes.H8
-rw-r--r--src/usr/hwas/common/hwas.C3
-rw-r--r--src/usr/hwas/hwasPlat.C647
-rw-r--r--src/usr/i2c/i2cTargetPres.C5
-rw-r--r--src/usr/isteps/istep10/call_proc_cen_ref_clk_enable.C10
5 files changed, 527 insertions, 146 deletions
diff --git a/src/include/usr/hwas/common/hwas_reasoncodes.H b/src/include/usr/hwas/common/hwas_reasoncodes.H
index 7b4b0cd39..f2d4e0da0 100644
--- a/src/include/usr/hwas/common/hwas_reasoncodes.H
+++ b/src/include/usr/hwas/common/hwas_reasoncodes.H
@@ -43,6 +43,9 @@ namespace HWAS
MOD_UPDATE_PROC_COMPAT_RISK_LEVEL = 0x0C,
MOD_CHECK_PG_FOR_DESC = 0x0D,
MOD_OCMB_IDEC = 0x0E,
+ MOD_OCMB_IDEC_PHASE_1 = 0x0F,
+ MOD_OCMB_IDEC_PHASE_2 = 0x10,
+ MOD_OCMB_TRANSLATE_SPD_IDEC = 0x11,
};
enum HwasReasonCode
@@ -81,8 +84,11 @@ namespace HWAS
RC_FORCED_NATIVE_INVALID_MIXED_EC = HWAS_COMP_ID | 0x1C,
RC_FORCED_NATIVE_OF_INCOMPATIBLE_RISK = HWAS_COMP_ID | 0x1D,
RC_PARTIAL_GOOD_MISSING_TARGET = HWAS_COMP_ID | 0x1E,
- RC_OCMB_SPD_IDEC_MISMATCH = HWAS_COMP_ID | 0x1F,
+ RC_OCMB_SPD_REVISION_MISMATCH = HWAS_COMP_ID | 0x1F,
RC_OCMB_UNEXPECTED_IDEC = HWAS_COMP_ID | 0x20,
+ RC_OCMB_UNKNOWN_CHIP_TYPE = HWAS_COMP_ID | 0x21,
+ RC_OCMB_INTERFACE_TYPE_MISMATCH = HWAS_COMP_ID | 0x22,
+ RC_OCMB_CHIP_ID_MISMATCH = HWAS_COMP_ID | 0x23,
};
enum HwasPlatUserDetailsTypes
diff --git a/src/usr/hwas/common/hwas.C b/src/usr/hwas/common/hwas.C
index 569061814..432d2d4f0 100644
--- a/src/usr/hwas/common/hwas.C
+++ b/src/usr/hwas/common/hwas.C
@@ -732,8 +732,7 @@ errlHndl_t discoverTargets()
&& (l_targetType != TYPE_TPM)
&& (l_targetType != TYPE_SP)
&& (l_targetType != TYPE_BMC)
- && (l_targetType != TYPE_I2C_MUX)
- && (l_targetType != TYPE_OCMB_CHIP))
+ && (l_targetType != TYPE_I2C_MUX))
{
// read Chip ID/EC data from these physical chips
errl = platReadIDEC(pTarget);
diff --git a/src/usr/hwas/hwasPlat.C b/src/usr/hwas/hwasPlat.C
index 543814d82..1fc6f939d 100644
--- a/src/usr/hwas/hwasPlat.C
+++ b/src/usr/hwas/hwasPlat.C
@@ -88,13 +88,19 @@ errlHndl_t platReadIDEC(const TargetHandle_t &i_target)
// Call over to the target-specific layer since every chip can have
// unique registers
size_t sz = 0;
- errlHndl_t l_errl =
- DeviceFW::deviceWrite(i_target,
- nullptr,
- sz,
- DEVICE_IDEC_ADDRESS());
+ errlHndl_t errl = nullptr;
- return l_errl;
+ // Pass a 1 as va_arg to signal phase 1 of ocmbIDEC to execute.
+ // Other IDEC functions will ignore this argument.
+ const uint64_t Phase1 = 1;
+ errl = DeviceFW::deviceWrite(i_target,
+ nullptr,
+ sz,
+ DEVICE_IDEC_ADDRESS(),
+ Phase1);
+
+
+ return errl;
}
/**
@@ -259,6 +265,70 @@ uint64_t formatOcmbIdecToCfamStandard(const uint64_t i_idec)
return convertedIdec;
}
+/**
+ * @brief During early IPL the OCMB isn't able to be read from so this function,
+ * executed during discover targets, will read from the SPD and set the
+ * CHIP_ID, EC, and HDAT_EC attributes with what is found there.
+ *
+ * @param[in] i_target Presence detect target
+ *
+ * @return errlHndl_t An error log if reading from the SPD failed.
+ * Otherwise, other errors are predictive and
+ * committed. So nullptr will be returned in those
+ * cases and on success.
+ */
+errlHndl_t ocmbIdecPhase1(const TARGETING::TargetHandle_t& i_target);
+
+/**
+ * @brief Once the OCMB is able to be read from the second phase will execute
+ * and cross-check the data given from the SPD is consistent with what
+ * was read from the chip itself. If the data is not consistent then the
+ * CHIP_ID, EC, and HDAT_EC attributes will be updated with what was
+ * found from the OCMB read since that data would be correct.
+ *
+ * @param[in] i_target Presence detect target
+ *
+ * @return errlHndl_t An error log if reading from the OCMB ID/EC
+ * register failed. Otherwise, other errors are
+ * predictive and committed. So nullptr will be
+ * returned in those cases and on success.
+ */
+errlHndl_t ocmbIdecPhase2(const TARGETING::TargetHandle_t& i_target);
+
+/**
+ * @brief Read the chipid and EC/DD-level for OCMB chips and set the attributes.
+ * In this function there are two phases that are executed at different
+ * times during IPL. The OCMB is held in reset and unable to be read from
+ * during early IPL. So the first phase, executed during discover
+ * targets, will read from the SPD and set the attributes with what is
+ * found there. Once the OCMB is able to be read from the second phase
+ * will execute and cross-check the data given from the SPD is consistent
+ * with what was read from the chip itself. If the data is not consistent
+ * then the attributes will be updated with what was found from the OCMB
+ * read since that data would be correct.
+ *
+ * @param[in] i_opType Operation type, see DeviceFW::OperationType
+ * in driverif.H
+ *
+ * @param[in] i_target Presence detect target
+ *
+ * @param[in/out] io_buffer Unused by this function
+ *
+ * @param[in/out] io_buflen Unused by this function
+ *
+ * @param[in] i_accessType DeviceFW::AccessType enum (userif.H)
+ *
+ * @param[in] i_args This is an argument list for DD framework.
+ * In this function, there is one argument to
+ * signal which phase to execute.
+ *
+ * @return errlHndl_t If there is an issue while reading from the SPD
+ * or the OCMB chip, or an unexpected memory
+ * interface type then this function will return an
+ * error. Otherwise, all other errors are
+ * predictive and committed. So nullptr will be
+ * returned in that case or on success.
+ */
errlHndl_t ocmbIDEC(DeviceFW::OperationType i_opType,
TARGETING::Target* i_target,
void* io_buffer,
@@ -266,51 +336,177 @@ errlHndl_t ocmbIDEC(DeviceFW::OperationType i_opType,
int64_t i_accessType,
va_list i_args)
{
- //@fixme when we know what register to read the IDEC from.
- const uint16_t OCMB_IDEC_REGISTER = 0x2134;
+ errlHndl_t error = nullptr;
+
+ // Determine which phase of this function to run.
+ uint64_t phase = va_arg(i_args, uint64_t);
+
+ // Execute the correct phase based on the va_arg given.
+ if (phase == 1)
+ {
+ error = ocmbIdecPhase1(i_target);
+ }
+ else
+ {
+ error = ocmbIdecPhase2(i_target);
+ }
+
+
+ return error;
+}
+
+/**
+ * @brief This is a small helper function that the ocmb IDEC functions use to
+ * add all the proper callouts and commit errorlogs.
+ *
+ * @param[in] i_target Presence detect target
+ *
+ * @param[in] io_error The error log to be committed
+ *
+ */
+void ocmbErrlCommit(const TARGETING::TargetHandle_t& i_target,
+ errlHndl_t& io_error)
+{
+ io_error->addHwCallout(i_target,
+ SRCI_PRIORITY_HIGH,
+ NO_DECONFIG,
+ GARD_NULL);
+
+ io_error->addPartCallout(i_target,
+ VPD_PART_TYPE,
+ SRCI_PRIORITY_MED,
+ NO_DECONFIG,
+ GARD_NULL);
+
+ io_error->addProcedureCallout(EPUB_PRC_HB_CODE,
+ SRCI_PRIORITY_LOW);
+
+ ERRORLOG::errlCommit(io_error, HWAS_COMP_ID);
+
+}
+
+/**
+ * @brief This is a small helper function that is used to translate from SPD
+ * to OCMB IDEC register values.
+ *
+ * @param[in] i_value The value to translate
+ *
+ * @param[in] i_isID The type of value passed in. Used to search
+ * the corresponding map and for FFDC.
+ *
+ * @param[in] i_spdFFDCBytes Byte 1: SPD Module Revision
+ * Byte 2: DRAM Interface Type Presented or
+ * Emulated
+ * Byte 3: Memory Module Interface Type
+ * Byte 4: Unused
+ *
+ * @param[out] o_translatedValue The value resulting from the map.find()
+ *
+ * @param[in] i_id The SPD ID used to construct the association
+ * map. Defaulted to 0xFFFF. This MUST be set
+ * when i_isID == false.
+ *
+ * @return errlHndl_t nullptr on success. Otherwise an error log
+ * indicating that the translation failed.
+ *
+ */
+errlHndl_t ocmbTranslateSpdToIdec(const uint16_t i_value,
+ const bool i_isID,
+ const uint32_t i_spdFFDCBytes,
+ uint16_t& o_translatedValue,
+ const uint16_t i_id = 0xFFFF)
+{
+
+ assert((i_isID || (i_id != 0xFFFF)), "i_id must be set to a valid OCMB SPD Chip ID value when attempting to translate an SPD EC value.");
- uint64_t idec = 0;
- size_t op_size = sizeof(idec);
errlHndl_t error = nullptr;
- // Read the ID/EC
- error = DeviceFW::deviceRead(i_target,
- &idec,
- op_size,
- DEVICE_SCOM_ADDRESS(OCMB_IDEC_REGISTER));
+ const uint16_t OCMB_ID = i_isID ? i_value : i_id;
- do {
+ const uint32_t GEMINI_EC = 0x0000;
+ const uint32_t GEMINI_SPD_EC = 0x0000;
+ const uint32_t EXPLORER_EC = 0x0010;
+ const uint32_t EXPLORER_SPD_EC = 0x0000;
+ // This map will hold the associated values between what is read from
+ // the OCMB's IDEC register and the SPD since they use different
+ // standards and thus cannot be directly compared.
+ std::map<uint32_t, uint32_t> OCMB_ASSOCIATION_MAP;
- if (error != nullptr)
+ if (i_isID)
+ {
+ if (DDIMM_DMB_ID::EXPLORER == OCMB_ID)
{
- HWAS_ERR("ocmbIDEC> OCMB 0x%.8X - failed to read ID/EC",
- TARGETING::get_huid(i_target));
-
- break;
+ OCMB_ASSOCIATION_MAP[DDIMM_DMB_ID::EXPLORER] =
+ POWER_CHIPID::EXPLORER_16;
+ }
+ else if (DDIMM_DMB_ID::GEMINI == OCMB_ID)
+ {
+ OCMB_ASSOCIATION_MAP[DDIMM_DMB_ID::GEMINI] =
+ POWER_CHIPID::GEMINI_16;
+ }
+ }
+ else
+ {
+ if (DDIMM_DMB_ID::EXPLORER == OCMB_ID)
+ {
+ OCMB_ASSOCIATION_MAP[EXPLORER_SPD_EC] = EXPLORER_EC;
}
+ else if (DDIMM_DMB_ID::GEMINI == OCMB_ID)
+ {
+ OCMB_ASSOCIATION_MAP[GEMINI_SPD_EC] = GEMINI_EC;
+ }
+ }
- assert(op_size == sizeof(idec), "ocmbIDEC> Size returned from OCMB "
- "IDEC read size %d not the expected size %d",
- op_size, sizeof(idec));
+ auto map_it = OCMB_ASSOCIATION_MAP.find(i_value);
- idec = formatOcmbIdecToCfamStandard(idec);
+ if (map_it == OCMB_ASSOCIATION_MAP.end())
+ {
+ HWAS_ERR("ocmbTranslateSpdToIdec> Unable to translate "
+ "given %s 0x%.4X to a known OCMB IDEC register equivalent",
+ i_isID ? "Chip ID" : "Revision",
+ i_value);
- uint8_t ec = POWER_CHIPID::extract_ddlevel(idec);
- uint32_t id = POWER_CHIPID::extract_chipid16(idec);
+ /*@
+ * @errortype
+ * @severity ERRL_SEV_PREDICTIVE
+ * @moduleid MOD_OCMB_TRANSLATE_SPD_IDEC
+ * @reasoncode RC_OCMB_UNEXPECTED_IDEC
+ * @userdata1[0:7] SPD Module Revision
+ * @userdata1[8:15] DRAM Interface Type Presented or Emulated
+ * @userdata1[16:23] Memory Module Interface Type
+ * @userdata1[24:31] Unused
+ * @userdata1[32:47] The value given to the translate function
+ * @userdata1[48:63] 0x1 = value is Chip ID, 0x0 = value is Revision
+ * @devdesc The IDEC values read from the OCMB did not
+ * appear in the OCMB IDEC to SPD association map.
+ * Please update the map with new values.
+ * @custdesc Firmware Error
+ */
+ error = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ MOD_OCMB_TRANSLATE_SPD_IDEC,
+ RC_OCMB_UNEXPECTED_IDEC,
+ TWO_UINT32_TO_UINT64(i_spdFFDCBytes,
+ TWO_UINT16_TO_UINT32(i_value, i_isID)));
- HWAS_DBG("ocmbIDEC> OCMB 0x%.8X - read ID/EC successful. "
- "ID = 0x%.4X, EC = 0x%.2X, Full IDEC 0x%x",
- TARGETING::get_huid(i_target),
- id,
- ec,
- idec);
+ }
+ else
+ {
+ o_translatedValue = map_it->second;
+ }
+
+ return error;
+}
+
+errlHndl_t ocmbIdecPhase1(const TARGETING::TargetHandle_t& i_target)
+{
+ errlHndl_t error = nullptr;
- // Verify the OCMB ID is an expected value
+ // Allocate buffer to hold SPD and init to 0
+ size_t spdBufferSize = SPD::OCMB_SPD_EFD_COMBINED_SIZE;
+ uint8_t* spdBuffer = new uint8_t[spdBufferSize];
+ memset(spdBuffer, 0, spdBufferSize);
- // Allocate buffer to hold SPD and init to 0
- size_t spdBufferSize = SPD::OCMB_SPD_EFD_COMBINED_SIZE;
- uint8_t* spdBuffer = new uint8_t[spdBufferSize];
- memset(spdBuffer, 0, spdBufferSize);
+ do {
// Read the full SPD.
error = deviceRead(i_target,
@@ -320,7 +516,7 @@ errlHndl_t ocmbIDEC(DeviceFW::OperationType i_opType,
// If unable to retrieve the SPD buffer then can't
// extract the IDEC data, so return error.
- if (error)
+ if (error != nullptr)
{
HWAS_ERR("ocmbIDEC> Error while trying to read "
"ENTIRE SPD from 0x%.08X ",
@@ -330,112 +526,155 @@ errlHndl_t ocmbIDEC(DeviceFW::OperationType i_opType,
// Make sure we got back the size we were expecting.
assert(spdBufferSize == SPD::OCMB_SPD_EFD_COMBINED_SIZE,
- "ocmbIDEC> OCMB SPD read size %d "
- "doesn't match the expected size %d",
- spdBufferSize,
- SPD::OCMB_SPD_EFD_COMBINED_SIZE);
-
- // SPD IDEC info is in the following three bytes
- const size_t SPD_ID_LEAST_SIGNIFICANT_BYTE_OFFSET = 198;
- const size_t SPD_ID_MOST_SIGNIFICANT_BYTE_OFFSET = 199;
- const size_t SPD_EC_OFFSET = 200;
-
- // Get the ID from the SPD and verify that it matches what we read from
- // the IDEC register.
- uint16_t spdId = 0;
-
- spdId = TWO_UINT8_TO_UINT16(
- *(spdBuffer + SPD_ID_MOST_SIGNIFICANT_BYTE_OFFSET),
- *(spdBuffer + SPD_ID_LEAST_SIGNIFICANT_BYTE_OFFSET));
-
- uint8_t spdEc = *(spdBuffer + SPD_EC_OFFSET);
-
- // This map will hold the associated values between what is read from
- // the OCMB's IDEC register and the SPD since they use different
- // standards and thus cannot be directly compared.
- // @TODO RTC 205563 Fix Gemini info when it is known.
- const uint32_t GEMINI_ID = 0x20D2;
- const uint32_t GEMINI_SPD_ID = 0x80A4;
- const uint32_t GEMINI_EC = 0x0000;
- const uint32_t GEMINI_SPD_EC = 0x0000;
- const uint32_t EXPLORER_SPD_ID = 0x2980;
- const uint32_t EXPLORER_EC = 0x0010;
- const uint32_t EXPLORER_SPD_EC = 0x0000;
- const std::map<uint32_t, uint32_t> OCMB_ID_SPD_ASSOCIATION_MAP
+ "ocmbIDEC> OCMB SPD read size %d "
+ "doesn't match the expected size %d",
+ spdBufferSize,
+ SPD::OCMB_SPD_EFD_COMBINED_SIZE);
+
+ // These bytes are used for FFDC and verification purposes.
+ const size_t SPD_REVISION_OFFSET = 1;
+ const size_t DRAM_INTERFACE_TYPE_OFFSET = 2;
+ const size_t MEMORY_MODULE_INTERFACE_TYPE_OFFSET = 3;
+
+ // This is the value that signifies the SPD we read is for a DDIMM.
+ const uint32_t DDIMM_MEMORY_INTERFACE_TYPE = 0x0A;
+
+ const uint8_t spdModuleRevision =
+ *(spdBuffer + SPD_REVISION_OFFSET);
+
+ const uint8_t spdDRAMInterfaceType =
+ *(spdBuffer + DRAM_INTERFACE_TYPE_OFFSET);
+
+ const uint8_t spdMemoryInterfaceType =
+ *(spdBuffer + MEMORY_MODULE_INTERFACE_TYPE_OFFSET);
+
+ // Byte 1 SPD Module Revision
+ // Byte 2 DRAM Interface Type Presented or Emulated
+ // Byte 3 Memory Module Interface Type
+ const uint32_t SPD_FFDC_BYTES = TWO_UINT16_TO_UINT32(
+ TWO_UINT8_TO_UINT16(spdModuleRevision, spdDRAMInterfaceType),
+ TWO_UINT8_TO_UINT16(spdMemoryInterfaceType, 0));
+
+ // Since the byte offsets used to get the IDEC info out of the SPD are
+ // specific to the DDIMM interface type we must first verify that we
+ // read from an SPD of that type.
+ if (DDIMM_MEMORY_INTERFACE_TYPE != spdMemoryInterfaceType)
{
- {POWER_CHIPID::EXPLORER_16, EXPLORER_SPD_ID},
- {GEMINI_ID, GEMINI_SPD_ID},
- };
+ HWAS_ERR("ocmbIDEC> OCMB 0x%.8X memory module interface type "
+ "didn't match the expected type. "
+ "Expected 0x%.2X, Actual 0x%.2X",
+ TARGETING::get_huid(i_target),
+ DDIMM_MEMORY_INTERFACE_TYPE,
+ spdMemoryInterfaceType);
- const std::map<uint32_t, uint32_t> OCMB_EC_SPD_ASSOCIATION_MAP
- {
- {EXPLORER_EC, EXPLORER_SPD_EC},
- {GEMINI_EC, GEMINI_SPD_EC},
- };
+ /*@
+ * @errortype
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid MOD_OCMB_IDEC
+ * @reasoncode RC_OCMB_INTERFACE_TYPE_MISMATCH
+ * @userdata1[0:7] SPD Module Revision
+ * @userdata1[8:15] DRAM Interface Type Presented or Emulated
+ * @userdata1[16:23] Memory Module Interface Type
+ * @userdata1[24:31] Unused
+ * @userdata1[32:63] Expected memory interface type
+ * @userdata2 HUID of OCMB target
+ * @devdesc The memory interface type read from the SPD did
+ * not match the DDIMM value. Setting the
+ * appropriate IDEC values for this target cannot
+ * continue.
+ * @custdesc Invalid or unsupported memory card installed.
+ */
+ error = hwasError(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ MOD_OCMB_IDEC,
+ RC_OCMB_INTERFACE_TYPE_MISMATCH,
+ TWO_UINT32_TO_UINT64(SPD_FFDC_BYTES,
+ DDIMM_MEMORY_INTERFACE_TYPE),
+ TARGETING::get_huid(i_target));
+
+ error->addProcedureCallout(EPUB_PRC_HB_CODE,
+ SRCI_PRIORITY_LOW);
+
+ error->addHwCallout(i_target,
+ SRCI_PRIORITY_HIGH,
+ NO_DECONFIG,
+ GARD_NULL);
+
+
+ break;
+ }
- auto id_it = OCMB_ID_SPD_ASSOCIATION_MAP.find(id);
- auto ec_it = OCMB_EC_SPD_ASSOCIATION_MAP.find(ec);
+ // SPD IDEC info is in the following three bytes
+ const size_t SPD_ID_LEAST_SIGNIFICANT_BYTE_OFFSET = 198;
+ const size_t SPD_ID_MOST_SIGNIFICANT_BYTE_OFFSET = 199;
+ const size_t SPD_EC_OFFSET = 200;
- if (( id_it == OCMB_ID_SPD_ASSOCIATION_MAP.end())
- || ec_it == OCMB_EC_SPD_ASSOCIATION_MAP.end())
+ // Get the ID from the SPD and verify that it matches what we read from
+ // the IDEC register.
+ uint16_t spdId = TWO_UINT8_TO_UINT16(
+ *(spdBuffer + SPD_ID_LEAST_SIGNIFICANT_BYTE_OFFSET),
+ *(spdBuffer + SPD_ID_MOST_SIGNIFICANT_BYTE_OFFSET));
+
+ uint8_t spdEc = *(spdBuffer + SPD_EC_OFFSET);
+
+ if (DDIMM_DMB_ID::EXPLORER == spdId)
+ {
+ HWAS_INF("ocmbIdecPhase1> OCMB 0x%.8X chip type is EXPLORER",
+ TARGETING::get_huid(i_target));
+ }
+ else if (DDIMM_DMB_ID::GEMINI == spdId)
{
- HWAS_ERR("ocmbIDEC> Unexpected ID/EC value.");
-
- /*@
- * @errortype
- * @severity ERRL_SEV_UNRECOVERABLE
- * @moduleid MOD_OCMB_IDEC
- * @reasoncode RC_OCMB_UNEXPECTED_IDEC
- * @userdata1[00:31] ID (Chip ID)
- * @userdata1[32:63] EC (Revision)
- * @userdata2 HUID of OCMB target
- * @devdesc The IDEC values read from the OCMB did not
- * appear in the IDEC to SPD association map.
- * Please update the map with new values.
- * @custdesc Firmware Error
- */
- error = hwasError(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- MOD_OCMB_IDEC,
- RC_OCMB_UNEXPECTED_IDEC,
- TWO_UINT32_TO_UINT64(id, ec),
- TARGETING::get_huid(i_target));
-
- break;
+ HWAS_INF("ocmbIdecPhase1> OCMB 0x%.8X chip type is GEMINI",
+ TARGETING::get_huid(i_target));
+ }
+ else
+ {
+ HWAS_ERR("ocmbIdecPhase1> Unknown OCMB chip type discovered in SPD "
+ "ID=0x%.4X OCMB HUID 0x%.8X",
+ spdId,
+ TARGETING::get_huid(i_target));
+
+ /*@
+ * @errortype
+ * @severity ERRL_SEV_PREDICTIVE
+ * @moduleid MOD_OCMB_IDEC_PHASE_1
+ * @reasoncode RC_OCMB_UNKNOWN_CHIP_TYPE
+ * @userdata1[0:7] SPD Module Revision
+ * @userdata1[8:15] DRAM Interface Type Presented or Emulated
+ * @userdata1[16:23] Memory Module Interface Type
+ * @userdata1[24:31] Unused
+ * @userdata1[32:63] SPD Chip Id
+ * @userdata2 HUID of OCMB target
+ * @devdesc The ID read from the SPD didn't match any known
+ * OCMB chip types.
+ * @custdesc Unsupported memory installed.
+ */
+ error = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ MOD_OCMB_IDEC_PHASE_1,
+ RC_OCMB_UNKNOWN_CHIP_TYPE,
+ TWO_UINT32_TO_UINT64(SPD_FFDC_BYTES, spdId),
+ TARGETING::get_huid(i_target));
+
+ // Add callouts and commit
+ ocmbErrlCommit(i_target, error);
+ break;
}
- if ((id_it->second != spdId) || (ec_it->second != spdEc))
+ uint16_t id = 0;
+ uint16_t ec = 0;
+ bool isId = true;
+
+
+ error = ocmbTranslateSpdToIdec(spdId, isId, SPD_FFDC_BYTES, id);
+ if (error)
{
- HWAS_ERR("ocmbIDEC> OCMB IDEC and associated SPD IDEC don't match: "
- "OCMB ID=0x%.4X, EC=0x%.2X; SPD ID=0x%.4X, EC=0x%.2X; "
- "Expected SPD ID=0x%.4X, EC=0x%.2X",
- id, ec, spdId, spdEc, id_it->second, ec_it->second);
-
- uint32_t bothIds = TWO_UINT16_TO_UINT32(id, spdId);
- uint32_t bothEcs = TWO_UINT16_TO_UINT32(ec, spdEc);
-
- /*@
- * @errortype
- * @severity ERRL_SEV_UNRECOVERABLE
- * @moduleid MOD_OCMB_IDEC
- * @reasoncode RC_OCMB_SPD_IDEC_MISMATCH
- * @userdata1[00:15] OCMB ID from device read
- * @userdata1[16:31] SPD ID from device read
- * @userdata1[32:47] OCMB EC from device read
- * @userdata1[48:63] SPD EC from device read
- * @userdata2 HUID of OCMB target
- * @devdesc The IDEC info read from the OCMB and SPD
- * did not match the expected values.
- * @custdesc Firmware Error
- */
- error = hwasError(ERRORLOG::ERRL_SEV_UNRECOVERABLE,
- MOD_OCMB_IDEC,
- RC_OCMB_SPD_IDEC_MISMATCH,
- TWO_UINT32_TO_UINT64(bothIds, bothEcs),
- TARGETING::get_huid(i_target));
-
- break;
+ ocmbErrlCommit(i_target, error);
+ }
+ error = ocmbTranslateSpdToIdec(spdEc, !isId, SPD_FFDC_BYTES, ec, spdId);
+ if (error)
+ {
+ ocmbErrlCommit(i_target, error);
}
// set the explorer chip EC attributes.
@@ -447,7 +686,145 @@ errlHndl_t ocmbIDEC(DeviceFW::OperationType i_opType,
} while(0);
+ delete[] spdBuffer;
return error;
+
+}
+
+errlHndl_t ocmbIdecPhase2(const TARGETING::TargetHandle_t& i_target)
+{
+ //@TODO RTC-209353: Read IDEC for Gemini.
+ const uint16_t OCMB_IDEC_REGISTER = 0x2134;
+
+ errlHndl_t error = nullptr;
+ uint64_t idec = 0;
+ size_t op_size = sizeof(idec);
+
+ do {
+ // Read the ID/EC
+ // @TODO RTC-209353: Make this work for both Gemini and Explorer cards
+ // when more information is known about which
+ // registers to read from.
+ error = DeviceFW::deviceRead(i_target,
+ &idec,
+ op_size,
+ DEVICE_SCOM_ADDRESS(OCMB_IDEC_REGISTER));
+
+ if (error != nullptr)
+ {
+ HWAS_ERR("ocmbIdecPhase2> OCMB 0x%.8X - failed to read ID/EC",
+ TARGETING::get_huid(i_target));
+
+ break;
+ }
+
+ idec = formatOcmbIdecToCfamStandard(idec);
+
+ uint8_t ec = POWER_CHIPID::extract_ddlevel(idec);
+ uint32_t id = POWER_CHIPID::extract_chipid16(idec);
+
+ HWAS_INF("ocmbIdecPhase2> OCMB 0x%.8X - read ID/EC successful. "
+ "ID = 0x%.4X, EC = 0x%.2X, Full IDEC 0x%x",
+ TARGETING::get_huid(i_target),
+ id,
+ ec,
+ idec);
+
+ // Get the id that was translated from the SPD read during phase 1.
+ const uint16_t translatedId =
+ i_target->getAttr<TARGETING::ATTR_CHIP_ID>();
+
+ if (id != translatedId)
+ {
+ HWAS_ERR("ocmbIdecPhase2> OCMB Chip Id and associated SPD Chip Id "
+ "don't match: OCMB ID=0x%.4X; Translated SPD ID=0x%.4X;",
+ id,
+ translatedId);
+
+ HWAS_ERR("ocmbIdecPhase2> Previous CHIP_ID 0x%.4X translated from "
+ "SPD read will be overwritten with OCMB IDEC register "
+ "ID=0x%.4X",
+ translatedId,
+ id);
+ /*@
+ * @errortype
+ * @severity ERRL_SEV_PREDICTIVE
+ * @moduleid MOD_OCMB_IDEC
+ * @reasoncode RC_OCMB_CHIP_ID_MISMATCH
+ * @userdata1[00:31] OCMB IDEC Register ID
+ * @userdata1[32:63] Translated SPD ID
+ * @userdata2[32:63] HUID of OCMB target
+ * @devdesc The IDEC info read from the OCMB and SPD
+ * did not match the expected values.
+ * @custdesc Firmware Error
+ */
+ error = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ MOD_OCMB_IDEC,
+ RC_OCMB_CHIP_ID_MISMATCH,
+ TWO_UINT32_TO_UINT64(id, translatedId),
+ TARGETING::get_huid(i_target));
+
+ // Add callouts and commit
+ ocmbErrlCommit(i_target, error);
+
+ // Since there was an error then the ID values don't agree between
+ // the OCMB read and the SPD read. Since the OCMB has the correct
+ // answer, set the attributes to the values read from that instead
+ // of the SPD.
+ i_target->setAttr<TARGETING::ATTR_CHIP_ID>(id);
+ }
+
+ const uint8_t translatedEc = i_target->getAttr<TARGETING::ATTR_EC>();
+
+ if (ec != translatedEc)
+ {
+ HWAS_ERR("ocmbIdecPhase2> OCMB Revision and associated SPD "
+ "Revision don't match: OCMB EC=0x%.2X; "
+ "Translated SPD EC=0x%.2X; ",
+ ec, translatedEc);
+
+ HWAS_ERR("ocmbIdecPhase2> Previous EC and HDAT_EC 0x%.2X "
+ "translated from SPD read will be overwritten with OCMB "
+ "IDEC register ID=0x%.2X",
+ translatedEc,
+ ec);
+
+ /*@
+ * @errortype
+ * @severity ERRL_SEV_PREDICTIVE
+ * @moduleid MOD_OCMB_IDEC
+ * @reasoncode RC_OCMB_SPD_REVISION_MISMATCH
+ * @userdata1[00:31] OCMB IDEC register EC
+ * @userdata1[32:63] Translated SPD EC
+ * @userdata2[00:31] OCMB Chip ID Attribute
+ * @userdata2[32:63] HUID of OCMB target
+ * @devdesc The EC (Revision) info read from the OCMB and
+ * SPD did not match the expected values.
+ * @custdesc Firmware Error
+ */
+ error = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ MOD_OCMB_IDEC,
+ RC_OCMB_SPD_REVISION_MISMATCH,
+ TWO_UINT32_TO_UINT64(ec, translatedEc),
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_CHIP_ID>(),
+ TARGETING::get_huid(i_target)));
+
+ // Add callouts and commit
+ ocmbErrlCommit(i_target, error);
+
+ // Since there was an error then the EC values don't agree between
+ // the OCMB read and the SPD read. Since the OCMB has the correct
+ // answer, set the attributes to the values read from that instead
+ // of the SPD.
+ i_target->setAttr<TARGETING::ATTR_EC>(ec);
+ i_target->setAttr<TARGETING::ATTR_HDAT_EC>(ec);
+ }
+
+ } while(0);
+
+ return error;
+
}
// Register the presence detect function with the device framework
diff --git a/src/usr/i2c/i2cTargetPres.C b/src/usr/i2c/i2cTargetPres.C
index c3809f099..13bfa88c1 100644
--- a/src/usr/i2c/i2cTargetPres.C
+++ b/src/usr/i2c/i2cTargetPres.C
@@ -33,7 +33,6 @@
#include <errl/errlmanager.H>
#include "i2c_common.H"
-
extern trace_desc_t* g_trac_i2c;
//#define TRACSSCOMP(args...) TRACFCOMP(args)
@@ -223,10 +222,6 @@ errlHndl_t ocmbI2CPresencePerformOp(DeviceFW::OperationType i_opType,
{
errlHndl_t l_invalidateErrl = nullptr;
- // @TODO RTC 208696: Gemini vs Explorer Presence Detection via SPD
- // This function will be updated to differentiate between Explorer and
- // Gemini OCMB chips. For now, presense of an OCMB chip is inferred by
- // the presense of the eeprom.
bool l_ocmbPresent = EEPROM::eepromPresence(i_target);
memcpy(io_buffer, &l_ocmbPresent, sizeof(l_ocmbPresent));
diff --git a/src/usr/isteps/istep10/call_proc_cen_ref_clk_enable.C b/src/usr/isteps/istep10/call_proc_cen_ref_clk_enable.C
index 627b5803d..30341144d 100644
--- a/src/usr/isteps/istep10/call_proc_cen_ref_clk_enable.C
+++ b/src/usr/isteps/istep10/call_proc_cen_ref_clk_enable.C
@@ -1101,10 +1101,14 @@ void* call_proc_cen_ref_clk_enable(void *io_pArgs )
// are set with the values found in that register. So, this
// deviceWrite functions more as a setter for an OCMB target's
// attributes.
+ // Pass 2 as a va_arg to signal the ocmbIDEC function to execute
+ // phase 2 of it's read process.
+ const uint64_t Phase2 = 2;
l_errl = DeviceFW::deviceWrite(l_ocmb,
- nullptr,
- size,
- DEVICE_IDEC_ADDRESS());
+ nullptr,
+ size,
+ DEVICE_IDEC_ADDRESS(),
+ Phase2);
if (l_errl)
{
// read of ID/EC failed even though we THOUGHT we were
OpenPOWER on IntegriCloud