/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/hwpf/fapi2/include/collect_reg_ffdc.H $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] International Business Machines Corp. */ /* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ /* You may obtain a copy of the License at */ /* */ /* http://www.apache.org/licenses/LICENSE-2.0 */ /* */ /* Unless required by applicable law or agreed to in writing, software */ /* distributed under the License is distributed on an "AS IS" BASIS, */ /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ /* implied. See the License for the specific language governing */ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ #ifndef FAPI2_COLLECT_REG_FFDC_H_ #define FAPI2_COLLECT_REG_FFDC_H_ #include #include #include #include #include #include #include #include #include #include #include #include namespace fapi2 { // in generated file collect_reg_ffdc_regs.C void getAddressData(const fapi2::HwpFfdcId i_ffdcId, std::vector& o_scomAddresses , std::vector& o_cfamAddresses , uint32_t& o_ffdcSize ); /// /// @brief converts value to a type to enable overloading based on values /// /// @tparam v - value to create to a unique type /// /// @return v - value. /// template struct toType { enum { value = v }; }; /// /// @class TargetPosition /// /// helper class to get the position for the passed in chip /// or chiplet. /// /// template < TargetType T, bool isChiplet = T& TARGET_TYPE_CHIPLETS > class TargetPosition { public: /// /// @brief constructor /// TargetPosition(const Target& t) : iv_targ(t) {}; /// /// @brief Return position of either a chip or chiplet target /// /// @param[out] o_pos - position of chip/chiplet target /// /// @return fapi2::ReturnCode. FAPI_RC_SUCCESS, or failure value. /// fapi2::ReturnCode getPosition( uint32_t& o_pos) { return getPosition(o_pos, toType()); } private: /// /// @brief return target position for chiplet /// /// @param[out] o_pos - chiplet position /// @param[in] is_chiplet = true /// /// @return fapi2::ReturnCode. FAPI_RC_SUCCESS, or failure value. /// fapi2::ReturnCode getPosition(uint32_t& o_pos, toType) { fapi2::ReturnCode l_rc; uint8_t l_chipletPos = 0; l_rc = FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, iv_targ, l_chipletPos); if (l_rc) { FAPI_ERR("collect_reg_ffdc.C: Error getting chiplet position"); l_chipletPos = 0xFF; } o_pos = static_cast(l_chipletPos); return l_rc; } /// /// @brief return target position for chip /// /// @param[out] o_pos - chiplet position /// @param[in] is_chiplet = false /// /// @return fapi2::ReturnCode. FAPI_RC_SUCCESS, or failure value. /// fapi2::ReturnCode getPosition(uint32_t& o_pos, toType) { fapi2::ReturnCode l_rc; uint32_t l_Pos = 0; l_rc = FAPI_ATTR_GET(fapi2::ATTR_POS, iv_targ, l_Pos); if (l_rc) { FAPI_ERR("collect_reg_ffdc.C: Error getting position"); l_Pos = 0xFF; } o_pos = l_Pos; return l_rc; } const fapi2::Target& iv_targ; }; const fapi2::TargetType TARGET_TYPE_PROC_CHIPLETS = fapi2::TARGET_TYPE_EX | fapi2::TARGET_TYPE_MCS | fapi2::TARGET_TYPE_XBUS | fapi2::TARGET_TYPE_CORE | fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MCA | fapi2::TARGET_TYPE_MCBIST | fapi2::TARGET_TYPE_MI | fapi2::TARGET_TYPE_CAPP | fapi2::TARGET_TYPE_DMI | fapi2::TARGET_TYPE_OBUS | fapi2::TARGET_TYPE_OBUS_BRICK | fapi2::TARGET_TYPE_SBE | fapi2::TARGET_TYPE_PPE | fapi2::TARGET_TYPE_PERV | fapi2::TARGET_TYPE_PEC | fapi2::TARGET_TYPE_PHB | fapi2::TARGET_TYPE_MC | fapi2::TARGET_TYPE_OMI | fapi2::TARGET_TYPE_MEM_PORT; const fapi2::TargetType TARGET_TYPE_SCOM_TARGET = fapi2::TARGET_TYPE_PROC_CHIP | fapi2::TARGET_TYPE_MEMBUF_CHIP | fapi2::TARGET_TYPE_EX | fapi2::TARGET_TYPE_MBA | fapi2::TARGET_TYPE_MCS | fapi2::TARGET_TYPE_XBUS | fapi2::TARGET_TYPE_ABUS | fapi2::TARGET_TYPE_L4 | fapi2::TARGET_TYPE_CORE | fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MCA | fapi2::TARGET_TYPE_MCBIST | fapi2::TARGET_TYPE_MI | fapi2::TARGET_TYPE_DMI | fapi2::TARGET_TYPE_OBUS | fapi2::TARGET_TYPE_OBUS_BRICK | fapi2::TARGET_TYPE_SBE | fapi2::TARGET_TYPE_PPE | fapi2::TARGET_TYPE_PERV | fapi2::TARGET_TYPE_PEC | fapi2::TARGET_TYPE_PHB | fapi2::TARGET_TYPE_MC | fapi2::TARGET_TYPE_OMI | fapi2::TARGET_TYPE_MEM_PORT; template< TargetType T> inline fapi2::Target getChipTarget(const fapi2::Target& i_target) { return getChipTarget(i_target); } // handle membuf/proc targets inline fapi2::Target getChipTarget(const fapi2::Target& i_target) { return i_target; } // handle dimms inline fapi2::Target getChipTarget(const fapi2::Target& i_target) { return i_target.getParent().getParent(); } // everything else is w/proc chip? inline fapi2::Target getChipTarget(const fapi2::Target& i_target) { return i_target.getParent(); } template < TargetType T> fapi2::Target getScomTarget(const fapi2::Target& i_target) { return i_target; } inline fapi2::Target getScomTarget(const fapi2::Target& i_target) { return i_target.getParent(); } template class CfamReader { public: CfamReader(const fapi2::Target& i_target) : iv_target(i_target) {}; ReturnCode read_register(const uint32_t address, fapi2::buffer& i_buf) { FAPI_DBG("CfamReader.read_register - no-op"); return FAPI2_RC_SUCCESS; } private: const fapi2::Target& iv_target; }; template<> class CfamReader { public: CfamReader(const fapi2::Target& i_target) : iv_target(i_target) {}; ReturnCode read_register (const uint32_t address, fapi2::buffer& i_buf) { FAPI_DBG("CfamReader.read_register - MEMBUF VERSION"); return fapi2::getCfamRegister(iv_target, address, i_buf); } private: const fapi2::Target& iv_target; }; template<> class CfamReader { public: CfamReader(const fapi2::Target& i_target) : iv_target(i_target) {}; ReturnCode read_register(const uint32_t address, fapi2::buffer& i_buf) { FAPI_DBG("CfamReader.read_register - PROC VERSION"); return fapi2::getCfamRegister(iv_target, address, i_buf); } private: const fapi2::Target& iv_target; }; /// /// @class ScomReader /// /// Class to abstract away details of reading of a scom register /// template< TargetType T > class ScomReader { public: ScomReader(const fapi2::Target& i_target) : iv_target(i_target) {}; ReturnCode read_register(const uint64_t i_address, fapi2::buffer& o_buf) { FAPI_DBG("ScomReader.read_register - BASE version"); return getScom(iv_target, i_address, o_buf); } private: const fapi2::Target& iv_target; }; /// /// @brief class to handle reading from scom registers from generic function /// template<> class ScomReader { public: ScomReader(const fapi2::Target& i_target) : iv_target(getScomTarget(i_target)) {}; ReturnCode read_register(const uint64_t i_address, fapi2::buffer& o_buf) { FAPI_DBG("ScomReader.read_register - DIMM version"); ReturnCode l_rc = getScom(iv_target, i_address, o_buf); return l_rc; } private: const fapi2::Target& iv_target; }; /// /// @brief collectRegisterData /// /// collect all the data from a list of registers and return it to the caller /// /// @tparam T register data size - uint32_t or uint64_t /// @tparam U - reader object for specific data type /// @param[in] i_addresses - vector containing either cfam or scom addresses /// @param[in] i_reader - input reader object /// @param[in] i_offset - optional offset to add to the address values /// passed in the vector of addresses /// @param[out] o_pData - pointer to the data destination /// /// @return fapi2::ReturnCode. FAPI_RC_SUCCESS, or failure value. /// template< typename T, class U> ReturnCode collectRegisterData(std::vector& i_addresses, U& i_reader, uint32_t i_offset, uint8_t*& o_pData) { FAPI_DBG("collectRegisterData -> address count: 0x%lx", i_addresses.size()); T l_data = 0; ReturnCode l_rc = FAPI2_RC_SUCCESS; for( auto address : i_addresses ) { fapi2::buffer l_buf; const T l_address = address + i_offset; l_rc = i_reader.read_register(l_address, l_buf); if(l_rc) { l_data = 0xbaddbadd; #ifdef __DELETE_PLATFORMDATA_SUPPORTED // delete the platform log if it exits deletePlatformDataPointer(l_rc); #endif } else { l_data = l_buf(); } memcpy(o_pData, &l_data, sizeof(T)); o_pData += sizeof(T); } return l_rc; } template< typename T, class U> ReturnCode collectRegisterAndAddressData(std::vector& i_addresses, U& i_reader, uint32_t i_offset, uint8_t*& o_pData) { FAPI_DBG("collectRegisterAndAddressData -> address count: 0x%lx", i_addresses.size()); T l_data = 0; uint32_t l_addr = 0; ReturnCode l_rc = FAPI2_RC_SUCCESS; for( auto address : i_addresses ) { fapi2::buffer l_buf; l_addr = address + i_offset; l_rc = i_reader.read_register(l_addr, l_buf); if(l_rc) { l_data = 0xbaddbadd; #ifdef __DELETE_PLATFORMDATA_SUPPORTED // delete the platform data pointer if it exists deletePlatformDataPointer(l_rc); #endif } else { l_data = l_buf(); } l_data = htobe64(l_data); memcpy(o_pData, &l_addr, sizeof(uint32_t)); o_pData += sizeof(uint32_t); memcpy(o_pData, &l_data, sizeof(T)); o_pData += sizeof(T); } return l_rc; } /// /// @brief readRegisters /// /// Template function to allow reading either scom and cfam data from registers /// for a given target /// /// @tparam T - fapi2::TargetType /// @param[in] i_target - fapi2::Target /// @param[out] o_pData - pointer to a location to store register data /// @param[in] i_cfamAddresses - vector of cfam addresses to read /// @param[in] i_scomAddresses - vector of scom addresses to read /// @param[in] i_childOffset - optional offset to address of child /// /// @return fapi2::ReturnCode. FAPI_RC_SUCCESS, or failure value. /// template void readRegisters(const fapi2::Target& i_target, uint8_t* o_pData, std::vector i_cfamAddresses, std::vector i_scomAddresses, uint32_t i_childOffset = 0) { FAPI_DBG("readRegisters()"); // create an object to read Cfam registers CfamReader l_cfamReader(i_target); // Create an object to read scom registers ScomReader l_scomReader(i_target); // read data from the cfam registers if required ReturnCode rc = collectRegisterData >(i_cfamAddresses, l_cfamReader, i_childOffset, o_pData); if(rc) { FAPI_ERR("An error occured when reading from the cfam registers skipping.."); } // read data from Scom registers if present rc = collectRegisterData >(i_scomAddresses, l_scomReader, i_childOffset, o_pData); if(rc) { FAPI_ERR("An error occured when reading the scom registers.."); } FAPI_DBG("readRegisters() exit"); } /// /// @brief Collect register data for child targets /// /// @tparam C - child target type /// @tparam T - parent target type /// @param[in] i_parent - fapi2::Target /// @param[in] i_childState - fapi2::TargetState for child targets /// @param[in] i_ffdcId - type of ffdc to be collected /// @param[out] o_errorInfoFfdc - vector of shared pointers to fapi2::ErrorInfoFfdc type /// for returned register data /// @param[in] i_childOffsetMult - child offset for register calculations /// /// template void collectRegFfdc(const fapi2::ffdc_t i_parent, const fapi2::TargetState i_childState, const HwpFfdcId i_ffdcId, std::vector>& o_errorInfoFfdc, uint32_t i_childOffsetMult = 0) { FAPI_INF("collectRegFfdc child targets version"); std::vector > l_targets; if( i_parent.ptr() == nullptr ) { FAPI_ERR("Target ptr in FFDC object was null, skipping register data collection."); } else { Target l_parent = *(static_cast*>(i_parent.ptr())); // Collect FFDC for functional or present chiplets of // type C associated with i_target - yeah, odd syntax. l_targets = l_parent.template getChildren(i_childState); if (l_targets.empty()) { FAPI_INF("collect_reg_ffdc.C: Error: No chiplets found. "); return; } std::vector l_cfamAddresses; std::vector l_scomAddresses; uint32_t l_ffdcSize = 0; // total size needed for all entries uint32_t l_ffdcRegReadSize = 0; // readRegisters size addition // call generated code to fetch the address vectors getAddressData(i_ffdcId, l_scomAddresses, l_cfamAddresses, l_ffdcRegReadSize); uint32_t l_position = 0; // initialize to single readRegister entry l_ffdcSize = l_ffdcRegReadSize; // add the position size to the total l_ffdcSize += sizeof(l_position); // update size for each target l_ffdcSize = (l_ffdcSize * l_targets.size()); uint8_t l_pBuf[l_ffdcSize]; uint8_t* l_pData = &l_pBuf[0]; // grab the data for each child target for( auto target : l_targets) { ReturnCode l_rc = TargetPosition(target).getPosition(l_position); // add chip/chiplets position to the data memcpy(l_pData, &l_position, sizeof(l_position)); // advance the pointer into our buffer l_pData += sizeof(l_position); if(i_childState == TARGET_STATE_FUNCTIONAL) { FAPI_INF(" calling version for TARGET_STATE_FUNCTIONAL "); // since its functional just read from the child target readRegisters(target, l_pData, l_cfamAddresses, l_scomAddresses, i_childOffsetMult); } else { // use the parent and read address + offset since the // child targets may not be functional uint32_t l_offset = i_childOffsetMult * l_position; FAPI_INF(" calling version for TARGET_STATE_PRESENT "); readRegisters(l_parent, l_pData, l_cfamAddresses, l_scomAddresses, l_offset); } // advance the pointer past readRegisters data entry l_pData += l_ffdcRegReadSize; } FAPI_INF("collectRegFfdc. SCOM address count: %#lx", l_scomAddresses.size()); FAPI_INF("collectRegFfdc. CFAM address count: %#lx", l_cfamAddresses.size()); FAPI_DBG("size info i_ffdcId = %d, l_pBuf = %p, l_ffdcSize=%d", i_ffdcId, l_pBuf, l_ffdcSize); // Create a ErrorInfoFfdc object and pass it back o_errorInfoFfdc.push_back(std::shared_ptr(new ErrorInfoFfdc(i_ffdcId, l_pBuf, l_ffdcSize))); } } /// /// @brief Collect register data for a single target /// /// @tparam T - target type /// @param[in] i_target - fapi2::Target /// @param[in] i_ffdcId - type of ffdc to be collected /// @param[out] o_errorInfoFfdc - shared pointer to fapi2::ErrorInfoFfdc type /// for returned register data /// @param[in] i_childOffset - child offset for register calculations /// template void collectRegFfdc(const fapi2::ffdc_t i_target, const HwpFfdcId i_ffdcId, std::vector >& o_errorInfoFfdc, uint32_t i_childOffset = 0) { FAPI_INF("single target no children - "); if( i_target.ptr() == nullptr ) { FAPI_ERR("Target ptr in FFDC object was null, skipping register data collection."); } else { Target l_target = *(static_cast*>(i_target.ptr())); std::vector l_cfamAddresses; std::vector l_scomAddresses; uint32_t l_ffdcSize = 0; // call generated code to fetch the address vectors getAddressData(i_ffdcId, l_scomAddresses, l_cfamAddresses, l_ffdcSize); uint32_t l_position = 0; ReturnCode l_rc = TargetPosition(l_target).getPosition(l_position); l_ffdcSize += sizeof(l_position); uint8_t l_pBuf[l_ffdcSize]; uint8_t* l_pData = &l_pBuf[0]; // add chip/chiplets position to the data memcpy(l_pData, &l_position, sizeof(l_position)); l_pData += sizeof(l_position); // do the work readRegisters(l_target, l_pData, l_cfamAddresses, l_scomAddresses, i_childOffset); FAPI_DBG("size info i_ffdcId = %d, l_pBuf = %p, l_ffdcSize=%d", i_ffdcId, l_pBuf, l_ffdcSize); // Create a ErrorInfoFfdc object and add it to the Error Information // object of the FFDC class o_errorInfoFfdc.push_back(std::shared_ptr(new ErrorInfoFfdc(i_ffdcId, l_pBuf, l_ffdcSize))); FAPI_INF("collectRegFfdc. SCOM address count: %d", (uint32_t)(l_scomAddresses.size())); FAPI_INF("collectRegFfdc. CFAM address count: %d", (uint32_t)(l_cfamAddresses.size())); } FAPI_INF("collectRegFfdc() - exit"); } }// end namespace #endif