diff --git a/src/include/usr/fapiwrap/fapiWrapif.H b/src/include/usr/fapiwrap/fapiWrapif.H index f37aea26b90..e3a50f3b778 100644 --- a/src/include/usr/fapiwrap/fapiWrapif.H +++ b/src/include/usr/fapiwrap/fapiWrapif.H @@ -55,6 +55,18 @@ namespace FAPIWRAP errlHndl_t explorer_getidec( TARGETING::Target * i_ocmbChip, uint16_t& o_chipId, uint8_t& o_ec); + + /** + * @brief This function wraps around the FAPI2 HWP "get_pmic_i2c_addr" which + * takes in a DDIMM's DDR4 SPD data and a PMIC's position relative to + * its parent OCMB's chip and returns the device address of that pmic + * @param[in] i_spd - Binary blob containing addresses a given OCMB's PMICs + * @param[in] i_pmic_id - PMIC's position relative to parent OCMB + * @return uint8_t 0 if invalid pmic_id is passed, PMIC's devAddress otherwise + */ + uint8_t get_pmic_dev_addr( const char* i_spd, + const uint8_t i_pmic_id); + } #endif \ No newline at end of file diff --git a/src/include/usr/i2c/eeprom_const.H b/src/include/usr/i2c/eeprom_const.H index 055aa21723a..275388450a9 100644 --- a/src/include/usr/i2c/eeprom_const.H +++ b/src/include/usr/i2c/eeprom_const.H @@ -170,9 +170,9 @@ struct eecacheSectionHeader */ struct eeprom_addr_t { - uint64_t port; - uint64_t engine; - uint64_t devAddr; + uint8_t port; + uint8_t engine; + uint8_t devAddr; int64_t eepromRole; uint64_t offset; eeprom_addr_size_t addrSize; diff --git a/src/usr/fapiwrap/fapiWrap.C b/src/usr/fapiwrap/fapiWrap.C index dc52570e6de..a65b7c23388 100644 --- a/src/usr/fapiwrap/fapiWrap.C +++ b/src/usr/fapiwrap/fapiWrap.C @@ -27,7 +27,8 @@ #include // FAPI_INVOKE_HWP #include // tracing includes -#include // exp_getidec +#include // exp_getidec +#include // get_pmic_i2c_addr trace_desc_t* g_trac_fapiwrap; TRAC_INIT(&g_trac_fapiwrap, FAPIWRAP_COMP_NAME, 6*KILOBYTE, TRACE::BUFFER_SLOW); @@ -55,4 +56,10 @@ namespace FAPIWRAP return l_errl; } + + uint8_t get_pmic_dev_addr( const char* i_spd, + const uint8_t i_pmic_id) + { + return get_pmic_i2c_addr(i_spd, i_pmic_id); + } } \ No newline at end of file diff --git a/src/usr/fapiwrap/makefile b/src/usr/fapiwrap/makefile index 61ccd9646cd..96d96e48bed 100644 --- a/src/usr/fapiwrap/makefile +++ b/src/usr/fapiwrap/makefile @@ -38,6 +38,7 @@ EXTRAINCDIR += ${ROOTPATH}/src/import/chips/p9/procedures/hwp/ffdc/ # HWP include directories : EXTRAINCDIR += ${ROOTPATH}/src/import/chips/ocmb/explorer/procedures/hwp/memory/ +EXTRAINCDIR += ${ROOTPATH}/src/import/chips/ocmb/common/spd_access/ # HWP objects OBJS += exp_getidec.o diff --git a/src/usr/hwas/common/hwas.C b/src/usr/hwas/common/hwas.C index 8498b12b77b..9464e59c9f1 100644 --- a/src/usr/hwas/common/hwas.C +++ b/src/usr/hwas/common/hwas.C @@ -569,6 +569,59 @@ errlHndl_t discoverMuxTargetsAndEnable(const Target &i_sysTarget) return l_err; } +/** + * @brief Do presence detect on only PMIC targets and enable HWAS state + * + * @param[in] i_sysTarget the top level target (CLASS_SYS) + * @return errlHndl_t return nullptr if no error, + * else return a handle to an error entry + * + */ +errlHndl_t discoverPmicTargetsAndEnable(const Target &i_sysTarget) +{ + HWAS_INF(ENTER_MRK"discoverPmicTargetsAndEnable"); + + errlHndl_t l_err{nullptr}; + + do + { + // Only get PMIC targets + const PredicateCTM l_pmicPred(CLASS_ASIC, TYPE_PMIC); + TARGETING::PredicatePostfixExpr l_asicPredExpr; + l_asicPredExpr.push(&l_pmicPred); + TargetHandleList l_pPmicCheckPres; + targetService().getAssociated( l_pPmicCheckPres, (&i_sysTarget), + TargetService::CHILD, TargetService::ALL, &l_asicPredExpr); + + // Do the presence detect on only PMIC targets + // NOTE: this function will remove any non-functional targets + // from pPmicCheckPres + l_err = platPresenceDetect(l_pPmicCheckPres); + + // If an issue with platPresenceDetect, then exit, returning + // error back to caller + if (nullptr != l_err) + { + break; + } + + // Enable the HWAS State for the PMICs + const bool l_present(true); + const bool l_functional(true); + const uint32_t l_errlEid(0); + for (TargetHandle_t pTarget : l_pPmicCheckPres) + { + // set HWAS state to show PMIC is present and functional + enableHwasState(pTarget, l_present, l_functional, l_errlEid); + } + } while (0); + + HWAS_INF(EXIT_MRK"discoverPmicTargetsAndEnable exit with %s", + (nullptr == l_err ? "no error" : "error")); + + return l_err; +} + errlHndl_t discoverTargets() { HWAS_DBG("discoverTargets entry"); @@ -643,11 +696,13 @@ errlHndl_t discoverTargets() PredicateCTM predPmic(CLASS_ASIC, TYPE_PMIC); // We can ignore chips of TYPE_I2C_MUX because they // were already detected above in discoverMuxTargetsAndEnable + // Also we can ignore chips of type PMIC because they will be processed + // below. PredicateCTM predMux(CLASS_CHIP, TYPE_I2C_MUX); PredicatePostfixExpr checkExpr; checkExpr.push(&predChip).push(&predDimm).Or().push(&predEnc).Or(). - push(&predMcs).Or().push(&predPmic).Or(). - push(&predMux).Not().And(); + push(&predMcs).Or().push(&predMux).Not().And(). + push(&predPmic).Not().And(); TargetHandleList pCheckPres; targetService().getAssociated( pCheckPres, pSys, @@ -865,6 +920,16 @@ errlHndl_t discoverTargets() } // for pTarget_it + // After processing all other targets look at the pmics, + // we must wait because we need the SPD cached from the OCMBs + // which occurs when OCMBs go through presence detection above + errl = discoverPmicTargetsAndEnable(*pSys); + + if (errl != NULL) + { + break; // break out of the do/while so that we can return + } + // Check for non-present Procs and if found, trigger // DeconfigGard::_invokeDeconfigureAssocProc() to run by setting // setXAOBusEndpointDeconfigured to true diff --git a/src/usr/i2c/eeprom_utils.C b/src/usr/i2c/eeprom_utils.C index 7935094a39b..8333ebf4926 100644 --- a/src/usr/i2c/eeprom_utils.C +++ b/src/usr/i2c/eeprom_utils.C @@ -87,6 +87,18 @@ bool eepromPresence ( TARGETING::Target * i_target ) break; } + // If the target has dynamic device address attribute, then use that instead of the + // read-only address found in ATTR_EEPROM_XX_INFO attrs. We use the dynamic address + // attribute because ATTR_EEPROM_XX_INFO attrs are not writable and its difficult + // to override complex attributes. + if(i_target->tryGetAttr(i2cInfo.devAddr)) + { + TRACDCOMP(g_trac_eeprom, + "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x", + i2cInfo.devAddr, + TARGETING::get_huid(i_target)); + } + //Check for the target at the I2C level l_present = I2C::i2cPresence(i2cMasterTarget, i2cInfo.port, diff --git a/src/usr/i2c/fapi_i2c_dd.C b/src/usr/i2c/fapi_i2c_dd.C index d800af376b4..46e0720a1b5 100644 --- a/src/usr/i2c/fapi_i2c_dd.C +++ b/src/usr/i2c/fapi_i2c_dd.C @@ -108,6 +108,18 @@ errlHndl_t fapiI2cPerformOp(DeviceFW::OperationType i_opType, break; } + // If the target has dynamic device address attribute, then use that instead of the + // read-only address found in ATTR_FAPI_I2C_CONTROL_INFO. We use the dynamic address + // attribute because ATTR_FAPI_I2C_CONTROL_INFO is not writable and its difficult + // to override complex attributes. + if(i_target->tryGetAttr(l_i2cInfo.devAddr)) + { + TRACDCOMP(g_trac_i2c, + "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x", + l_i2cInfo.devAddr, + TARGETING::get_huid(i_target)); + } + // grab target pointer to master TARGETING::TargetService& ts = TARGETING::targetService(); TARGETING::Target * i2cm = ts.toTarget(l_i2cInfo.i2cMasterPath); diff --git a/src/usr/i2c/i2cTargetPres.C b/src/usr/i2c/i2cTargetPres.C index 13bfa88c1b8..2aba61de397 100644 --- a/src/usr/i2c/i2cTargetPres.C +++ b/src/usr/i2c/i2cTargetPres.C @@ -32,6 +32,8 @@ #include #include #include "i2c_common.H" +#include +#include extern trace_desc_t* g_trac_i2c; @@ -181,6 +183,18 @@ errlHndl_t genericI2CTargetPresenceDetect(TARGETING::Target* i_target, //* If we make it through all of the checks then we have verified master is present * //*********************************************************************************** + // If the target has dynamic device address attribute, then use that instead of the + // read-only address found in ATTR_FAPI_I2C_CONTROL_INFO. We use the dynamic address + // attribute because ATTR_FAPI_I2C_CONTROL_INFO is not writable and its difficult + // to override complex attributes. + if(i_target->tryGetAttr(l_i2cInfo.devAddr)) + { + TRACDCOMP(g_trac_i2c, + "Using DYNAMIC_I2C_DEVICE_ADDRESS %.2x for HUID %.8x", + l_i2cInfo.devAddr, + TARGETING::get_huid(i_target)); + } + //Check for the target at the I2C level l_target_present = I2C::i2cPresence(l_i2cMasterTarget, l_i2cInfo.port, @@ -231,10 +245,89 @@ errlHndl_t ocmbI2CPresencePerformOp(DeviceFW::OperationType i_opType, } /** - * @brief Performs a presence detect operation on a Target that has the + * @brief Performs a presence detect operation on a PMIC Target + * + * @param[in] i_opType Operation type, see DeviceFW::OperationType + * in driverif.H + * @param[in] i_target Presence detect target + * @param[in/out] io_buffer Read: Pointer to output data storage + * Write: Pointer to input data storage + * @param[in/out] io_buflen Input: size of io_buffer (in bytes, always 1) + * Output: Success = 1, Failure = 0 + * @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 are no arguments. + * @return errlHndl_t + */ +errlHndl_t pmicI2CPresencePerformOp(DeviceFW::OperationType i_opType, + TARGETING::Target* i_target, + void* io_buffer, + size_t& io_buflen, + int64_t i_accessType, + va_list i_args) +{ + + errlHndl_t l_errl = nullptr; + bool l_pmicPresent = 0; + TARGETING::Target* l_parentOcmb = TARGETING::getImmediateParentByAffinity(i_target); + + uint8_t l_spdBlob[SPD::DDIMM_DDR4_SPD_SIZE]; + size_t l_spdSize = SPD::DDIMM_DDR4_SPD_SIZE; + + do{ + + l_errl = deviceRead(l_parentOcmb, + l_spdBlob, + l_spdSize, + DEVICE_SPD_ADDRESS(SPD::ENTIRE_SPD_WITHOUT_EFD)); + + if(l_errl) + { + TRACFCOMP( g_trac_i2c, ERR_MRK"pmicI2CPresencePerformOp() " + "Error reading SPD associated with PMIC 0x%.08X, failed to determine presence", + TARGETING::get_huid(i_target)); + break; + } + + TARGETING::ATTR_REL_POS_type l_relPos = i_target->getAttr(); + + // PMICs will have a different device address depending on the vendor. + // Prior to doing present detection on a pmic we must first query the + // device address from the parent OCMB's SPD + uint8_t l_devAddr = FAPIWRAP::get_pmic_dev_addr(reinterpret_cast(l_spdBlob), + l_relPos); + + assert(l_devAddr != 0, + "Found devAddr for PMIC 0x%.08x to be 0, this cannot be. Check SPD and REL_POS on target", + TARGETING::get_huid(i_target)); + + i_target->setAttr(l_devAddr); + + l_errl = genericI2CTargetPresenceDetect(i_target, + io_buflen, + l_pmicPresent); + + if (l_errl) + { + TRACFCOMP( g_trac_i2c, ERR_MRK"pmicI2CPresencePerformOp() " + "Error detecting target 0x%.08X, io_buffer will not be set", + TARGETING::get_huid(i_target)); + break; + } + + // Copy variable describing if target is present or not to i/o buffer param + memcpy(io_buffer, &l_pmicPresent, sizeof(l_pmicPresent)); + io_buflen = sizeof(l_pmicPresent); + + }while(0); + + return l_errl; +} + +/** + * @brief Performs a presence detect operation on a Mux Target that has the * ATTR_FAPI_I2C_CONTROL_INFO and can be detected via that device * - * Currently used to detect I2C_MUTEX targets * * @param[in] i_opType Operation type, see DeviceFW::OperationType * in driverif.H @@ -248,7 +341,7 @@ errlHndl_t ocmbI2CPresencePerformOp(DeviceFW::OperationType i_opType, * In this function, there are no arguments. * @return errlHndl_t */ -errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType, +errlHndl_t muxI2CPresencePerformOp(DeviceFW::OperationType i_opType, TARGETING::Target* i_target, void* io_buffer, size_t& io_buflen, @@ -256,13 +349,13 @@ errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType, va_list i_args) { bool l_muxPresent = 0; - errlHndl_t l_returnedError = nullptr; + errlHndl_t l_errl = nullptr; - l_returnedError = genericI2CTargetPresenceDetect(i_target, - io_buflen, - l_muxPresent); + l_errl = genericI2CTargetPresenceDetect(i_target, + io_buflen, + l_muxPresent); - if (l_returnedError) + if (l_errl) { TRACFCOMP( g_trac_i2c, ERR_MRK"basicI2CTargetPresenceDetect() " "Error detecting target 0x%.08X, io_buffer will not be set", @@ -275,7 +368,7 @@ errlHndl_t basicI2CPresencePerformOp(DeviceFW::OperationType i_opType, io_buflen = sizeof(l_muxPresent); } - return l_returnedError; + return l_errl; } // Register the ocmb presence detect function with the device framework @@ -288,12 +381,12 @@ DEVICE_REGISTER_ROUTE(DeviceFW::READ, DEVICE_REGISTER_ROUTE( DeviceFW::READ, DeviceFW::PRESENT, TARGETING::TYPE_I2C_MUX, - basicI2CPresencePerformOp ); + muxI2CPresencePerformOp ); // Register the pmic vrm presence detect function with the device framework DEVICE_REGISTER_ROUTE( DeviceFW::READ, DeviceFW::PRESENT, TARGETING::TYPE_PMIC, - basicI2CPresencePerformOp ); + pmicI2CPresencePerformOp ); } diff --git a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml index 4910ca681d3..3e651b4984c 100755 --- a/src/usr/targeting/common/xmltohb/attribute_types_hb.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types_hb.xml @@ -174,6 +174,21 @@ + + DYNAMIC_I2C_DEVICE_ADDRESS + + This attribute is used when a given target could have different + i2c device addresses depending on which manufacture's device we + are using. + + + + + volatile-zeroed + + + + EARLY_TESTCASES_ISTEP diff --git a/src/usr/targeting/common/xmltohb/target_types_hb.xml b/src/usr/targeting/common/xmltohb/target_types_hb.xml index 03ae7a01d76..26cf81f6f48 100644 --- a/src/usr/targeting/common/xmltohb/target_types_hb.xml +++ b/src/usr/targeting/common/xmltohb/target_types_hb.xml @@ -265,6 +265,14 @@ + + pmic + + DYNAMIC_I2C_DEVICE_ADDRESS + 0 + + + sys-sys-power9