summaryrefslogtreecommitdiffstats
path: root/src/usr/hwas/hwasPlat.C
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/hwas/hwasPlat.C')
-rw-r--r--src/usr/hwas/hwasPlat.C548
1 files changed, 532 insertions, 16 deletions
diff --git a/src/usr/hwas/hwasPlat.C b/src/usr/hwas/hwasPlat.C
index bea5b4d8f..1cea60415 100644
--- a/src/usr/hwas/hwasPlat.C
+++ b/src/usr/hwas/hwasPlat.C
@@ -43,13 +43,16 @@
#include <sys/misc.h>
#include <pnor/pnorif.H>
+#include <fapiwrap/fapiWrapif.H>
#include <hwas/common/hwas_reasoncodes.H>
#include <targeting/common/utilFilter.H>
#include <fsi/fsiif.H>
-#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>
@@ -85,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;
}
/**
@@ -234,6 +243,70 @@ DEVICE_REGISTER_ROUTE(DeviceFW::WRITE,
TARGETING::TYPE_MEMBUF,
cfamIDEC);
+/**
+ * @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,
@@ -241,16 +314,456 @@ 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);
+ 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);
- // 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);
+ ERRORLOG::errlCommit(io_error, HWAS_COMP_ID);
+
+}
+
+/**
+ * @brief This helper function will lookup the chip id and ec levels of
+ * a given OCMB based on what is found in a provided SPD buffer.
+ * The target is passed along for trace information.
+ *
+ * @param[in] i_target OCMB target we are looking up IDEC for
+ *
+ * @param[in] i_spdBuffer Buffer of at least SPD::OCMB_SPD_EFD_COMBINED_SIZE
+ * bytes of the given OCMB's SPD
+ *
+ * @param[out] o_chipId Chip Id associated with the given OCMB
+ * (see src/import/chips/common/utils/chipids.H)
+ *
+ * @param[out] o_ec EC level associated with the given OCMB
+ *
+ * @return nullptr if success, error log otherwise
+ *
+ */
+errlHndl_t getOcmbIdecFromSpd(const TARGETING::TargetHandle_t& i_target,
+ uint8_t * i_spdBuffer,
+ uint16_t& o_chipId,
+ uint8_t& o_ec)
+{
+ errlHndl_t l_errl = nullptr;
+ // 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 uint8_t DDIMM_MEMORY_INTERFACE_TYPE = 0x0A;
+
+ const uint8_t l_spdModuleRevision =
+ *(i_spdBuffer + SPD_REVISION_OFFSET);
+
+ const uint8_t l_spdDRAMInterfaceType =
+ *(i_spdBuffer + DRAM_INTERFACE_TYPE_OFFSET);
+
+ const uint8_t l_spdMemoryInterfaceType =
+ *(i_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(l_spdModuleRevision, l_spdDRAMInterfaceType),
+ TWO_UINT8_TO_UINT16(l_spdMemoryInterfaceType, 0));
+
+ do{
+
+ // 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 != l_spdMemoryInterfaceType)
+ {
+ HWAS_ERR("getOcmbIdecFromSpd> memory module interface type "
+ "didn't match the expected type. "
+ "Expected 0x%.2X, Actual 0x%.2X",
+ DDIMM_MEMORY_INTERFACE_TYPE,
+ l_spdMemoryInterfaceType);
+
+ /*@
+ * @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.
+ */
+ l_errl = 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));
+
+ l_errl->addProcedureCallout(EPUB_PRC_HB_CODE,
+ SRCI_PRIORITY_LOW);
+
+ l_errl->addHwCallout(i_target,
+ SRCI_PRIORITY_HIGH,
+ NO_DECONFIG,
+ GARD_NULL);
+
+
+ break;
+ }
+
+ // 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 DMB_REV_OFFSET = 200;
+
+ // Get the ID from the SPD and verify that it matches what we read from
+ // the IDEC register.
+ uint16_t l_spdId = TWO_UINT8_TO_UINT16(
+ *(i_spdBuffer + SPD_ID_LEAST_SIGNIFICANT_BYTE_OFFSET),
+ *(i_spdBuffer + SPD_ID_MOST_SIGNIFICANT_BYTE_OFFSET));
+
+ // Bytes 200 of the SPD contains the DMB Revision, this is essentially the
+ // OCMB manufacture's version of the chip. The manufacture can define any
+ // format for this field and we must add special logic to convert the
+ // manufacture's DMB_REV to the EC level IBM is familiar with.
+ uint8_t l_spdDmbRev = *(i_spdBuffer + DMB_REV_OFFSET);
+
+ HWAS_INF("getOcmbIdecFromSpd> OCMB 0x%.8x l_spdId = 0x%.4X l_spdDmbRev = 0x%.2x",
+ TARGETING::get_huid(i_target), l_spdId, l_spdDmbRev);
+
+ if (DDIMM_DMB_ID::EXPLORER == l_spdId)
+ {
+ o_chipId = POWER_CHIPID::EXPLORER_16;
+ // Must convert Explorer's versioning into IBM-style EC levels.
+ // Explorer vendor has stated versioning will start at 0xA0 and increment
+ // 1st nibble for major revisions and 2nd nibble by 1 for minor revisions
+ // Examples :
+ // Version 0xA0 = EC 0x10
+ // Version 0xA1 = EC 0x11
+ // Version 0xB2 = EC 0x22
+
+ // Resulting formula from pattern in examples above is as follows:
+ o_ec = (l_spdDmbRev - 0x90);
+ }
+ else if (DDIMM_DMB_ID::GEMINI == l_spdId)
+ {
+ o_chipId = POWER_CHIPID::GEMINI_16;
+
+ HWAS_ASSERT(l_spdDmbRev == 0x0,
+ "Invalid Gemini DMB Revision Number, expected to find 0x0 at byte 200 in Gemini SPD");
+
+ // 0x10 is the only valid EC level for Gemini cards. If we find 0x0 @ byte 200 in
+ // the Gemini SPD then we will return 0x10 as the EC level
+ o_ec = 0x10;
+ }
+ else
+ {
+ HWAS_ERR("getOcmbIdecFromSpd> Unknown OCMB chip type discovered in SPD "
+ "ID=0x%.4X OCMB HUID 0x%.8x",
+ l_spdId,
+ TARGETING::get_huid(i_target));
+
+ /*@
+ * @errortype
+ * @severity ERRL_SEV_PREDICTIVE
+ * @moduleid MOD_OCMB_IDEC
+ * @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.
+ */
+ l_errl = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ MOD_OCMB_IDEC_PHASE_1,
+ RC_OCMB_UNKNOWN_CHIP_TYPE,
+ TWO_UINT32_TO_UINT64(SPD_FFDC_BYTES, l_spdId),
+ TARGETING::get_huid(i_target));
+
+ break;
+ }
+
+ }while(0);
+
+ return l_errl;
+
+}
+
+
+errlHndl_t ocmbIdecPhase1(const TARGETING::TargetHandle_t& i_target)
+{
+ errlHndl_t l_errl = nullptr;
+
+ // Allocate buffer to hold SPD and init to 0
+ size_t l_spdBufferSize = SPD::DDIMM_DDR4_SPD_SIZE;
+ uint8_t* l_spdBuffer = new uint8_t[l_spdBufferSize];
+ memset(l_spdBuffer, 0, l_spdBufferSize);
+ uint16_t l_chipId = 0;
+ uint8_t l_chipEc = 0;
+
+ do {
+
+ // Read the SPD off the ocmb but skip reading the EFD to save time.
+ l_errl = deviceRead(i_target,
+ l_spdBuffer,
+ l_spdBufferSize,
+ DEVICE_SPD_ADDRESS(SPD::ENTIRE_SPD_WITHOUT_EFD));
+
+ // If unable to retrieve the SPD buffer then can't
+ // extract the IDEC data, so return error.
+ if (l_errl != nullptr)
+ {
+ HWAS_ERR("ocmbIdecPhase1> 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(l_spdBufferSize == SPD::DDIMM_DDR4_SPD_SIZE,
+ "ocmbIdecPhase1> OCMB SPD read size %d "
+ "doesn't match the expected size %d",
+ l_spdBufferSize,
+ SPD::DDIMM_DDR4_SPD_SIZE);
+
+ l_errl = getOcmbIdecFromSpd(i_target,
+ l_spdBuffer,
+ l_chipId,
+ l_chipEc);
+
+ // If we were unable to read the IDEC information from the SPD
+ // then break out early and do not set the associated attributes
+ if (l_errl != nullptr)
+ {
+ HWAS_ERR("ocmbIdecPhase1> Error while trying to parse "
+ "chip id and ec values from SPD read from OCMB 0x%.08X ",
+ TARGETING::get_huid(i_target));
+ break;
+ }
+
+ HWAS_INF("ocmbIdecPhase1> Read Chip ID = 0x%x Chip EC = 0x%x from target 0x%.08X",
+ l_chipId, l_chipEc, TARGETING::get_huid(i_target) );
+
+ // set the explorer chip EC attributes.
+ i_target->setAttr<TARGETING::ATTR_EC>(l_chipEc);
+ i_target->setAttr<TARGETING::ATTR_HDAT_EC>(l_chipEc);
+
+ // set the explorer chip id attribute.
+ i_target->setAttr<TARGETING::ATTR_CHIP_ID>(l_chipId);
+
+ } while(0);
+
+ delete[] l_spdBuffer;
+ return l_errl;
+
+}
+
+errlHndl_t ocmbIdecPhase2(const TARGETING::TargetHandle_t& i_target)
+{
+ const uint32_t GEM_IDEC_SCOM_REGISTER = 0x0801240e;
+ const TARGETING::ATTR_CHIP_ID_type l_chipIdFromSpd =
+ i_target->getAttr<TARGETING::ATTR_CHIP_ID>();
+
+ errlHndl_t l_errl = nullptr;
+ uint64_t l_idec = 0;
+ size_t l_op_size = sizeof(l_idec);
+ uint8_t l_ec = 0;
+ uint16_t l_id = 0;
+
+ do {
+
+ if(l_chipIdFromSpd == POWER_CHIPID::EXPLORER_16)
+ {
+ // Call platform independent lookup for Explorer OCMBs
+ l_errl = FAPIWRAP::explorer_getidec(i_target, l_id, l_ec);
+
+ if (l_errl != nullptr)
+ {
+ HWAS_ERR("ocmbIdecPhase2> explorer OCMB 0x%.8X - failed to read ID/EC",
+ TARGETING::get_huid(i_target));
+
+ break;
+ }
+ }
+ else
+ {
+ // read the register containing IDEC info on Gemini OCMBs
+ l_errl = DeviceFW::deviceRead(i_target,
+ &l_idec,
+ l_op_size,
+ DEVICE_SCOM_ADDRESS(GEM_IDEC_SCOM_REGISTER));
+
+ if (l_errl != nullptr)
+ {
+ HWAS_ERR("ocmbIdecPhase2> gemini OCMB 0x%.8X - failed to read ID/EC",
+ TARGETING::get_huid(i_target));
+
+ break;
+ }
+
+ // Need to convert Gemini's IDEC register from MmL000CC
+ // to cfam standard format MLmCC000
+ uint32_t l_major = 0xF0000000 & static_cast<uint32_t>(l_idec);
+ uint32_t l_minor = 0x0F000000 & static_cast<uint32_t>(l_idec);
+ uint32_t l_location = 0x00F00000 & static_cast<uint32_t>(l_idec);
+ l_idec = (l_major | (l_location << 4) | (l_minor >> 4)
+ | ((l_idec & 0x000000FF) << 12));
+ // Parse out the information we need
+ l_ec = POWER_CHIPID::extract_ddlevel(l_idec);
+ l_id = POWER_CHIPID::extract_chipid16(l_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),
+ l_id,
+ l_ec,
+ l_idec);
+
+ if (l_id != l_chipIdFromSpd)
+ {
+ HWAS_ERR("ocmbIdecPhase2> OCMB Chip Id and associated SPD Chip Id "
+ "don't match: OCMB ID=0x%.4X; SPD ID=0x%.4X;",
+ l_id,
+ l_chipIdFromSpd);
+
+ HWAS_ERR("ocmbIdecPhase2> Previous CHIP_ID 0x%.4X was set based on values from "
+ "SPD read will now be overwritten with values from OCMB IDEC register "
+ "ID=0x%.4X",
+ l_chipIdFromSpd,
+ l_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] IDEC ID found in OCMB's SPD
+ * @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
+ */
+ l_errl = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ MOD_OCMB_IDEC,
+ RC_OCMB_CHIP_ID_MISMATCH,
+ TWO_UINT32_TO_UINT64(l_id, l_chipIdFromSpd),
+ TARGETING::get_huid(i_target));
+
+ // Add callouts and commit
+ ocmbErrlCommit(i_target, l_errl);
+
+ // 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>(l_id);
+ }
+
+ const uint8_t l_ecFromSpd = i_target->getAttr<TARGETING::ATTR_EC>();
+
+ if (l_ec != l_ecFromSpd)
+ {
+ HWAS_ERR("ocmbIdecPhase2> OCMB Revision and associated SPD "
+ "Revision don't match: OCMB EC=0x%.2X; "
+ "SPD EC=0x%.2X; ",
+ l_ec, l_ecFromSpd);
+
+ HWAS_ERR("ocmbIdecPhase2> Previous EC and HDAT_EC attributes 0x%.2X,"
+ " which were set with values found in SPD will be overwritten"
+ " with value from OCMB IDEC register ID=0x%.2X",
+ l_ecFromSpd,
+ l_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] EC found in OCMB's SPD
+ * @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
+ */
+ l_errl = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ MOD_OCMB_IDEC,
+ RC_OCMB_SPD_REVISION_MISMATCH,
+ TWO_UINT32_TO_UINT64(l_ec, l_ecFromSpd),
+ TWO_UINT32_TO_UINT64(
+ i_target->getAttr<TARGETING::ATTR_CHIP_ID>(),
+ TARGETING::get_huid(i_target)));
+
+ // Add callouts and commit
+ ocmbErrlCommit(i_target, l_errl);
+
+ // 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>(l_ec);
+ i_target->setAttr<TARGETING::ATTR_HDAT_EC>(l_ec);
+ }
+
+ } while(0);
+
+ return l_errl;
- return nullptr;
}
// Register the presence detect function with the device framework
@@ -628,7 +1141,10 @@ errlHndl_t platPresenceDetect(TargetHandleList &io_targets)
DEVICE_CACHE_EEPROM_ADDRESS(present, EEPROM::VPD_PRIMARY));
errl = deviceRead(pTarget, &present, presentSize,
DEVICE_CACHE_EEPROM_ADDRESS(present, EEPROM::VPD_PRIMARY));
- errlCommit(errl, HWAS_COMP_ID);
+ if( errl )
+ {
+ errlCommit(errl, HWAS_COMP_ID);
+ }
// errl is now null, move on to next target
}
#endif
OpenPOWER on IntegriCloud