summaryrefslogtreecommitdiffstats
path: root/src/usr
diff options
context:
space:
mode:
authorMatthew Raybuck <matthew.raybuck@ibm.com>2019-04-05 08:57:50 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2019-04-30 09:37:07 -0500
commitf177dd883e86aef80c75e40de11adc43e304e014 (patch)
treec4046533e2ee040a4f0b29d8adf544cf3be3fc30 /src/usr
parent6fbd4f33e00e69a97a97a77c8e5185795b6662f7 (diff)
downloadtalos-hostboot-f177dd883e86aef80c75e40de11adc43e304e014.tar.gz
talos-hostboot-f177dd883e86aef80c75e40de11adc43e304e014.zip
Collect IDEC for Explorer chip
The OCMB Explorer Chip doesn't read for IDEC but instead assumes hardcoded values. Since the Explorer chip is held in reset until iStep 10.4, this commit will prevent IDEC reads during discoverTargets and instead perform the read when exp_check_for_ready() is successful. Change-Id: I4ef5a01badb195acca0c2187ef76ea55f58eafe4 RTC:201996 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/75881 Reviewed-by: Matt Derksen <mderkse1@us.ibm.com> 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: 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> Tested-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr')
-rw-r--r--src/usr/hwas/common/hwas.C25
-rw-r--r--src/usr/hwas/hwasPlat.C213
-rw-r--r--src/usr/isteps/istep10/call_proc_cen_ref_clk_enable.C31
3 files changed, 250 insertions, 19 deletions
diff --git a/src/usr/hwas/common/hwas.C b/src/usr/hwas/common/hwas.C
index 45a88cf85..569061814 100644
--- a/src/usr/hwas/common/hwas.C
+++ b/src/usr/hwas/common/hwas.C
@@ -728,19 +728,23 @@ errlHndl_t discoverTargets()
MOD_DISCOVER_TARGETS,
RC_PARTIAL_GOOD_INFORMATION);
- if( (pTarget->getAttr<ATTR_CLASS>() == CLASS_CHIP) &&
- (l_targetType != TYPE_TPM) &&
- (l_targetType != TYPE_SP) &&
- (l_targetType != TYPE_BMC) &&
- (l_targetType != TYPE_I2C_MUX))
+ if( (pTarget->getAttr<ATTR_CLASS>() == CLASS_CHIP)
+ && (l_targetType != TYPE_TPM)
+ && (l_targetType != TYPE_SP)
+ && (l_targetType != TYPE_BMC)
+ && (l_targetType != TYPE_I2C_MUX)
+ && (l_targetType != TYPE_OCMB_CHIP))
{
// read Chip ID/EC data from these physical chips
errl = platReadIDEC(pTarget);
if (errl)
- { // read of ID/EC failed even tho we THOUGHT we were present.
- HWAS_INF("pTarget %.8X - read IDEC failed (eid 0x%X) - bad",
- errl->eid(), pTarget->getAttr<ATTR_HUID>());
+ {
+ // read of ID/EC failed even tho we THOUGHT we were present.
+ HWAS_INF("pTarget 0x%.8X - read IDEC failed "
+ "(eid 0x%X) - bad",
+ get_huid(pTarget), errl->eid());
+
// chip NOT present and NOT functional, so that FSP doesn't
// include this for HB to process
chipPresent = false;
@@ -758,8 +762,9 @@ errlHndl_t discoverTargets()
if (errl)
{ // read of PG failed even tho we were present..
- HWAS_INF("pTarget %.8X - read PG failed (eid 0x%X)- bad",
- errl->eid(), pTarget->getAttr<ATTR_HUID>());
+ HWAS_INF("pTarget 0x%.8X - read PG failed "
+ "(eid 0x%X) - bad",
+ get_huid(pTarget), errl->eid());
chipFunctional = false;
errlEid = errl->eid();
diff --git a/src/usr/hwas/hwasPlat.C b/src/usr/hwas/hwasPlat.C
index bea5b4d8f..543814d82 100644
--- a/src/usr/hwas/hwasPlat.C
+++ b/src/usr/hwas/hwasPlat.C
@@ -50,6 +50,9 @@
#include <config.h>
#include <targeting/common/targetservice.H>
#include <chipids.H>
+#include <vpd/spdenums.H>
+
+#include <map>
#ifdef CONFIG_SUPPORT_EEPROM_CACHING
#include <i2c/eepromif.H>
@@ -234,6 +237,28 @@ DEVICE_REGISTER_ROUTE(DeviceFW::WRITE,
TARGETING::TYPE_MEMBUF,
cfamIDEC);
+/* @brief A helper function used to convert the contents of the IDEC register
+ * to the CFAM ID format.
+ *
+ * @param[in] i_idec The contents of the IDEC register
+ *
+ * @return uint64_t The converted result.
+ */
+uint64_t formatOcmbIdecToCfamStandard(const uint64_t i_idec)
+{
+ uint64_t convertedIdec = 0;
+
+ // Need to convert register contents from Mm0L00CC to MLmCC000
+ uint32_t idec = static_cast<uint32_t>(i_idec);
+ uint32_t major = 0xF0000000 & idec;
+ uint32_t minor = 0x0F000000 & idec;
+ uint32_t location = 0x000F0000 & idec;
+ convertedIdec = (major | (location << 8) | (minor >> 4)
+ | ((idec & 0x000000FF) << 12));
+
+ return convertedIdec;
+}
+
errlHndl_t ocmbIDEC(DeviceFW::OperationType i_opType,
TARGETING::Target* i_target,
void* io_buffer,
@@ -241,16 +266,188 @@ errlHndl_t ocmbIDEC(DeviceFW::OperationType i_opType,
int64_t i_accessType,
va_list i_args)
{
- // for now just hardcode the answer to something explicitly invalid
- uint8_t l_ec = INVALID__ATTR_EC;
- i_target->setAttr<TARGETING::ATTR_EC>(l_ec);
- i_target->setAttr<TARGETING::ATTR_HDAT_EC>(l_ec);
+ //@fixme when we know what register to read the IDEC from.
+ const uint16_t OCMB_IDEC_REGISTER = 0x2134;
+
+ 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));
+
+ do {
+
+ if (error != nullptr)
+ {
+ HWAS_ERR("ocmbIDEC> OCMB 0x%.8X - failed to read ID/EC",
+ TARGETING::get_huid(i_target));
+
+ break;
+ }
+
+ assert(op_size == sizeof(idec), "ocmbIDEC> Size returned from OCMB "
+ "IDEC read size %d not the expected size %d",
+ op_size, sizeof(idec));
+
+ idec = formatOcmbIdecToCfamStandard(idec);
+
+ uint8_t ec = POWER_CHIPID::extract_ddlevel(idec);
+ uint32_t id = POWER_CHIPID::extract_chipid16(idec);
+
+ 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);
+
+ // Verify the OCMB ID is an expected value
- // we can assume this is an Explorer chip though
- uint32_t l_id = POWER_CHIPID::EXPLORER_16;
- i_target->setAttr<TARGETING::ATTR_CHIP_ID>(l_id);
+ // 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);
+
+ // Read the full SPD.
+ error = deviceRead(i_target,
+ spdBuffer,
+ spdBufferSize,
+ DEVICE_SPD_ADDRESS(SPD::ENTIRE_SPD));
+
+ // If unable to retrieve the SPD buffer then can't
+ // extract the IDEC data, so return error.
+ if (error)
+ {
+ HWAS_ERR("ocmbIDEC> Error while trying to read "
+ "ENTIRE SPD from 0x%.08X ",
+ TARGETING::get_huid(i_target));
+ break;
+ }
+
+ // 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
+ {
+ {POWER_CHIPID::EXPLORER_16, EXPLORER_SPD_ID},
+ {GEMINI_ID, GEMINI_SPD_ID},
+ };
+
+ const std::map<uint32_t, uint32_t> OCMB_EC_SPD_ASSOCIATION_MAP
+ {
+ {EXPLORER_EC, EXPLORER_SPD_EC},
+ {GEMINI_EC, GEMINI_SPD_EC},
+ };
+
+ auto id_it = OCMB_ID_SPD_ASSOCIATION_MAP.find(id);
+ auto ec_it = OCMB_EC_SPD_ASSOCIATION_MAP.find(ec);
+
+ if (( id_it == OCMB_ID_SPD_ASSOCIATION_MAP.end())
+ || ec_it == OCMB_EC_SPD_ASSOCIATION_MAP.end())
+ {
+ 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;
+
+ }
+
+ if ((id_it->second != spdId) || (ec_it->second != spdEc))
+ {
+ 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;
+
+ }
+
+ // set the explorer chip EC attributes.
+ i_target->setAttr<TARGETING::ATTR_EC>(ec);
+ i_target->setAttr<TARGETING::ATTR_HDAT_EC>(ec);
+
+ // set the explorer chip id attribute.
+ i_target->setAttr<TARGETING::ATTR_CHIP_ID>(id);
+
+ } while(0);
- return nullptr;
+ return error;
}
// Register the presence detect function with the device framework
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 67a11b775..627b5803d 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
@@ -1086,8 +1086,37 @@ void* call_proc_cen_ref_clk_enable(void *io_pArgs )
else
{
TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
- "SUCCESS : exp_check_for_ready"
+ "SUCCESS : exp_check_for_ready "
"completed ok");
+
+ size_t size = 0;
+
+ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
+ "Read IDEC from OCMB 0x%.8X",
+ TARGETING::get_huid(l_ocmb));
+
+ // This write gets translated into a read of the explorer chip
+ // in the device driver. First, a read of the chip's IDEC
+ // register occurs then ATTR_EC, ATTR_HDAT_EC, and ATTR_CHIP_ID
+ // are set with the values found in that register. So, this
+ // deviceWrite functions more as a setter for an OCMB target's
+ // attributes.
+ l_errl = DeviceFW::deviceWrite(l_ocmb,
+ nullptr,
+ size,
+ DEVICE_IDEC_ADDRESS());
+ if (l_errl)
+ {
+ // read of ID/EC failed even though we THOUGHT we were
+ // present.
+ TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
+ "OCMB 0x%.8X - read IDEC failed (eid 0x%X) - bad",
+ TARGETING::get_huid(l_ocmb), l_errl->eid());
+
+ // commit the error but keep going
+ errlCommit(l_errl, HWAS_COMP_ID);
+ // l_errl is now nullptr
+ }
}
}
#endif
OpenPOWER on IntegriCloud