diff options
Diffstat (limited to 'src/usr/isteps/istep18')
-rw-r--r-- | src/usr/isteps/istep18/TodAssert.H | 60 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodControls.C | 1371 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodControls.H | 637 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodDrawer.C | 200 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodDrawer.H | 254 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodHwpIntf.C | 220 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodHwpIntf.H | 120 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodProc.C | 548 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodProc.H | 410 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodSvc.C | 298 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodSvc.H | 196 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodSvcUtil.C | 270 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodSvcUtil.H | 163 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodTopologyManager.C | 619 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodTopologyManager.H | 171 | ||||
-rw-r--r-- | src/usr/isteps/istep18/TodTrace.H | 52 | ||||
-rwxr-xr-x | src/usr/isteps/istep18/TodTypes.H | 108 | ||||
-rw-r--r-- | src/usr/isteps/istep18/makefile | 72 | ||||
-rw-r--r-- | src/usr/isteps/istep18/tod_init.C | 89 | ||||
-rw-r--r-- | src/usr/isteps/istep18/tod_init.H | 34 |
20 files changed, 5892 insertions, 0 deletions
diff --git a/src/usr/isteps/istep18/TodAssert.H b/src/usr/isteps/istep18/TodAssert.H new file mode 100644 index 000000000..a3609f5a1 --- /dev/null +++ b/src/usr/isteps/istep18/TodAssert.H @@ -0,0 +1,60 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodAssert.H $ */ +/* */ +/* 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 */ +#ifndef TODASSERT_H +#define TODASSERT_H + +/** + * @file TodAssert.H + * + * There are two different assert types provided: + * Standard assert behavior: + * assert(foo) + * + * Standard assert behavior with a custom trace message: + * assert(foo, "This is a trace %d", 1234) + */ + +#include <assert.h> + +namespace TOD +{ + +/** + * @brief Forward common tod assert requests to platform specific handler + * + * @par Detailed Description: + * Forwards assert request to platform specific assert macro which verifies + * condition, calls custom trace if provided, and ultimately calls platform + * assert + * + * @param[in] expr,... + * Printf-like expression to act as the assert message + */ +#define TOD_ASSERT(expr,...) \ + assert(expr,__VA_ARGS__) + +} + +#endif diff --git a/src/usr/isteps/istep18/TodControls.C b/src/usr/isteps/istep18/TodControls.C new file mode 100755 index 000000000..20c87c13d --- /dev/null +++ b/src/usr/isteps/istep18/TodControls.C @@ -0,0 +1,1371 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodControls.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 TodControls.C + * + * @brief This file implements the methods declared in TodControls class + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <fapiPlatHwpInvoker.H> +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> +#include <targeting/common/utilFilter.H> +#include <p8_scom_addresses.H> +#include <tod_init/tod_init_reasoncodes.H> +#include "TodAssert.H" +#include "TodTrace.H" +#include "TodDrawer.H" +#include "TodProc.H" +#include "TodTypes.H" +#include "TodControls.H" +#include "TodSvcUtil.H" +#include "proc_tod_setup/proc_tod_setup.H" +#include <list> +#include <map> + +using namespace TARGETING; + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Static globals +//------------------------------------------------------------------------------ +//const static char DIR_PATH_SERERATOR = '/'; +//const static mode_t DIR_CREATION_MODE = 0777; +//const static char * FILE_WRITE_MODE = "w+"; +//const static char * FILE_READ_MODE = "r"; + +TodControls & TodControls::getTheInstance() +{ + return Singleton<TodControls>::instance(); +} + +//****************************************************************************** +//TodControls::TodControls +//****************************************************************************** +TodControls::TodControls() +{ + TOD_ENTER("TodControls constructor"); + TOD_EXIT("TodControls constructor"); +} + +//****************************************************************************** +//TodControls::~TodControls +//****************************************************************************** +TodControls::~TodControls() +{ + TOD_ENTER("TodControls destructor"); + + destroy(TOD_PRIMARY); + destroy(TOD_SECONDARY); + + TOD_EXIT("TodControls destructor"); +} + +//****************************************************************************** +//TodControls::pickMDMT +//****************************************************************************** +errlHndl_t TodControls::pickMdmt(const proc_tod_setup_tod_sel i_config) +{ + TOD_ENTER("pickMdmt"); + errlHndl_t l_errHdl=NULL; + + //MDMT is the master processor that drives TOD signals to all the remaining + //processors on the system, as such wherever possible algoritm will try to + //ensure that primary and secondary topology provides redundancy of MDMT. + + //Whenever there is an existing MDMT for the opposite configuration following + //considerations will go in deciding the MDMT for configuration passed + //through i_config + //1. MDMT will be chosen from a node other that the node on which other MDMDT + // belongs in multinode system + //2. In single node system MDMT will be chosen from a different fabric node + // (tod drawer ) + //3. Last a processor different from MDMT on the same fabric node will be + // chosen, if other options are not feasible + + do + { + proc_tod_setup_tod_sel l_oppConfig = (i_config == TOD_PRIMARY ) ? + TOD_SECONDARY : TOD_PRIMARY; + + TodProc * l_pTodProc = NULL; + TodProc * l_oppMdmt = iv_todConfig[l_oppConfig].iv_mdmt; + TodDrawerContainer l_todDrawerList; + l_todDrawerList = iv_todConfig[i_config].iv_todDrawerList; + + TodProc * l_lastProcWithMaxCores = NULL; + TodDrawer * l_lastMasterTodDrawer = NULL; + uint32_t l_lastMaxCoreCount = 0; + uint32_t l_coreCount=0; + uint32_t l_maxPossibleCoresPerProc = getMaxPossibleCoresPerProc(); + + if ( l_oppMdmt ) + { + //1.Try to find MDMT on a TOD drawer that is not on the same + // physical node as opposite MDMT + + //Iterate the list of TOD drawers + for (TodDrawerContainer::iterator l_todDrawerIter = + l_todDrawerList.begin(); + l_todDrawerIter != l_todDrawerList.end() ; + ++l_todDrawerIter) + { + //TodProc --> TodDrawer --> Node + if ( l_oppMdmt->getParentDrawer()->getParentNodeTarget()-> + getAttr<ATTR_HUID>() + != + (*l_todDrawerIter)->getParentNodeTarget()-> + getAttr<ATTR_HUID>()) + { + l_pTodProc = NULL; + l_coreCount = 0; + (*l_todDrawerIter)-> + getProcWithMaxCores(NULL,l_pTodProc,l_coreCount); + if ( l_pTodProc ) + { + TOD_INF("returned core count = %d ",l_coreCount); + if ( l_coreCount > l_lastMaxCoreCount) + { + l_lastProcWithMaxCores = l_pTodProc; + l_lastMaxCoreCount = l_coreCount; + l_lastMasterTodDrawer = (*l_todDrawerIter); + if (l_lastMaxCoreCount == l_maxPossibleCoresPerProc) + { + break; + } + } + } + + } + } + + if ( l_lastProcWithMaxCores ) + { + l_lastMasterTodDrawer->setMasterDrawer(true); + iv_todConfig[i_config].iv_mdmt = l_lastProcWithMaxCores; + l_lastProcWithMaxCores->setMasterType(TodProc::TOD_MASTER); + break; + } + + //2.Try to find MDMT on a TOD drawer that is on the same physical + // node as the possible opposite MDMT but on different TOD drawer + for (TodDrawerContainer::iterator l_todDrawerIter = + l_todDrawerList.begin(); + l_todDrawerIter != l_todDrawerList.end() ; + ++l_todDrawerIter) + { + if ( (l_oppMdmt->getParentDrawer()->getParentNodeTarget()-> + getAttr<ATTR_HUID>() + == + (*l_todDrawerIter)->getParentNodeTarget()-> + getAttr<ATTR_HUID>()) + //Same node as opposite MDMT + && + (l_oppMdmt->getParentDrawer()->getId() + != + (*l_todDrawerIter)->getId()))//Different Drawer + { + l_pTodProc = NULL; + l_coreCount = 0; + (*l_todDrawerIter)-> + getProcWithMaxCores(NULL,l_pTodProc,l_coreCount); + if ( l_pTodProc ) + { + if ( l_coreCount > l_lastMaxCoreCount) + { + l_lastProcWithMaxCores = l_pTodProc; + l_lastMaxCoreCount = l_coreCount; + l_lastMasterTodDrawer = (*l_todDrawerIter); + if (l_lastMaxCoreCount == l_maxPossibleCoresPerProc) + { + break; + } + } + + } + + } + } + + if ( l_lastProcWithMaxCores ) + { + l_lastMasterTodDrawer->setMasterDrawer(true); + iv_todConfig[i_config].iv_mdmt = l_lastProcWithMaxCores; + l_lastProcWithMaxCores->setMasterType(TodProc::TOD_MASTER); + break; + } + + //3.Try to find MDMT on the same TOD drawer as the TOD Drawer of + // opposite MDMT + for (TodDrawerContainer::iterator l_todDrawerIter = + l_todDrawerList.begin(); + l_todDrawerIter != l_todDrawerList.end() ; + ++l_todDrawerIter) + { + l_coreCount = 0; + if ( l_oppMdmt->getParentDrawer()->getId() == + (*l_todDrawerIter)->getId() ) + { + //This is the TOD drawer on which opposite MDMT exists, + //try to avoid processor chip of opposite MDMT while + //getting the proc with max cores + (*l_todDrawerIter)->getProcWithMaxCores( + iv_todConfig[l_oppConfig].iv_mdmt,l_pTodProc + ,l_coreCount); + if ( l_pTodProc ) + { + iv_todConfig[i_config].iv_mdmt = l_pTodProc; + (*l_todDrawerIter)->setMasterDrawer(true); + l_pTodProc->setMasterType(TodProc::TOD_MASTER); + break; + } + } + } + + if ( iv_todConfig[i_config].iv_mdmt ) + { + break; + } + + //If we reach here only option left is MDMT on the other config so + //select it. So we look for a proc in this config's set of TOD + //drawers, find the one which is same as the MDMT on the other + //config (based on the HUID). + bool l_mdmtFound = false; + for(TodDrawerContainer::iterator l_drwItr = + iv_todConfig[i_config].iv_todDrawerList.begin(); + l_drwItr != iv_todConfig[i_config].iv_todDrawerList.end(); + ++l_drwItr) + { + const TodProcContainer& l_procs = (*l_drwItr)->getProcs(); + for(TodProcContainer::const_iterator + l_procItr = l_procs.begin(); + l_procItr != l_procs.end(); + ++l_procItr) + { + if( (*l_procItr)->getTarget()->getAttr<ATTR_HUID>() + == + (iv_todConfig[l_oppConfig].iv_mdmt)-> + getTarget()->getAttr<ATTR_HUID>() ) + { + iv_todConfig[i_config].iv_mdmt = (*l_procItr); + (*l_procItr)->setMasterType(TodProc::TOD_MASTER); + (*l_drwItr)->setMasterDrawer(true); + l_mdmtFound = true; + break; + } + } + + if(l_mdmtFound) + { + break; + } + } + + if(l_mdmtFound) + { + break; + } + } + else + { //There is no MDMT configured for the other topology hence select + //the MDMT from any TOD drawer + for (TodDrawerContainer::iterator l_todDrawerIter = + l_todDrawerList.begin(); + l_todDrawerIter != l_todDrawerList.end() ; + ++l_todDrawerIter) + { + l_pTodProc = NULL; + l_coreCount = 0; + (*l_todDrawerIter)->getProcWithMaxCores( + NULL,l_pTodProc,l_coreCount); + if ( l_pTodProc ) + { + if ( l_coreCount > l_lastMaxCoreCount) + { + l_lastProcWithMaxCores = l_pTodProc; + l_lastMaxCoreCount = l_coreCount; + l_lastMasterTodDrawer = (*l_todDrawerIter); + if (l_lastMaxCoreCount == l_maxPossibleCoresPerProc) + { + break; + } + } + } + } + + if ( l_lastProcWithMaxCores ) + { + l_lastMasterTodDrawer->setMasterDrawer(true); + iv_todConfig[i_config].iv_mdmt = l_lastProcWithMaxCores; + l_lastProcWithMaxCores->setMasterType(TodProc::TOD_MASTER); + break; + } + } + + if ( !iv_todConfig[i_config].iv_mdmt ) + { + TOD_ERR("MDMT NOT FOUND for configuration 0x%02X",i_config); + + /*@ + * @errortype + * @reasoncode TOD_NO_MASTER_PROC + * @moduleid TOD_PICK_MDMT + * @userdata1 TOD configuration type + * @devdesc MDMT could not be found for the supplied topology + * type + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_PICK_MDMT, + TOD_NO_MASTER_PROC, + i_config); + } + + }while(0); + + if ( iv_todConfig[i_config].iv_mdmt ) + { + TOD_INF("MDMT for configuration %d , is proc " + "0%08X", i_config, iv_todConfig[i_config].iv_mdmt-> + getTarget()->getAttr<ATTR_HUID>()); + } + TOD_EXIT("pickMdmt. errHdl = %p", l_errHdl); + return l_errHdl; + +} + +//****************************************************************************** +//TodControls::buildTodDrawers +//****************************************************************************** +errlHndl_t TodControls::buildTodDrawers( + const proc_tod_setup_tod_sel i_config) +{ + TOD_ENTER("buildTodDrawers"); + errlHndl_t l_errHdl = NULL; + + do{ + + TARGETING::TargetHandleList l_funcNodeTargetList; + + //Get the system pointer + TARGETING::Target* l_pSysTarget = NULL; + (void)TARGETING::targetService().getTopLevelTarget(l_pSysTarget); + + //We should not be reaching here without a valid system target + TOD_ASSERT(l_pSysTarget,"NULL system target "); + + //Build the list of functional nodes + l_errHdl = getFuncNodeTargetsOnSystem( l_pSysTarget, + l_funcNodeTargetList); + if ( l_errHdl ) + { + TOD_ERR("For System target 0x%08X getFuncNodeTargetsOnSystem " + "returned error ",l_pSysTarget->getAttr<ATTR_HUID>()); + break; + } + + //If there was no functional node found then we must return + if ( l_funcNodeTargetList.empty() ) + { + TOD_ERR("For System target 0x%08X no functional node found ", + l_pSysTarget->getAttr<TARGETING::ATTR_HUID>()); + /*@ + * @errortype + * @reasoncode TOD_NO_FUNC_NODE_AVAILABLE + * @moduleid TOD_BUILD_TOD_DRAWERS + * @userdata1 system target's HUID + * @devdesc MDMT could not find a functional node + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_BUILD_TOD_DRAWERS, + TOD_NO_FUNC_NODE_AVAILABLE, + l_pSysTarget->getAttr<ATTR_HUID>()); + break; + } + + //For each node target find the prcessor chip on it + TARGETING::TargetHandleList l_funcProcTargetList; + + TARGETING::PredicateCTM + l_procCTM(TARGETING::CLASS_CHIP,TARGETING::TYPE_PROC); + + TARGETING::PredicateHwas l_funcPred; + l_funcPred.functional(true); + TARGETING::PredicatePostfixExpr l_funcProcPostfixExpr; + l_funcProcPostfixExpr.push(&l_procCTM).push(&l_funcPred).And(); + + TodDrawerContainer& l_todDrawerList = + iv_todConfig[i_config].iv_todDrawerList; + TodDrawerContainer::iterator l_todDrawerIter; + bool b_foundDrawer = false; + + for( uint32_t l_nodeIndex = 0; + l_nodeIndex < l_funcNodeTargetList.size(); + ++l_nodeIndex ) + { + l_funcProcTargetList.clear(); + + //Find the funcational Proc targets on the system + TARGETING::targetService().getAssociated(l_funcProcTargetList, + l_funcNodeTargetList[l_nodeIndex], + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_funcProcPostfixExpr); + + //Go over the list of procs and insert them in respective fabric + //node list ( TOD drawer ) + for ( uint32_t l_procIndex =0 ; + l_procIndex < l_funcProcTargetList.size(); + ++l_procIndex ) + { + b_foundDrawer = false; + //Traverse over the fabric node list (TOD drawer) and find if + //there is an existing fabric node for this proc + + for ( l_todDrawerIter = l_todDrawerList.begin() ; + l_todDrawerIter != l_todDrawerList.end() ; + ++l_todDrawerIter) + { + if ( (*l_todDrawerIter)->getId() == + l_funcProcTargetList[l_procIndex]-> + getAttr<ATTR_FABRIC_NODE_ID>()) + { + //Add the proc to this fabric node, such that + //TodProc has the target pointer and the pointer to + //the TOD drawer to which it belongs + TodProc *l_procPtr = + new TodProc + (l_funcProcTargetList[l_procIndex], + (*l_todDrawerIter)); + (*l_todDrawerIter)->addProc(l_procPtr); + l_procPtr = NULL; //Nullifying the pointer after + //transferring ownership + + b_foundDrawer = true; + break; + } + + } // end drawer list loop + + if (!b_foundDrawer ) + { + //Create a new TOD drawer and add it to the TOD drawer list + //Create a TOD drawer with the fabric node id and the + //pointer to the node to which this fabric node belongs + TodDrawer *l_pTodDrawer = new + TodDrawer(l_funcProcTargetList[l_procIndex]-> + getAttr<ATTR_FABRIC_NODE_ID>(), + l_funcNodeTargetList[l_nodeIndex]); + + //Create a TodProc passing the target pointer and the + //pointer of TodDrawer to which this processor belongs + TodProc *l_pTodProc = new + TodProc(l_funcProcTargetList[l_procIndex], + l_pTodDrawer); + + //push the processor ( TodProc ) , into the TOD drawer + l_pTodDrawer->addProc(l_pTodProc); + + //push the Tod drawer ( TodDrawer ) , into the + //TodControls + l_todDrawerList.push_back(l_pTodDrawer); + //Nullify the pointers after transfering the ownership + l_pTodDrawer = NULL; + l_pTodProc = NULL; + + } + + }// end proc list loop + + } // end node list loop + + //Validate that we had atlease one TOD drawer at the end of this process + //else generate an error + if (iv_todConfig[i_config].iv_todDrawerList.empty()) + { + TOD_ERR("No TOD drawer could be built for the configuration " + " %s ", (i_config == TOD_PRIMARY ? "Primary " : + "Secondary") ); + /*@ + * @errortype + * @reasoncode TOD_NO_DRAWERS + * @moduleid TOD_BUILD_TOD_DRAWERS + * @userdata1 TOD configuration + * @devdesc No TOD drawer could be configured for this topology + * type + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_BUILD_TOD_DRAWERS, + TOD_NO_DRAWERS, + i_config); + } + + }while(0); + TOD_EXIT("buildTodDrawers. errHdl = %p", l_errHdl); + return l_errHdl; +} + +//****************************************************************************** +//TodControls::getTodConfigState +//****************************************************************************** +errlHndl_t TodControls::getTodConfigState( + TOD_CONFIG_STATE& o_configState, + proc_tod_setup_tod_sel& o_activeConfig, + bool& o_isTodRunning)const +{ + TOD_ENTER("getTodConfigState"); + errlHndl_t l_errHdl = NULL; + o_configState = TOD_UNCHANGED; + o_activeConfig = TOD_PRIMARY; + o_isTodRunning = false; + + do + { + //Get the currently active TOD configuration + l_errHdl = queryActiveConfig (o_activeConfig,o_isTodRunning); + if ( l_errHdl ) + { + TOD_ERR("Call to queryActiveConfig failed "); + break; + } + //Need to read the TodSystemFile to decide if HW configuration has + //changed since the last time TOD was configured + std::vector<TodChipData> l_todChipDataVector; + l_errHdl = TodControls::readTodProcDataFromFile(l_todChipDataVector); + if ( l_errHdl ) //Indicates hard failure not limited to failure of tod + //logic only, we cannot continue with flow + { + TOD_ERR("Failed loading TodChipData from TodSystemFile"); + break; + } + + //Determine if the TOD HW has changed since the last time topology was + //created + //1) File data is valid but HW has changed => Report TOD_MODIFIED + //2) File data is valid and HW has not changed => Report TOD_UNCHANGED + //3) Authenticity of file data is in question => Report + //TOD_UNKNOWN + + //Check if TodSystemFile has topology data for atleast one node + if ( hasNoValidData ( l_todChipDataVector )) + { + TOD_INF("No valid data found in the file TodSystemFile"); + o_configState = TOD_UNKNOWN; + break; + } + + //For each functional processor present in the system, if we + //have, old configuration data in the TodSystemConfig file then + //validate it. + + //Get the processors present in the system + TARGETING::PredicateCTM + l_procFilter(TARGETING::CLASS_CHIP,TARGETING::TYPE_PROC, + TARGETING::MODEL_NA); + + TARGETING::PredicateHwas l_presencePredicate; + l_presencePredicate.present(true); + + TARGETING::PredicatePostfixExpr l_presenceAndProcChipFilter; + l_presenceAndProcChipFilter.push(&l_procFilter). + push(&l_presencePredicate).And(); + + TARGETING::TargetRangeFilter l_filter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_presenceAndProcChipFilter); + + bool l_state = false; //Variable for keeping functional state of + //the processor + uint32_t l_ordinalId = TOD_INVALID_UNITID; + //Initializing to some value not expected to be ordinal id + + ecmdDataBufferBase l_chipCtrlRegBuf(64); + + //Initialize l_chipCtrlRegBuf it will be used later + + FAPI_INVOKE_HWP(l_errHdl, init_chip_ctrl_reg, l_chipCtrlRegBuf); + if ( l_errHdl ) + { + TOD_ERR("init_chip_ctrl_reg returned error "); + break; + } + + for ( ; l_filter ; ++l_filter ) + { + l_state = false; + if ((*l_filter)->getAttr<ATTR_HWAS_STATE>().functional) + { + l_state = true; + } + + // use position attribute on one drawer only machine + l_ordinalId=(*l_filter)->getAttr<ATTR_POSITION>(); + + if ( l_state ) //Functional processor + { + //Check if TodSystemData file also indicates the processor as + //functional + + //Indexing into l_todChipDataVector is safe as size of vector is + //always determined by the maximum possible processors for this + //system type + if(((l_todChipDataVector[l_ordinalId].header.flags) & + TOD_FUNC) != 0 ) + { + + //File data says that the chip is functional do some more + //validation on the data + + //Check if the chip control register (0x40010) data is valid + //This data does not depend on topology, so it should tally + if ( (l_todChipDataVector[l_ordinalId].regs.ccr) != + l_chipCtrlRegBuf.getWord(0) ) + { + TOD_INF("Chip control register read from TodSystemData" + "is not valid for the processor 0x%08X", + (*l_filter)->getAttr<TARGETING::ATTR_HUID>()); + //We do not have a valid data no need to continue + //further + o_configState = TOD_UNKNOWN; + break; + } + } + else + { + //New hardware has been added + TOD_INF("New processor detected 0x%08X", + (*l_filter)->getAttr<ATTR_HUID>()); + o_configState = TOD_MODIFIED; + } + + } + else + { + //Check if this chip was functional earlier + if ( ((l_todChipDataVector[l_ordinalId].header.flags) & + TOD_FUNC) != 0 ) + { + //HW has been removed + o_configState = TOD_MODIFIED; + TOD_INF("Processor 0x%08X is no more available ", + (*l_filter)->getAttr<ATTR_HUID>()); + } + } + } + + }while(0); + + TOD_EXIT(" config state = %d, active config = %d, TOD HW State = " + "%d errHdl = %p", + o_configState, o_activeConfig , o_isTodRunning, l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodControls::isTodRunning +//****************************************************************************** +errlHndl_t TodControls::isTodRunning(bool& o_isTodRunning)const +{ + TOD_ENTER("isTodRunning"); + errlHndl_t l_errHdl = NULL; + TARGETING::Target* l_primaryMdmt=NULL; + TARGETING::Target* l_secondaryMdmt=NULL; + o_isTodRunning = false; + + do + { + //Read the TOD HW to get the configured MDMT + l_errHdl = getConfiguredMdmt(l_primaryMdmt,l_secondaryMdmt); + if ( l_errHdl ) + { + TOD_ERR("Failed getting configured MDMTs" ); + break; + } + + if ( l_primaryMdmt || l_secondaryMdmt ) //If there is atleast one MDMT + //configured , check the chipTOD HW status by reading the TOD + //status register TOD_PSS_MSS_STATUS_REG_00040008 + { + ecmdDataBufferBase l_primaryMdmtBuf(64); + ecmdDataBufferBase l_secondaryMdmtBuf(64); + + if ( l_primaryMdmt ) + { + l_errHdl = todGetScom(l_primaryMdmt, + TOD_PSS_MSS_STATUS_REG_00040008, + l_primaryMdmtBuf); + if ( l_errHdl ) + { + TOD_ERR("Scom failed for status register " + "TOD_PSS_MSS_STATUS_REG_00040008 on primary MDMT"); + break; + } + } + + if ( l_secondaryMdmt ) + { + l_errHdl = todGetScom(l_secondaryMdmt, + TOD_PSS_MSS_STATUS_REG_00040008, + l_secondaryMdmtBuf); + if ( l_errHdl ) + { + TOD_ERR("Scom failed for status register " + "TOD_PSS_MSS_STATUS_REG_00040008 on secondary MDMT"); + break; + } + } + + //If all the bits of TOD_PSS_MSS_STATUS_REG_00040008 are off then + //ChipTOD HW is not running + if ((l_primaryMdmtBuf.getWord(0) == 0 ) && + (l_secondaryMdmtBuf.getWord(0)== 0)) + { + break; + } + + o_isTodRunning = true; + } + + }while(0); + + TOD_EXIT("TOD HW State = %d errHdl = %p",o_isTodRunning, l_errHdl); + return l_errHdl; +} + +//****************************************************************************** +//TodControls::queryActiveConfig +//****************************************************************************** +errlHndl_t TodControls::queryActiveConfig( + proc_tod_setup_tod_sel& o_activeConfig, + bool& o_isTodRunning)const +{ + TOD_ENTER("queryActiveConfig"); + errlHndl_t l_errHdl = NULL; + TARGETING::Target* l_primaryMdmt=NULL; + TARGETING::Target* l_secondaryMdmt=NULL; + + o_isTodRunning = false; + o_activeConfig = TOD_PRIMARY; + + do + { + //Read the configured Mdmt from TOD HW + l_errHdl = getConfiguredMdmt(l_primaryMdmt,l_secondaryMdmt); + if ( l_errHdl ) + { + TOD_ERR("Failed to get configured MDMTs" ); + break; + } + + if ( l_primaryMdmt || l_secondaryMdmt ) //If there is atleast one MDMT + //configured,` check the ChipTOD HW status by reading the TOD + //status register TOD_PSS_MSS_STATUS_REG_00040008 + { + ecmdDataBufferBase l_primaryMdmtBuf(64); + ecmdDataBufferBase l_secondaryMdmtBuf(64); + + if ( l_primaryMdmt ) + { + l_errHdl = todGetScom(l_primaryMdmt, + TOD_PSS_MSS_STATUS_REG_00040008, + l_primaryMdmtBuf); + if ( l_errHdl ) + { + TOD_ERR("Scom failed for status register " + "TOD_PSS_MSS_STATUS_REG_00040008 on primary MDMT"); + break; + } + } + + if ( l_secondaryMdmt ) + { + l_errHdl = todGetScom(l_secondaryMdmt, + TOD_PSS_MSS_STATUS_REG_00040008, + l_secondaryMdmtBuf); + if ( l_errHdl ) + { + TOD_ERR("Scom failed for status register " + "TOD_PSS_MSS_STATUS_REG_00040008 secondary MDMT "); + break; + } + } + + //If all the bits of TOD_PSS_MSS_STATUS_REG_00040008 are off then + //ChipTOD HW is not running + if ((l_primaryMdmtBuf.getWord(0) == 0 ) && + (l_secondaryMdmtBuf.getWord(0)== 0)) + { + break; + } + + o_isTodRunning = true; + + //First 3 bits of TOD_PSS_MSS_STATUS_REG_00040008 indicates + //active TOD topology + // [0:2] == '111' secondary, '000' is primary - just check bit 0 + + //Putting the below check because of past TOD HW error. + //Both primary and secondary MDMT would claim that it is the active + //one,this happened during CHARM operation after failover from + //primary to econdary + //May be that error does not exists in P8 HW but in case it still + //exists we will be able to catch it + if ( l_primaryMdmt && l_secondaryMdmt ) + { + if ( + l_primaryMdmtBuf.isBitSet + (TOD_PSS_MSS_STATUS_REG_00040008_ACTIVE_BIT) + != + l_secondaryMdmtBuf.isBitSet + (TOD_PSS_MSS_STATUS_REG_00040008_ACTIVE_BIT) + ) + { + TOD_ERR("TOD HW error, primary and secondary MDMT do not" + "agree on bits 0 of TOD status register 0x40008"); + /*@ + * @errortype + * @reasoncode TOD_HW_ERROR + * @moduleid TOD_QUERY_ACTIVE_CONFIG + * @userdata1 Status register bits of primary MDMT + * @userdata2 Status register bits of secondary MDMT + * @devdesc Error: primary and secondary MDMT do not + * agree on bits 0 of TOD status register + * 0x40008 + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_QUERY_ACTIVE_CONFIG, + TOD_HW_ERROR, + l_primaryMdmtBuf.getWord(0), + l_secondaryMdmtBuf.getWord(0) ); + break; + } + } + + if(l_primaryMdmtBuf.isBitSet + (TOD_PSS_MSS_STATUS_REG_00040008_ACTIVE_BIT)) + { + TOD_INF("Primary MDMT says secondary is configured "); + o_activeConfig = TOD_SECONDARY; + // If the primary says the secondary is active then what the + // secondary MDMT says is not important - no more checking + // required. + break; + } + + //The secondaryMDMT only needs to be checked if the primaryMDMT + //said it is active ( i.e. bit 0 is clear ) + + //If the secondary says the secondary is active then primary was + //not found + if ( l_secondaryMdmtBuf.isBitSet + (TOD_PSS_MSS_STATUS_REG_00040008_ACTIVE_BIT)) + { + TOD_INF("Secondary MDMT says secondary is configured "); + o_activeConfig = TOD_SECONDARY; + break; + } + } + //Else not yet initialized, just return primary + + }while(0); + + TOD_EXIT("queryActiveConfig. errHdl = %p", l_errHdl); + return l_errHdl; +} + +//****************************************************************************** +//TodControls::getConfiguredMdmt +//****************************************************************************** +errlHndl_t TodControls::getConfiguredMdmt( + TARGETING::Target*& o_primaryMdmt, + TARGETING::Target*& o_secondaryMdmt) const +{ + TOD_ENTER("getConfiguredMdmt"); + errlHndl_t l_errHdl = NULL; + o_primaryMdmt = NULL; + o_secondaryMdmt = NULL; + + do + { + //Find MDMT for primary and secondary topology from HW + + //Get the functional procs on the system + TARGETING::PredicateCTM + l_procFilter(TARGETING::CLASS_CHIP,TARGETING::TYPE_PROC, + TARGETING::MODEL_NA); + + TARGETING::PredicateHwas l_funcPred; + l_funcPred.functional(true); + + TARGETING::PredicatePostfixExpr l_stateAndProcChipFilter; + l_stateAndProcChipFilter.push(&l_procFilter). + push(&l_funcPred).And(); + + TARGETING::TargetHandleList l_procTargetList; + + ecmdDataBufferBase l_todCtrlReg(64); + + //TOD_PSS_MSS_CTRL_REG_00040007 + + TARGETING::TargetRangeFilter l_filter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_stateAndProcChipFilter); + + //Read the TOD control register TOD_PSS_MSS_CTRL_REG_00040007 for each + //processor and check for bits 1 and 9 + for ( ; l_filter; ++l_filter ) + { + l_errHdl = todGetScom(*l_filter, + TOD_PSS_MSS_CTRL_REG_00040007, + l_todCtrlReg); + + if ( l_errHdl ) + { + TOD_ERR("Scom failed for target 0x%08X on register" + "TOD_PSS_MSS_CTRL_REG_00040007 ", + (*l_filter)->getAttr<ATTR_HUID>()); + break; + } + + if ( + l_todCtrlReg.isBitSet + (TOD_PSS_MSS_CTRL_REG_00040007_PRIMARY_MDMT_BIT) )//primary MDMT + { + o_primaryMdmt = *l_filter; + TOD_INF("found primary MDMT HUID = 0x%08X", + o_primaryMdmt->getAttr<ATTR_HUID>()); + } + + if ( + l_todCtrlReg.isBitSet + (TOD_PSS_MSS_CTRL_REG_00040007_SECONDARY_MDMT_BIT) ) + //secondary MDMT + { + o_secondaryMdmt = *l_filter; + TOD_INF("found secondary MDMT HUID = 0x%08X", + o_secondaryMdmt->getAttr<ATTR_HUID>()); + } + + if ( o_primaryMdmt && o_secondaryMdmt ) + { + break; + } + } + + }while(0); + + TOD_EXIT("getConfiguredMdmt. errHdl = %p", l_errHdl); + return l_errHdl; +} + +//****************************************************************************** +//TodControls::destroy +//****************************************************************************** +void TodControls::destroy(const proc_tod_setup_tod_sel i_config) +{ + TOD_ENTER("destroy"); + + for(TodDrawerContainer::iterator l_itr = + iv_todConfig[i_config].iv_todDrawerList.begin(); + l_itr != iv_todConfig[i_config].iv_todDrawerList.end(); + ++l_itr) + { + if(*l_itr) + { + delete (*l_itr); + } + } + iv_todConfig[i_config].iv_todDrawerList.clear(); + iv_todConfig[i_config].iv_mdmt = NULL; + iv_todConfig[i_config].iv_isConfigured = false; + + TOD_EXIT("destroy"); +} + +//****************************************************************************** +//TodControls::writeTodProcData +//****************************************************************************** +errlHndl_t TodControls::writeTodProcData( + const proc_tod_setup_tod_sel i_config) +{ + TOD_ENTER("writeTodProcData"); + errlHndl_t l_errHdl = NULL; + + do + { + //As per the requirement specified by PHYP/HDAT, HB needs to fill + //data for every chip that can be installed on the system. + //It is also required that chip ID match the index of the entry in the + //array so we can possibly have valid chip data at different indexes in + //the array and the intermittent locations filled with the chip entries + //that does not exist on the system. All such entires will have default + //non-significant values + + TodChipData blank; + uint32_t l_maxProcCount = getMaxProcsOnSystem(); + + TOD_INF("Max possible processor chips for this system when configured " + "completely is %d",l_maxProcCount); + + iv_todChipDataVector.assign(l_maxProcCount,blank); + + TARGETING::ATTR_POSITION_type l_ordId = 0x0; + //Ordinal Id of the processors that form the topology + + //Fill the TodChipData structures with the actual value in the + //ordinal order + for(TodDrawerContainer::iterator l_itr = + iv_todConfig[i_config].iv_todDrawerList.begin(); + l_itr != iv_todConfig[i_config].iv_todDrawerList.end(); + ++l_itr) + { + const TodProcContainer& l_procs = + (*l_itr)->getProcs(); + + for(TodProcContainer::const_iterator + l_procItr = l_procs.begin(); + l_procItr != l_procs.end(); + ++l_procItr) + { + l_ordId = + (*l_procItr)->getTarget()->getAttr<ATTR_POSITION>(); + + //Clear the default flag for this chip, defaults to + //NON_FUNCTIONAL however this is a functional chip + iv_todChipDataVector[l_ordId].header.flags = TOD_NONE; + + //Fill the todChipData structure at position l_ordId + //inside iv_todChipDataVector with TOD register data + //values + (*l_procItr )->setTodChipData( + iv_todChipDataVector[l_ordId]); + + //Set flags to indicate if the proc chip is an MDMT + //See if the current proc chip is MDMT of the primary + //topology + if ( getConfigStatus(TOD_PRIMARY) + && + getMDMT(TOD_PRIMARY)) + { + if ( + (getMDMT(TOD_PRIMARY)->getTarget()-> + getAttr<ATTR_HUID>()) + == + ((*l_procItr)->getTarget()-> + getAttr<ATTR_HUID>()) + ) + { + + iv_todChipDataVector[l_ordId].header.flags |= + TOD_PRI_MDMT; + } + } + + //See if the current proc chip is MDMT of the secondary + //network + //Note: The chip can be theoretically both primary and + //secondary MDMDT + if ( getConfigStatus(TOD_SECONDARY) + && + getMDMT(TOD_SECONDARY)) + { + if ( + (getMDMT(TOD_SECONDARY)->getTarget()-> + getAttr<ATTR_HUID>()) + == + ((*l_procItr)->getTarget()-> + getAttr<ATTR_HUID>()) + ) + { + + iv_todChipDataVector[l_ordId].header.flags |= + TOD_SEC_MDMT; + } + + } + + } + } + + //Done with setting the data write it to the file + l_errHdl = writeTodProcDataToFile(); + if ( l_errHdl ) + { + TOD_ERR( "Failed writing TOD chip data to the file "); + break; + } + + }while(0); + + TOD_EXIT("writeTodProcData. errHdl = %p", l_errHdl); + return l_errHdl; + +}//end of writeTodProcData + + +//****************************************************************************** +//TodControls::writeTodProcDataToFile() +//****************************************************************************** +errlHndl_t TodControls::writeTodProcDataToFile() +{ + TOD_ENTER("writeTodProcDataToFile"); + errlHndl_t l_errHdl = NULL; +#ifndef __HOSTBOOT_MODULE + do + { + std::string l_fileOpenMode(FILE_WRITE_MODE); + char l_fileName[128]; + l_errHdl = getTodProcDataFilePath(l_fileName); + if(l_errHdl) + { + TOD_ERR("Failed getting the file path for sharing TOD data with " + " HDAT "); + break; + } + + //Create the parent directory in which file has to be written + std::string l_dirPath = l_fileName.substr + (0,l_fileName.find_last_of(DIR_PATH_SERERATOR)); + int rc = mkdir(l_dirPath.c_str(),DIR_CREATION_MODE); + + if ( rc != 0 ) + { + //EEXIST just means it already exists, which is fine + if (errno != EEXIST) + { + TOD_ERR("Error creating the directory %s " + "system returned error code %d", + l_dirPath.c_str(),errno); + break; + } + } + + UtilFile file; + l_errHdl = file.open(l_fileName.c_str(), l_fileOpenMode.c_str()); + if ( l_errHdl ) + { + TOD_ERR("Failed opening the file %s, with mode %s" , + l_fileName.c_str(),l_fileOpenMode.c_str()); + break; + } + + TodChipDataContainer::iterator l_chipDataItr = + iv_todChipDataVector.begin(); + file.write(reinterpret_cast<void *>((&(*l_chipDataItr))), + (iv_todChipDataVector.size()* sizeof(TodChipData))); + + l_errHdl = file.getLastError(); + if ( l_errHdl ) + { + TOD_ERR("Failed writing the tod chip data to file "); + break; + } + + l_errHdl = file.close(); + if ( l_errHdl ) + { + TOD_ERR("Failed closing the file %s", l_fileName.c_str()); + break; + } + + }while(0); +#endif + TOD_EXIT("writeTodProcDataToFile. errHdl = %p", l_errHdl); + return l_errHdl; + +} + +//***************************************************************************** +//TodControls::readTodProcDataFromFile +//****************************************************************************** +errlHndl_t TodControls::readTodProcDataFromFile( + std::vector<TodChipData>& o_todChipDataVector )const +{ + TOD_ENTER("readTodProcDataFromFile"); + errlHndl_t l_errHdl = NULL; +#ifndef __HOSTBOOT_MODULE + do + { + std::string l_todProcDataFile; + UtilFile l_file; + + l_errHdl = getTodProcDataFilePath(l_todProcDataFile); + if(l_errHdl) + { + TOD_ERR("Failed getting the path of TodSystemFile "); + break; + } + + if ( !UtilFile::exists(l_todProcDataFile.c_str())) + { + TOD_INF("File %s , does not exist",l_todProcDataFile.c_str()); + break; + } + + //Open the file for reading + l_errHdl = l_file.open(l_todProcDataFile.c_str(),FILE_READ_MODE); + if ( l_errHdl ) + { + TOD_ERR("Failed opening the file %s, with mode %s" , + l_todProcDataFile.c_str(),FILE_READ_MODE); + break; + } + + //The amount of data stored on TodSystemFile always depend on the + //maximum processor possible for the given system type + uint32_t l_maxProcCount = getMaxProcsOnSystem(); + + uint32_t l_bytesToRead = l_file.size(); + + if ( (l_bytesToRead == 0) || (l_bytesToRead > (l_maxProcCount * + sizeof(TodChipData)))) //Check for further safeguards + { + TOD_ERR("Error, File %s is corrupted" + ,l_todProcDataFile.c_str()); + + //Commit this locally, because system can still proceed if TOD HW is + //not running + l_errHdl->commit(HWSV_COMP_ID, ERRL_ACTION_REPORT, + ERRL_SEV_INFORMATIONAL); + delete l_errHdl; + l_errHdl = 0; + break; + } + + TodChipData blank; + o_todChipDataVector.assign(l_maxProcCount,blank); //Allocate memory with + //default values + + //Read the data from file + l_file.read(reinterpret_cast<void *>(&(*(o_todChipDataVector.begin()))), + l_bytesToRead); + + + l_errHdl = l_file.getLastError(); + if ( l_errHdl ) + { + TOD_ERR("Failed reading tod chip data from file "); + break; + + } + + l_errHdl = l_file.close(); + if ( l_errHdl ) + { + TOD_ERR("Failed closing the file %s", l_todProcDataFile.c_str()); + break; + } + //Not going to close the file in error path , UtilFile will close it. + + }while(0); +#endif + TOD_EXIT("readTodProcDataFromFile. errHdl = %p", l_errHdl); + return l_errHdl; +} + +//****************************************************************************** +//TodControls::getTodProcDataFilePath() +//****************************************************************************** +errlHndl_t TodControls::getTodProcDataFilePath(char * o_fileName) + const +{ + TOD_ENTER("getTodProcDataFilePath"); + errlHndl_t l_errHdl = NULL; +#ifndef __HOSTBOOT_MODULE + char *l_buf = NULL; + do + { + uint32_t l_fileSize = 0; + const char* l_stringToAppend = NULL; + const char* l_filePathKey[2] = + { P1_ROOT_PATH, + CINI_SYSTODFILE_PATH + }; + + + l_errHdl = UtilReg::path(l_filePathKey,(sizeof(l_filePathKey) / + sizeof(l_filePathKey[0])), + l_stringToAppend,l_buf,l_fileSize); + + if ( l_errHdl ) + { + TOD_ERR("Failed getting file path from the registry using keys" + "P1_ROOT_PATH and CINI_SYSTODFILE_PATH " ); + break; + } + + o_fileName = std::string(l_buf); + TOD_INF("Found file path %s",o_fileName.c_str()); + + + }while(0); + + if ( l_buf ) + { + delete l_buf; + } +#endif + TOD_EXIT("getTodProcDataFilePath. errHdl = %p", l_errHdl); + return l_errHdl; +} + + +//****************************************************************************** +//HwsvTodControls::hasNoValidData() +//****************************************************************************** +bool TodControls::hasNoValidData(const std::vector<TodChipData>& + i_todChipDataVector)const +{ + TOD_ENTER("hasNoValidData"); + bool result = true; + for(std::vector<TodChipData>::const_iterator l_iter = + i_todChipDataVector.begin(); + l_iter != i_todChipDataVector.end(); ++l_iter) + { + if(((*l_iter).header.flags & TOD_FUNC) != 0) + { + result = false; + break; + } + } + TOD_EXIT("hasNoValidData"); + return result; +} + + +}//end of namespace diff --git a/src/usr/isteps/istep18/TodControls.H b/src/usr/isteps/istep18/TodControls.H new file mode 100755 index 000000000..d072f5ff5 --- /dev/null +++ b/src/usr/isteps/istep18/TodControls.H @@ -0,0 +1,637 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodControls.H $ */ +/* */ +/* 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 TodControls.H + * + * @brief This file declares the methods and members of TodControls class + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#ifndef TODCONTROLS_H +#define TODCONTROLS_H + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +#include <util/singleton.H> +#include "proc_tod_utils.H" +#include "TodDrawer.H" +#include <map> + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Forward declarations +//------------------------------------------------------------------------------ +class TodDrawer; +class TodProc; +class TodControls; +struct TodChipData; + +//------------------------------------------------------------------------------ +//Typedefs +//------------------------------------------------------------------------------ +typedef std::vector<TodChipData> TodChipDataContainer; + +//------------------------------------------------------------------------------ +//Static globals +//------------------------------------------------------------------------------ +//2 configs - primary/secondary +const static uint8_t TOD_NUM_CONFIGS = 2; +const static uint8_t TOD_PSS_MSS_STATUS_REG_00040008_ACTIVE_BIT = 0; +const static uint8_t TOD_PSS_MSS_CTRL_REG_00040007_PRIMARY_MDMT_BIT = 1; +const static uint8_t TOD_PSS_MSS_CTRL_REG_00040007_SECONDARY_MDMT_BIT = 9; + +const static uint32_t TOD_INVALID_UNITID = 0xFFFFFFEF; + +/** + * @class TodControls + * + * @brief TOD topology tree will comprise of the interconnected processor chips. + * This class manages the objects representing proc chips (TodProc) + * that are available to be wired in TOD network. + * The proc chips are contained in one or more Tod drawers + * (TodDrawer). + * The class has data structures that represent this relationship and + * hence enable establishment of TOD topology. + */ +class TodControls +{ +public: + + /** + * @brief Get singleton instance of this class. + * + * @return the (one and only) instance of TodControls + */ + static TodControls& getTheInstance(); + + /** + * @brief TOD_CONFIG_STATE enum will help to determine if there has been HW + * changes since the last time topology was created. + * i.e. new functional processor has become available or one of the + * processor that was part of old TOD topology has become non-functional + */ + enum TOD_CONFIG_STATE + { + TOD_UNCHANGED, //No change in the HW + TOD_MODIFIED, //Either new HW is available or some of them have + //been deconfigured + TOD_UNKNOWN, //Failed to determine if there was any change in the + //HW based on old topology data + }; + + /** + * @brief This method will build a list of functional TOD drawers + * available in the system + * + * @par Detailed Description: + * TOD drawers are represented by HwsvTodDrawer class, that + * basically provides a grouping of the HwsvTodProc objects such + * that processor chips beloning to a specific drawer connect + * over X bus and inter drawer connection is over A bus. TOD drawer + * is analogous to fabic node on the system. + * + * On a TULETA system each DCM chip is a fabric node however on a + * Brazos they can be different physical nodes. + * Each proc chip has an arribute representing the fabric node + * to which it belongs. + * + * The method will get all the functional proc chips on the system , + * and then group them according to fabric nodes. + * + * At the end of operation TOD topology infrastructure will either + * have iv_primTodDrawer or iv_secTodDrawerList completed with each + * drawer having a list of functional proc chips represented as + * HwsvTodProc pointers. + * + * @param[in] i_config + * Indicates the primary/secondary topology + * + * @return Error log handle indicating status of request. + * @retval NULL indicates successful completion of operation + * @retval !NULL indicates that the system doesn't have a TOD drawer, + * TOD topologies can't be created. + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t buildTodDrawers(const proc_tod_setup_tod_sel i_config); + + /** + * @brief This method will pick MDMT chip for the configuration + * requested + * + * @par Detailed Description: + * MDMT is a processor chip that is chosen to receive signals from + * the oscillator and it drives TOD signals to the remaining + * processors on the system. + * The criteria for choosing MDMT on a processor are as follows + * 1.Processor should be connected to the oscillator. ( This is + * invariably true for all processors on TULETA systems ) + * 2.Processor should be marked as functional in the targeting + * model. + * 3.Among the possible candidates the one which is having maximum + * number of functional cores should be preferred. + * + * Whenever possible the MDMT for the primary and secondary + * configurations should be located on different TOD drawers. In + * case of multi node systems, MDMT on secondary topology + * should be located on a TOD drawer that belongs to different + * node as compared to the MDMT of primary configuration. If it + * is not possible to locate the MDMTs on different TOD drawers, + * then different processor within the same TOD drawer should be + * preferred. + * + * @param[in] i_config + * Indicates the primary/secondary configuration for which the MDMT + * has to be picked + * + * @return Error log handle indicating the status of the request. + * @retval NULL if successful + * @retval !NULL if failed to pick the MDMT + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t pickMdmt(const proc_tod_setup_tod_sel i_config); + + /** + * @brief Destroy information pertaining to topology type + * i_config and free up associated memory + * + * @param[in] i_config + * Indicates the primary/secondary topology + * + * @return N/A + */ + void destroy(const proc_tod_setup_tod_sel i_config); + + /** + * @brief Gets a list of TOD drawers for a specific + * topology + * + * @param[in] i_config + * Indicates the primary/secondary topology + * + * @param[out] o_drawerList + * list of HwsvTodDrawer pointers, empty in case of error + * + * @return N/A + */ + void getDrawers(const proc_tod_setup_tod_sel i_config, + TodDrawerContainer& o_drawerList) const + { + o_drawerList = iv_todConfig[i_config].iv_todDrawerList; + } + + /** + * @brief Gets the MDMT for a specific topology + * + * @param[in] i_config + * Indicates the primary/secondary topology + * + * @param[out] o_pMDMT + * The HwsvTodProc pointer corresponding to the MDMT. NULL if error. + * + * @return Pointer to the data member iv_todConfig[i_config].iv_mdmt + */ + TodProc* getMDMT(const proc_tod_setup_tod_sel i_config) const + { + return iv_todConfig[i_config].iv_mdmt; + } + + /** + * + * @brief Setter method for iv_isConfigured variable of TodConfig structure + * for a specific configuration + * + * @param[in] i_config + * Indicates the primary/secondary topology + * + * @param[in] i_isConfigured + * Boolean variable to indicate the configuration status + * + * @return NA + */ + void setConfigStatus(const proc_tod_setup_tod_sel i_config, + const bool i_isConfigured ) + { + iv_todConfig[i_config].iv_isConfigured = i_isConfigured; + } + + /** + * + * @brief Getter method for iv_isConfigured variable of TodConfig structure + * for a specific configuration + * + * @param[in] i_config + * Indicates the primary/secondary topology + * + * @return bool, indicating iv_isConfigured's value + */ + bool getConfigStatus(const proc_tod_setup_tod_sel i_config) const + { + return iv_todConfig[i_config].iv_isConfigured; + } + + /** + * + * @brief getTodConfigState will enable other methods to make a decision + * regarding valid action to be performed to modify the + * topology. + * + * @par Detailed Description: + * On getting a topology creation/modification request, TOD service + * methods need to determine next course of action based on the ChipTOD + * HW state and the state of the data that is available in the + * TodSystemData file.(TodSystemData file contains the previously + * created TOD topology's information). This method will provide all + * the information that is required to determine next course of action. + * + * Following algorithm is used + * 1) Check TOD status register to determine TOD HW state and the active + * configuration + * 2) Read the TodSystemData to find, if HW has changed i.e. new + * functional processors became available or one of the processor that + * was functional when topology was created last time became + * non-functional. + * + * Method can report TOD config state as one of the following + * a)TOD_UNCHANGED ==> No change in the HW + * b)TOD_MODIFIED ==> HW has changed + * c)TOD_UNKNOWN ==> It is not possible to determine the state + * + * @param[out] o_configState + * This parameter will indicate to caller if the HW as seen by + * getTodConfigState is same as indicated by the TodSystemData or not. + * One of the enums listed in TOD_CONFIG_STATE will be returned. + * + * @param[out] o_isTodRunning + * It will be true if the ChipTOD HW is running. + * + * @param[out] o_activeConfig + * This parameter will carry back the information regarding the topology + * that has been currently selected by PHYP, if ChipTOD HW is running. + * In case TOD HW is not running then it will report TOD_PRIMARY, as + * that is the configuration to be picked by PHYP once the TOD logic + * starts running. + * + * @return Error log handle that will determine if method was successful in + * determining various parameters or not + * @retval NULL , Indicates success + * @retval !NULL , Failed getting the output parameters,in this case + * value of o_configState,o_isTodRunning and o_activeConfig should + * not be considered for any further action. + * + * This API may return one of the following "special" reason codes: + * NA + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t getTodConfigState ( TOD_CONFIG_STATE& o_configState, + proc_tod_setup_tod_sel& o_activeConfig, + bool& o_isTodRunning)const; + /** + * @brief isTodRunning returns the current state of ChipTOD HW i.e. + * whether it is running or not + * + * @par Detailed Description: + * This method should be used by the methods that want to make a decision + * on creating TOD topology. If TOD HW is not running then it is safe to + * create new topology, however if TOD HW is running, program cannot + * modify the currently active topology.( It is still possible to + * modify/re-create a backup topology) + * TOD status register bits are clear as long as TOD HW is not running, + * method will read status register. + * + * @param[out] o_isTodRunning, boolean parameter that will be set to true if + * ChipTOD HW is running + * + * @return Error log handle that will determine if method was successful in + * determining ChipTOD HW state + * @retval NULL , Indicates success i.e. o_isTodRunning parameter indicates + * ChipTOD HW state + * @retval !NULL , Failed getting the ChipTOD HW state , in this case value + * of o_isTodRunning should be ignored. + * + * This API may return one of the following "special" reason codes: + * NA + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t isTodRunning ( bool& o_isTodRunning)const; + + + + /** + * @brief This method will provide TOD topology register data to HDAT + * + * @par Detailed Description: + * HWSV needs to share TOD topology data with HDAT. + * HWSV also needs to persist with TOD topology data across non-memory + * preserving IPL's. + * Both the above requirements will be fulfilled by writing data + * to a file. + * This method will take the TOD register data and put it in the format + * required by HDAT, and then call helper method to write the same to a + * file + * + * @param[in] i_config + * Indicates the primary/secondary topology. When both Primary and + * Secondary topologies are successfully configured, the TOD register + * should be in synch for both primary and secondary, so passing any + * topology type will work here. However if there was a problem in + * building one of the topologies i.e. primary could be built but not + * the secondary then primary should be passed as i_config. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if successful + * @retval !NULL if failed to write TOD configuration data + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the returned + * error based on what it decides to do with it. By default any + * returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t writeTodProcData(const proc_tod_setup_tod_sel i_config); + + + /** + * + * @brief This is a helper method for writeTodProcDataToFile, it will + * determine file path where array of hwsvTodChipData structure has to + * be written by HWSV , HDAT will read this file. + * + * @par Detailed Description: + * The file to which data has to be written will be determined by the + * following registry keys + * 1. fstp/P1_Root (To determine the root directory of P1) + * 2. CINI_SYSTODFILE_PATH (To determine the directory and file name + * within P1_Root where the data is to be written) + * + * @param[in] o_fileName + * Output parameter to carry back the file name qualified by full path + * where the data has has to be written. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if file path could be determined successfully + * @retval !NULL if file path could not be found + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the returned error + * based on what it decides to do with it. By default any returned + * error created by this function will be a non-reported tracing event + * error log. + */ + errlHndl_t getTodProcDataFilePath(char * o_fileName) const; + + /** + * @brief This is a helper method for writeTodProcData, it will write the + * array of hwsvTodChipData structures created by writeTodProcData to a + * file with P1 persistancy + * + * @par Detailed Description: + * The method will work on iv_todChipData and take help of + * getTodProcDataFilePath to detrmine the file path where + * iv_todChipData has to be written. + * + * @return Error log handle indicating the status of the request + * @retval NULL if the data could not be written successfully + * @retval !NULL if the data was written successfully + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the returned + * error based on what it decides to do with it. By default any + * returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t writeTodProcDataToFile(); + + /** + * + * @brief Getter method for iv_todChipDataVector + * + * @return Constant reference to vector<hwsvTodChipData> that will carry + * back iv_todChipDataVector + * + */ + const TodChipDataContainer& getTodChipDataVector()const + { + return iv_todChipDataVector; + } + +protected: + /** + * @brief Constructor for the TodControls object. + */ + TodControls(); + + /** + * @brief Destructor for the TodControls object. + */ + ~TodControls(); + +private: + + /** + * + * @brief queryActiveConfig method will help to find the active TOD topology + * when ChipTOD HW is running,It will also report ChipTOD HW status. + * i.e. wheather it is currently running. In case ChipTOD HW is running + * active configuration should never be modified. + * + * @par Detailed Description: + * This method ports logic from P7. + * Bits 00:02 of the TOD status register ( 0x40008 ), indicates the + * topology that is currently active in HW. + * + * @param[out] o_activeConfig, active configuration [primary | secondary] + * In case the TOD HW is not running then primary will be returned. + * + * @param[out] o_isTodRunning, It will indicate if HW is running or not + * + * @return Error log handle that will indicate if method was successfully + * able to determine various parameters or not + * @retval NULL , Indicates success + * @retval !NULL , Failed getting all the output parameters,in this case + * values of o_configAction,o_isTodRunning should not be considered for + * any further action. + * + * This API may return one of the following "special" reason codes: + * NA + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + + errlHndl_t queryActiveConfig( proc_tod_setup_tod_sel& o_activeConfig, + bool& o_isTodRunning) const; + + /** + * + * @brief getConfiguredMdmt method will determine primary and secondary MDMT + * ,if they are configured, using TOD register data. + * + * @par Detailed Description: + * TOD control register (0x40007) has bits that + * will be set for the processor when it is designated as primary MDMT + * or secondary MDMT. In case TOD HW indicates that MDMT is not set, + * output variables will be NULL. + * + * @param[out] o_primaryMdmt, Parameter in which target pointer of primary + * MDMT will be returned, it will be set to NULL if TOD HW does not + * shows that primary MDMT is configured. + * + * @param[out] o_secondaryMdmt, Parameter in which target pointer of + * secondary MDMT will be returned, it will be set to NULL if TOD HW + * does not show that secondary MDMT is configured. + * + * @return Error log handle indicating the status of request. + * @retval NULL , Indicates that method successfully executed its + * algorithm for determining MDMTs, however the individual output + * parameters must be checked to determine if the respective MDMT were + * found or not. + * @retval !NULL , Indicates a problem condition where method was not able + * to complete all the steps for determining MDMTs successfully. In the + * error condition output parameters should be ignored. + * + * This API may return one of the following "special" reason codes: + * NA + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t getConfiguredMdmt(TARGETING::Target*& o_primaryMdmt, + TARGETING::Target*& o_secondaryMdmt)const; + + /** + * @brief This method will read the TOD topology register data from + * TodSystemData file + * + * @par Detailed Description: + * TodSystemData file is a P1 persistent file that will retain the TOD + * topology data from previous configuration. Any request to recofigure + * backup topology should consider the previous topology data. This + * method will read the TodSystemData file and put the data in + * hwsvTodChipData structures. + * + * @param[out ] o_todChipDataVector , Array of hwsvTodChipData structures + * that will be populated with the data from TodSystemData file. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if TodSystemData was successfully read. + * @retval !NULL if TodSystemData could not be read. This will happen if + * the file does not exist, one of the file operation failed or file + * does not have expected data. + * + * This API may return one of the following "special" reason codes: + * NA + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t readTodProcDataFromFile(std::vector<TodChipData>& + o_todChipDataVector )const; + + /** + * @brief This method will be used to determine if the data read from + * TodSystemData file indicates at least one functional processor + * + * @retval boolean value indicating presence or absence of valid data + * @retval false , There is useful data + * @retval true, No useful data found + */ + bool hasNoValidData(const std::vector<TodChipData>& + i_todChipDataVector)const; + + //Datastructure for a TOD topology : + //A list of TOD drawers (which will contain a list of HWSVTodProc's) + //The MDMT for this topology + struct TodConfig{ + TodDrawerContainer iv_todDrawerList; + TodProc* iv_mdmt; + bool iv_isConfigured; + TodConfig() : + iv_mdmt(NULL), + iv_isConfigured(false) + { + } + }; + + //Disabled copy constructor and assignment operator + TodControls(const TodControls& rhs); + TodControls& operator=(const TodControls& rhs); + + //Array of TOD configs + //The fact that TOD_PRIMARY and TOD_SECONDARY are defined as 0 and 1 + //make then as appropriate indices to the array + //iv_todConfig[0] -> primary + //iv_todConfig[1] -> secondary + TodConfig iv_todConfig[TOD_NUM_CONFIGS]; + + //hwsvTodChipData for the whole system (in ordinal order) + TodChipDataContainer iv_todChipDataVector; +}; + +} //end of namespace +#endif //TODCONTROLS_H diff --git a/src/usr/isteps/istep18/TodDrawer.C b/src/usr/isteps/istep18/TodDrawer.C new file mode 100755 index 000000000..caaac1e5b --- /dev/null +++ b/src/usr/isteps/istep18/TodDrawer.C @@ -0,0 +1,200 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodDrawer.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 TodDrawer.C + * + * @brief The file implements methods of TodDrawer class + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +#include "TodSvcUtil.H" +#include "TodDrawer.H" +#include "TodAssert.H" +#include "TodTrace.H" +#include <tod_init/tod_init_reasoncodes.H> + + +namespace TOD +{ + +//****************************************************************************** +// TodDrawer::TodDrawer +//****************************************************************************** +TodDrawer::TodDrawer(const uint8_t i_drawerId, + const TARGETING::Target* i_parentNode): + iv_todDrawerId(i_drawerId), + iv_isTodMaster(false), + iv_parentNodeTarget(i_parentNode) +{ + TOD_ASSERT(iv_parentNodeTarget, + "Error creating TOD drawer with id 0x%.2X, parent node" + "pointer passed as NULL", i_drawerId); + + TOD_ENTER("Created TOD drawer with id 0x%.2X, parent node 0x%.8X", + i_drawerId, + i_parentNode->getAttr<TARGETING::ATTR_HUID>()); + TOD_EXIT("TodDrawer constructor"); +} + +//****************************************************************************** +// TodDrawer::~TodDrawer +//****************************************************************************** +TodDrawer::~TodDrawer() +{ + TOD_ENTER("TodDrawer destructor"); + + for(TodProcContainer::iterator l_itr = iv_todProcList.begin(); + l_itr != iv_todProcList.end(); + ++l_itr) + { + delete (*l_itr); + } + iv_todProcList.clear(); + TOD_EXIT("TodDrawer destructor"); +} + +//****************************************************************************** +// TodDrawer::getProcWithMaxCores +//****************************************************************************** +void TodDrawer::getProcWithMaxCores( + const TodProc* i_procToIgnore, + TodProc*& o_pTodProc, + uint32_t& o_coreCount) const +{ + TOD_ENTER("getProcWithMaxCores"); + o_pTodProc = NULL; + o_coreCount = 0; + + do{ + //List of functional cores + TARGETING::TargetHandleList l_funcCoreTargetList; + TARGETING::PredicateCTM + l_coreCTM(TARGETING::CLASS_UNIT,TARGETING::TYPE_CORE); + + TARGETING::PredicateHwas l_funcPred; + l_funcPred.functional(true); + TARGETING::PredicatePostfixExpr l_funcCorePostfixExpr; + l_funcCorePostfixExpr.push(&l_coreCTM).push(&l_funcPred).And(); + + TodProc* l_pSelectedTarget = NULL; + uint32_t l_maxCores = 0; + + for(TodProcContainer::const_iterator l_procIter = + iv_todProcList.begin(); + l_procIter != iv_todProcList.end(); + ++l_procIter) + { + if((NULL != i_procToIgnore) && + (i_procToIgnore->getTarget()->getAttr<TARGETING::ATTR_HUID>() == + (*l_procIter)->getTarget()->getAttr<TARGETING::ATTR_HUID>())) + { + continue; + } + l_funcCoreTargetList.clear(); + //Find the funcational core targets on this proc + TARGETING::targetService().getAssociated(l_funcCoreTargetList, + (*l_procIter)->getTarget(), + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_funcCorePostfixExpr); + + if ( l_funcCoreTargetList.size() > l_maxCores ) + { + l_pSelectedTarget = *l_procIter; + l_maxCores = l_funcCoreTargetList.size(); + } + } + if ( l_maxCores > 0 ) + { + o_pTodProc = l_pSelectedTarget; + o_coreCount = l_maxCores; + TOD_INF("getProcWithMaxCores,On drawer %d, processor 0x%08X " + "has maximum cores count = %d ", + iv_todDrawerId, + l_pSelectedTarget->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_maxCores); + } + + }while(0); + + TOD_EXIT("getProcWithMaxCores"); +} + + +//****************************************************************************** +// TodDrawer::findMasterProc +//****************************************************************************** +errlHndl_t TodDrawer::findMasterProc(TodProc*& o_drawerMaster) const +{ + TOD_ENTER("findMasterProc"); + + errlHndl_t l_errHdl = NULL; + + TodProc* l_pMasterProc = NULL; + + do{ + TodProcContainer::const_iterator l_procIter = iv_todProcList.begin(); + for (; l_procIter != iv_todProcList.end(); ++l_procIter) + { + if(((*l_procIter)->getMasterType() == TodProc::TOD_MASTER) + || + ((*l_procIter)->getMasterType() == TodProc::DRAWER_MASTER)) + { + l_pMasterProc = (*l_procIter); + break; + } + } + if(iv_todProcList.end() == l_procIter) + { + TOD_ERR("No master proc for drawer 0x%.2X",iv_todDrawerId); + /*@ + * @errortype + * @reasoncode TOD_NO_MASTER_PROC + * @moduleid TOD_FIND_MASTER_PROC + * @userdata1 TOD drawer id + * @devdesc No master proc set for this drawer + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_LOG_INVALID_CONFIG, + TOD_INVALID_CONFIG, + iv_todDrawerId, 0); + } + }while(0); + + o_drawerMaster = l_pMasterProc; + + TOD_EXIT("findMasterProc, errHdl = %p", l_errHdl); + + return l_errHdl; +} + +}//end of namespace diff --git a/src/usr/isteps/istep18/TodDrawer.H b/src/usr/isteps/istep18/TodDrawer.H new file mode 100755 index 000000000..80257d836 --- /dev/null +++ b/src/usr/isteps/istep18/TodDrawer.H @@ -0,0 +1,254 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodDrawer.H $ */ +/* */ +/* 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 */ +#ifndef TODDRAWER_H +#define TODDRAWER_H + +/** + * @file TodDrawer.H + * + * @brief Contains TodDrawer class declaration + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> +#include "TodProc.H" + +namespace TOD +{ + +class TodDrawer; // forward declaration +typedef std::list<TodDrawer*> TodDrawerContainer; + +/** + * @class TodDrawer + * + * @brief TodDrawer class provides a grouping of the TodProc objects + * that belong to a particular TOD drawer. Each processor chip belonging + * to a specific TOD drawer connect over X bus and inter TOD drawer + * connection is over A bus.Concept of TOD drawer is analogous + * to fabric node on the system. + * + * TOD drawers fall under two categories,master TOD drawer and slave + * TOD drawers. Master TOD drawer is the one on which MDMT sits, all + * the remaining TOD drawers are designated as slave drawers. + * + * MDMT should drive TOD signals to other processors on the master + * TOD drawer over X buses and to one processor on each slave drawer over + * A bus ( This processor is designated as MDST ). + * MDST is responsible for driving the TOD signals to the remaining + * processors on slave drawer. + */ +class TodDrawer +{ +public: + /** + * @brief Constructor for the TodDrawer object + * + * @param[in] i_drawerId + * this TOD drawer's id, it is nothing but the fabric node id attribute + * of the processors that belong to a fabric node type + * + * @param[in] i_parentNode + * container node's target + */ + TodDrawer(const uint8_t i_drawerId, + const TARGETING::Target* i_parentNode); + + /** + * @brief Destructor for the TodDrawer object. + * + * @par Detailed Description: + * Will destroy all HwsvTodProc objects that were added to this TOD + * drawer. + */ + ~TodDrawer(); + + /** + * @brief This method will return the TodProc object that is either a + * TOD master or Drawer Master + * + * @par Detailed Description: + * While creating the topology MDMT and MDST should be wired to the + * other processors on that TOD drawer over X buses. + * TodTopologyManager will use this method to determine which + * processor is the master for that drawer. + * The method will go over the iv_todProcList and return the processor + * that is marked as TodProc::TOD_MASTER or TodProc::DRAWER_MASTER + * + * @param[out] o_drawerMaster + * It will be set to master processor's address if master processor is + * successfully found. + * In case the master processor could not be found successfully + * o_drawerMaster will be set to NULL, and error handle will be retured. + * + * @return Error log handle, indicates status of request + * @retval NULL indicates that master processor was successfully found + * @retval !NULL indicates that the master processor could not be found + * successfully. The only possible reason for returning NULL can be + * that this method was called out of sequence i.e even before + * TodTopologyManager designated a processor on a given TOD drawer as + * master for that drawer. + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t findMasterProc(TodProc*& o_drawerMaster) const; + + /** + * @brief This method will determine the processor that has maximum number + * functional cores among the list of processor owned by the TOD drawer + * object + * + * @par Detailed Description: + * For creation of topology , first task is to choose the MDMT. One of + * the criteria for choosing MDMT is that it should be the processor + * with maximum number of functional cores. + * This method will serve as a a helper for pickMdmt, to determine + * which processor in the TOD drawer has maximum number of functional + * cores + * + * @param[in] i_procToIgnore , The TodProc object to be ignored while + * choosing desired proc. This is the case when there is existing MDMT + * for primar/secondary topology and MDMT has to be chosen for the + * other topology, peviously chosen MDMT should be avoided. + * + * @param[out] o_pTodProc, It will carry back pointer to the HwsvTodProc + * object that has the maximum number of cores. + * In the unlikely case of TOD drawer not having any processor with + * functional cores, this parameter will be set to NULL + * + * @param[out] o_coreCount, This will carry back the no. of cores that was + * found on processor with max functional core count. In case o_pTodProc + * is set to NULL this will be zero. + * + * @return N/A + */ + void getProcWithMaxCores( + const TodProc * i_procToIgnore, + TodProc *& o_pTodProc, + uint32_t& o_coreCount)const; + + /** + * @brief Getter method for iv_todProcList + * + * @param[out] o_procList + * Parameter in which iv_todProcList will be returned + * + * @return N/A + */ + const TodProcContainer& getProcs() const + { + return iv_todProcList; + } + + /** + * @brief setter method for iv_isTodMaster + * + * @param[in] i_masterTodDrawer + * true/false, indicating whether this TOD drawer is a master or not + * + * @return N/A + */ + void setMasterDrawer(const bool i_masterTodDrawer) + { + iv_isTodMaster = i_masterTodDrawer; + } + + /** + * @brief Adds a processor to this TOD drawer + * + * @param[in] i_proc + * A VTodProc pointer correspnding to the proc to be added + * + * @return N/A + */ + void addProc(TodProc* i_proc) + { + iv_todProcList.push_back(i_proc); + } + + /** + * @brief Get this TOD drawer's id (this will be + * the corresponding fabric node's id) + * + * @return TOD drawer's id + * @retval corresponding fabric node's id + */ + TARGETING::ATTR_FABRIC_NODE_ID_type getId() const + { + return iv_todDrawerId; + } + + /** + * @brief Checks if this TOD drawer is a master drawer for the system. + * The master status of TOD drawer is contained in iv_isTodMaster. + * + * @return bool value, it will be true if this TOD drawer is a master drawer + * ,false otherwise + */ + bool isMaster() const + { + return iv_isTodMaster; + } + + /** + * @brief Returns the containing node's target + * + * @return Target pointer + */ + const TARGETING::Target* getParentNodeTarget() const + { + return iv_parentNodeTarget; + } + +private: + //List of TodProc objects that belongs to TodDrawer instance + TodProcContainer iv_todProcList; + + //TOD drawer id, the value of this attribute will be derived from + //ATTR_FABRIC_NODE_ID attribute of the processors that belong to this + //TOD drawer, all the processors belonging to this TOD drawer will share + //the same value for ATTR_FABRIC_NODE_ID + TARGETING::ATTR_FABRIC_NODE_ID_type iv_todDrawerId; + + //This data member will identify if the current drawer is a Tod master + bool iv_isTodMaster; + + //Target pointer of the node to which TodDrawer belongs + const TARGETING::Target * iv_parentNodeTarget; +}; + +} //end of namespace + +#endif //TODDRAWER_H diff --git a/src/usr/isteps/istep18/TodHwpIntf.C b/src/usr/isteps/istep18/TodHwpIntf.C new file mode 100755 index 000000000..b66f379ad --- /dev/null +++ b/src/usr/isteps/istep18/TodHwpIntf.C @@ -0,0 +1,220 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodHwpIntf.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 TodHwpIntf.C + * + * @brief Implementation of TOD Hardware Procedure interfaces + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +#include <fapiPlatHwpInvoker.H> +#include <tod_init/tod_init_reasoncodes.H> +#include "TodTrace.H" +#include "TodHwpIntf.H" +#include "TodControls.H" +#include "proc_tod_setup.H" +#include "proc_tod_save_config.H" +#include "proc_tod_init.H" + +namespace TOD +{ + +errlHndl_t todSetupHwp(const proc_tod_setup_tod_sel i_topologyType) +{ + TOD_ENTER("todSetupHwp"); + + errlHndl_t l_errHdl = NULL; + + do + { + //Get the MDMT + TodProc* l_pMDMT = + TodControls::getTheInstance().getMDMT(i_topologyType); + if(NULL == l_pMDMT) + { + TOD_ERR("MDMT not found"); + /*@ + * @errortype + * @reasoncode TOD_NO_MASTER_PROC + * @moduleid TOD_SETUP_HWP + * @devdesc MDMT could not be found + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_SETUP_HWP, + TOD_NO_MASTER_PROC,0,0); + break; + } + + FAPI_INVOKE_HWP(l_errHdl, + proc_tod_setup, + l_pMDMT->getTopologyNode(), + i_topologyType, + TOD_OSC_0); + if(l_errHdl) + { + TOD_ERR("Error in call to proc_tod_setup. " + "Topology type 0x%.8X. " + "MDMT's HUID is 0x%.8X. " + "MDMT Master type : 0x%.8X. ", + i_topologyType, + l_pMDMT->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_pMDMT->getMasterType()); + TOD_ERR("MDMT Bus RX 0x%.8X, Bus TX 0x%.8X.", + l_pMDMT->getBusIn(), l_pMDMT->getBusOut()); + break; + } + + //Mark the MDMT role in ATTR. Note the same chip + //can be both primary/secondary. Attr is volatile + //init'ed to zero + TARGETING::Target * l_proc = + const_cast<TARGETING::Target*>(l_pMDMT->getTarget()); + uint8_t l_role = l_proc->getAttr<TARGETING::ATTR_TOD_ROLE>(); + if (TOD_PRIMARY == i_topologyType) + { + l_role |= TARGETING::TOD_ROLE_PRIMARY; + } + else //Secondary + { + l_role |= TARGETING::TOD_ROLE_SECONDARY; + } + l_proc->setAttr<TARGETING::ATTR_TOD_ROLE>(l_role); + + }while(0); + + TOD_EXIT("todSetupHwp. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +errlHndl_t todSaveRegsHwp(const proc_tod_setup_tod_sel i_topologyType) +{ + TOD_ENTER("todSaveRegsHwp"); + + errlHndl_t l_errHdl = NULL; + + do + { + //Get the MDMT + TodProc* l_pMDMT = + TodControls::getTheInstance().getMDMT(i_topologyType); + if(NULL == l_pMDMT) + { + TOD_ERR("MDMT not found"); + /*@ + * @errortype + * @reasoncode TOD_NO_MASTER_PROC + * @moduleid TOD_SAVEREGS_HWP + * @devdesc MDMT could not be found + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_SAVEREGS_HWP, + TOD_NO_MASTER_PROC,0,0); + break; + } + + FAPI_INVOKE_HWP(l_errHdl, + proc_tod_save_config, + l_pMDMT->getTopologyNode()); + if(l_errHdl) + { + TOD_ERR("Error in call to proc_tod_save_config. " + "Topology type 0x%.8X. " + "MDMT's HUID is 0x%.8X. " + "MDMT Master type : 0x%.8X. ", + i_topologyType, + l_pMDMT->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_pMDMT->getMasterType()); + TOD_ERR("MDMT Bus RX 0x%.8X, Bus TX 0x%.8X.", + l_pMDMT->getBusIn(), l_pMDMT->getBusOut()); + break; + } + }while(0); + + TOD_EXIT("todSaveRegsHwp. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +errlHndl_t todInitHwp(const proc_tod_setup_tod_sel i_topologyType) +{ + TOD_ENTER("todInitHwp"); + + errlHndl_t l_errHdl = NULL; + + do + { + //Get the MDMT + TodProc* l_pMDMT = + TodControls::getTheInstance().getMDMT(i_topologyType); + if(NULL == l_pMDMT) + { + TOD_ERR("MDMT not found"); + /*@ + * @errortype + * @reasoncode TOD_NO_MASTER_PROC + * @moduleid TOD_INIT_HWP + * @devdesc MDMT could not be found + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_INIT_HWP, + TOD_NO_MASTER_PROC,0,0); + break; + } + + FAPI_INVOKE_HWP(l_errHdl, + proc_tod_init, + l_pMDMT->getTopologyNode()); + + if(l_errHdl) + { + TOD_ERR("Error in call to proc_tod_init. " + "Topology type 0x%.8X. " + "MDMT's HUID is 0x%.8X. " + "MDMT Master type : 0x%.8X. ", + i_topologyType, + l_pMDMT->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_pMDMT->getMasterType()); + TOD_ERR("MDMT Bus RX 0x%.8X, Bus TX 0x%.8X.", + l_pMDMT->getBusIn(), l_pMDMT->getBusOut()); + break; + } + }while(0); + + TOD_EXIT("todInitHwp. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +} //namespace TOD diff --git a/src/usr/isteps/istep18/TodHwpIntf.H b/src/usr/isteps/istep18/TodHwpIntf.H new file mode 100755 index 000000000..94f15cb80 --- /dev/null +++ b/src/usr/isteps/istep18/TodHwpIntf.H @@ -0,0 +1,120 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodHwpIntf.H $ */ +/* */ +/* 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 */ +#ifndef TODHWPINTF_H +#define TODHWPINTF_H + +/** + * @file TodHwpIntf.H + * + * @brief TOD Hardware Procedure interfaces + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <errl/errlentry.H> +#include "proc_tod_utils.H" + +namespace TOD +{ + +/** + * @brief Invokes the TOD setup hardware procedure + * + * @par Detailed Description: + * We pass in the TOD topology to the HWP. The HWP traverses the + * the topology and writes various TOD registers with TOD specific + * information. It also computes TOD delays and writes appropriate regs. + * + * @param[in] i_topologyType + * Topology type : primary/secondary + * + * @return Error log handle indicating the status of the request + * @retval NULL HWP executed succesfully + * @retval !NULL HWP failure + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ +errlHndl_t todSetupHwp(const proc_tod_setup_tod_sel i_topologyType); + +/** + * @brief Invokes the TOD registry read HWP. + * + * @par Detailed Description: + * We pass in the TOD topology to the HWP. The HWP traverses the + * topology and fills up, for each TOD proc datastructure, an output + * field which corresponds to the TOD registers for that proc. The HWP + * gets the register content by scomming the register. + * Check proc_tod_utils.H : proc_tod_setup_conf_regs for the list of regs. + * + * @param[in] i_topologyType + * Topology type : primary/secondary + * + * @return Error log handle indicating the status of the request + * @retval NULL HWP executed succesfully + * @retval !NULL HWP failure + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ +errlHndl_t todSaveRegsHwp(const proc_tod_setup_tod_sel i_topologyType); + +/** + * @brief Invokes the TOD init HWP. + * + * @param[in] i_topologyType + * Topology type : primary/secondary + * + * @return Error log handle indicating the status of the request + * @retval NULL HWP executed succesfully + * @retval !NULL HWP failure + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ +errlHndl_t todInitHwp(const proc_tod_setup_tod_sel i_topologyType); + +} //namespace TOD + +#endif //TODHWPINTF_H diff --git a/src/usr/isteps/istep18/TodProc.C b/src/usr/isteps/istep18/TodProc.C new file mode 100755 index 000000000..656b19fb6 --- /dev/null +++ b/src/usr/isteps/istep18/TodProc.C @@ -0,0 +1,548 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodProc.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 TodProc.C + * + * @brief The file implements methods of TodProc class + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> +#include <targeting/common/utilFilter.H> +#include <tod_init/tod_init_reasoncodes.H> +#include "TodDrawer.H" +#include "TodProc.H" +#include "TodTypes.H" +#include "TodAssert.H" +#include "TodTrace.H" + +namespace TOD +{ + +//****************************************************************************** +// TodProc::TodProc +//****************************************************************************** +TodProc::TodProc( + const TARGETING::Target* i_procTarget, + const TodDrawer* i_parentDrawer): + iv_procTarget(i_procTarget), + iv_parentDrawer(i_parentDrawer), + iv_tod_node_data(NULL), + iv_masterType(NOT_MASTER) +{ + TOD_ASSERT(iv_procTarget, "Target input i_procTarget is NULL "); + TOD_ASSERT(iv_parentDrawer, "TOD drawer input iv_parentDrawer is NULL "); + + TOD_ENTER("Created proc 0x%.8X on drawer 0x%.2X", + iv_procTarget->getAttr<TARGETING::ATTR_HUID>(), + iv_parentDrawer->getId()); + init(); + + TOD_EXIT("TodProc constructor"); +} + +//****************************************************************************** +// TodProc::~TodProc +//****************************************************************************** +TodProc::~TodProc() +{ + TOD_ENTER("TodProc destructor"); + + if(iv_tod_node_data) + { + delete iv_tod_node_data->i_target; + iv_tod_node_data->i_target = NULL; + delete iv_tod_node_data; + iv_tod_node_data = NULL; + } + iv_xbusTargetList.clear(); + iv_abusTargetList.clear(); + + TOD_EXIT("TodProc destructor"); +} + + +//****************************************************************************** +// TodProc::getMasterType +//****************************************************************************** +TodProc::ProcMasterType TodProc::getMasterType() const +{ + return iv_masterType; +} + +//****************************************************************************** +// TodProc::setMasterType +//****************************************************************************** +void TodProc::setMasterType(const ProcMasterType i_masterType) +{ + TOD_ENTER("setMasterType"); + + iv_masterType = i_masterType; + iv_tod_node_data->i_drawer_master = true; + if(TOD_MASTER == i_masterType) + { + iv_tod_node_data->i_tod_master = true; + } + + TOD_EXIT("setMasterType"); +} + +//****************************************************************************** +// TodProc::init +//****************************************************************************** +void TodProc::init() +{ + TOD_ENTER("init"); + + if(iv_tod_node_data) + { + if(iv_tod_node_data->i_target) + { + delete iv_tod_node_data->i_target; + } + delete iv_tod_node_data; + } + iv_tod_node_data = new tod_topology_node(); + //Initialize the iv_tod_node_data structure + iv_tod_node_data->i_target = new fapi::Target; + iv_tod_node_data->i_target->setType(fapi::TARGET_TYPE_PROC_CHIP); + iv_tod_node_data->i_target->set + (reinterpret_cast<void*>(const_cast<TARGETING::Target*>(iv_procTarget))); + iv_tod_node_data->i_tod_master = false; + iv_tod_node_data->i_drawer_master = false; + iv_tod_node_data->i_bus_rx = NONE; + iv_tod_node_data->i_bus_tx = NONE; + + TodTopologyNodeContainer::iterator l_childItr; + + for(l_childItr = iv_tod_node_data->i_children.begin(); + l_childItr != iv_tod_node_data->i_children.end(); + ++l_childItr) + { + delete (*l_childItr); + } + iv_tod_node_data->i_children.clear(); + + iv_xbusTargetList.clear(); + iv_abusTargetList.clear(); + + //Make a list of outgoing bus targets for this processor + TARGETING::PredicateCTM + l_xbusCTM(TARGETING::CLASS_UNIT,TARGETING::TYPE_XBUS); + TARGETING::PredicateCTM + l_abusCTM(TARGETING::CLASS_UNIT,TARGETING::TYPE_ABUS); + + TARGETING::TargetHandleList l_xbusTargetList; + TARGETING::TargetHandleList l_abusTargetList; + + TARGETING::PredicateIsFunctional l_func; + TARGETING::PredicatePostfixExpr l_funcAndXbusFilter; + TARGETING::PredicatePostfixExpr l_funcAndAbusFilter; + l_funcAndXbusFilter.push(&l_xbusCTM).push(&l_func).And(); + l_funcAndAbusFilter.push(&l_abusCTM).push(&l_func).And(); + + TARGETING::targetService().getAssociated(l_xbusTargetList, + iv_procTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_funcAndXbusFilter); + + //Push the X bus targets found to the iv_xbusTargetList + for(uint32_t l_index =0 ; l_index < l_xbusTargetList.size(); + ++l_index) + { + iv_xbusTargetList.push_back(l_xbusTargetList[l_index]); + } + + TARGETING::targetService().getAssociated(l_abusTargetList, + iv_procTarget, + TARGETING::TargetService::CHILD, + TARGETING::TargetService::ALL, + &l_funcAndAbusFilter); + //Push the A bus targets found to the iv_abusTargetList + for(uint32_t l_index =0 ; l_index < l_abusTargetList.size(); + ++l_index) + { + iv_abusTargetList.push_back(l_abusTargetList[l_index]); + } + + TOD_EXIT("init"); + + return; +} + +//****************************************************************************** +// TodProc::connect +//****************************************************************************** +errlHndl_t TodProc::connect( + TodProc* i_destination, + const TARGETING::TYPE i_busChipUnitType, + bool& o_isConnected) +{ + TOD_ENTER("Source proc HUID = 0x%08X " + "Destination proc HUID = 0x%08X " + "Bus type for connection = 0x%08X ", + iv_procTarget->getAttr<TARGETING::ATTR_HUID>(), + i_destination->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + static_cast<uint32_t>(i_busChipUnitType)); + + errlHndl_t l_errHndl = NULL; + o_isConnected = false; + + do + { + if(iv_procTarget->getAttr<TARGETING::ATTR_HUID>() == + i_destination->getTarget()->getAttr<TARGETING::ATTR_HUID>()) + { + TOD_INF("This and the destination are the same procs"); + o_isConnected = true; + break; + } + + TARGETING::TargetHandleList* l_pBusList = NULL; + + //Check whether we've to connect over X or A bus + if(TARGETING::TYPE_XBUS == i_busChipUnitType) + { + l_pBusList = &iv_xbusTargetList; + } + else if(TARGETING::TYPE_ABUS == i_busChipUnitType) + { + l_pBusList = &iv_abusTargetList; + } + else + { + TOD_ERR("Bus type 0x%.8X passed to the method is not " + "supported", i_busChipUnitType); + logUnsupportedBusType(i_busChipUnitType,l_errHndl); + break; + } + + //From this proc (iv_procTarget), find if destination(i_destination) + //has a connection via the bus type i_busChipUnitType : + + //Step 1: Sequentially pick buses from either iv_xbusTargetList or + //iv_abusTargetList depending on the bus type specified as input + //Step 2: Get the parent of peer target of the bus target found in the + //previous step. If it matches with the destination, we got a connection + //Step 3: If a match is found then fill the i_bus_tx and i_bus_rx + //attributes for the destination proc and return + + const TARGETING::Target * l_proc = NULL; + TARGETING::TargetHandleList l_busList; + + TARGETING::TargetHandleList::iterator l_busIter = (*l_pBusList).begin(); + for(;l_busIter != (*l_pBusList).end() ; ++l_busIter) + { + l_busList.clear(); + + //Get the peer target for this bus connection + //I need to know the peer's (bus endpoint) attributes such as + //HUID, chip unit. Applying a result filter will get me the proc + //on the other end, but will abstract away the bus, which is not + //what I want. + getPeerTargets( + l_busList, + *l_busIter, + NULL, + NULL); + + //There should be only 1 peer + if(1 == l_busList.size()) + { + l_proc = getParentChip(l_busList[0]); + + if((l_proc) && + l_proc->getAttr<TARGETING::ATTR_HWAS_STATE>().functional && + (l_proc->getAttr<TARGETING::ATTR_HUID>() == + i_destination->iv_procTarget-> + getAttr<TARGETING::ATTR_HUID>())) + { + //We found a connection : + //iv_procTarget --- i_busChipUnitType --- i_destination + TOD_INF("Source processor 0x%.8X connects with the " + "destination processor 0x%.8X over " + "source bus 0x%.8X and destination bus 0x%.8X " + "via bus type 0x%.8X", + iv_procTarget->getAttr<TARGETING::ATTR_HUID>(), + i_destination->iv_procTarget-> + getAttr<TARGETING::ATTR_HUID>(), + (*l_busIter)->getAttr<TARGETING::ATTR_HUID>(), + l_busList[0]->getAttr<TARGETING::ATTR_HUID>(), + i_busChipUnitType); + + //Determine the bus type as per our format, for eg XBUS0 + //ATTR_CHIP_UNIT gives the instance number of + //the bus and it has direct correspondance to + //the port no. + //For instance a processor has two A buses + //then the one with ATTR_CHIP_UNIT 0 will be A0 + //and the one with ATTR_CHIP_UNIT 1 will be A1 + proc_tod_setup_bus l_busOut = NONE; + proc_tod_setup_bus l_busIn = NONE; + l_errHndl = getBusPort(i_busChipUnitType, + (*l_busIter)-> + getAttr<TARGETING::ATTR_CHIP_UNIT>(), + l_busOut); + if(NULL == l_errHndl) + { + l_errHndl = getBusPort(i_busChipUnitType, + l_busList[0]-> + getAttr<TARGETING::ATTR_CHIP_UNIT>(), + l_busIn); + } + if(l_errHndl) + { + //Should not be hitting this path if HW procedure is + //correctly defining all the bus types and ports + TOD_ERR("proc_tod_setup_bus type not found for " + "port 0x%.2X of bus type 0x%.8X. Source processor " + "0x%.8X, destination processor 0x%.8X", + (*l_busIter)-> + getAttr<TARGETING::ATTR_CHIP_UNIT>(), + i_busChipUnitType, + iv_procTarget-> + getAttr<TARGETING::ATTR_HUID>(), + i_destination->iv_procTarget-> + getAttr<TARGETING::ATTR_HUID>()); + break; + } + + //Set the bus connections for i_destination : + //Bus out from this proc = l_busOut; + //Bus in to destination = l_busIn; + i_destination->setConnections(l_busOut, l_busIn); + o_isConnected = true; + break; + } + } + } + if(l_errHndl) + { + break; + } + }while(0); + + TOD_EXIT("connect. errHdl = %p", l_errHndl); + + return l_errHndl; +} + +//****************************************************************************** +//TodProc::getBusPort +//****************************************************************************** +errlHndl_t TodProc::getBusPort( + const TARGETING::TYPE i_busChipUnitType, + const uint32_t i_busPort, + proc_tod_setup_bus& o_busPort) const +{ + TOD_ENTER("getBusPort"); + + errlHndl_t l_errHndl = NULL; + + if(TARGETING::TYPE_XBUS == i_busChipUnitType) + { + switch(i_busPort) + { + case 0: + o_busPort = XBUS0; + break; + case 1: + o_busPort = XBUS1; + break; + case 2: + o_busPort = XBUS2; + break; + case 3: + o_busPort = XBUS3; + break; + default: + TOD_ERR("Port 0x%.8X not supported for X bus", + i_busPort); + logUnsupportedBusPort(i_busPort, + i_busChipUnitType, + l_errHndl); + break; + } + } + else if(TARGETING::TYPE_ABUS == i_busChipUnitType) + { + switch(i_busPort) + { + case 0: + o_busPort = ABUS0; + break; + case 1: + o_busPort = ABUS1; + break; + case 2: + o_busPort = ABUS2; + break; + default: + TOD_ERR("Port 0x%.8X not supported for A bus", + i_busPort); + logUnsupportedBusPort(i_busPort, + i_busChipUnitType, + l_errHndl); + break; + } + } + else + { + TOD_ERR("Bus type 0X%.8X not supported",i_busChipUnitType); + logUnsupportedBusType(i_busChipUnitType, l_errHndl); + } + + TOD_EXIT("getBusPort. errHdl = %p", l_errHndl); + + return l_errHndl; +} + + +//****************************************************************************** +//TodProc::logUnsupportedBusType +//****************************************************************************** +void TodProc::logUnsupportedBusType(const int32_t i_busChipUnitType, + errlHndl_t& io_errHdl) const +{ + /*@ + * @errortype + * @moduleid TOD_LOG_UNSUPPORTED_BUSTYPE + * @reasoncode TOD_UNSUPPORTED_BUSTYPE + * @userdata1 Bus type that is not currently supported + * @devdesc Error: Unsupported bus type was detected + * Possible Causes: Invalid bus configuration in targeting, or + * getBusPort method has not been updated to support all the + * bus type on a given system. + * Resolution:Development team should be contacted. + */ + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_LOG_UNSUPPORTED_BUSTYPE, + TOD_UNSUPPORTED_BUSTYPE, + i_busChipUnitType, 0); +} + +//****************************************************************************** +//TodProc::logUnsupportedBusPort +//****************************************************************************** +void TodProc::logUnsupportedBusPort( + const int32_t i_busPort, + const int32_t i_busChipUnitType, + errlHndl_t& io_errHdl) const +{ + /*@ + * @errortype + * @reasoncode TOD_UNSUPPORTED_BUSPORT + * @moduleid TOD_LOG_UNSUPPORTED_BUSPORT + * @userdata1 Bus port that is not currently supported + * @userdata2 Bus Type for which the unsupported port has been reported + * @devdesc Error: Unsupported bus port was detected for the specified + * bus type. + * Possible Causes: Invalid bus configuration in targeting, or + * getBusPort method has not been updated to support all the + * possible port for a bus on a given system type. + * Resolution:Development team should be contacted. + */ + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_LOG_UNSUPPORTED_BUSPORT, + TOD_UNSUPPORTED_BUSPORT, + i_busPort, i_busChipUnitType); +} + +//****************************************************************************** +// TodProc::addChild +//****************************************************************************** +void TodProc::addChild(TodProc* i_child) +{ + TOD_ENTER("addChild"); + + if(iv_procTarget->getAttr<TARGETING::ATTR_HUID>() != + i_child->getTarget()->getAttr<TARGETING::ATTR_HUID>()) + { + iv_childrenList.push_back(i_child); + (iv_tod_node_data->i_children).push_back(i_child->getTopologyNode()); + } + + TOD_EXIT("addChild"); +} + +//****************************************************************************** +// TodProc::getTodRegs +//****************************************************************************** +void TodProc::getTodRegs(proc_tod_setup_conf_regs& o_todRegs) const +{ + o_todRegs.tod_m_path_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_m_path_ctrl_reg; + o_todRegs.tod_pri_port_0_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_pri_port_0_ctrl_reg; + o_todRegs.tod_pri_port_1_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_pri_port_1_ctrl_reg; + o_todRegs.tod_sec_port_0_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_sec_port_0_ctrl_reg; + o_todRegs.tod_sec_port_1_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_sec_port_1_ctrl_reg; + o_todRegs.tod_s_path_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_s_path_ctrl_reg; + o_todRegs.tod_i_path_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_i_path_ctrl_reg; + o_todRegs.tod_pss_mss_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_pss_mss_ctrl_reg; + o_todRegs.tod_chip_ctrl_reg = + iv_tod_node_data->o_todRegs.tod_chip_ctrl_reg; +} + +//****************************************************************************** +//TodProc::setTodChipData +//****************************************************************************** +void TodProc::setTodChipData(TodChipData& o_todChipData) const +{ + proc_tod_setup_conf_regs& l_todRegs = iv_tod_node_data->o_todRegs; + + o_todChipData.header.chipID = iv_procTarget-> + getAttr<TARGETING::ATTR_POSITION>(); + + o_todChipData.header.flags |= TOD_FUNC; + + o_todChipData.regs.mpcr = l_todRegs.tod_m_path_ctrl_reg.getWord(0); + o_todChipData.regs.pcrp0 = l_todRegs.tod_pri_port_0_ctrl_reg.getWord(0); + o_todChipData.regs.pcrp1 = l_todRegs.tod_pri_port_1_ctrl_reg.getWord(0); + o_todChipData.regs.scrp0 = l_todRegs.tod_sec_port_0_ctrl_reg.getWord(0); + o_todChipData.regs.scrp1 = l_todRegs.tod_sec_port_1_ctrl_reg.getWord(0); + o_todChipData.regs.spcr = l_todRegs.tod_s_path_ctrl_reg.getWord(0); + o_todChipData.regs.ipcr = l_todRegs.tod_i_path_ctrl_reg.getWord(0); + o_todChipData.regs.psmscr = l_todRegs.tod_pss_mss_ctrl_reg.getWord(0); + o_todChipData.regs.ccr = l_todRegs.tod_chip_ctrl_reg.getWord(0); +} + +} //end of namespace diff --git a/src/usr/isteps/istep18/TodProc.H b/src/usr/isteps/istep18/TodProc.H new file mode 100755 index 000000000..b020378f2 --- /dev/null +++ b/src/usr/isteps/istep18/TodProc.H @@ -0,0 +1,410 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodProc.H $ */ +/* */ +/* 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 */ +#ifndef TODPROC_H +#define TODPROC_H + +/** + * @file TodProc.H + * + * @brief Contains TodProc class declaration + * TodProc class encapsulates a proc chip target with other attributes + * that are necessary to define the proc chip in a TOD topology + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include "proc_tod_utils.H" +#include "TodTypes.H" +#include "TodSvcUtil.H" + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Forward declarations +//------------------------------------------------------------------------------ +struct TodChipData; +class TodDrawer; +class TodProc; + +//------------------------------------------------------------------------------ +//Typedefs +//------------------------------------------------------------------------------ +typedef std::list<TodProc*> TodProcContainer; +typedef std::list<tod_topology_node*> TodTopologyNodeContainer; + +/** + * @class TodProc + * + * @brief TodProc class encapsulates a proc chip target with other + * attributes that helps to identify the position of proc chip in a + * TOD netwok and also define its connection with other proc chips + */ +class TodProc +{ +public: + //Specify proc master type : + //TOD master/drawer master + enum ProcMasterType + { + NOT_MASTER = 0x00, + TOD_MASTER = 0x01, + DRAWER_MASTER = 0x02 + }; + + /** + * @brief Constructor + * + * @param[in] i_procTarget + * Pointer to proc target + * + * @param[in] i_parentDrawer + * Pointer to TOD drawer in which this proc is contained + */ + TodProc(const TARGETING::Target* i_procTarget, + const TodDrawer* i_parentDrawer); + + /** + * @brief Destructor + */ + ~TodProc(); + + /** + * @brief The method will try to connect TodProc object, for which the + * method has been called to the TodProc object specificed in + * destination argument. + * + * @par Detailed Description: + * While creating the TOD topology TodTopologyManager will connect + * TodProc objects to the topology if they + * physically connect over A/X bus, to a TodProc object + * that is already part of the topology and also valid candidate for + * connecting the TodProc object under consideration. + * + * The process of connecting processors starts with MDMT and will + * continue till all the processors are connected. + * At each step TodTopologyManager will make call to connect + * method. This method will check if processor chip owned by + * TodProc object (for which the method is called ) is physically + * connected to the destination (passed as argument), over the bus type + * specified in argument to the method. + * + * If they connect then the i_bus_rx and i_bus_tx members of + * iv_tod_node_data will be filled up for the destination object + * such that + * i_bus_rx == The bus on destination object that connects to the + * this proc + * i_bus_tx == The bus on this proc that connects to the + * destination + * + * @param[in] i_destination, Pointer to destination TodProc object + * that has to be connected. + * + * @param[in] i_busChipUnitType, Type of the bus (A/X) for which connection + * has to be determined + * + * @param[out] o_isConnected, this parameter will be set to true if + * source and destination connect over the specified bus type. Before + * looking for o_isConnected the caller should check for returned error + * log handle and only if it is NULL o_isConnected should be considered. + * + * @return Error log handle, indicates status of request + * @retval NULL indicates that connect method's algorithm executed + * successfully, however in order to know if two processor objects + * connect over the specified bus or not o_isConnected has to be + * examined. + * @retval !NULL indicates that method connect could not be completed + * successfully. In this case o_isConnected should be ignored. + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t connect( + TodProc* i_destination, + const TARGETING::TYPE i_busChipUnitType, + bool& o_isConnected); + + /** + * @brief This is a helper method for connect, that will pick a value + * from proc_tod_setup_bus enum corresponding to the bus type and + * the port specified as argument + * + * @param[in] i_busChipUnitType , This will indicate A/X bus type + * + * @param[in] i_busPort , The port of the bus + * + * @param[out] o_busId , proc_tod_setup_bus enum member corresponding to + * the bus type and bus port specified as parameter. Before looking for + * o_busId caller should look for returned error handle and only if it + * is NULL, o_busId should be considered. + * + * @return Error log handle, indicates status of request + * @retval NULL, indicates o_busId was successfully found + * @retval !NULL, indicates that o_busId could not be found possibly + * because specified bus type and port combination is not supported + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t getBusPort( + const TARGETING::TYPE i_busChipUnitType, + const uint32_t i_busPort, + proc_tod_setup_bus& o_busId) const; + + /** + * @brief Method to create an errlHndl_t object for + * TOD_UNSUPPORTED_BUSTYPE + * + * @par Detailed Description: + * This error will be logged by a method if it finds that a particular + * bus type is not supported on TOD topology. + * + * @param[in] i_busChipUnitType, Type of bus that is not supported + * + * @param[out] io_errHdl + * On input this parameter will be either NULL or pointing to + * an existing error handle. + * On output this parameter will either have a newly created handle + * assigned to it ( If input parameter was NULL ) or a new SRC will be + * appened to existing error handle ( If the input was not NULL ) + * + * @return N/A + */ + void logUnsupportedBusType(const int32_t i_busChipUnitType, + errlHndl_t& io_errHdl) const; + + /** + * @brief Method to create an errlHndl_t object for + * TOD_UNSUPPORTED_BUSPORT + * + * @par Detailed Description: + * This error will be logged by getBusPort if it finds that the input + * bus port is not supported for a specified bus type, from + * TOD topology point of view. + * + * @param[in] i_busPort , Type of bus that is not currently supported. + * + * @param[out] io_errHdl + * On input this parameter will be either NULL or pointing to + * an existing error handle. + * On output this parameter will either have a newly created handle + * assigned to it ( If input parameter was NULL ) or a new SRC will be + * appened to existing error handle ( If the input was not NULL ) + * + * @return N/A + */ + void logUnsupportedBusPort( + const int32_t i_busPort, + const int32_t i_busChipUnitType, + errlHndl_t& io_errHdl) const; + + /** + * @brief Add a child TodProc to this (adds to iv_childrenList). + * Added child will receive TOD signal from the processor + * represented by this TodProc object. + * + * @param[in] i_child + * Pointer to child TodProc + * + * @return N/A + */ + void addChild(TodProc* i_child); + + /** + * @brief Setter method for iv_masterType + * + * @param[in] i_masterType + * Parameter to indicate the master type + * + * @return N/A + */ + void setMasterType(const ProcMasterType i_masterType); + + /** + * @brief Getter method for iv_masterType + * + * @return ProcMasterType, value of iv_masterType + */ + ProcMasterType getMasterType() const ; + + /** + * @brief Getter for TOD registers for this proc + * Check proc_tod_utils.H : proc_tod_setup_conf_regs for the list of + * registers. The registers are updated by the TOD HWP. + * + * @param[out] o_todRegs + * container of TOD registers + * + * @return N/A + */ + void getTodRegs(proc_tod_setup_conf_regs& o_todRegs) const; + + /** + * @brief This method will populate the TodChipData object passed as + * input with the TOD register values of the this proc. + * + * @param[out] o_todChipData + * The TodChipData object in which data has to be output + * + * @return NA + * + */ + void setTodChipData(TodChipData& o_todChipData) const; + + /** + * @brief Getter method for iv_tod_node_data + * + * @return tod_topology_node*, pointer to this proc's topology + * node structure + */ + tod_topology_node* getTopologyNode() + { + return iv_tod_node_data; + } + + /** + * @brief Getter method for iv_parentDrawer + * + * @return TodDrawer*, pointer to this proc's containing TOD drawer + */ + const TodDrawer* getParentDrawer() const + { + return iv_parentDrawer; + } + + /** + * @brief Getter method for tod_topology_node::i_bus_rx data member , + * i_bus_rx is the fabric bus over which current processor receives + * signals from its parent + * + * @return proc_tod_setup_bus bus type and port + */ + proc_tod_setup_bus getBusIn() const + { + return iv_tod_node_data->i_bus_rx; + } + + /** + * @brief Getter method for tod_topology_node::i_bus_tx data member , + * i_bus_tx is the bus over which signal is transmitted by the + * parent of this processor + * + * @return proc_tod_setup_bus bus type and port + */ + proc_tod_setup_bus getBusOut() const + { + return iv_tod_node_data->i_bus_tx; + } + + /** + * @brief Getter method for iv_procTarget + * + * @return Target pointer for this proc + */ + const TARGETING::Target* getTarget() const + { + return iv_procTarget; + } + + /** + * @brief Getter method for iv_childrenList. + * see also addChild + * + * @param[out] o_childrenList + * List of pointers to children TodProc + * + * @return N/A + */ + void getChildren(TodProcContainer& o_childrenList) const + { + o_childrenList = iv_childrenList; + } + + /** + * @brief Sets bus in and bus out + * + * @return N/A + */ + void setConnections(const proc_tod_setup_bus i_parentBusOut, + const proc_tod_setup_bus i_thisBusIn) + { + iv_tod_node_data->i_bus_tx = i_parentBusOut; + iv_tod_node_data->i_bus_rx = i_thisBusIn; + } + +private: + /* + * @brief Helper method to initialize the bus parameters + * (iv_xbusTargetList and iv_abusTargetList) and iv_tod_node_data, for + * this object. + * It will be called from the constructor. + * + * @return N/A + */ + void init(); + + //Target pointer to the processor chip, that is been encapsulated in + //the TodProc object + const TARGETING::Target* iv_procTarget; + + //Pointer to the parent TodDrawer object to which this processor + //belong + const TodDrawer * iv_parentDrawer; + + //List of X bus targets for this processor + TARGETING::TargetHandleList iv_xbusTargetList; + + //List of A bus targets for this processor + TARGETING::TargetHandleList iv_abusTargetList; + + //List of children that will receive TOD signal from this processor belongs + TodProcContainer iv_childrenList; + + //Pointer to the tod_topology_node object that defines TOD specific + //attributes for this processor chip, the reason this has been kept + //seperate is this data structure is shared across HB and HW procedure + tod_topology_node* iv_tod_node_data; + + //Data member to indicate if this processor is either a TOD_MASTER or + //DRAWER_MASTER + ProcMasterType iv_masterType; +}; + +}//end of namespace + +#endif // TODPROC_H diff --git a/src/usr/isteps/istep18/TodSvc.C b/src/usr/isteps/istep18/TodSvc.C new file mode 100755 index 000000000..6b03e0355 --- /dev/null +++ b/src/usr/isteps/istep18/TodSvc.C @@ -0,0 +1,298 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodSvc.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 TodSvc.C + * + * @brief Implements the TodSvc class that provides the Time Of Day service + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <p8_scom_addresses.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <tod_init/tod_init_reasoncodes.H> +#include "TodTopologyManager.H" +#include "TodTrace.H" +#include "TodSvcUtil.H" +#include "TodHwpIntf.H" +#include "TodControls.H" +#include "TodSvc.H" +#include "proc_tod_utils.H" + +namespace TOD +{ + +TodSvc & TodSvc::getTheInstance() +{ + return Singleton<TodSvc>::instance(); +} + +//****************************************************************************** +//TodSvc::todSetup +//****************************************************************************** +errlHndl_t TodSvc::todSetup() +{ + TOD_ENTER("todSetup"); + + errlHndl_t l_errHdl = NULL; + bool l_isTodRunning = false; + TodTopologyManager l_primary(TOD_PRIMARY); + TodControls & l_Tod = TodControls::getTheInstance(); + + do + { + l_errHdl = l_Tod.isTodRunning(l_isTodRunning); + if ( l_errHdl ) + { + TOD_INF("Call to isTodRunning failed , cannot create topology"); + break; + } + + if ( l_isTodRunning ) + { + TOD_ERR("Cannot create TOD topology while the Chip TOD logic" + "is running "); + /*@ + * @errortype + * @reasoncode TOD_INVALID_ACTION + * @moduleid TOD_SETUP + * @userdata1 ChipTOD logic HW state , 1=running , zero otherwise + * @devdesc Error: can not create TOD topology when TOD + * HW is running + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_SETUP, + TOD_INVALID_ACTION, + l_isTodRunning ? 1 : 0, 0); + break; + } + + l_Tod.destroy(TOD_PRIMARY); + l_Tod.destroy(TOD_SECONDARY); + + //We're going to setup TOD for this IPL + //1) Build a set of datastructures to setup creation of the TOD + //topologies. + l_errHdl = l_Tod.buildTodDrawers(TOD_PRIMARY); + if(l_errHdl) + { + TOD_ERR("TOD setup failure: failed to build TOD drawers " + "for primary topology."); + break; + } + + //2) Ask the topology manager to setup the primary topology + l_errHdl = l_primary.create(); + if(l_errHdl) + { + TOD_ERR("TOD setup failure: failed to create primary topology."); + break; + } + l_primary.dumpTopology(); + + //3) Call hardware procedures to configure the TOD hardware logic for + //the primary topology and to fill up the TOD regs. + l_errHdl = todSetupHwp(TOD_PRIMARY); + if(l_errHdl) + { + TOD_ERR("TOD setup failure: primary topology setup HWP."); + break; + } + l_errHdl = todSaveRegsHwp(TOD_PRIMARY); + if(l_errHdl) + { + TOD_ERR("TOD setup failure: primary topology register save HWP."); + break; + } + + //Primary successfully configured + l_Tod.setConfigStatus(TOD_PRIMARY,true); + + //Build datastructures for secondary topology + l_errHdl = l_Tod.buildTodDrawers(TOD_SECONDARY); + if(l_errHdl) + { + TOD_ERR("TOD setup failure: failed to build TOD drawers " + "for secondary topology."); + //Report the error as informational - loss of redundancy, + //but no loss of TOD function. + errlCommit( l_errHdl, TOD_COMP_ID ); + break; + } + + //4) Ask the topology manager to setup the secondary topology + TodTopologyManager l_secondary(TOD_SECONDARY); + l_errHdl = l_secondary.create(); + if(l_errHdl) + { + TOD_ERR("TOD setup failure: failed to create secondary topology."); + //Report the error as informational - loss of redundancy, + //but no loss of TOD function. + errlCommit( l_errHdl, TOD_COMP_ID ); + break; + } + l_secondary.dumpTopology(); + + //5) Call hardware procedures to configure the TOD hardware logic for + //the secondary topology and to fill up the TOD regs. + l_errHdl = todSetupHwp(TOD_SECONDARY); + if(l_errHdl) + { + TOD_ERR("TOD setup failure: secondary topology setup HWP."); + //Report the error as informational - loss of redundancy, + //but no loss of TOD function. + errlCommit( l_errHdl, TOD_COMP_ID ); + break; + } + + //Secondary successfully configured + l_Tod.setConfigStatus(TOD_SECONDARY,true); + + //Need to call this again if the secondary topology got set up, + //that would have updated more regs. + l_errHdl = todSaveRegsHwp(TOD_PRIMARY); + if(l_errHdl) + { + TOD_ERR("TOD setup failure: primary topology register save HWP."); + break; + } + + //Done with TOD setup + }while(0); + + if((NULL == l_errHdl) && + (false == l_isTodRunning )) + { + l_primary.dumpTodRegs(); + + //If we are then atleast Primary or both configurations were + //successfully setup. If both were successfuly setup then we can use + //writeTodProcData for either of them else we should call + //writeTodProcData for only primary. + //Ultimately it should be good enough to call the method for Primary + l_errHdl = l_Tod.writeTodProcData(TOD_PRIMARY); + if(l_errHdl) + { + TOD_ERR("TOD setup failure:Failed to write topology register data" + " to the file."); + } + } + + TOD_EXIT("todSetup. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodSvc::todInit +//****************************************************************************** +errlHndl_t TodSvc::todInit() +{ + return todInitHwp(TOD_PRIMARY); +} + +//****************************************************************************** +//TodSvc::readTod +//****************************************************************************** +errlHndl_t TodSvc::readTod(uint64_t& o_todValue) const +{ + TOD_ENTER("readTod"); + + errlHndl_t l_errHdl = NULL; + + do + { + //Get the MDMT + TodProc* l_pMDMT = + TodControls::getTheInstance().getMDMT(TOD_PRIMARY); + if(NULL == l_pMDMT) + { + TOD_ERR("MDMT not found"); + /*@ + * @errortype + * @reasoncode TOD_NO_MASTER_PROC + * @moduleid TOD_READ + * @devdesc MDMT could not be found + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_READ, + TOD_NO_MASTER_PROC); + break; + } + + //SCOM the TOD value reg + ecmdDataBufferBase o_todValueBuf(64); + l_errHdl = todGetScom(l_pMDMT->getTarget(), + TOD_VALUE_REG_00040020, + o_todValueBuf); + if(l_errHdl) + { + TOD_ERR("TOD read error: failed to SCOM TOD value register " + "address 0x%.16llX on MDMT 0x%.8X.", + TOD_VALUE_REG_00040020, + l_pMDMT->getTarget()->getAttr<TARGETING::ATTR_HUID>()); + break; + } + o_todValue = o_todValueBuf.getDoubleWord(0); + + TOD_INF("TOD value : 0x%.16llx", o_todValue ); + + }while(0); + + TOD_EXIT("readTod. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodSvc::TodSvc +//****************************************************************************** +TodSvc::TodSvc() +{ + TOD_ENTER("TodSvc constructor"); + + TOD_EXIT("TodSvc constructor"); +} + +//****************************************************************************** +//TodSvc::~TodSvc +//****************************************************************************** +TodSvc::~TodSvc() +{ + TOD_ENTER("TodSvc destructor"); + + //Free up held memory + TodControls::getTheInstance().destroy(TOD_PRIMARY); + TodControls::getTheInstance().destroy(TOD_SECONDARY); + + TOD_EXIT("TodSvc destructor"); +} + +} //namespace TOD diff --git a/src/usr/isteps/istep18/TodSvc.H b/src/usr/isteps/istep18/TodSvc.H new file mode 100755 index 000000000..11b052857 --- /dev/null +++ b/src/usr/isteps/istep18/TodSvc.H @@ -0,0 +1,196 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodSvc.H $ */ +/* */ +/* 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 */ +#ifndef TODSVC_H +#define TODSVC_H + +/** + * @file TodSvc.H + * + * @brief Defines the TodSvc class that provides the Time Of Day service + * The TodSvc class is a thread-safe singleton. + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <util/singleton.H> + +namespace TOD +{ + +/** + * @class TodSvc + * + * @brief Time Of Day service entry point + */ +class TodSvc +{ +public: + + /** + * @brief Get singleton instance of this class. + * + * @return the (one and only) instance of TodSvc + */ + static TodSvc& getTheInstance(); + + /** + * @brief This interface should be called during IPL to setup the + * time of day logic on the P8 processors sitting on the system. + * + * @par Detailed Description: + * All processors of a symmetric multiprocessor model must appear to + * have the same time. This is in order to ensure that time stamps + * accurately reflect the sequence of events occuring on these procs. + * + * To achieve this, each proc has a hardware time of day (TOD) logic. + * A TOD oscillator(a fixed frequency clock) can send out signals to + * keep the TOD clocks on the various procs in sync. + * + * Since the procs are connected by fabric buses, a signal sent out by + * the oscillator will reach the procs at different times. Besides, + * there are multiple bus paths to propagate TOD signals. To solve these + * issues, we (FSP HWSV) need to create a TOD topology. A TOD topology + * has a single Master Drawer Master TOD processor chip (MDMT), which + * receives input directly from the oscillator. The MDMT will propagate + * signals to other procs, MDSTs (Master Drawer Slave TOD Chips), + * in the fabric node/physical drawer in which it's contained, via X + * buses. This group of procs will be part of a TOD drawer. Inter TOD + * drawer communications will be via A buses. Via A bus, the MDMT will + * propagate TOD signals to designated masters in other drawers, SDMTs + * (Slave Drawer Master TOD Chips). In the their respective TOD + * drawers, SDMTs, like the MDMT, will use X buses to propagate signals + * to other SDSTs (Slave Drawer Slave TOD Chips). + * + * We will create a primary topology and a secondary topology, for + * redundancy. Once we create the topologies, the same will be passed + * on to a hardware procedure. The procedure will set bits in the TOD + * registers of the procs, to indicate the topology. THe procedure will + * also compute "delays", to be introduced to signals sent out by the + * oscillator. MDMT will have the longest delay and the furthest proc + * from the oscillator will have 0 delay. This helps ensuring that TOD + * signals are received at the same wall clock time. + * + * At runtime, PHYP will be able to read the TOD registers and + * determine the TOD topolgies. It will use the primary topology as the + * active topology for timekeeping. On detecting errors in the active + * topology, it can switch to the secondary and ask us to reconfigure a + * backup. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if successful + * @retval !NULL if failed to setup TOD + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + * + * @note TOD setup is not allowed at FSP runtime + * @note Presence of a secondary topology is not critical to + * to TOD functionality, so an error in creating the same + * will be noted but not returned. + */ + errlHndl_t todSetup(); + + /** + * @brief This interface should be called during IPL to set the TOD + * into running state + * + * @return Error log handle indicating the status of the request. + * @retval NULL if successful + * @retval !NULL if failed to setup TOD + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t todInit(); + + /** + * @brief Reads the Time Of Day (TOD) value from the TOD register on + * the processor chip and returns the same. + * + * @par Detailed Description: + * This interface will read the TOD value from the TOD value register. + * We could read this from any of the processor that's part of the + * TOD topology, since the TOD value should be in sync across procs, + * so we'll read this from the MDMT's register. + * + * @param[out] o_todValue + * 64-bit contents of the TOD value register will be copied here + * in a big-endian format. Will be 0 on error. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if successful + * @retval !NULL if failed to read TOD value + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t readTod(uint64_t& o_todValue) const; + +protected: + /** + * @brief Constructor. + * + * @note This is protected so that only SingletonHolder can call. + */ + TodSvc(); + + /** + * @brief Destructor. + * + * @note This is protected so that only SingletonHolder can call. + */ + ~TodSvc(); + +private: + //Disabled copy constructor and assignment operator + TodSvc(const TodSvc& rhs); + TodSvc& operator=(const TodSvc& rhs); + + //Indicates if we've already setup TOD + bool iv_todSetup; +}; + +} //namespace TOD + +#endif //TODSVC_H diff --git a/src/usr/isteps/istep18/TodSvcUtil.C b/src/usr/isteps/istep18/TodSvcUtil.C new file mode 100755 index 000000000..ea00ca90e --- /dev/null +++ b/src/usr/isteps/istep18/TodSvcUtil.C @@ -0,0 +1,270 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodSvcUtil.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 TodSvcUtil.C + * + * @brief This file implements the various utility methods + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <targeting/common/attributes.H> +#include <targeting/common/targetservice.H> +#include <tod_init/tod_init_reasoncodes.H> +#include <devicefw/userif.H> + +#include "TodTrace.H" +#include "TodSvcUtil.H" + +using namespace TARGETING; + +namespace TOD { + +//****************************************************************************** +//logInvalidTodConfig +//****************************************************************************** +void logInvalidTodConfig( + const uint32_t i_config, + errlHndl_t& io_errHdl) +{ + /*@ + * @errortype + * @reasoncode TOD_INVALID_CONFIG + * @moduleid TOD_LOG_INVALID_CONFIG + * @userdata1 The problematic configuration (Primary/Secondary) + * @devdesc Error: Erroneous TOD configuration + * Possible Causes: Programming issue + * Resolution: Development team should be contacted. + */ + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_LOG_INVALID_CONFIG, + TOD_INVALID_CONFIG, + i_config, 0); +} + +//****************************************************************************** +//logUnsupportedOrdinalId +//****************************************************************************** +void logUnsupportedOrdinalId( + const uint32_t i_ordinalId, + errlHndl_t& io_errHdl) +{ + /*@ + * @errortype + * @reasoncode TOD_UNSUPORTED_ORDINALID + * @moduleid TOD_LOG_UNSUPORTED_ORDINALID + * @userdata1 Ordinal Id for which the error is logged + * @devdesc Error: The ordinal Id of one of the TOD procs did not fall + * in the range 0 <= Ordinal Id < getMaxProcsOnSystem + * Possible Causes: TOD logic has not been updated to support + * the latest system type where the no. of processor chips is + * either equal to or more than getMaxProcsOnSystem + * Resolution: Development team should be contacted. + */ + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_LOG_UNSUPORTED_ORDINALID, + TOD_UNSUPORTED_ORDINALID, + i_ordinalId, 0 ); +} + +//****************************************************************************** +//getMaxProcsOnSystem() +//****************************************************************************** +uint32_t getMaxProcsOnSystem() +{ + Target* sys = NULL; + targetService().getTopLevelTarget(sys); + + uint8_t l_maxProcs = 0; + sys->tryGetAttr<ATTR_MAX_PROC_CHIPS_PER_NODE>(l_maxProcs); + + return ( (uint32_t)l_maxProcs ); +} + +//****************************************************************************** +//getMaxPossibleCoresPerProc() +//****************************************************************************** +uint32_t getMaxPossibleCoresPerProc() +{ + Target* sys = NULL; + targetService().getTopLevelTarget(sys); + + uint8_t l_maxCores = 0; + sys->tryGetAttr<ATTR_MAX_EXS_PER_PROC_CHIP>(l_maxCores); + + return ( (uint32_t)l_maxCores ); +} + +//****************************************************************************** +//todGetScom() +//****************************************************************************** +errlHndl_t todGetScom(const TARGETING::Target * i_target, + const uint64_t i_address, + ecmdDataBufferBase & o_data) +{ + uint32_t l_ecmdRc; + errlHndl_t l_err = NULL; + + // Perform SCOM read + uint64_t l_data = 0; + size_t l_size = sizeof(uint64_t); + + l_err = deviceRead((TARGETING::Target *)i_target, + &l_data, + l_size, + DEVICE_SCOM_ADDRESS(i_address)); + + if (!l_err) + { + l_ecmdRc = o_data.setBitLength(64); + l_ecmdRc |= o_data.setDoubleWord(0, l_data); + if (l_ecmdRc) + { + /*@ + * @errortype + * @reasoncode TOD_ECMD_ERROR + * @moduleid TOD_GETSCOM + * @userdata1 return code from ecmdDataBufferBase operation(s) + * @devdesc Scom access error + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_LOG_UNSUPORTED_ORDINALID, + TOD_UNSUPORTED_ORDINALID, + l_ecmdRc, 0 ); + } + } + + return l_err; +} + +//****************************************************************************** +//getFuncNodeTargetsOnSystem +//****************************************************************************** +errlHndl_t getFuncNodeTargetsOnSystem(const TARGETING::Target* + i_pInputTarget, TARGETING::TargetHandleList& + o_functionalNodeTargetList) +{ + TOD_ENTER("getFuncNodeTargetsOnSystem"); + errlHndl_t l_errHdl = NULL; + o_functionalNodeTargetList.clear(); + + do{ + if (i_pInputTarget == NULL ) + { + TOD_ERR("NULL target passed in the call to method " + "getFuncNodeTargetsOnSystem "); + /*@ + * @errortype + * @reasoncode TOD_NULL_INPUT_TARGET + * @moduleid TOD_GETFUNCNODETARGETSONSYSTEM + * @userdata1 HUID of the target that was validated + * @devdesc Scom access error + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_GETFUNCNODETARGETSONSYSTEM, + TOD_NULL_INPUT_TARGET ); + break; + } + + CLASS l_class = i_pInputTarget->getAttr<ATTR_CLASS>(); + TYPE l_type = i_pInputTarget->getAttr<ATTR_TYPE>(); + + if((TARGETING::CLASS_SYS == l_class) && + (TARGETING::TYPE_SYS == l_type))//System target + { + //create the predicate with CLASS_ENC and TYPE_NODE + TARGETING::PredicateCTM + l_nodeFilter(TARGETING::CLASS_ENC,TARGETING::TYPE_NODE); + + //Use PredicateIsFunctional to filter only functional nodes + TARGETING::PredicateIsFunctional l_isFunctional; + TARGETING::PredicatePostfixExpr l_functionalAndNodeFilter; + + l_functionalAndNodeFilter.push(&l_nodeFilter). + push(&l_isFunctional).And(); + + //Create an iterator to loop over the selected targets + TARGETING::TargetRangeFilter l_pFuncNode( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_functionalAndNodeFilter ); + + for ( ; l_pFuncNode ; ++l_pFuncNode) + { + o_functionalNodeTargetList.push_back(*l_pFuncNode); + } + } + else if ((TARGETING::CLASS_ENC == l_class ) && + (TARGETING::TYPE_NODE == l_type )) //Node target + { + if (i_pInputTarget->getAttr<ATTR_HWAS_STATE>().functional) + { + o_functionalNodeTargetList.push_back( + const_cast<TARGETING::Target*>(i_pInputTarget)); + } + else + { + TOD_ERR("Failed to get the functional state for target 0x%08X", + i_pInputTarget->getAttr<TARGETING::ATTR_HUID>()); + break; + } + } + else + { + TOD_ERR("Invalid target 0x%08X passed in the call to method " + "getFuncNodeTargetsOnSystem ", + i_pInputTarget->getAttr<TARGETING::ATTR_HUID>()); + /*@ + * @errortype + * @reasoncode TOD_INVALID_TARGET + * @moduleid TOD_GETFUNCNODETARGETSONSYSTEM + * @userdata1 HUID of the target that was validated + * @devdesc Scom access error + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_GETFUNCNODETARGETSONSYSTEM, + TOD_INVALID_TARGET, + i_pInputTarget->getAttr<TARGETING::ATTR_HUID>()); + break; + } + }while(0); + + if ( l_errHdl ) + { + o_functionalNodeTargetList.clear(); + } + + TOD_EXIT("getFuncNodeTargetsOnSystem. errHdl = %p", l_errHdl); + return l_errHdl; +} + +} //End of namespace TOD diff --git a/src/usr/isteps/istep18/TodSvcUtil.H b/src/usr/isteps/istep18/TodSvcUtil.H new file mode 100755 index 000000000..aca27ae52 --- /dev/null +++ b/src/usr/isteps/istep18/TodSvcUtil.H @@ -0,0 +1,163 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodSvcUtil.H $ */ +/* */ +/* 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 TodSvcUtil.H + * + * @brief This file declares the various utility methods + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#ifndef TODSVCUTIL_H +#define TODSVCUTIL_H + +#include <errl/errlentry.H> +#include <ecmddatabuffer/ecmdDataBufferBase.H> + +namespace TOD +{ + /** + * @brief Method to create an errlHndl_t object for + * TOD_INVALID_CONFIG error + * + * @par Detailed Description: + * This will be logged if during the course of TOD operation an + * anomaly was found with the topology configuration or + * its related data. + * + * @param[in] i_config + * The problematic configuration Primary/Secondary + * + * @param[out] io_errHdl + * On input this parameter will be either NULL or pointing to + * an existing error handle. + * On output this parameter will either have a newly created handle + * assigned to it ( If input parameter was NULL ) or a new SRC will be + * appened to existing error handle ( If the input was not NULL ) + * @return NA + */ + void logInvalidTodConfig(const uint32_t i_config, + errlHndl_t& io_errHdl); + + /** + * @brief Method to create an errlHndl_t object for + * TOD_UNSUPPORTED_ORDINALID + * + * @par Detailed Description: + * The ordinal Id's of TOD procs should fall within the range of 0 + * <= Ordinal Id < getMaxProcsOnSystem. + * getMaxProcsOnSystem defines static count of the array of + * hwsvTodChipData structures that will be written in the file + * shared between HWSV and HDAT. + * Each hwsvTodChipData structure contains TOD chip register data + * for a specific chip. + * This error will be logged if at any point of time because of + * changes in system configuration the no. of proc chips becomes + * equal to or more than getMaxProcsOnSystem, and corresponding + * support still does not exist in TOD code and HDAT + * + * @param[in] i_ordId + * The ordinal Id that was found to be unsupported + * + * @param[out] io_errHdl + * On input this parameter will be either NULL or pointing to + * an existing error handle. + * On output this parameter will either have a newly created handle + * assigned to it ( If input parameter was NULL ) or a new SRC will be + * appened to existing error handle ( If the input was not NULL ) + * @return NA + * + */ + void logUnsupportedOrdinalId(const uint32_t i_ordId, + errlHndl_t& io_errHdl); + + /** + * + * @brief This method finds out the maximum number of proc chips that are + * possible on fully configured system of this type + * + * @return Count of procs + * The method should succeed always + */ + uint32_t getMaxProcsOnSystem(); + + + /** + * + * @brief This method finds out the maximum number of cores that is + * possible per proc for fully configured system of this type + * + * @return Count of cores + * The method should succeed always + */ + uint32_t getMaxPossibleCoresPerProc(); + + /** + * @brief This method read the scom register + * + * @param[in] i_target : target object + * @param[in] i_address : SCOM register address + * + * @param[out] o_data : content of the register if no error + * + * @return errlHndl_t : NULL if ok. Otherwise, there is an error + */ + errlHndl_t todGetScom(const TARGETING::Target * i_target, + const uint64_t i_address, + ecmdDataBufferBase & o_data); + + /** + * + * @brief This method will get the list of functional node target + * pointers for the supplied target that can be a node or system + * type. + * + * @par Detailed Description: + * If the input target is a system level target then target + * pointers for all the functional nodes in system will be + * collected. + * If the target sent is of node type then the method will simply + * push back the target that has been passed as argument, provided + * it is functional + * + * @param[in] i_pInputTarget + * Target sent as input to this method + * + * @param[out] o_functionalNodeTargetList + * List of functional node targets collected by the method + * @return Error log handle to carry back status of request + * @retval !NULL Indicates an error in collecting the node target.This + * can happen if input target is neither of system/node + * type. In error case o_functionalNodeTargetList will be empty. + * @retval NULL Indicates that there was no error in getting the targets. + */ + errlHndl_t getFuncNodeTargetsOnSystem(const TARGETING::Target * i_target, + TARGETING::TargetHandleList& o_functionalNodeTargetList); + +} //End of namespace TOD + +#endif diff --git a/src/usr/isteps/istep18/TodTopologyManager.C b/src/usr/isteps/istep18/TodTopologyManager.C new file mode 100755 index 000000000..4a7d09435 --- /dev/null +++ b/src/usr/isteps/istep18/TodTopologyManager.C @@ -0,0 +1,619 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodTopologyManager.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 TodTopologyManager.C + * + * @brief TOD Topology Manager class implementation. Responsible for + * creating/modifying the primary and secondary topologies. + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <targeting/common/target.H> +#include <targeting/common/targetservice.H> +#include <tod_init/tod_init_reasoncodes.H> +#include "TodTopologyManager.H" +#include "TodControls.H" +#include "TodDrawer.H" +#include "TodProc.H" +#include "TodTrace.H" + +using namespace TARGETING; + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Global defines +//------------------------------------------------------------------------------ +//Strings used in topology/register dump to fsp-trace +static const char* TOD_PRIMARY_TOPOLOGY = "PRIMARY"; +static const char* TOD_SECONDARY_TOPOLOGY = "SECONDARY"; +static const char* NO_BUS = "NONE"; +static const char* X_BUS_0 = "XBUS0"; +static const char* X_BUS_1 = "XBUS1"; +static const char* X_BUS_2 = "XBUS2"; +static const char* X_BUS_3 = "XBUS3"; +static const char* A_BUS_0 = "ABUS0"; +static const char* A_BUS_1 = "ABUS1"; +static const char* A_BUS_2 = "ABUS2"; + +//****************************************************************************** +//TodTopologyManager::TodTopologyManager +//****************************************************************************** +TodTopologyManager::TodTopologyManager( + const proc_tod_setup_tod_sel i_topologyType) : + iv_topologyType(i_topologyType) +{ + TOD_ENTER("Topology type 0X%.8X", i_topologyType); + + TOD_EXIT("TodTopologyManager constructor"); +} + +//****************************************************************************** +//TodTopologyManager::~TodTopologyManager +//****************************************************************************** +TodTopologyManager::~TodTopologyManager() +{ + TOD_ENTER("TodTopologyManager destructor"); + + TOD_EXIT("TodTopologyManager destructor"); +} + +//****************************************************************************** +//TodTopologyManager::create +//****************************************************************************** +errlHndl_t TodTopologyManager::create() +{ + TOD_ENTER("create"); + + errlHndl_t l_errHdl = NULL; + + //The topology creation algorithm goes as follows : + //1)Pick the MDMT. + //2)In the master TOD drawer (the one in which MDMT lies), + //wire the procs together. + //3)Connect the MDMT to one processor in each of the slave TOD drawers + //(the TOD drawers other than the master TOD drawer) + //4)Wire the procs in the slave TOD drawers. + do + { + //1) Pick the MDMT. + l_errHdl = TodControls::getTheInstance().pickMdmt(iv_topologyType); + if(l_errHdl) + { + TOD_ERR("Couldn't pick MDMT."); + break; + } + + //Get the TOD drawers + TodDrawerContainer l_todDrwList; + TodControls::getTheInstance().getDrawers(iv_topologyType, + l_todDrwList); + //Find the TOD system master drawer (the one in which the MDMT lies) + TodDrawer* l_pMasterDrawer = NULL; + for(TodDrawerContainer::const_iterator l_itr = l_todDrwList.begin(); + l_itr != l_todDrwList.end(); + ++l_itr) + { + if((*l_itr)->isMaster()) + { + l_pMasterDrawer = *l_itr; + TOD_INF("TOD drawer(0x%.2X) is the master drawer", + l_pMasterDrawer->getId()); + break; + } + } + if(NULL == l_pMasterDrawer) + { + TOD_ERR("TOD master drawer not found"); + /*@ + * @errortype + * @reasoncode TOD_CREATION_ERR + * @moduleid TOD_TOPOLOGY_CREATE + * @userdata1 Topology type : primary/secondary + * @devdesc TOD master drawer not found + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_TOPOLOGY_CREATE, + TOD_CREATION_ERR, + iv_topologyType ); + break; + } + + //2)In the master TOD drawer, wire the procs together. + l_errHdl = wireProcs(l_pMasterDrawer); + if(l_errHdl) + { + TOD_ERR("Couldn't wire one or more processors for " + "the master TOD drawer(0x%.2X)", + l_pMasterDrawer->getId()); + break; + } + + //3)Connect the MDMT to one processor in each of the TOD drawers + //other than the master TOD drawer. + for(TodDrawerContainer::iterator l_itr = l_todDrwList.begin(); + l_itr != l_todDrwList.end(); + ++l_itr) + { + if((*l_itr)->isMaster()) + { + //This is the master TOD drawer, we are connecting other + //TOD drawers to this. + continue; + } + l_errHdl = wireTodDrawer(*l_itr); + if(l_errHdl) + { + TOD_ERR("Couldn't wire TOD drawer(0x%.2X) to MDMT.", + (*l_itr)->getId()); + break; + } + } + if(l_errHdl) + { + break; + } + + //4)Wire the procs in the other TOD drawers (i.e other than the master) + for(TodDrawerContainer::const_iterator l_itr = + l_todDrwList.begin(); + l_itr != l_todDrwList.end(); + ++l_itr) + { + if((*l_itr)->isMaster()) + { + //We've done this already for the master TOD drawer + continue; + } + l_errHdl = wireProcs(*l_itr); + if(l_errHdl) + { + TOD_ERR("Couldn't wire one or more processors for " + "TOD drawer(0x%.2X).", + (*l_itr)->getId()); + break; + } + } + if(l_errHdl) + { + break; + } + }while(0); + + TOD_EXIT("create. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::wireProcs +//****************************************************************************** +errlHndl_t TodTopologyManager::wireProcs(const TodDrawer* i_pTodDrawer) +{ + TOD_ENTER("wireProcs"); + + errlHndl_t l_errHdl = NULL; + + do + { + if(NULL == i_pTodDrawer) + { + TOD_ERR("TOD drawer not specified"); + /*@ + * @errortype + * @reasoncode TOD_CREATION_ERR_NO_DRAWER + * @moduleid TOD_WIRE_PROCS + * @userdata1 Topology type : primary/secondary + * @devdesc TOD drawer not specified + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_PROCS, + TOD_CREATION_ERR_NO_DRAWER, + iv_topologyType ); + break; + } + + TOD_INF("TOD drawer id %d", i_pTodDrawer->getId()); + + //The algorithm to wire procs in a TOD drawer goes as follows : + /* + Have a "sources" list which initially has only the drawer master + Have a "targets" list which has all the other procs. + While the sources list isn't empty, for each source "s" in sources + For each target "t" in targets + If s connects t via X bus + Remove t from targets and add it to sources, + since it's now a potential source + If targets isn't empty, we couldn't wire one or more procs + */ + + //Get the targets + TodProcContainer l_targetsList = i_pTodDrawer->getProcs(); + + //Check if we have procs to wire in the first place + if(l_targetsList.empty()) + { + TOD_INF("Nothing to wire on TOD drawer(0x%.2X)", + i_pTodDrawer->getId()); + break; + } + + //Push the drawer master onto the sources list + TodProc* l_pDrawerMaster = NULL; + l_errHdl = i_pTodDrawer->findMasterProc(l_pDrawerMaster); + if(l_errHdl) + { + TOD_ERR("Master TOD proc not set for TOD drawer(0x%.2X)", + i_pTodDrawer->getId()); + break; + } + TodProcContainer l_sourcesList; + l_sourcesList.push_back(l_pDrawerMaster); + + //Start connecting targets to sources + TodProcContainer::iterator l_sourceItr = l_sourcesList.begin(); + TodProcContainer::iterator l_targetItr; + bool l_connected = false; + while((NULL == l_errHdl) && (l_sourcesList.end() != l_sourceItr)) + { + for(l_targetItr = l_targetsList.begin(); + l_targetItr != l_targetsList.end();) + { + l_errHdl = (*l_sourceItr)->connect(*l_targetItr, + TARGETING::TYPE_XBUS, + l_connected); + if(l_errHdl) + { + TOD_ERR("Error tying to connect target 0x%.8X " + "to source 0x%.8X.", + (*l_targetItr)->getTarget()->getAttr<ATTR_HUID>(), + (*l_sourceItr)->getTarget()->getAttr<ATTR_HUID>()); + break; + } + if(l_connected) + { + //Prefer push_back to push_front since in case of multiple + //X bus path alternatives, the paths and hence the TOD + //delays will be shorter. + l_sourcesList.push_back(*l_targetItr); + (*l_sourceItr)->addChild(*l_targetItr); + l_targetItr = l_targetsList.erase(l_targetItr); + } + else + { + ++l_targetItr; + } + } + ++l_sourceItr; + } + if(l_errHdl) + { + break; + } + if(false == l_targetsList.empty()) + { + //We couldn't connect one or more procs in this drawer + TOD_ERR("TOD drawer(0x%.2X) has one or more procs not connected. " + "0x%.8X is the first such proc.", + i_pTodDrawer->getId(), + (*(l_targetsList.begin()))->getTarget()->getAttr<ATTR_HUID>()); + /*@ + * @errortype + * @reasoncode TOD_CREATION_ERR + * @moduleid TOD_WIRE_PROCS + * @userdata1 DrawerId = bit[0:31], Topology type = bit[32:63] + * @userdata2 HUID of first disconnected proc + * @devdesc TOD drawer has one or more disconnected procs + */ + uint64_t l_data = i_pTodDrawer->getId(); + l_data <<= 32; + l_data |= iv_topologyType; + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_PROCS, + TOD_CREATION_ERR, + l_data, + (*(l_targetsList.begin()))->getTarget()-> + getAttr<ATTR_HUID>()); + break; + } + }while(0); + + TOD_EXIT("wireProcs. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::wireTodDrawer +//****************************************************************************** +errlHndl_t TodTopologyManager::wireTodDrawer(TodDrawer* i_pTodDrawer) +{ + TOD_ENTER("wireTodDrawer"); + + errlHndl_t l_errHdl = NULL; + + do + { + if(NULL == i_pTodDrawer) + { + TOD_ERR("TOD drawer not specified"); + /*@ + * @errortype + * @reasoncode TOD_CREATION_ERR + * @moduleid TOD_WIRE_DRAWERS + * @userdata1 Topology type : primary/secondary + * @devdesc TOD drawer not specified + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_CREATION_ERR, + iv_topologyType); + break; + } + + TOD_INF("TOD drawer id %d", i_pTodDrawer->getId()); + + //The algorithm to wire the slave TOD drawers to the mater TOD + //drawer (to the MDMT to be specific) goes as follows : + /* + For each slave TOD drawer "d" + For each proc "p" in d + If MDMT connects p via A bus + we are done, exit + */ + + //Get the MDMT + TodProc* l_pMDMT = + TodControls::getTheInstance().getMDMT(iv_topologyType); + if(NULL == l_pMDMT) + { + TOD_ERR("MDMT not found for topology type 0X%.8X", + iv_topologyType); + /*@ + * @errortype + * @reasoncode TOD_NO_MASTER_PROC + * @moduleid TOD_WIRE_DRAWERS + * @userdata1 Topology type : primary/secondary + * @devdesc MDMT could not be found + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_NO_MASTER_PROC, + iv_topologyType); + break; + } + + //Get the procs in this TOD drawer + TodProcContainer l_procs = i_pTodDrawer->getProcs(); + + //Check if we have procs + if(l_procs.empty()) + { + TOD_INF("Nothing to wire on TOD drawer(0x%.2X)", + i_pTodDrawer->getId()); + break; + } + + //Find a proc which connects to the MDMT via A bus + bool l_connected = false; + TodProcContainer::iterator l_itr; + for(l_itr = l_procs.begin(); + l_itr != l_procs.end(); + ++l_itr) + { + l_errHdl = l_pMDMT->connect(*l_itr, + TARGETING::TYPE_ABUS, + l_connected); + if(l_errHdl) + { + TOD_ERR("Error tying to connect target 0x%.4X " + "to MDMT 0x%.8X.", + (*l_itr)->getTarget()->getAttr<ATTR_HUID>(), + l_pMDMT->getTarget()->getAttr<ATTR_HUID>()); + break; + } + if(l_connected) + { + //Found a proc, designate this as the SDMT for this TOD drawer. + l_pMDMT->addChild(*l_itr); + (*l_itr)->setMasterType(TodProc::DRAWER_MASTER); + break; + } + } + if(l_errHdl) + { + break; + } + if(l_procs.end() == l_itr) + { + TOD_ERR("TOD drawer(0x%.2X) couldn't be wired", + i_pTodDrawer->getId()); + /*@ + * @errortype + * @reasoncode TOD_CANNOT_WIRE_DRAWER + * @moduleid TOD_WIRE_DRAWERS + * @userdata1 Topology type : primary/secondary + * @userdata2 TOD drawer id + * @devdesc TOD drawer couldn't be wired + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_CANNOT_WIRE_DRAWER, + iv_topologyType, + i_pTodDrawer->getId()); + break; + } + }while(0); + + TOD_EXIT("wireTodDrawer. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::dumpTopology +//****************************************************************************** +void TodTopologyManager::dumpTopology() const +{ + TOD_ENTER("dumpTopology"); + + static const char* busnames[8] = {0}; + busnames[NONE] = NO_BUS; + busnames[XBUS0] = X_BUS_0; + busnames[XBUS1] = X_BUS_1; + busnames[XBUS2] = X_BUS_2; + busnames[XBUS3] = X_BUS_3; + busnames[ABUS0] = A_BUS_0; + busnames[ABUS1] = A_BUS_1; + busnames[ABUS2] = A_BUS_2; + + static const char* topologynames[2] = {0}; + topologynames[TOD_PRIMARY] = TOD_PRIMARY_TOPOLOGY; + topologynames[TOD_SECONDARY] = TOD_SECONDARY_TOPOLOGY; + + do + { + //Dump the inter and intra TOD drawer connections + TOD_INF("TOPOLOGY DUMP> Start, topology type %s", + topologynames[iv_topologyType]); + //Get the TOD drawers + TodDrawerContainer l_todDrwList; + TodControls::getTheInstance().getDrawers(iv_topologyType, l_todDrwList); + TodDrawerContainer::const_iterator l_drwItr = l_todDrwList.begin(); + while(l_todDrwList.end() != l_drwItr) + { + TOD_INF("TOPOLOGY DUMP> TOD Drawer(0x%.2X)",(*l_drwItr)->getId()); + //Get the procs on this drawer + TodProcContainer l_procList = (*l_drwItr)->getProcs(); + + TOD_INF("TOPOLOGY DUMP> " + "parent_huid---bus out---bus in---child_huid"); + TodProcContainer::const_iterator l_procItr = l_procList.begin(); + while(l_procList.end() != l_procItr) + { + //Get the children for this TOD proc + TodProcContainer l_childList; + (*l_procItr)->getChildren(l_childList); + TodProcContainer::const_iterator l_childItr = + l_childList.begin(); + while(l_childList.end() != l_childItr) + { + TOD_INF("TOPOLOGY DUMP> 0x%08X---%s---%s---0x%08X", + (*l_procItr)->getTarget()->getAttr<ATTR_HUID>(), + busnames[(*l_childItr)->getBusIn()], + busnames[(*l_childItr)->getBusOut()], + (*l_childItr)->getTarget()->getAttr<ATTR_HUID>()); + ++l_childItr; + } + ++l_procItr; + } + ++l_drwItr; + } + TOD_INF("TOPOLOGY DUMP> End"); + }while(0); + + TOD_EXIT("dumpTopology"); +} + +//****************************************************************************** +//TodTopologyManager::dumpTodRegs +//****************************************************************************** +void TodTopologyManager::dumpTodRegs() const +{ + TOD_ENTER("dumpTodRegs"); + + static const char* topologynames[2] = {0}; + topologynames[TOD_PRIMARY] = TOD_PRIMARY_TOPOLOGY; + topologynames[TOD_SECONDARY] = TOD_SECONDARY_TOPOLOGY; + + do + { + TOD_INF("TOD REGDUMP> Start, topology type %s", + topologynames[iv_topologyType]); + //Get the TOD drawers + TodDrawerContainer l_todDrwList; + TodControls::getTheInstance().getDrawers(iv_topologyType, l_todDrwList); + TodDrawerContainer::const_iterator l_drwItr = l_todDrwList.begin(); + while(l_todDrwList.end() != l_drwItr) + { + TOD_INF("TOD REGDUMP> TOD Drawer(0x%.2X)",(*l_drwItr)->getId()); + //Get the procs on this drawer + TodProcContainer l_procList = (*l_drwItr)->getProcs(); + TodProcContainer::const_iterator l_procItr = l_procList.begin(); + while(l_procList.end() != l_procItr) + { + TOD_INF("TOD REGDUMP> Proc HUID 0x%.8X", + (*l_procItr)->getTarget()->getAttr<ATTR_HUID>()); + if(TodProc::TOD_MASTER == (*l_procItr)->getMasterType()) + { + TOD_INF("TOD REGDUMP> This proc is the MDMT"); + } + else if(TodProc::DRAWER_MASTER == (*l_procItr)->getMasterType()) + { + TOD_INF("TOD REGDUMP> This proc is the SDMT " + " for this drawer"); + } + proc_tod_setup_conf_regs l_todRegs; + (*l_procItr)->getTodRegs(l_todRegs); + TOD_INF("TOD REGDUMP> MASTER PATH CONTROL REG 0x%.16llX", + l_todRegs.tod_m_path_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PORT 0 PRIMARY CONFIG REG 0x%.16llX", + l_todRegs.tod_pri_port_0_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PORT 1 PRIMARY CONFIG REG 0x%.16llX", + l_todRegs.tod_pri_port_1_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PORT 0 SECONDARY CONFIG REG 0x%.16llX", + l_todRegs.tod_sec_port_0_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PORT 1 SECONDARY CONFIG REG 0x%.16llX", + l_todRegs.tod_sec_port_1_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> SLAVE PATH CONTROL REG 0x%.16llX", + l_todRegs.tod_s_path_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> INTERNAL PATH CONTROL REG 0x%.16llX", + l_todRegs.tod_i_path_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PRIMARY/SECONDARY MASTER/SLAVE CONTROL" + " REG 0x%.16llX", + l_todRegs.tod_pss_mss_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> CHIP CONTROL REG 0x%.16llX", + l_todRegs.tod_chip_ctrl_reg.getDoubleWord(0)); + ++l_procItr; + } + ++l_drwItr; + } + TOD_INF("TOD REGDUMP> End"); + }while(0); + + TOD_EXIT("dumpTodRegs"); +} + +} //namespace TOD diff --git a/src/usr/isteps/istep18/TodTopologyManager.H b/src/usr/isteps/istep18/TodTopologyManager.H new file mode 100755 index 000000000..447fe4432 --- /dev/null +++ b/src/usr/isteps/istep18/TodTopologyManager.H @@ -0,0 +1,171 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodTopologyManager.H $ */ +/* */ +/* 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 */ +#ifndef TODTOPOLOGYMANAGER_H +#define TODTOPOLOGYMANAGER_H + +/** + * @file TodTopologyManager.H + * + * @brief TOD Topology Manager class definition. Responsible for + * creating/modifying the primary and secondary topologies + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <errl/errlentry.H> +#include "proc_tod_utils/proc_tod_utils.H" + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Forward declarations +//------------------------------------------------------------------------------ +class TodDrawer; + +class TodTopologyManager +{ +public: + /** + * @brief Constructor. + * + * @par Detailed Description: + * Create a topology manager by specifying the type : + * TOD_PRIMARY/TOD_SECONDARY. Having separate managers + * for the primary/secondary topology allows exclusive + * operations on the topology and a greater degree of + * error management. + * + * @param[in] i_type + * Primary(TOD_PRIMARY) or Secondary(TOD_SECONDARY) + */ + TodTopologyManager(const proc_tod_setup_tod_sel i_type); + + /** + * @brief Destructor. + */ + ~TodTopologyManager(); + + /** + * @brief Create a TOD topology + * + * @par Detailed Description: + * The topology creation algorithm goes as follows: + * 1)Pick the MDMT. + * 2)In the master TOD drawer (the one in which MDMT lies), + * wire the procs together. + * 3)Connect the MDMT to one processor in each of the slave TOD drawers + * (the TOD drawers other than the master TOD drawer). + * 4)Wire the procs in the slave TOD drawers. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if successful + * @retval !NULL if failed to create topology + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t create(); + + /** + * @brief Dumps the topology connections in this format to fsp-trace: + * parent---bus out---bus in---child. An example would be + * pu:k0:n0:s0:p00---XBUS1---XBUS1---pu:k0:n0:s0:p01 + * + * @return N/A + */ + void dumpTopology() const; + + /** + * @brief Dumps the TOD register values that the hardware procedure + * supplied us with to fsp-trace. Check proc_tod_utils.H : + * proc_tod_setup_conf_regs for the list of registers. + * + * @return N/A + */ + void dumpTodRegs() const; + +private: + /** + * @brief Wires, or sets the X bus connection paths between + * processors in the input TOD drawer + * + * @param[in] i_pTodDrawer + * Pointer to a HwsvTodDrawer + * + * @return Error log handle indicating the status of the request. + * @retval NULL if successful + * @retval !NULL if failed to wire one or more procs in the TOD drawer + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t wireProcs(const TodDrawer* i_pTodDrawer); + + /** + * @brief Wires, or sets the A bus connection paths between + * the MDMT and one of the processors in the input TOD + * drawer (thus designating that processor as the SDMT). + * + * @param[in] i_pTodDrawer + * Pointer to a TodDrawer + * + * @return Error log handle indicating the status of the request. + * @retval NULL if successful + * @retval !NULL if failed to connect the MDMT to any processor in the + * input TOD drawer. + * + * Error log handle points to a valid error log object whose primary + * SRC reason code (pError->getSRC()->reasonCode()) indicates the type + * of error. + * + * @note It is up to the caller to change the severity of the + * returned error based on what it decides to do with it. By default + * any returned error created by this function will be a non-reported + * tracing event error log. + */ + errlHndl_t wireTodDrawer(TodDrawer* i_pTodDrawer); + + //Holds the type of the topology this manager is working on : + //primary/secondary + proc_tod_setup_tod_sel iv_topologyType; +}; + +} //namespace TOD + +#endif //#define TODTOPOLOGYMANAGER_H diff --git a/src/usr/isteps/istep18/TodTrace.H b/src/usr/isteps/istep18/TodTrace.H new file mode 100644 index 000000000..6bb2a9031 --- /dev/null +++ b/src/usr/isteps/istep18/TodTrace.H @@ -0,0 +1,52 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodTrace.H $ */ +/* */ +/* 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 */ +#ifndef TODTRACE_H +#define TODTRACE_H + +#include <tracinterface.H> + +namespace TOD +{ + +extern trace_desc_t * g_trac_tod; + +// field traces ------------------- + +#define TOD_TRAC(args...) TRACFCOMP(TOD::g_trac_tod, args) +#define TOD_ENTER(args...) TRACFCOMP(TOD::g_trac_tod, ENTER_MRK"" args) +#define TOD_EXIT(args...) TRACFCOMP(TOD::g_trac_tod, EXIT_MRK"" args) +#define TOD_ERR(args...) TRACFCOMP(TOD::g_trac_tod, ERR_MRK"" args) +#define TOD_INF(args...) TRACFCOMP(TOD::g_trac_tod, INFO_MRK"" args) + +// debug traces ------------------- + +#define TOD_DTRAC(args...) TRACDCOMP(TOD::g_trac_tod, args) +#define TOD_DENTER(args...) TRACDCOMP(TOD::g_trac_tod, ENTER_MRK"" args) +#define TOD_DEXIT(args...) TRACDCOMP(TOD::g_trac_tod, EXIT_MRK"" args) + +} + +#endif + diff --git a/src/usr/isteps/istep18/TodTypes.H b/src/usr/isteps/istep18/TodTypes.H new file mode 100755 index 000000000..e94a1d2d7 --- /dev/null +++ b/src/usr/isteps/istep18/TodTypes.H @@ -0,0 +1,108 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodTypes.H $ */ +/* */ +/* 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 */ +#ifndef TODTYPES_H +#define TODTYPES_H + +/** + * @file TodTypes.H + * + * @brief The file primarily conatins definition of data strucrtures that are + * required to share the tod topology register data between HB and HDAT. + * It also define the format of data that will be saved in file + * for persistency of TOD configuration data. + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +namespace TOD +{ + + /** + * Enums for the TodChipHeader->flags, These values are defined as per + * details provided by HDAT data structure details provided by HDAT + */ + enum + { + TOD_NONE = 0x00000000, + TOD_SEC_MDMT = 0x00000001, + TOD_PRI_MDMT = 0x00000002, + TOD_FUNC = 0x00000004, + TOD_NONFUNC = 0x00000008, + }; + + + /** + * Sub structure of TodChipData, Represents the Chip ID details required + * by HDAT + * + */ + struct TodChipHeader + { + uint32_t chipID; //Chip ID + uint32_t flags; //Flags + TodChipHeader(void) : chipID(0),flags(TOD_NONFUNC) {} + }; + + /** + * Sub structure of TodChipData, That will contain the first 32 bits of + * all the TOD register values, that were populated during creation of the + * TOD topology. + * Out of the below register ipcr and ccr are required by HDAT. Others are + * there for persistancy + * + */ + struct TodRegs + { + uint32_t mpcr; //Master Path Control Register + uint32_t pcrp0; //Primary Configuration Register Port 0 + uint32_t pcrp1; //Primary Configuration Register Port 1 + uint32_t scrp0; //Secondary Configuration Register Port 0 + uint32_t scrp1; //Secondary Configuration Register Port 1 + uint32_t spcr; //Slave Path Control Register + uint32_t ipcr; //Internal Path Control Register + uint32_t psmscr; //Primary/Secondary Master/Slave Control Register + uint32_t ccr; //Chip Control Register + TodRegs(void) + : + mpcr(0),pcrp0(0),pcrp1(0),scrp0(0),scrp1(0), + spcr(0),ipcr(0),psmscr(0),ccr(0) + {} + }; + + /** + * TOD Data for each chip that HDAT will communicate + * to PHYP. + */ + struct TodChipData + { + TodChipHeader header; + TodRegs regs; + TodChipData(void) : header(), regs() {} + }; + +} //end of namespace + +#endif diff --git a/src/usr/isteps/istep18/makefile b/src/usr/isteps/istep18/makefile new file mode 100644 index 000000000..d411bdcec --- /dev/null +++ b/src/usr/isteps/istep18/makefile @@ -0,0 +1,72 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/isteps/istep18/makefile $ +# +# 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 +ROOTPATH = ../../../../.. + +MODULE = tod_init + +## support for Targeting and fapi +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/ecmddatabuffer +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/fapi +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/plat +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp + +## pointer to common HWP files +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/include + +## NOTE: add the base istep dir here. +##@ EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/@istepname +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init + +## Include sub dirs +## NOTE: add a new EXTRAINCDIR when you add a new HWP +##@ EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/??? +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init/proc_tod_setup +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init/proc_tod_save_config +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init/proc_tod_utils +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init/proc_tod_init + + +## NOTE: add new object files when you add a new HWP +OBJS += tod_init.o +OBJS += TodControls.o +OBJS += TodDrawer.o +OBJS += TodProc.o +OBJS += TodSvc.o +OBJS += TodSvcUtil.o +OBJS += TodHwpIntf.o +OBJS += TodTopologyManager.o +OBJS += proc_tod_setup.o +OBJS += proc_tod_save_config.o +OBJS += proc_tod_init.o +OBJS += proc_tod_utils.o + +## NOTE: add a new directory onto the vpaths when you add a new HWP +##@ VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/??? +VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init/proc_tod_setup +VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init/proc_tod_save_config +VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init/proc_tod_utils +VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/tod_init/proc_tod_init + +include ${ROOTPATH}/config.mk diff --git a/src/usr/isteps/istep18/tod_init.C b/src/usr/isteps/istep18/tod_init.C new file mode 100644 index 000000000..2fb12a7fe --- /dev/null +++ b/src/usr/isteps/istep18/tod_init.C @@ -0,0 +1,89 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/tod_init.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 tod_init.C + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +/******************************************************************************/ +// Includes +/******************************************************************************/ + +#include <trace/interface.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include <targeting/common/targetservice.H> +#include <initservice/initserviceif.H> +#include "TodTrace.H" +#include "tod_init.H" +#include "TodSvc.H" + +namespace TOD +{ + +const char TOD_TRACE_NAME[] = "TOD"; +trace_desc_t* g_trac_tod = NULL; +TRAC_INIT(&g_trac_tod, TOD_TRACE_NAME, KILOBYTE, TRACE::BUFFER_SLOW); + +void * call_tod_setup(void *dummy) +{ + errlHndl_t l_errl; + + if (!INITSERVICE::spBaseServicesEnabled()) + { + l_errl = TodSvc::getTheInstance().todSetup(); + + if (l_errl) + { + TOD_ERR("todSetup() return errl handle %p", l_errl); + errlCommit( l_errl, TOD_COMP_ID ); + } + } + + return NULL; +} + +void * call_tod_init(void *dummy) +{ + errlHndl_t l_errl; + + if (!INITSERVICE::spBaseServicesEnabled()) + { + l_errl = TodSvc::getTheInstance().todInit(); + + if (l_errl) + { + TOD_ERR("todInit() return errl handle %p", l_errl); + errlCommit( l_errl, TOD_COMP_ID ); + } + } + + return NULL; +} + +}; // end namespace diff --git a/src/usr/isteps/istep18/tod_init.H b/src/usr/isteps/istep18/tod_init.H new file mode 100644 index 000000000..0ff41aba4 --- /dev/null +++ b/src/usr/isteps/istep18/tod_init.H @@ -0,0 +1,34 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/tod_init.H $ */ +/* */ +/* 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 */ +#ifndef TOD_INIT_H +#define TOD_INIT_H + +namespace TOD +{ + void * call_tod_setup(void *dummy); + void * call_tod_init(void *dummy); +}; + +#endif |