/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/usr/diag/prdf/common/plat/p9/prdfP9PllDomain.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2016 */ /* [+] 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 prdfPllDomain.C * @brief Definition of PllDomain class */ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace TARGETING; namespace PRDF { using namespace PlatServices; //------------------------------------------------------------------------------ int32_t PllDomain::Initialize(void) { int32_t rc = SUCCESS; return(rc); } //------------------------------------------------------------------------------ bool PllDomain::Query(ATTENTION_TYPE attentionType) { bool atAttn = false; // System always checks for RE's first, even if there is an XSTOP // So we only need to check for PLL errors on RECOVERABLE type if(attentionType == RECOVERABLE) { // check sysdbug for attention first SYSTEM_DEBUG_CLASS sysdbug; for(unsigned int index = 0; (index < GetSize()) && (atAttn == false); ++index) { ExtensibleChip * l_chip = LookUp( index ); TARGETING::TargetHandle_t l_chipTgt = l_chip->getTrgt(); bool l_analysisPending = sysdbug.isActiveAttentionPending( l_chipTgt, RECOVERABLE ); if( l_analysisPending ) { ExtensibleChipFunction * l_query = l_chip->getExtensibleFunction("QueryPll"); int32_t rc = (*l_query)(l_chip,PluginDef::bindParm(atAttn)); // if rc then scom read failed - Error log has already been generated if( PRD_POWER_FAULT == rc ) { PRDF_ERR( "prdfPllDomain::Query() Power Fault detected!" ); break; } else if(SUCCESS != rc) { PRDF_ERR( "prdfPllDomain::Query() SCOM fail. RC=%x", rc ); } } } } return(atAttn); } //------------------------------------------------------------------------------ int32_t PllDomain::Analyze(STEP_CODE_DATA_STRUCT & serviceData, ATTENTION_TYPE attentionType) { #define PRDF_FUNC "[PllDomain::Analyze] " typedef ExtensibleChip * ChipPtr; CcAutoDeletePointerVector chip(new ChipPtr[GetSize()]()); int count = 0; int32_t rc = SUCCESS; // Due to clock issues some chips may be moved to non-functional during // analysis. In this case, these chips will need to be removed from their // domains. typedef std::vector NonFuncChips; NonFuncChips nfchips; // Count # of chips that had PLL error for(unsigned int index = 0; index < GetSize(); ++index) { ExtensibleChip * l_chip = LookUp(index); bool atAttn = false; ExtensibleChipFunction * l_query = l_chip->getExtensibleFunction("QueryPll"); rc |= (*l_query)(l_chip,PluginDef::bindParm(atAttn)); if ( atAttn ) { chip()[count] = LookUp(index); ++count; l_chip->CaptureErrorData( serviceData.service_data->GetCaptureData()); // Capture PllFIRs group l_chip->CaptureErrorData( serviceData.service_data->GetCaptureData(), Util::hashString("PllFIRs")); // Call this chip's capturePllFfdc plugin if it exists. ExtensibleChipFunction * l_captureFfdc = l_chip->getExtensibleFunction("capturePllFfdc", true); if ( NULL != l_captureFfdc ) { (*l_captureFfdc)( l_chip, PluginDef::bindParm(serviceData) ); } } else if ( !PlatServices::isFunctional(l_chip->getTrgt()) ) { // The chip is now non-functional. nfchips.push_back( l_chip ); } } // Remove all non-functional chips. for ( NonFuncChips::iterator i = nfchips.begin(); i != nfchips.end(); i++ ) { systemPtr->RemoveStoppedChips( (*i)->getTrgt() ); } // always suspect the clock source closeClockSource.Resolve(serviceData); if(&closeClockSource != &farClockSource) { farClockSource.Resolve(serviceData); } const uint32_t tmpCount = serviceData.service_data->getMruListSize(); // If only one detected the error, add it to the callout list. if ( 1 == count ) { // Call this chip's CalloutPll plugin if it exists. ExtensibleChipFunction * l_callout = chip()[0]->getExtensibleFunction( "CalloutPll", true ); if ( NULL != l_callout ) { (*l_callout)( chip()[0], PluginDef::bindParm(serviceData) ); } // If CalloutPll plugin does not add anything new to the callout // list, callout this chip if ( tmpCount == serviceData.service_data->getMruListSize() ) { // No additional callouts were made so add this chip to the list. serviceData.service_data->SetCallout( chip()[0]->getTrgt()); } } iv_threshold.Resolve(serviceData); // Test for threshold if(serviceData.service_data->IsAtThreshold()) { // Mask in all chips in domain ExtensibleDomainFunction * l_mask = getExtensibleFunction("MaskPll"); (*l_mask)(this, PluginDef::bindParm(serviceData)); } // Set Signature serviceData.service_data->GetErrorSignature()-> setChipId(chip()[0]->getHuid()); serviceData.service_data->SetErrorSig( PRDFSIG_PLL_ERROR ); #ifndef __HOSTBOOT_MODULE // Set dump flag dg09a serviceData.service_data->SetDump(iv_dumpContent,chip()[0]->getTrgt()); #endif // Clear PLLs from this domain. ExtensibleDomainFunction * l_clear = getExtensibleFunction("ClearPll"); (*l_clear)(this, PluginDef::bindParm(serviceData)); // Run any PLL Post Analysis functions from this domain. for(int i = 0; i < count; i++) { ExtensibleChip * l_chip = chip()[i]; // Send any special messages indicating there was a PLL error. ExtensibleChipFunction * l_pllPostAnalysis = l_chip->getExtensibleFunction("PllPostAnalysis", true); (*l_pllPostAnalysis)(l_chip, PluginDef::bindParm(serviceData)); } return rc; #undef PRDF_FUNC } //------------------------------------------------------------------------------ void PllDomain::Order(ATTENTION_TYPE attentionType) { // Order is not important for PLL errors } //------------------------------------------------------------------------------ int32_t PllDomain::ClearPll( ExtensibleDomain * i_domain, STEP_CODE_DATA_STRUCT & i_sc ) { PllDomain * l_domain = (PllDomain *) i_domain; const char * clearPllFuncName = "ClearPll"; // Clear children chips. for ( uint32_t i = 0; i < l_domain->GetSize(); i++ ) { ExtensibleChip * l_chip = l_domain->LookUp(i); ExtensibleChipFunction * l_clear = l_chip->getExtensibleFunction(clearPllFuncName); (*l_clear)( l_chip, PluginDef::bindParm(i_sc) ); } // Clear children domains. // This looks like a recursive call. It calls other domains of Clear. ParentDomain::iterator i; for (i = l_domain->getBeginIterator(); i != l_domain->getEndIterator(); i++) { // Clear PLLs from this domain. ExtensibleDomainFunction * l_clear = (i->second)->getExtensibleFunction("ClearPll"); (*l_clear)( i->second, PluginDef::bindParm(i_sc) ); } return SUCCESS; } PRDF_PLUGIN_DEFINE( PllDomain, ClearPll ); //------------------------------------------------------------------------------ int32_t PllDomain::MaskPll( ExtensibleDomain * i_domain, STEP_CODE_DATA_STRUCT & i_sc ) { PllDomain * l_domain = (PllDomain *) i_domain; // Mask children chips. for ( uint32_t i = 0; i < l_domain->GetSize(); i++ ) { ExtensibleChip * l_chip = l_domain->LookUp(i); ExtensibleChipFunction * l_mask = l_chip->getExtensibleFunction("MaskPll"); (*l_mask)( l_chip, PluginDef::bindParm(i_sc) ); } // Mask children domains. // This looks like a recursive call. It calls other domains of Mask. ParentDomain::iterator i; for (i = l_domain->getBeginIterator(); i != l_domain->getEndIterator(); i++) { ExtensibleDomainFunction * l_mask = (i->second)->getExtensibleFunction("MaskPll"); (*l_mask)( i->second, PluginDef::bindParm(i_sc) ); } return SUCCESS; } PRDF_PLUGIN_DEFINE( PllDomain, MaskPll ); //------------------------------------------------------------------------------ } // end namespace PRDF