/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/usr/fapi2/plat_utils.C $ */ /* */ /* 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 */ /// /// @file plat_utils.C /// /// @brief Implements the plat_utils.H utility functions. /// /// Note that platform code must provide the implementation. /// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //****************************************************************************** // Trace descriptors //****************************************************************************** trace_desc_t* g_fapiTd; trace_desc_t* g_fapiImpTd; trace_desc_t* g_fapiScanTd; trace_desc_t* g_fapiDbgTd; trace_desc_t* g_fapiMfgTd; //****************************************************************************** // Global TracInit objects. Construction will initialize the trace buffer //****************************************************************************** TRAC_INIT(&g_fapiTd, FAPI_TRACE_NAME, 2*KILOBYTE); TRAC_INIT(&g_fapiImpTd, FAPI_IMP_TRACE_NAME, 2*KILOBYTE); TRAC_INIT(&g_fapiScanTd, FAPI_SCAN_TRACE_NAME, 4*KILOBYTE); TRAC_INIT(&g_fapiDbgTd, FAPI_DBG_TRACE_NAME, 4*KILOBYTE); TRAC_INIT(&g_fapiMfgTd, FAPI_MFG_TRACE_NAME, 4*KILOBYTE); namespace fapi2 { // Define global current_err #ifndef PLAT_NO_THREAD_LOCAL_STORAGE thread_local ReturnCode current_err; #else ReturnCode current_err; #endif /// /// @brief Retrieve the ring data from the centaur hw image /// for a given ring id /// /// @param[in] i_target - TARGET_TYPE_MEMBUF_CHIP /// @param[in] i_ringId - Ring id to extract from hw image /// @param[out] o_ringdata - uncompressed ring data /// @param[out] o_ringLength - length of uncompressd ring in bits /// @param[out] o_ringAddress - scom address of ring /// /// @return fapi2::ReturnCode /// template<> ReturnCode get_ring(Targeti_target, const RingId_t i_ringId, unsigned char *&o_ringData, size_t &o_ringLength, uint64_t &o_ringAddress) { FAPI_INF(">>>get_ring()"); fapi2::ReturnCode l_fapi2Rc; errlHndl_t l_err = NULL; PNOR::SectionInfo_t l_info; P9XipSection l_ringSection; o_ringLength = 0; o_ringAddress = 0; // buffer as the max size uint32_t l_ringBufSizeInBytes = MAX_CENTAUR_RING_SIZE; // create some work spaces // max ring size in centaur is 76490 bits - allocate 10k buffers uint8_t * care = (uint8_t*)malloc(l_ringBufSizeInBytes); void * l_rs4RingData = malloc(l_ringBufSizeInBytes); do { // setup pointers to hw image data // Get Centaur hw image PNOR section info from PNOR RP l_err = PNOR::getSectionInfo( PNOR::CENTAUR_HW_IMG, l_info ); if( l_err ) { FAPI_ERR("get_ring() - call to getSectionInfo(" "PNOR::CENTAUR_HW_IMG failed"); l_fapi2Rc.setPlatDataPtr(reinterpret_cast(l_err)); break; } // local pointer to the centaur hw image char * l_centaurHwImageAddr = reinterpret_cast(l_info.vaddr); FAPI_DBG("CENTAUR_HW_IMG addr = 0x%.16llX ", l_centaurHwImageAddr); TRACDBIN(g_fapiImpTd,"Centaur Image Header: ", l_centaurHwImageAddr, sizeof(P9XipHeader)); if(((P9XipHeader*)l_centaurHwImageAddr)->iv_magic == P9_XIP_MAGIC_CENTAUR) { uint8_t l_ddLevel = UNDEFINED_DD_LEVEL; MyBool_t l_bDdSupport = UNDEFINED_BOOLEAN; int l_rc = p9_xip_dd_section_support(l_centaurHwImageAddr, P9_XIP_SECTION_HW_RINGS, &l_bDdSupport); if( l_rc != INFRASTRUCT_RC_SUCCESS ) { FAPI_INF("get_ring() - call to p9_xip_dd_section_support()" " call failed with rc = %d ",l_rc); /*@ * @errortype * @moduleid fapi2::MOD_FAPI2_GET_RING * @reasoncode fapi2::RC_DD_SUPPORT_CHECK_FAILED * @userdata1 requested section id * @userdata2 return code from p9_xip_dd_section_support * @devdesc Call to p9_xip_dd_section_support failed. * @custdesc Internal firmware error */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi2::MOD_FAPI2_GET_RING, fapi2::RC_DD_SUPPORT_CHECK_FAILED, P9_XIP_SECTION_HW_RINGS, l_rc, true /*SW error*/); l_err->collectTrace(FAPI_TRACE_NAME); l_fapi2Rc.setPlatDataPtr(reinterpret_cast(l_err)); break; } // if there is ddcontainer support, then set dd level to 20 // since that is the only value centaur currently supports if( l_bDdSupport == true ) { l_ddLevel = 0x20; } // get the offset to the ring section for the tor_get_ring call l_rc = p9_xip_get_section((const void*)l_centaurHwImageAddr, P9_XIP_SECTION_HW_RINGS, &l_ringSection, l_ddLevel); if( l_rc != INFRASTRUCT_RC_SUCCESS ) { FAPI_INF("get_ring() - call to p9_xip_get_section()" " call failed with rc = %d ",l_rc); /*@ * @errortype * @moduleid fapi2::MOD_FAPI2_GET_RING * @reasoncode fapi2::RC_GET_RING_SECTION_FAILED * @userdata1 requested section id * @userdata2 return code from p9_xip_get_section * @devdesc Call to p9_xip_get_section to retrieve * the hw rings section has failed. See * userdata2 for the return code value. * @custdesc Internal firmware error */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi2::MOD_FAPI2_GET_RING, fapi2::RC_GET_RING_SECTION_FAILED, P9_XIP_SECTION_HW_RINGS, l_rc, true /*SW error*/); l_err->collectTrace(FAPI_TRACE_NAME); l_fapi2Rc.setPlatDataPtr(reinterpret_cast(l_err)); break; } FAPI_INF("get_ring() - got the ring section.."); char ringName[MAX_RING_NAME_LENGTH] = {0}; // only a single instance for centaur uint8_t instanceId = 1; // only base rings in centaur image RingVariant_t ringVariant = RV_BASE; // default ppe type PpeType_t ppeType = PT_SBE; // extract rs4 ring info from the hw image - pass in a big buffer // and skip the extra call to get the compressed ring size int rc = tor_access_ring(l_ringSection.iv_offset + l_centaurHwImageAddr, i_ringId, l_ddLevel, ppeType, ringVariant, instanceId, GET_SINGLE_RING, &l_rs4RingData, l_ringBufSizeInBytes, //compressed ring size here.. ringName, 0 ); if( rc != 0 ) { FAPI_ERR("get_ring() - call to tor_access_ring()" " call failed with rc = %d ",rc); if( rc != TOR_RING_NOT_FOUND ) { /*@ * @errortype * @moduleid fapi2::MOD_FAPI2_GET_RING * @reasoncode fapi2::RC_ACCESS_RING_FAILED * @userdata1 requested ring id * @userdata2 return code from tor_access_ring * @devdesc A call to the tor_access_ring function * failed. There could be an issue with the * centaur hardware image. See userdata2 for * the return code value. * * @custdesc Internal firmware error */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi2::MOD_FAPI2_GET_RING, fapi2::RC_ACCESS_RING_FAILED, i_ringId, rc, true /*SW error*/); l_err->collectTrace(FAPI_TRACE_NAME); l_fapi2Rc.setPlatDataPtr(reinterpret_cast(l_err)); } break; }; FAPI_INF("Found the ring:" \ " Name: %s" \ " Compressed size: %d bytes", ringName, l_ringBufSizeInBytes); CompressedScanData *rs4 = (CompressedScanData*)l_rs4RingData; RingId_t l_ringId = be16toh(rs4->iv_ringId); if( l_ringId == i_ringId ) { FAPI_DBG("get_ring() - its the correct ring...."); // reset to the buffer size, it was modified above // in the tor call l_ringBufSizeInBytes = MAX_CENTAUR_RING_SIZE; uint32_t l_ringSizeInBits = 0; // expand the ring rc = _rs4_decompress(o_ringData, care, l_ringBufSizeInBytes, &l_ringSizeInBits, rs4); if( rc != SCAN_COMPRESSION_OK ) { FAPI_ERR("get_ring() - call to _rs4_decompress()" " failed rc = %d",rc); /*@ * @errortype * @moduleid fapi2::MOD_FAPI2_GET_RING * @reasoncode fapi2::RC_FAILED_TO_DECOMPRESS_RING * @userdata1 return code from scan compression * @devdesc There was an error returned from the * RS4 decompression routine see userdata1 * for return code value. * @custdesc Internal firmware error */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi2::MOD_FAPI2_GET_RING, fapi2::RC_FAILED_TO_DECOMPRESS_RING, rc, 0, true /*SW error*/); l_err->collectTrace(FAPI_TRACE_NAME); l_fapi2Rc.setPlatDataPtr(reinterpret_cast(l_err)); break; } FAPI_DBG("get_ring() - call to _rs4_decompress() worked.." " ring size in bits %d",l_ringSizeInBits ); // return the ring lenght in bits o_ringLength = l_ringSizeInBits; // grab the address from the Generic ring id list GenRingIdList* l_idList; rc = ringid_get_ring_list(CT_CEN, l_ringId, &l_idList); if (rc != INFRASTRUCT_RC_SUCCESS) { FAPI_ERR("get_ring() - call to ringid_get_ring_list() " "failed w/rc=%d", rc); /*@ * @errortype * @moduleid fapi2::MOD_FAPI2_GET_RING * @reasoncode fapi2::RC_FAILED_TO_GET_RING_LIST * @userdata1 return code from ringid_get_ring_list * @devdesc There was an error returned from the * common ringid_get_ring_list API - see * userdata1 for return code value. * @custdesc Internal firmware error */ l_err = new ERRORLOG::ErrlEntry( ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi2::MOD_FAPI2_GET_RING, fapi2::RC_FAILED_TO_GET_RING_LIST, rc, 0, true /*SW error*/); l_err->collectTrace(FAPI_TRACE_NAME); l_fapi2Rc.setPlatDataPtr(reinterpret_cast(l_err)); break; } o_ringAddress = l_idList->scanScomAddress; } else { // didnt find the ring FAPI_INF("get_ring() - Ring not found, ringId = %d ",i_ringId); } } else { FAPI_INF("get_ring() - not a centaur hw image magic = 0x%llx ", ((P9XipHeader*)l_centaurHwImageAddr)->iv_magic); /*@ * @errortype * @moduleid fapi2::MOD_FAPI2_GET_RING * @reasoncode fapi2::RC_INCORRECT_HW_IMAGE_TYPE * @userdata1 expected HW image type * @userdata2 actual HW image type * @devdesc The magic header for the hw image is not * correct - expected value is "XIP CNTR" * @custdesc Internal firmware error */ l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, fapi2::MOD_FAPI2_GET_RING, fapi2::RC_INCORRECT_HW_IMAGE_TYPE, P9_XIP_MAGIC_CENTAUR, ((P9XipHeader*)l_centaurHwImageAddr)->iv_magic, true /*SW error*/); l_err->collectTrace(FAPI_TRACE_NAME); l_fapi2Rc.setPlatDataPtr(reinterpret_cast(l_err)); } }while(0); // free the compressed ring buffer and the care buffer, // caller will need to free the actual ring data buffer. free(l_rs4RingData); free(care); FAPI_INF("<< child? /// @return Return true if the types have physically parent <-> child /// relationship; false otherwise. /// bool isPhysParentChild(const TargetType i_parentType, const TargetType i_childType) { bool l_result = false; if (i_parentType == TARGET_TYPE_PROC_CHIP) { if ( (i_childType & (TARGET_TYPE_EX | TARGET_TYPE_MCS | TARGET_TYPE_XBUS | TARGET_TYPE_ABUS | TARGET_TYPE_CORE | TARGET_TYPE_EQ | TARGET_TYPE_MCA | TARGET_TYPE_MCBIST | TARGET_TYPE_MC | TARGET_TYPE_MCC | TARGET_TYPE_OMIC | TARGET_TYPE_OMI | TARGET_TYPE_MI | TARGET_TYPE_CAPP | TARGET_TYPE_DMI | TARGET_TYPE_OBUS | TARGET_TYPE_OBUS_BRICK | TARGET_TYPE_SBE | TARGET_TYPE_PPE | TARGET_TYPE_PERV | TARGET_TYPE_PEC)) != 0 ) { l_result = true; } } else if (i_parentType == TARGET_TYPE_MEMBUF_CHIP) { if ( (i_childType & (TARGET_TYPE_MBA | TARGET_TYPE_L4)) != 0 ) { l_result = true; } } else if (i_parentType == TARGET_TYPE_OCMB_CHIP) { if ( (i_childType & (TARGET_TYPE_MEM_PORT)) != 0 ) { l_result = true; } } return l_result; } /// /// @brief Processes any FFDC in the ReturnCode Error Information and adds them /// to the error log /// /// @param[i] i_errInfo Reference to ReturnCode Error Information /// @param[io] io_pError Errorlog Handle /// void processEIFfdcs(const ErrorInfo & i_errInfo, errlHndl_t io_pError) { // Iterate through the FFDC sections, adding each to the error log uint32_t l_size = 0; for (auto itr = i_errInfo.iv_ffdcs.begin(); itr != i_errInfo.iv_ffdcs.end(); ++itr) { const void * l_pFfdc = (*itr)->getData(l_size); uint32_t l_ffdcId = (*itr)->getFfdcId(); // Add the FFDC ID as the first word, then the FFDC data FAPI_DBG("processEIFfdcs: Adding %d bytes of FFDC (id:0x%08x)", l_size, l_ffdcId); ERRORLOG::ErrlUD * l_pUD = io_pError->addFFDC( HWPF_COMP_ID, &l_ffdcId, sizeof(l_ffdcId), 1, HWPF_FAPI2_UDT_HWP_FFDC); if (l_pUD) { io_pError->appendToFFDC(l_pUD, l_pFfdc, l_size); } } } /// /// @brief Processes any HW callouts requests in the ReturnCode Error /// Information and adds them to the error log /// /// @param[i] i_errInfo Reference to ReturnCode Error Information /// @param[io] io_pError Errorlog Handle /// void processEIHwCallouts(const ErrorInfo & i_errInfo, errlHndl_t io_pError) { // Iterate through the HW callout requests, adding each to the error log for (auto itr = i_errInfo.iv_hwCallouts.begin(); itr != i_errInfo.iv_hwCallouts.end(); ++itr) { HWAS::callOutPriority l_priority = xlateCalloutPriority((*itr)->iv_calloutPriority); HwCallouts::HwCallout l_hw = ((*itr)->iv_hw); TARGETING::Target * l_pRefTarget = reinterpret_cast((*itr)->iv_refTarget.get()); if ( ((l_hw == HwCallouts::TOD_CLOCK) || (l_hw == HwCallouts::MEM_REF_CLOCK) || (l_hw == HwCallouts::PROC_REF_CLOCK) || (l_hw == HwCallouts::PCI_REF_CLOCK)) && l_pRefTarget != NULL) { HWAS::clockTypeEnum l_clock = xlateClockHwCallout((*itr)->iv_hw); FAPI_ERR("processEIHwCallouts: Adding clock-callout" " (clock:%d, pri:%d)", l_clock, l_priority); // Force PCI clocks to be deconfigured and garded if( l_hw == HwCallouts::PCI_REF_CLOCK ) { io_pError->addClockCallout(l_pRefTarget, l_clock, l_priority, HWAS::DECONFIG, HWAS::GARD_Predictive); } else { io_pError->addClockCallout(l_pRefTarget, l_clock, l_priority); } } else if ( (l_hw == HwCallouts::FLASH_CONTROLLER_PART) || (l_hw == HwCallouts::PNOR_PART) || (l_hw == HwCallouts::SBE_SEEPROM_PART) || (l_hw == HwCallouts::VPD_PART) || (l_hw == HwCallouts::LPC_SLAVE_PART) || (l_hw == HwCallouts::GPIO_EXPANDER_PART) || (l_hw == HwCallouts::SPIVID_SLAVE_PART) ) { HWAS::partTypeEnum l_part = xlatePartHwCallout((*itr)->iv_hw); FAPI_ERR("processEIHwCallouts: Adding part-callout" " (part:%d, pri:%d)", l_part, l_priority); io_pError->addPartCallout(l_pRefTarget, l_part, l_priority); } else { FAPI_ERR("processEIHwCallouts: Unsupported HW callout (%d)", l_hw); io_pError->addPartCallout(l_pRefTarget, HWAS::NO_PART_TYPE, l_priority); io_pError->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE, l_priority); } } } /// /// @brief Processes any Procedure callouts requests in the ReturnCode Error /// Information and adds them to the error log /// /// @param[i] i_errInfo Reference to ReturnCode Error Information /// @param[io] io_pError Errorlog Handle /// void processEIProcCallouts(const ErrorInfo & i_errInfo, errlHndl_t io_pError) { // Iterate through the procedure callout requests, adding each to the error // log for (auto itr = i_errInfo.iv_procedureCallouts.begin(); itr != i_errInfo.iv_procedureCallouts.end(); ++itr) { HWAS::epubProcedureID l_procedure = xlateProcedureCallout((*itr)->iv_procedure); HWAS::callOutPriority l_priority = xlateCalloutPriority((*itr)->iv_calloutPriority); FAPI_DBG("processEIProcCallouts: Adding proc-callout" " (proc:0x%02x, pri:%d)", l_procedure, l_priority); io_pError->addProcedureCallout(l_procedure, l_priority); } } /// /// @brief Processes any Bus callouts requests in the ReturnCode Error /// Information and adds them to the error log /// /// @param[i] i_errInfo Reference to ReturnCode Error Information /// @param[io] io_pError Errorlog Handle /// void processEIBusCallouts(const ErrorInfo & i_errInfo, errlHndl_t io_pError) { // Iterate through the bus callout requests, adding each to the error log for (auto itr = i_errInfo.iv_busCallouts.begin(); itr != i_errInfo.iv_busCallouts.end(); ++itr) { TARGETING::Target * l_pTarget1 = reinterpret_cast((*itr)->iv_target1.get()); TARGETING::Target * l_pTarget2 = reinterpret_cast((*itr)->iv_target2.get()); HWAS::callOutPriority l_priority = xlateCalloutPriority((*itr)->iv_calloutPriority); bool l_busTypeValid = true; HWAS::busTypeEnum l_busType = HWAS::FSI_BUS_TYPE; TARGETING::TYPE l_type1 = l_pTarget1->getAttr(); TARGETING::TYPE l_type2 = l_pTarget2->getAttr(); if ( ((l_type1 == TARGETING::TYPE_MCS) && (l_type2 == TARGETING::TYPE_MEMBUF)) || ((l_type1 == TARGETING::TYPE_MEMBUF) && (l_type2 == TARGETING::TYPE_MCS)) ) { l_busType = HWAS::DMI_BUS_TYPE; } else if ( ((l_type1 == TARGETING::TYPE_DMI) && (l_type2 == TARGETING::TYPE_MEMBUF)) || ((l_type1 == TARGETING::TYPE_MEMBUF) && (l_type2 == TARGETING::TYPE_DMI)) ) { l_busType = HWAS::DMI_BUS_TYPE; } else if ((l_type1 == TARGETING::TYPE_ABUS) && (l_type2 == TARGETING::TYPE_ABUS)) { l_busType = HWAS::A_BUS_TYPE; } else if ((l_type1 == TARGETING::TYPE_XBUS) && (l_type2 == TARGETING::TYPE_XBUS)) { l_busType = HWAS::X_BUS_TYPE; } else if ((l_type1 == TARGETING::TYPE_OBUS) && (l_type2 == TARGETING::TYPE_OBUS)) { l_busType = HWAS::O_BUS_TYPE; } else if ( ((l_type1 == TARGETING::TYPE_OMI) && (l_type2 == TARGETING::TYPE_OCMB_CHIP)) || ((l_type1 == TARGETING::TYPE_OCMB_CHIP) && (l_type2 == TARGETING::TYPE_OMI)) ) { l_busType = HWAS::OMI_BUS_TYPE; } else { FAPI_ERR("processEIBusCallouts: Bus between target types not known (0x%08x:0x%08x)", l_type1, l_type2); l_busTypeValid = false; } if (l_busTypeValid) { FAPI_DBG("processEIBusCallouts: Adding bus-callout" " (bus:%d, pri:%d)", l_busType, l_priority); io_pError->addBusCallout(l_pTarget1, l_pTarget2, l_busType, l_priority); } } } /// /// @brief Processes any Callout/Deconfigure/GARD requests in the /// ReturnCode Error Information and adds them to the error log /// /// @param[i] i_errInfo Reference to ReturnCode Error Information /// @param[io] io_pError Errorlog Handle /// void processEICDGs(const ErrorInfo & i_errInfo, errlHndl_t io_pError) { // Iterate through the CGD requests, adding each to the error log for (auto itr = i_errInfo.iv_CDGs.begin(); itr != i_errInfo.iv_CDGs.end(); ++itr) { TARGETING::Target * l_pTarget = reinterpret_cast((*itr)->iv_target.get()); HWAS::callOutPriority l_priority = xlateCalloutPriority((*itr)->iv_calloutPriority); HWAS::DeconfigEnum l_deconfig = HWAS::NO_DECONFIG; if ((*itr)->iv_deconfigure) { l_deconfig = HWAS::DELAYED_DECONFIG; } HWAS::GARD_ErrorType l_gard = HWAS::GARD_NULL; if ((*itr)->iv_gard) { l_gard = HWAS::GARD_Unrecoverable; } FAPI_DBG("processEICDGs: Calling out target" " (huid:%.8x, pri:%d, deconf:%d, gard:%d)", TARGETING::get_huid(l_pTarget), l_priority, l_deconfig, l_gard); io_pError->addHwCallout(l_pTarget, l_priority, l_deconfig, l_gard); } } /// /// @brief Returns child targets to Callout/Deconfigure/GARD /// /// @param[i] i_parentTarget FAPI2 Parent Target /// @param[i] i_childType FAPI2 Child Type /// @param[i] i_childPort Child Port Number /// For DIMMs: MBA Port Number /// Else unused /// @param[i] i_childNum Child Number /// For DIMMs: DIMM Socket Number /// For Chips: Chip Position /// For Chiplets: Chiplet Position /// @param[o] o_childTargets List of child targets matching input /// criteria. /// void getChildTargetsForCDG( const fapi2::Target& i_parentTarget, const fapi2::TargetType i_childType, const uint8_t i_childPort, const uint8_t i_childNum, TARGETING::TargetHandleList & o_childTargets) { o_childTargets.clear(); do { // Get the parent TARGETING::Target TARGETING::Target * l_pTargParent = reinterpret_cast(i_parentTarget.get()); if (l_pTargParent == NULL) { FAPI_ERR("getChildTargetsForCDG: NULL Target pointer"); break; } // Find if the child target type is a dimm, chip or chiplet bool l_childIsDimm = false; bool l_childIsChip = false; bool l_childIsChiplet = false; if (i_childType == fapi2::TARGET_TYPE_DIMM) { l_childIsDimm = true; } else { l_childIsChip = fapi2::Target::isChip(i_childType); if (!l_childIsChip) { l_childIsChiplet = fapi2::Target:: isChiplet(i_childType); } } // Translate the FAPI child target type into TARGETING Class/Type TARGETING::CLASS l_targChildClass = TARGETING::CLASS_NA; TARGETING::TYPE l_targChildType = TARGETING::TYPE_NA; xlateTargetType(i_childType, l_targChildClass, l_targChildType); if (l_targChildType == TARGETING::TYPE_NA) { FAPI_ERR("getChildTargetsForCDG: Could not xlate child type (0x%08x)", i_childType); break; } // Get the child targets TARGETING::TargetHandleList l_targChildList; if ( isPhysParentChild(i_parentTarget.getType(), i_childType) ) { // Child by containment TARGETING::getChildChiplets(l_targChildList, l_pTargParent, l_targChildType); FAPI_ERR("getChildTargetsForCDG: Got %d candidate children by containment", l_targChildList.size()); } else { // Assumption is child by affinity TARGETING::getChildAffinityTargets(l_targChildList, l_pTargParent, l_targChildClass, l_targChildType); FAPI_ERR("getChildTargetsForCDG: Got %d candidate children by affinity", l_targChildList.size()); } // Filter out child targets based on type and input port/number for (TARGETING::TargetHandleList::const_iterator l_itr = l_targChildList.begin(); l_itr != l_targChildList.end(); ++l_itr) { if (l_childIsDimm) { // Match i_childPort and i_childNum if ( ((i_childPort == ErrorInfoChildrenCDG::ALL_CHILD_PORTS) || (i_childPort == (*l_itr)->getAttr())) && ((i_childNum == ErrorInfoChildrenCDG::ALL_CHILD_NUMBERS) || (i_childNum == (*l_itr)->getAttr())) ) { o_childTargets.push_back(*l_itr); } } else if (l_childIsChip) { // Match i_childNum if ((i_childNum == ErrorInfoChildrenCDG::ALL_CHILD_NUMBERS) || (i_childNum == (*l_itr)->getAttr())) { o_childTargets.push_back(*l_itr); } } else if (l_childIsChiplet) { // Match i_childNum if ((i_childNum == ErrorInfoChildrenCDG::ALL_CHILD_NUMBERS) || (i_childNum == (*l_itr)->getAttr())) { o_childTargets.push_back(*l_itr); } } else { // Do not match on anything o_childTargets.push_back(*l_itr); } } } while(0); } /// /// @brief Processes any Children Callout/Deconfigure/GARD requests in the /// ReturnCode Error Information and adds them to the error log /// /// @param[i] i_errInfo Reference to ReturnCode Error Information /// @param[io] io_pError Errorlog Handle /// void processEIChildrenCDGs(const ErrorInfo & i_errInfo, errlHndl_t io_pError) { // Iterate through the Child CGD requests, adding each to the error log for (auto itr = i_errInfo.iv_childrenCDGs.begin(); itr != i_errInfo.iv_childrenCDGs.end(); ++itr) { HWAS::callOutPriority l_priority = xlateCalloutPriority((*itr)->iv_calloutPriority); HWAS::DeconfigEnum l_deconfig = HWAS::NO_DECONFIG; if ((*itr)->iv_deconfigure) { l_deconfig = HWAS::DELAYED_DECONFIG; } HWAS::GARD_ErrorType l_gard = HWAS::GARD_NULL; if ((*itr)->iv_gard) { l_gard = HWAS::GARD_Unrecoverable; } // Get a list of children to callout TARGETING::TargetHandleList l_children; getChildTargetsForCDG((*itr)->iv_parent, (*itr)->iv_childType, (*itr)->iv_childPort, (*itr)->iv_childNumber, l_children); // Callout/Deconfigure/GARD each child as appropriate for (TARGETING::TargetHandleList::const_iterator itr = l_children.begin(); itr != l_children.end(); ++itr) { FAPI_DBG("processEIChildrenCDGs: Calling out target" " (huid:%.8x, pri:%d, deconf:%d, gard:%d)", TARGETING::get_huid(*itr), l_priority, l_deconfig, l_gard); io_pError->addHwCallout(*itr, l_priority, l_deconfig, l_gard); } } } /// /// @brief Converts a fapi2::ReturnCode to a HostBoot PLAT error log /// See doxygen in plat_utils.H /// errlHndl_t rcToErrl(ReturnCode & io_rc, ERRORLOG::errlSeverity_t i_sev) { errlHndl_t l_pError = NULL; FAPI_DBG("Entering rcToErrl"); if (io_rc) { uint32_t l_rcValue = io_rc; // ReturnCode contains an error. Find out which component of the HWPF // created the error ReturnCode::returnCodeCreator l_creator = io_rc.getCreator(); l_pError = reinterpret_cast(io_rc.getPlatDataPtr()); if (l_creator == ReturnCode::CREATOR_PLAT) { // PLAT error, get the platform data from the return code FAPI_ERR("rcToErrl: PLAT error: 0x%08x", l_rcValue); } else if (nullptr == l_pError) { if (l_creator == ReturnCode::CREATOR_HWP) { // HWP Error. Create an error log FAPI_ERR("rcToErrl: HWP error: 0x%08x", l_rcValue); /*@ * @errortype * @moduleid MOD_FAPI2_RC_TO_ERRL * @reasoncode RC_HWP_GENERATED_ERROR * @userdata1 RC value from HWP * @userdata2 * @devdesc HW Procedure generated error. See User Data. * @custdesc Error initializing processor/memory subsystem * during boot. See FRU list for repair actions */ l_pError = new ERRORLOG::ErrlEntry(i_sev, MOD_FAPI2_RC_TO_ERRL, RC_HWP_GENERATED_ERROR, l_rcValue); // Note - If location of RC value changes, must update // ErrlEntry::getFapiRC accordingly // Add the rcValue as FFDC. This will explain what the error was l_pError->addFFDC(HWPF_COMP_ID, &l_rcValue, sizeof(l_rcValue), 1, HWPF_FAPI2_UDT_HWP_RCVALUE); // Get the Error Information Pointer const ErrorInfo* l_pErrorInfo = io_rc.getErrorInfo(); if (l_pErrorInfo) { // There is error information associated with the ReturnCode processEIFfdcs(*l_pErrorInfo, l_pError); processEIProcCallouts(*l_pErrorInfo, l_pError); processEIBusCallouts(*l_pErrorInfo, l_pError); processEICDGs(*l_pErrorInfo, l_pError); processEIChildrenCDGs(*l_pErrorInfo, l_pError); processEIHwCallouts(*l_pErrorInfo, l_pError); } else { FAPI_ERR("rcToErrl: No Error Information"); } } else { // FAPI error. Create an error log FAPI_ERR("rcToErrl: FAPI error: 0x%08x", l_rcValue); // The errlog reason code is the HWPF compID and the rcValue LSB uint16_t l_reasonCode = l_rcValue; l_reasonCode &= 0xff; l_reasonCode |= HWPF_COMP_ID; // HostBoot errlog tags for FAPI errors are in hwpfReasonCodes.H l_pError = new ERRORLOG::ErrlEntry(i_sev, MOD_FAPI2_RC_TO_ERRL, l_reasonCode); // FAPI may have added Error Information. // Get the Error Information Pointer const ErrorInfo* l_pErrorInfo = io_rc.getErrorInfo(); if (l_pErrorInfo) { processEIFfdcs(*l_pErrorInfo, l_pError); processEIProcCallouts(*l_pErrorInfo, l_pError); processEIBusCallouts(*l_pErrorInfo, l_pError); processEICDGs(*l_pErrorInfo, l_pError); processEIChildrenCDGs(*l_pErrorInfo, l_pError); processEIHwCallouts(*l_pErrorInfo, l_pError); } } } // else if no elog yet // add the fapi traces to the elog l_pError->collectTrace(FAPI_TRACE_NAME, 256 ); l_pError->collectTrace(FAPI_IMP_TRACE_NAME, 384 ); l_pError->collectTrace(FAPI_SCAN_TRACE_NAME, 256 ); l_pError->collectTrace(FAPI_DBG_TRACE_NAME, 256 ); // Make sure the severity is set correctly for all errors. // The severity of PLAT errors is not set above, so set it here. l_pError->setSev(i_sev); } FAPI_DBG("Exiting rcToErrl"); return l_pError; } // Convert the RC passed in to a platform error log and // assign it to the platform data pointer of the RC void createPlatLog( fapi2::ReturnCode & io_rc, fapi2::errlSeverity_t i_sev ) { FAPI_DBG("Entering createLog"); errlHndl_t l_pError = NULL; // Convert a FAPI severity to a ERRORLOG severity ERRORLOG::errlSeverity_t l_sev = ERRORLOG::ERRL_SEV_UNRECOVERABLE; switch (i_sev) { case fapi2::FAPI2_ERRL_SEV_RECOVERED: l_sev = ERRORLOG::ERRL_SEV_RECOVERED; break; case fapi2::FAPI2_ERRL_SEV_PREDICTIVE: l_sev = ERRORLOG::ERRL_SEV_PREDICTIVE; break; case fapi2::FAPI2_ERRL_SEV_UNRECOVERABLE: // l_sev set above break; default: FAPI_ERR("severity (i_sev) of %d is unknown",i_sev); break; } // Convert the return code to an error log. // This will set the return code to FAPI2_RC_SUCCESS and clear any // PLAT Data, HWP FFDC data, and Error Target associated with it. l_pError = rcToErrl(io_rc, l_sev); io_rc.setPlatDataPtr(reinterpret_cast(l_pError)); } /// /// @brief Log an error - Create a platform error from the passed // RC passed in and commit it. /// void logError( fapi2::ReturnCode & io_rc, fapi2::errlSeverity_t i_sev, bool i_unitTestError ) { FAPI_INF("logError(rc=%x, sev=%d)", (uint32_t)io_rc, i_sev ); createPlatLog( io_rc, i_sev ); errlHndl_t l_pError = reinterpret_cast(io_rc.getPlatDataPtr()); // Commit the error log. This will delete the error log and set the handle // to NULL. if (i_unitTestError) { errlCommit(l_pError, CXXTEST_COMP_ID); } else { errlCommit(l_pError, HWPF_COMP_ID); } // error log is deleted so need to make sure nobody uses it again io_rc.forgetData(); //error is committed, no current error fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; return; } /// /// @brief Free platform log ptr - free a platform error from the /// passed in RC. /// void deletePlatformDataPointer(fapi2::ReturnCode & io_rc) { delete(reinterpret_cast(io_rc.getPlatDataPtr())); } /// /// @brief Internal Function associates PRD and HW elogs /// Used by log_related_error /// void set_log_id( const Target& i_fapiTrgt, fapi2::ReturnCode& io_rc, fapi2::errlSeverity_t i_sev ) { do { // Get TARGETING target. TARGETING::Target* attrTrgt = reinterpret_cast(i_fapiTrgt.get()); if ( nullptr == attrTrgt ) { FAPI_ERR( "[set_log_id] attrTrgt is null" ); break; } // Create an error log for this FAPI error. createPlatLog( io_rc, i_sev ); // Get the PLID from this error log. errlHndl_t errl = reinterpret_cast(io_rc.getPlatDataPtr()); uint32_t plid = ERRL_GETPLID_SAFE(errl); io_rc.setPlatDataPtr(reinterpret_cast(errl)); // Set the PLID in this attribute. if ( ! attrTrgt->trySetAttr(plid) ) { FAPI_ERR( "[set_log_id] failed to set ATTR_PRD_HWP_PLID on 0x%08x", TARGETING::get_huid(attrTrgt) ); break; } } while (0); } // end set_log_id /// /// @brief Associate an error to PRD PLID. /// Used to connect HW error log to the PRD log. /// void log_related_error( const Target& i_target, fapi2::ReturnCode& io_rc, const fapi2::errlSeverity_t i_sev, const bool i_unitTestError ) { // This call will associate the FAPI and PRD logs set_log_id( i_target, io_rc, i_sev ); // Commit the log logError( io_rc, i_sev, i_unitTestError ); } // end log_related_error /// /// @brief Delay this thread. Hostboot will use the nanoseconds parameter /// and make a syscall to nanosleep. While in the syscall, the hostboot /// kernel will continue to consume CPU cycles as it looks for a runnable /// task. When the delay time expires, the task becomes runnable and will soon /// return from the syscall. Callers of delay() in the hostboot environment /// will likely have to know the mHz clock speed they are running on and /// compute a non-zero value for i_nanoSeconds. /// ReturnCode delay(uint64_t i_nanoSeconds, uint64_t i_simCycles, bool i_fixed) { //Note: i_fixed is deliberately ignored // We don't need to waste time for hardware delays if we're running in Simics if( !Util::isSimicsRunning() ) { nanosleep( 0, i_nanoSeconds ); } return FAPI2_RC_SUCCESS; } /// /// @brief Assert a condition, and halt /// /// @param[in] a boolean representing the assertion /// void Assert(bool i_expression) { assert(i_expression); } bool platIsScanTraceEnabled() { // SCAN trace can be dynamically turned on/off, always return true here return 1; } //****************************************************************************** // platSpecialWakeup //****************************************************************************** fapi2::ReturnCode platSpecialWakeup(const Target& i_target, const bool i_enable) { fapi2::ReturnCode fapi_rc = fapi2::FAPI2_RC_SUCCESS; TARGETING::Target* l_target = reinterpret_cast(i_target.get()); FAPI_INF("platSpecialWakeup : HUID=%.8X, enable=%d", TARGETING::get_huid(l_target), i_enable); WAKEUP::HandleOptions_t l_option = WAKEUP::DISABLE; if( i_enable ) { l_option = WAKEUP::ENABLE; } errlHndl_t err_SW = WAKEUP::handleSpecialWakeup(l_target,l_option); if(err_SW) { fapi_rc.setPlatDataPtr(reinterpret_cast(err_SW)); } // On Hostboot, processor cores cannot sleep so return success to the // fapiSpecialWakeup enable/disable calls return fapi_rc; } /// /// @brief Resets all HWP thread_local variables /// void hwpResetGlobals(void) { // Reset all HWP thread_local vars fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; fapi2::opMode = fapi2::NORMAL; fapi2::setPIBErrorMask(0); } } //end namespace