diff options
author | Roland Veloz <rveloz@us.ibm.com> | 2017-10-10 10:55:09 -0500 |
---|---|---|
committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2017-12-20 17:47:47 -0500 |
commit | a69cb64611f39c3320e71a025cc612690305926d (patch) | |
tree | debcc9b99e0c0f0fc5fafa47c9f0efbb20c38765 /src/usr/isteps/tod | |
parent | f0db3bed83349756e9182077b02c1c73e473a569 (diff) | |
download | talos-hostboot-a69cb64611f39c3320e71a025cc612690305926d.tar.gz talos-hostboot-a69cb64611f39c3320e71a025cc612690305926d.zip |
Adding support for TOD RAS on FSP systems
Moved the TOD files from directory /hostboot/src/usr/isteps/istep18
into a new TOD directory - /hostboot/src/usr/isteps/tod. Created a tod
library from the files within the new TOD directory. Added a runtime
directory underneath the tod directory. Created the rt_todintf.C file
which contains the two newly added interfaces -
readTodProcDataFromFile and resetBackupTopology.
Change-Id: I68c9edcd8f59adf9a2cf1f1f3fff07fea2d94e99
RTC:171490
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/48188
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/isteps/tod')
-rw-r--r-- | src/usr/isteps/tod/TodAssert.H | 59 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodControls.C | 1821 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodControls.H | 936 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodDrawer.C | 297 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodDrawer.H | 290 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodHwpIntf.C | 231 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodHwpIntf.H | 127 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodProc.C | 613 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodProc.H | 415 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodSvc.C | 613 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodSvc.H | 261 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodSvcUtil.C | 311 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodSvcUtil.H | 168 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodTopologyManager.C | 712 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodTopologyManager.H | 211 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodTrace.H | 61 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodUtils.C | 181 | ||||
-rw-r--r-- | src/usr/isteps/tod/TodUtils.H | 212 | ||||
-rw-r--r-- | src/usr/isteps/tod/makefile | 39 | ||||
-rw-r--r-- | src/usr/isteps/tod/runtime/makefile | 37 | ||||
-rw-r--r-- | src/usr/isteps/tod/runtime/rt_todintf.C | 753 | ||||
-rw-r--r-- | src/usr/isteps/tod/tod.mk | 43 |
22 files changed, 8391 insertions, 0 deletions
diff --git a/src/usr/isteps/tod/TodAssert.H b/src/usr/isteps/tod/TodAssert.H new file mode 100644 index 000000000..1fa1b7f20 --- /dev/null +++ b/src/usr/isteps/tod/TodAssert.H @@ -0,0 +1,59 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodAssert.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] 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_ERR_ASSERT(expr,...) \ + assert(expr,__VA_ARGS__) +} + +#endif diff --git a/src/usr/isteps/tod/TodControls.C b/src/usr/isteps/tod/TodControls.C new file mode 100644 index 000000000..51121dd0d --- /dev/null +++ b/src/usr/isteps/tod/TodControls.C @@ -0,0 +1,1821 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodControls.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +//Standard library +#include <list> + +#include <targeting/common/attributes.H> + +//Targeting support +#include <targeting/common/targetservice.H> +#include <targeting/common/util.H> +#include "TodProc.H" +#include "TodDrawer.H" +#include "TodSvcUtil.H" +#include "TodControls.H" +#include "TodTrace.H" +#include "TodUtils.H" +#include <devicefw/userif.H> +#include <hwas/common/deconfigGard.H> + +//HWPF +#include <plat_hwp_invoker.H> +#include <p9_perv_scom_addresses.H> +#include <p9_tod_setup.H> +#include <errl/errlentry.H> +#include <errl/errludtarget.H> +#include <p9_tod_utils.H> +#include <isteps/tod_init_reasoncodes.H> + +using namespace TARGETING; + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Static globals +//------------------------------------------------------------------------------ + +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 p9_tod_setup_tod_sel i_config) +{ + + TOD_ENTER("Input config is 0x%.2X", i_config); + + 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 algorithm will try to + //ensure that primary and secondary topology provides redundancy of MDMT. + + do{ + + + p9_tod_setup_tod_sel l_oppConfig = + (i_config == TOD_PRIMARY) ? TOD_SECONDARY : TOD_PRIMARY; + TodProc* l_otherConfigMdmt = iv_todConfig[l_oppConfig].iv_mdmt; + TodDrawerContainer l_todDrawerList = + iv_todConfig[i_config].iv_todDrawerList; + TodProcContainer l_procList; + + if(l_otherConfigMdmt) + { + TOD_INF("MDMT(0x%.8X) is configured for the " + "opposite config(0x%.2X)", + GETHUID(l_otherConfigMdmt->getTarget()), + l_oppConfig); + if(NULL == pickMdmt(l_otherConfigMdmt, i_config)) + { + TOD_INF("For config 0x%.2X, the only option for the MDMT " + "is the MDMT(0x%.8X) chosen for " + "the opposite config 0x%.2X", + i_config, + GETHUID(l_otherConfigMdmt->getTarget()), + l_oppConfig); + + //Get the TodProc pointer to l_otherConfigMdmt from this + //config's data structures. + for (const auto & l_drwItr: l_todDrawerList) + { + //This call will filter out GARDed/blacklisted chips + l_drwItr-> + getPotentialMdmts(l_procList); + //Now we check if l_otherConfigMdmt is still good. + for (const auto & l_procItr: l_procList) + { + if(l_procItr->getTarget() == + (iv_todConfig[l_oppConfig].iv_mdmt)->getTarget()) + { + //Found l_otherConfigMdmt pointer + l_errHdl = setMdmt(i_config, + l_procItr, + l_drwItr); + if(l_errHdl) + { + TOD_ERR("Error setting proc 0x%.8X on " + "TOD drawer 0x%.2X as MDMT " + "for config 0x%.2X", + GETHUID(l_procItr->getTarget()), + l_drwItr->getId(), + i_config); + errlCommit(l_errHdl, TOD_COMP_ID); + } + break; + } + } + if(iv_todConfig[i_config].iv_mdmt) + { + break; + } + } + } + } + else + { + TOD_INF("No MDMT configured for other config(0x%.2X) yet", + l_oppConfig); + + uint32_t l_coreCount = 0; + uint32_t l_maxCoreCount = 0; + TodProc* l_newMdmt = NULL; + TodProc* l_pTodProc = NULL; + TodDrawer* l_pTodDrw = NULL; + + //No MDMT configured yet. Our criteria to pick one is to + //look at TOD drawers and pick the one with max no of cores + + for (const auto & l_drwItr: l_todDrawerList) + { + l_pTodProc = NULL; + l_coreCount = 0; + //Get the list of procs on this TOD drawer that have oscillator + //input. Each of them is a potential MDMT, choose the one with + //max no. of cores + l_drwItr-> + getPotentialMdmts(l_procList); + l_drwItr-> + getProcWithMaxCores(NULL, + l_pTodProc, + l_coreCount, + &l_procList); + if(l_coreCount > l_maxCoreCount) + { + l_maxCoreCount = l_coreCount; + l_pTodDrw = l_drwItr; + l_newMdmt = l_pTodProc; + } + } + + if(l_newMdmt) + { + // If new MDMT, we set the todConfig + l_errHdl = setMdmt(i_config, + l_newMdmt, + l_pTodDrw); + if(l_errHdl) + { + TOD_ERR("Error setting proc 0x%.8X on " + "TOD drawer 0x%.2X as MDMT " + "for config 0x%.2X", + l_newMdmt->getTarget()-> + getAttr<TARGETING::ATTR_HUID>(), + l_pTodDrw->getId(), + i_config); + errlCommit(l_errHdl, TOD_COMP_ID); + } + } + } + }while(0); + + if(!iv_todConfig[i_config].iv_mdmt) + { + TOD_ERR("MDMT couldn't be chosen for configuration 0x%.2X", + i_config); + + /*@ + * @errortype + * @moduleid TOD_PICK_MDMT + * @reasoncode TOD_MASTER_TARGET_NOT_FOUND + * @userdata1 TOD topology type + * @devdesc MDMT could not be chosen for the supplied + * topology type + * @custdesc Host Processor Firmware couldn't detect any + * functional master processor required to boot the host + */ + const bool hbSwError = true; + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_PICK_MDMT, + TOD_MASTER_TARGET_NOT_FOUND, + i_config, + hbSwError); + + //Check the list of garded targets on the system and pick the garded + //targets for adding it into FFDC data. + // + std::vector<TARGETING::ATTR_HUID_type>::iterator l_iter; + + for ( l_iter = iv_gardedTargets.begin(); + l_iter != iv_gardedTargets.end(); + ++l_iter ) + { + //Get the target corresponding to the HUID stored in + //iv_gardedTargets + TARGETING::Target* l_pTarget = + TARGETING::Target::getTargetFromHuid(*l_iter); + if ( l_pTarget ) + { + if ( TARGETING::TYPE_PROC == GETTYPE(l_pTarget)) + { + // Add garded PROC targets into the errorlog + ERRORLOG::ErrlUserDetailsTarget(l_pTarget, + "GARDed Part").addToLog(l_errHdl); + } + } + } + } + else + { + TOD_INF("MDMT for configuration 0x%.2X, is proc 0x%.8X", + i_config, + iv_todConfig[i_config].iv_mdmt-> + getTarget()->getAttr<TARGETING::ATTR_HUID>()); + } + + TOD_EXIT(); + + return l_errHdl; +} + +//****************************************************************************** +//TodControls::buildTodDrawers +//****************************************************************************** +errlHndl_t TodControls::buildTodDrawers( + const p9_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); + + if (NULL == l_pSysTarget) + { + //We should not be reaching here without a valid system target + TOD_ERR_ASSERT("buildTodDrawers: NULL system target "); + break; + } + + //Build the list of functional nodes + l_errHdl = TOD::TodSvcUtil::getFuncNodeTargetsOnSystem( l_pSysTarget, + l_funcNodeTargetList, true); + if ( l_errHdl ) + { + TOD_ERR("For System target 0x%08X getFuncNodeTargetsOnSystem " + "returned error ",l_pSysTarget-> + getAttr<TARGETING::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 + * @moduleid TOD_BUILD_TOD_DRAWERS + * @reasoncode TOD_NO_FUNC_NODE_AVAILABLE + * @userdata1 system target's HUID + * @devdesc MDMT could not find a functional node + */ + const bool hbSwError = true; + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_BUILD_TOD_DRAWERS, + TOD_NO_FUNC_NODE_AVAILABLE, + l_pSysTarget->getAttr<ATTR_HUID>(), + hbSwError); + 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 TOD drawer + for ( uint32_t l_procIndex =0 ; + l_procIndex < l_funcProcTargetList.size(); + ++l_procIndex ) + { + b_foundDrawer = false; + + //Get the ordinal id of the parent node and find if there is an + //existing TOD drawer whose id matches with the ordinal id of + //this node + for ( l_todDrawerIter = l_todDrawerList.begin() ; + l_todDrawerIter != l_todDrawerList.end() ; + ++l_todDrawerIter) + { + if ( (*l_todDrawerIter)->getId() == + l_funcNodeTargetList[l_nodeIndex]-> + getAttr<TARGETING::ATTR_ORDINAL_ID>()) + { + //Add the proc to this TOD drawer, 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 drawer id same as parent + //node's id , and the pointer to the node target to which + //the TOD drawer belongs + TodDrawer *l_pTodDrawer = new + TodDrawer(l_funcNodeTargetList[l_nodeIndex]-> + getAttr<TARGETING::ATTR_ORDINAL_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); + //Delete the pointers after transfering the ownership + l_pTodDrawer = NULL; + l_pTodProc = NULL; + + } + + }// end proc list loop + + } // end node list loop + + //Validate that we had at least 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 + * @moduleid TOD_BUILD_TOD_DRAWERS + * @reasoncode TOD_NO_DRAWERS + * @userdata1 TOD configuration + * @devdesc No TOD drawer could be configured for this topology + * type + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_BUILD_TOD_DRAWERS, + TOD_NO_DRAWERS, + i_config); + + l_errHdl->addProcedureCallout( + HWAS::EPUB_PRC_FIND_DECONFIGURED_PART, + HWAS::SRCI_PRIORITY_LOW); + + } + + }while(0); + TOD_EXIT("buildTodDrawers"); + 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; + } + + //PHYP starts TOD logic. TOD logic can be started using either primary + //or secondary TOD configuration, if both configuration exist primary + //topology is considered for starting TOD logic. After the TOD logic is + //started successfully, TOD FSM ( finite state machine ) register will + //report the TOD status as running. + + //If there is atleast one MDMT + //configured , check the chipTOD HW status by reading the TOD + //register PERV_TOD_FSM_REG + + fapi2::variable_buffer l_primaryMdmtBuf(64); + l_primaryMdmtBuf.flush<0>(); + fapi2::variable_buffer l_secondaryMdmtBuf(64); + l_secondaryMdmtBuf.flush<0>(); + + if ( l_primaryMdmt ) + { + l_errHdl = todGetScom(l_primaryMdmt, + PERV_TOD_FSM_REG, + l_primaryMdmtBuf); + if ( l_errHdl ) + { + TOD_ERR("Scom failed for TOD FSM register " + "PERV_TOD_FSM_REG on primary MDMT"); + break; + } + + } + + if ( l_secondaryMdmt ) + { + l_errHdl = todGetScom(l_secondaryMdmt, + PERV_TOD_FSM_REG, + l_secondaryMdmtBuf); + if ( l_errHdl ) + { + TOD_ERR("Scom failed for TOD FSM register " + "PERV_TOD_FSM_REG on secondary MDMT"); + break; + } + } + + //If the bit 4 of the TOD_FSM_REG related to primary or + //secondary topology is set then the chip TOD logic is considered to + //be in the running state. + if(l_primaryMdmtBuf.isBitSet(TOD_FSM_REG_TOD_IS_RUNNING)) + { + o_isTodRunning = true; + TOD_INF("TOD logic is in the running state considering primary" + "topology as active topology"); + } + else if( l_secondaryMdmtBuf.isBitSet(TOD_FSM_REG_TOD_IS_RUNNING) ) + { + o_isTodRunning = true; + TOD_INF("TOD logic is in the running state considering" + "secondary topology as active topology"); + } + }while(0); + + TOD_EXIT("TOD HW State = %d",o_isTodRunning); + return l_errHdl; +} + +//****************************************************************************** +//TodControls::queryActiveConfig +//****************************************************************************** +errlHndl_t TodControls ::queryActiveConfig( + p9_tod_setup_tod_sel& o_activeConfig, + bool& o_isTodRunning, + TARGETING::Target*& o_mdmtOnActiveTopology, + bool i_determineTodRunningState)const +{ + TOD_ENTER(); + errlHndl_t l_errHdl = NULL; + TARGETING::Target* l_primaryMdmt=NULL; + TARGETING::Target* l_secondaryMdmt=NULL; + o_isTodRunning = false; + + do + { + + if ( i_determineTodRunningState ) + { + l_errHdl = isTodRunning(o_isTodRunning); + if ( l_errHdl ) + { + TOD_INF("Call to isTodRunning() failed,cannot query active " + "config state"); + break; + } + } + + //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; + } + + //Check for case where no MDMT could be found.. this can happen only + //when the method is called before topology was configured + if ( ! ( l_primaryMdmt || l_secondaryMdmt )) + { + TOD_ERR(" Neither primary not Secondary MDMT is configured "); + //Return an error + /*@ + * @errortype + * @moduleid TOD_QUERY_ACTIVE_CONFIG + * @reasoncode TOD_NO_VALID_MDMT_FOUND + * @devdesc No valid MDMT found on either topology + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_QUERY_ACTIVE_CONFIG, + TOD_NO_VALID_MDMT_FOUND); + break; + + } + + //Initialize the output variables, in case TOD is not running then + //these values will be returned. + o_activeConfig = TOD_PRIMARY; + + if ( l_primaryMdmt ) + { + o_mdmtOnActiveTopology = l_primaryMdmt; + } + else + { + o_mdmtOnActiveTopology = l_secondaryMdmt; + } + + //If TOD is running then query the configured MDMT to get the active + //configuration data else return Primary as default active + //configuration. + if (o_isTodRunning) + { + o_mdmtOnActiveTopology = NULL; + //Make it NULL again, since TOD is running we cannot return + //l_primaryMdmt as the MDMT on the active topology + + fapi2::variable_buffer l_primaryMdmtBuf(64); + l_primaryMdmtBuf.flush<0>(); + fapi2::variable_buffer l_secondaryMdmtBuf(64); + l_secondaryMdmtBuf.flush<0>(); + + 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; + } + + //Check 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 + if( l_primaryMdmtBuf.isBitSet + (TOD_PSS_MSS_STATUS_REG_00040008_ACTIVE_BIT)) + { + TOD_INF("Primary MDMT 0x%08X is indicating active " + " configuration as TOD_PRIMARY ", + GETHUID(l_secondaryMdmt)); + o_activeConfig = TOD_SECONDARY; + o_mdmtOnActiveTopology = l_secondaryMdmt; + } + else + { + o_mdmtOnActiveTopology = l_primaryMdmt; + } + //else Primary Topology is considered active + } + //If Primary Mdmt is not present then querying the secondaryMdmt. + else if ( l_secondaryMdmt ) + { + l_errHdl = todGetScom(l_secondaryMdmt, + PERV_TOD_PSS_MSS_STATUS_REG, + l_secondaryMdmtBuf); + if ( l_errHdl ) + { + TOD_ERR("Scom failed for status register " + "TOD_PSS_MSS_STATUS_REG_00040008 on secondary " + " MDMT"); + break; + } + + //Check 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 + if ( l_secondaryMdmtBuf.isBitSet + (TOD_PSS_MSS_STATUS_REG_00040008_ACTIVE_BIT)) + { + TOD_INF("Secondary MDMT 0x%08X is indicating active " + " configuration as TOD_SECONDARY ", + GETHUID(l_secondaryMdmt)); + o_activeConfig = TOD_SECONDARY; + o_mdmtOnActiveTopology = l_secondaryMdmt; + } + else + { + o_mdmtOnActiveTopology = l_primaryMdmt; + } + } + + //It is highly unlikely that PRIMARY topology says SECONDARY is + //active however we don't have MDMT on the secondary topology. + if ( !o_mdmtOnActiveTopology ) + { + TOD_ERR("Active topology found but could not get the MDMT " + " on active TOPOLOGY "); + + /*@ + * @errortype + * @moduleid TOD_QUERY_ACTIVE_CONFIG + * @reasoncode TOD_NO_MDMT_ON_ACTIVE_CONFIG + * @userdata1 Active configuration + * @devdesc MDMT not found on active toplology + * @custdesc Service Processor Firmware encountered an + * internal error + */ + const bool hbSwError = true; + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_QUERY_ACTIVE_CONFIG, + TOD_NO_MDMT_ON_ACTIVE_CONFIG, + o_activeConfig, + hbSwError); + break; + } + }//isTodRunning check + + }while(0); + + //If TOD logic is running and no failure is hit in the code above. + if( l_errHdl == NULL ) + { + if (o_isTodRunning) + { + if ( o_activeConfig == TOD_PRIMARY ) + { + TOD_INF("Primary topology is considered as active "); + } + else if( o_activeConfig == TOD_SECONDARY) + { + TOD_INF("Secondary topology is considered as active"); + } + } + else + { + if ( i_determineTodRunningState ) + { + TOD_INF("TOD logic is not in the running state!!"); + } + } + } + else + { + TOD_ERR("Failed to get TOD running state and active configuration" + "details!!"); + } + + TOD_EXIT(); + 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; + //fapi2 data buffer for TOD register + fapi2::variable_buffer l_todStatusReg(64); + + /* TOD_PSS_MSS_STATUS_REG_00040008 has the following interpretation + * Primary configuration + * TOD_STATUS[13] TOD_STATUS[14] Inference + * 1 1 Master TOD Master Drawer + * 0 1 Slave TOD Master Drawer + * 0 0 Slave TOD Slave Drawer + * 1 0 Master TOD Slave Drawer + * + * Secondary configuration + * TOD_STATUS[17] TOD_STATUS[18] Inference + * Same as for primary + */ + + TARGETING::TargetRangeFilter l_filter( + TARGETING::targetService().begin(), + TARGETING::targetService().end(), + &l_stateAndProcChipFilter); + + //Read the TOD status register TOD_PSS_MSS_STATUS_REG_00040008 for each + //processor and check the TOD and Drawer bits + for ( ; l_filter; ++l_filter ) + { + l_errHdl = todGetScom(*l_filter, + PERV_TOD_PSS_MSS_STATUS_REG, + l_todStatusReg); + + if ( l_errHdl ) + { + TOD_ERR("Scom failed for target 0x%08X on register" + " TOD_PSS_MSS_STATUS_REG_00040008 ", + (*l_filter)->getAttr<TARGETING::ATTR_HUID>()); + break; + } + + if ( + l_todStatusReg.isBitSet( + TOD_PSS_MSS_STATUS_REG_00040008_PRI_M_S_TOD_SEL) + && + l_todStatusReg.isBitSet( + TOD_PSS_MSS_STATUS_REG_00040008_PRI_M_S_DRAWER_SEL ) ) + { + o_primaryMdmt = *l_filter; + TOD_INF("found primary MDMT HUID = 0x%08X", + o_primaryMdmt->getAttr<TARGETING::ATTR_HUID>()); + } + + if ( + l_todStatusReg.isBitSet( + TOD_PSS_MSS_STATUS_REG_00040008_SEC_M_S_TOD_SEL ) + && + l_todStatusReg.isBitSet( + TOD_PSS_MSS_STATUS_REG_00040008_SEC_M_S_DRAWER_SEL ) ) + { + o_secondaryMdmt = *l_filter; + TOD_INF("found secondary MDMT HUID = 0x%08X", + o_secondaryMdmt->getAttr<TARGETING::ATTR_HUID>()); + + } + + if ( o_primaryMdmt && o_secondaryMdmt ) + { + break; + } + } + + }while(0); + + TOD_EXIT(); + return l_errHdl; +} + +//****************************************************************************** +//TodControls::destroy +//****************************************************************************** +void TodControls ::destroy(const p9_tod_setup_tod_sel i_config) +{ + TOD_ENTER("TodControls::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; + iv_todChipDataVector.clear(); + iv_BlackListedProcs.clear(); + iv_gardedTargets.clear(); + + TOD_EXIT(); +} + +//****************************************************************************** +//TodControls::writeTodProcData +//****************************************************************************** +errlHndl_t TodControls :: writeTodProcData( + const p9_tod_setup_tod_sel i_config) +{ + TOD_ENTER("TodControls::writeTodProcData"); + errlHndl_t l_errHdl = NULL; + + do{ + + //As per the requirement specified by PHYP/HDAT, TOD 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 = TOD::TodSvcUtil::getMaxProcsOnSystem(); + Target* l_target = NULL; + + TOD_INF("Max possible processor chips for this system when configured " + "completely is %d",l_maxProcCount); + + iv_todChipDataVector.assign(l_maxProcCount,blank); + + TARGETING::ATTR_ORDINAL_ID_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<TARGETING::ATTR_ORDINAL_ID>(); + + //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<TARGETING::ATTR_HUID>()) + == + ((*l_procItr)->getTarget()-> + getAttr<TARGETING::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<TARGETING::ATTR_HUID>()) + == + ((*l_procItr)->getTarget()-> + getAttr<TARGETING::ATTR_HUID>()) + ) + { + + iv_todChipDataVector[l_ordId].header.flags |= + TOD_SEC_MDMT; + } + + } + + ATTR_TOD_CPU_DATA_type l_tod_array; + memcpy(l_tod_array, + &iv_todChipDataVector[l_ordId],sizeof(TodChipData)); + + l_target = const_cast<Target *>((*l_procItr)->getTarget()); + l_target->setAttr<ATTR_TOD_CPU_DATA>(l_tod_array); + } + } + + }while(0); + + TOD_EXIT("writeTodProcData. errHdl = %p", l_errHdl); + return l_errHdl; + +}//end of writeTodProcData + + +//****************************************************************************** +//TodControls::hasNoValidData() +//****************************************************************************** +bool TodControls ::hasNoValidData(const std::vector<TodChipData>& + i_todChipDataVector)const +{ + TOD_ENTER("TodControls::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; +} + +//****************************************************************************** +//TodControls::pickMdmt +//****************************************************************************** +TodProc* TodControls ::pickMdmt( + const TodProc* i_otherConfigMdmt, + const p9_tod_setup_tod_sel& i_config, + const bool i_setMdmt) +{ + TOD_ENTER("Other MDMT : 0x%.8X, " + "Input config : 0x%.2X", + GETHUID(i_otherConfigMdmt->getTarget()), + i_config); + + TodProc* l_newMdmt = NULL; + TodProc *l_pTodProc = NULL; + TodDrawer* l_pMasterDrw = NULL; + TodDrawerContainer l_todDrawerList = + iv_todConfig[i_config].iv_todDrawerList; + TodProcContainer l_procList; + uint32_t l_coreCount = 0; + uint32_t l_maxCoreCount = 0; + errlHndl_t l_errHdl = NULL; + + do + { + //1.MDMT will be chosen from a node other than the node on which + //this MDMT exists, in case of multinode systems + //Iterate the list of TOD drawers + l_maxCoreCount = 0; + for (TodDrawerContainer::iterator l_todDrawerIter = + l_todDrawerList.begin(); + l_todDrawerIter != l_todDrawerList.end(); + ++l_todDrawerIter) + { + + //TodProc --> TodDrawer --> Node + if(i_otherConfigMdmt->getParentDrawer()->getParentNodeTarget()-> + getAttr<TARGETING::ATTR_HUID>() + != + (*l_todDrawerIter)->getParentNodeTarget()-> + getAttr<TARGETING::ATTR_HUID>()) + { + l_pTodProc = NULL; + l_coreCount = 0; + l_procList.clear(); + //Get the list of procs on this TOD drawer that have oscillator + //input. Each of them is a potential MDMT, choose the one with + //max no. of cores + (*l_todDrawerIter)-> + getPotentialMdmts(l_procList); + (*l_todDrawerIter)-> + getProcWithMaxCores(NULL, + l_pTodProc, + l_coreCount, + &l_procList); + if(l_coreCount > l_maxCoreCount) + { + l_newMdmt = l_pTodProc; + l_maxCoreCount = l_coreCount; + l_pMasterDrw = *l_todDrawerIter; + } + } + } + if(l_newMdmt && i_setMdmt ) + { + l_errHdl = setMdmt(i_config, + l_newMdmt, + l_pMasterDrw); + if(l_errHdl) + { + TOD_ERR("Error setting proc 0x%.8X on " + "TOD drawer 0x%.2X as MDMT " + "for config 0x%.2X", + l_newMdmt->getTarget()-> + getAttr<TARGETING::ATTR_HUID>(), + l_pMasterDrw->getId(), + i_config); + errlCommit(l_errHdl, TOD_COMP_ID); + l_newMdmt = NULL; + } + else + { + TOD_INF("Found MDMT 0x%.8X on different node 0x%.8X", + l_newMdmt->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_pMasterDrw->getParentNodeTarget()-> + getAttr<TARGETING::ATTR_HUID>()); + l_pMasterDrw = NULL; + 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 + l_maxCoreCount = 0; + for(const auto & l_todDrawerIter : l_todDrawerList) + { + if((i_otherConfigMdmt->getParentDrawer()->getParentNodeTarget()-> + getAttr<TARGETING::ATTR_HUID>() == + l_todDrawerIter->getParentNodeTarget()-> + getAttr<TARGETING::ATTR_HUID>())//Same node + && + (i_otherConfigMdmt->getParentDrawer()->getId() != + l_todDrawerIter->getId()))//Different TOD Drawer + { + l_pTodProc = NULL; + l_coreCount = 0; + l_procList.clear(); + //Get the list of procs on this TOD drawer that have oscillator + //input. Each of them is a potential MDMT, choose the one with + //max no. of cores + l_todDrawerIter-> + getPotentialMdmts(l_procList); + l_todDrawerIter-> + getProcWithMaxCores(NULL, + l_pTodProc, + l_coreCount, + &l_procList); + if(l_coreCount > l_maxCoreCount) + { + l_newMdmt = l_pTodProc; + l_maxCoreCount = l_coreCount; + l_pMasterDrw = l_todDrawerIter; + } + } + } + if(l_newMdmt && i_setMdmt) + { + l_errHdl = setMdmt(i_config, + l_newMdmt, + l_pMasterDrw); + if(l_errHdl) + { + TOD_ERR("Error setting proc 0x%.8X on " + "TOD drawer 0x%.2X as MDMT " + "for config 0x%.2X", + l_newMdmt->getTarget()-> + getAttr<TARGETING::ATTR_HUID>(), + l_pMasterDrw->getId(), + i_config); + errlCommit(l_errHdl, TOD_COMP_ID); + l_newMdmt = NULL; + } + else + { + TOD_INF("Found MDMT 0x%.8X on different TOD drawer 0x%.2X", + l_newMdmt->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_pMasterDrw->getId()); + l_pMasterDrw = NULL; + break; + } + } + + //3.Try to find MDMT on the same TOD drawer as the TOD Drawer of + //opposite MDMT + l_maxCoreCount = 0; + for (const auto l_todDrawerIter : l_todDrawerList) + { + l_pTodProc = NULL; + l_coreCount = 0; + l_procList.clear(); + if(i_otherConfigMdmt->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 + //Get the list of procs on this TOD drawer that have oscillator + //input. Each of them is a potential MDMT, choose the one with + //max no. of cores + l_todDrawerIter-> + getPotentialMdmts(l_procList); + l_todDrawerIter->getProcWithMaxCores( + i_otherConfigMdmt, + l_pTodProc, + l_coreCount, + &l_procList); + l_newMdmt = l_pTodProc; + l_pMasterDrw = l_todDrawerIter; + break; + } + } + if(l_newMdmt && i_setMdmt) + { + l_errHdl = setMdmt(i_config, + l_newMdmt, + l_pMasterDrw); + if(l_errHdl) + { + TOD_ERR("Error setting proc 0x%.8X on " + "TOD drawer 0x%.2X as MDMT " + "for config 0x%.2X", + l_newMdmt->getTarget()-> + getAttr<TARGETING::ATTR_HUID>(), + l_pMasterDrw->getId(), + i_config); + errlCommit(l_errHdl, TOD_COMP_ID); + l_newMdmt = NULL; + } + else + { + TOD_INF( + "Found another MDMT 0x%.8X on the same TOD drawer 0x%.2X " + "on which i_otherConfigMdmt(0x%.8X) resides", + GETHUID(l_newMdmt->getTarget()), + l_pMasterDrw->getId(), + GETHUID(i_otherConfigMdmt->getTarget())); + l_pMasterDrw = NULL; + break; + } + } + }while(0); + + TOD_EXIT(); + + return l_newMdmt; +} + +//****************************************************************************** +//TodControls::setMdmtOfActiveConfig +//****************************************************************************** +void TodControls ::setMdmtOfActiveConfig( + const p9_tod_setup_tod_sel i_config, + TodProc* i_mdmt, + TodDrawer* i_masterDrawer) +{ + TOD_ENTER("setMdmtOfActiveConfig"); + + do + { + if ( !i_mdmt ) + { + TOD_ERR_ASSERT("Software error input MDMT must not be NULL"); + break; + } + + if ( !i_masterDrawer ) + { + TOD_ERR_ASSERT("Software error input master drawer must not be " + " NULL"); + break; + } + + iv_todConfig[i_config].iv_mdmt = i_mdmt; + i_mdmt->setMasterType(TodProc::TOD_MASTER); + i_masterDrawer->setMasterDrawer(true); + + TOD_INF("MDMT for configuration 0x%.2X is proc 0x%.8X", + i_config, + GETHUID(iv_todConfig[i_config].iv_mdmt->getTarget())); + } while (0); + TOD_EXIT(); +} + +//****************************************************************************** +//TodControls::setMdmt +//****************************************************************************** +errlHndl_t TodControls ::setMdmt(const p9_tod_setup_tod_sel i_config, + TodProc* i_mdmt, + TodDrawer* i_masterDrawer) +{ + TOD_ENTER("setMdmt"); + + errlHndl_t l_errHdl = NULL; + + do + { + if ( !i_mdmt ) + { + TOD_ERR_ASSERT("Software error input MDMT must not be NULL"); + break; + } + + if ( !i_masterDrawer ) + { + TOD_ERR_ASSERT("Software error input master drawer must not be " + " NULL"); + break; + } + + iv_todConfig[i_config].iv_mdmt = i_mdmt; + i_mdmt->setMasterType(TodProc::TOD_MASTER); + i_masterDrawer->setMasterDrawer(true); + + TOD_INF("MDMT for configuration 0x%.2X is proc 0x%.8X, ", + i_config, + iv_todConfig[i_config].iv_mdmt-> + getTarget()->getAttr<TARGETING::ATTR_HUID>()); + + } while (0); + TOD_EXIT(); + + return l_errHdl; +} + +//****************************************************************************** +//isProcBlackListed +//****************************************************************************** +bool TodControls::isProcBlackListed ( + TARGETING::ConstTargetHandle_t i_procTarget + )const +{ + TOD_ENTER(); + + bool l_blackListed = false; + + do + { + if(!i_procTarget) + { + TOD_ERR_ASSERT("Input target cannot be NULL for " + "isProcBlackListed"); + break; + } + + if ( + ( GETCLASS(i_procTarget) != TARGETING::CLASS_CHIP ) + || + ( GETTYPE(i_procTarget) != TARGETING::TYPE_PROC)) + { + TOD_ERR_ASSERT("Only processor target allowed as input for " + " isProcBlackListed "); + break; + } + + if(iv_BlackListedProcs.end() != std::find( + iv_BlackListedProcs.begin(), + iv_BlackListedProcs.end(), + i_procTarget)) + { + TOD_INF("Proc 0x%.8X is blacklisted!", GETHUID(i_procTarget)); + l_blackListed = true; + } + } while (0); + TOD_EXIT(); + + return l_blackListed; +} + +//****************************************************************************** +//buildGardedTargetsList +//****************************************************************************** +errlHndl_t TodControls::buildGardedTargetsList() +{ + TOD_ENTER("buildGardedTargetsList"); + errlHndl_t l_errHdl = NULL; + iv_gardListInitialized = false; + clearGardedTargetsList(); + + do + { + TARGETING::Target* l_pSystemTarget = NULL; + TARGETING::targetService().getTopLevelTarget(l_pSystemTarget); + if ( !l_pSystemTarget ) + { + TOD_ERR_ASSERT("System target could not be found"); + break; + } + + GardedUnitList_t l_gardedUnitList; + l_errHdl = gardGetGardedUnits(l_pSystemTarget,l_gardedUnitList); + if ( l_errHdl ) + { + TOD_ERR("Error getting garded units."); + break; + } + else + { + for(const auto & l_iter : l_gardedUnitList) + { + //Push the HUID to the set of garded targets + iv_gardedTargets.push_back(l_iter.iv_huid); + TOD_INF("Adding 0x%08X to the garded list of targets", + l_iter.iv_huid); + } + + + } + + }while(0); + + if ( !l_errHdl ) + { + iv_gardListInitialized = true; + } + TOD_EXIT(); + return l_errHdl; + +} + + +//****************************************************************************** +//checkGardStatusOfTarget +//****************************************************************************** +errlHndl_t TodControls::checkGardStatusOfTarget( + TARGETING::ConstTargetHandle_t i_target, + bool& o_isTargetGarded ) +{ + TOD_ENTER("checkGardStatusOfTarget"); + errlHndl_t l_errHdl = NULL; + o_isTargetGarded = false; + + do{ + + if ( !iv_gardListInitialized ) + { + TOD_INF("Local cache of garded targets is not initialized " + " the gard status will be retrieved from system model"); + } + else + { + if (iv_gardedTargets.end() != std::find( + iv_gardedTargets.begin(), + iv_gardedTargets.end(), + (GETHUID(i_target)))) + { + o_isTargetGarded = true; + } + + } + + }while(0); + + TOD_EXIT("Target 0x%08X is %s", + GETHUID(i_target),o_isTargetGarded?"garded":"not garded"); + return l_errHdl; +} + +const char *TodControls::getPhysicalPathString( + const TARGETING::ATTR_PHYS_PATH_type &i_path) +{ + const char *l_str = i_path.toString(); + return l_str; +} + +/******************************************************************************/ +// gardGetGardedUnits +/******************************************************************************/ +errlHndl_t TodControls::gardGetGardedUnits( + const TARGETING::Target* const i_pTarget, + GardedUnitList_t &o_gardedUnitList) +{ + TOD_ENTER("gardGetGardedUnits"); + errlHndl_t l_err = NULL; + o_gardedUnitList.clear(); + do + { + HWAS::DeconfigGard::GardRecords_t l_gardRecords; + l_err = HWAS::theDeconfigGard().getGardRecords(i_pTarget, + l_gardRecords); + if(l_err != NULL) + { + TOD_ERR("Error getting gard records for HUID :[0x%08X]", + GETHUID(i_pTarget)); + + break; + } + + for(const auto & l_iter : l_gardRecords) + { + TARGETING::Target * l_pTarget = NULL; + + // getTargetFromPhysicalPath will either succeed or assert + getTargetFromPhysicalPath(l_iter.iv_targetId, l_pTarget); + + GardedUnit_t l_gardedUnit; + memset(&l_gardedUnit,0,sizeof(GardedUnit_t)); + l_gardedUnit.iv_huid = + l_pTarget->getAttr<TARGETING::ATTR_HUID>(); + TARGETING::Target *l_pNodeTarget = NULL; + if((l_pTarget->getAttr<TARGETING::ATTR_CLASS>() == + TARGETING::CLASS_ENC)&& + (l_pTarget->getAttr<TARGETING::ATTR_TYPE>() == + TARGETING::TYPE_NODE)) + { + l_pNodeTarget = l_pTarget; + } + else + { + l_err = getParent(l_pTarget, + TARGETING::CLASS_ENC, + l_pNodeTarget); + if(l_err != NULL) + { + TOD_ERR("Error getting parent node, HUID:[0x%08X]", + l_pTarget->getAttr<TARGETING::ATTR_HUID>()); + + break; + } + } + l_gardedUnit.iv_nodeHuid = + l_pNodeTarget->getAttr<TARGETING::ATTR_HUID>(); + l_gardedUnit.iv_errlogId = + l_iter.iv_errlogEid; + l_gardedUnit.iv_errType = + static_cast<HWAS::GARD_ErrorType>(l_iter.iv_errorType); + l_gardedUnit.iv_domain = + l_pTarget->getAttr<TARGETING::ATTR_CDM_DOMAIN>(); + l_gardedUnit.iv_type = + l_pTarget->getAttr<TARGETING::ATTR_TYPE>(); + + l_gardedUnit.iv_class = + l_pTarget->getAttr<TARGETING::ATTR_CLASS>(); + + o_gardedUnitList.push_back(l_gardedUnit); + } + if(l_err != NULL) + { + break; + } + } + while(0); + if(l_err != NULL) + { + o_gardedUnitList.clear(); + } + TOD_EXIT(); + return l_err; +} + +//****************************************************************************** +// getTargetFromPhysicalPath +//****************************************************************************** + +void TodControls::getTargetFromPhysicalPath( + const TARGETING::ATTR_PHYS_PATH_type &i_path, + TARGETING::Target*& o_pTarget) + +{ + TOD_ENTER("getTargetFromPhysicalPath"); + do + { + o_pTarget = + TARGETING::targetService().toTarget(i_path); + TOD_ERR_ASSERT(o_pTarget != NULL, + "Error in getting target from entity path[%s]", + getPhysicalPathString(i_path)); + } + while(0); + TOD_EXIT(); +} + +//****************************************************************************** +// getParent +//****************************************************************************** + +errlHndl_t TodControls::getParent(const TARGETING::Target *i_pTarget, + const TARGETING::CLASS i_class, + TARGETING::Target *& o_parent_target) +{ + + //-------------------------------------------------------------------------- + // Local Variables + //-------------------------------------------------------------------------- + bool l_parent_found = false; + errlHndl_t l_errl = NULL; + TARGETING::TargetHandleList l_list; + // Initializing l_parentTarget here in-order to eliminate goto compilation + // error below + const TARGETING::Target * l_parentTarget = i_pTarget; + TARGETING::ATTR_TYPE_type l_type = TARGETING::TYPE_NA; + TARGETING::ATTR_CLASS_type l_class = TARGETING::CLASS_NA; + + //-------------------------------------------------------------------------- + // Code + //-------------------------------------------------------------------------- + TOD_ENTER("getParent"); + + do + { + TOD_ERR_ASSERT(i_pTarget != NULL, "Input Target handle is null"); + + // If we have a valid target, check if it is system + l_type = i_pTarget->getAttr<TARGETING::ATTR_TYPE>(); + + l_class = i_pTarget->getAttr<TARGETING::ATTR_CLASS>(); + + if((TARGETING::CLASS_SYS == l_class) && + (TARGETING::TYPE_SYS == l_type)) + { + TOD_ERR("Input target is SYSTEM which cannot have a parent target." + "Class [0x%08X], Type [0x%08X]", + static_cast<uint32_t>(l_class), + static_cast<uint32_t>(l_type)); + + //Create error + /*@ + * @errortype + * @moduleid TOD_UTIL_MOD_GET_PARENT + * @reasoncode TOD_INVALID_TARGET + * @userdata1 HUID of the input target + * @devdesc Invalid target is supplied as input, + * SYSTEM target has no parent + * @custdesc Service Processor Firmware encountered an internal + * error + */ + + const bool hbSwError = true; + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_UTIL_MOD_GET_PARENT, + TOD_INVALID_TARGET, + GETHUID(i_pTarget), + hbSwError); + + break; + } + + + // Clear existing elements of l_list, just to make sure, though + // getAssociated() clears l_list below when it gets called + l_list.clear(); + + // Get the immediate parent + TARGETING::targetService().getAssociated(l_list, l_parentTarget, + TARGETING::TargetService::PARENT, + TARGETING::TargetService::IMMEDIATE); + + if (l_list.size() != 1) + { + // Parent not found + break; + } + else + { + // Copy parent from list + l_parentTarget = l_list[0]; + + // Check input CLASS with parent CLASS + if ((i_class == TARGETING::CLASS_NA) || + (i_class == l_parentTarget->getAttr<TARGETING::ATTR_CLASS>())) + { + // Remove const-ness of l_parentTarget in-order to copy it to + // o_parent_target, which is not a const + o_parent_target = + const_cast<TARGETING::Target *>(l_parentTarget); + l_parent_found = true; + break; + } + } + }while(0); + + // Create an error log if parent is not found + if(!l_parent_found) + { + + //Create error + /*@ + * @errortype + * @moduleid TOD_UTIL_MOD_GET_PARENT + * @reasoncode TOD_PARENT_NOT_FOUND + * @userdata1 HUID of supplied Target + * @userdata2[0:31] Size of the list + * @userdata2[32:63] Input CLASS + * @devdesc Parent of input CLASS for supplied Target is not found + * @custdesc Service Processor Firmware encountered an internal + * error + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_UTIL_MOD_GET_PARENT, + TOD_PARENT_NOT_FOUND, + GETHUID(i_pTarget), + TWO_UINT32_TO_UINT64(l_list.size(), i_class)); + + } + + TOD_EXIT(); + return l_errl; + +} + +// Wrapper function for TodControls::getDrawers instance +void getDrawers(const p9_tod_setup_tod_sel i_config, + TodDrawerContainer& o_drawerList) +{ + Singleton<TodControls>::instance().getDrawers(i_config, o_drawerList); +} + +// Wrapper function for TodControls::isProcBlackListed instance +bool isProcBlackListed (TARGETING::ConstTargetHandle_t i_procTarget) +{ + return Singleton<TodControls>::instance().isProcBlackListed( + i_procTarget); +} + +// Wrapper function for TodControls::getMDMT instance +TodProc* getMDMT(const p9_tod_setup_tod_sel i_config) +{ + return Singleton<TodControls>::instance().getMDMT(i_config); +} + +// Wrapper function for TodControls::pickMdmt instance +errlHndl_t pickMdmt(const p9_tod_setup_tod_sel i_config) +{ + return Singleton<TodControls>::instance().pickMdmt(i_config); +} + +// Wrapper function for TodControls::isTodRunning instance +errlHndl_t isTodRunning ( bool& o_isTodRunning) +{ + return Singleton<TodControls>::instance().isTodRunning(o_isTodRunning); +} + +// Wrapper function for TodControls::checkGardStatusOfTarget instance +errlHndl_t checkGardStatusOfTarget(TARGETING::ConstTargetHandle_t i_target, + bool& o_isTargetGarded) +{ + return Singleton<TodControls>::instance().checkGardStatusOfTarget( + i_target, o_isTargetGarded); +} + +// Wrapper function for TodControls::destroy instance +void destroy(const p9_tod_setup_tod_sel i_config) +{ + Singleton<TodControls>::instance().destroy(i_config); +} + +// Wrapper function for TodControls::buildTodDrawers instance +errlHndl_t buildTodDrawers(const p9_tod_setup_tod_sel i_config) +{ + return Singleton<TodControls>::instance().buildTodDrawers(i_config); +} + +// Wrapper function for TodControls::buildGardedTargetsList instance +errlHndl_t buildGardedTargetsList() +{ + return Singleton<TodControls>::instance().buildGardedTargetsList(); +} + +// Wrapper function for TodControls::setConfigStatus instance +void setConfigStatus(const p9_tod_setup_tod_sel i_config, + const bool i_isConfigured ) +{ + Singleton<TodControls>::instance().setConfigStatus(i_config, + i_isConfigured); +} + +// Wrapper function for TodControls::getConfiguredMdmt instance +errlHndl_t getConfiguredMdmt(TARGETING::Target*& o_primaryMdmt, + TARGETING::Target*& o_secondaryMdmt) +{ + return Singleton<TodControls>::instance().getConfiguredMdmt(o_primaryMdmt, + o_secondaryMdmt); +} + +// Wrapper function for TodControls::writeTodProcData instance +errlHndl_t writeTodProcData(const p9_tod_setup_tod_sel i_config) +{ + return Singleton<TodControls>::instance().writeTodProcData(i_config); +} + +void clearGardedTargetsList() +{ + Singleton<TodControls>::instance().clearGardedTargetsList(); +} + +// Wrapper function for TodControls::queryActiveConfig instance +errlHndl_t queryActiveConfig(p9_tod_setup_tod_sel& o_activeConfig, + bool& o_isTodRunning, + TARGETING::Target*& o_mdmtOnActiveTopology, + bool i_determineTodRunningState) +{ + return Singleton<TodControls>::instance().queryActiveConfig(o_activeConfig, + o_isTodRunning, o_mdmtOnActiveTopology, i_determineTodRunningState); +} + +// Wrapper function for TodControls::setMdmtOfActiveConfig instance +void setMdmtOfActiveConfig(const p9_tod_setup_tod_sel i_config, + TodProc* i_proc, + TodDrawer* i_drawer) +{ + return Singleton<TodControls>::instance().setMdmtOfActiveConfig(i_config, + i_proc, i_drawer); +} + +// Wrapper function for TodControls::getConfigStatus instance +bool getConfigStatus(const p9_tod_setup_tod_sel i_config) +{ + return Singleton<TodControls>::instance().getConfigStatus(i_config); +} + +}//end of namespace diff --git a/src/usr/isteps/tod/TodControls.H b/src/usr/isteps/tod/TodControls.H new file mode 100644 index 000000000..7caf21ac8 --- /dev/null +++ b/src/usr/isteps/tod/TodControls.H @@ -0,0 +1,936 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodControls.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 TODCONTROLS_H +#define TODCONTROLS_H +/** + * @file TodControls.H + * + * @brief Contains TodControls class declaration + * TodControls class will maintain the data structures required for + * creating/modifying TOD topologies + */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +//System Include + +#include <util/singleton.H> +#include <vector> +#include "TodDrawer.H" +#include "TodProc.H" +#include "TodSvcUtil.H" +#include "TodAssert.H" +#include "TodTrace.H" +#include <isteps/tod/TodTypes.H> + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Forward declarations +//------------------------------------------------------------------------------ +class TodDrawer; +class TodProc; +class TodControls; + +//------------------------------------------------------------------------------ +//Typedefs +//------------------------------------------------------------------------------ +//Use "thesTodControls_t::Instance()" to access the singleton via reference +typedef Singleton<TodControls> theTodControls_t; +typedef std::vector<TARGETING::ConstTargetHandle_t> + BlacListedProcContainer; +typedef std::vector<TARGETING::ConstTargetHandle_t> + GardedProcContainer; +typedef std::vector<TARGETING::ATTR_HUID_type> + GardedTargetsContainer; + +//------------------------------------------------------------------------------ +//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 uint8_t TOD_PSS_MSS_STATUS_REG_00040008_PRI_M_S_TOD_SEL = 13; +const static uint8_t TOD_PSS_MSS_STATUS_REG_00040008_PRI_M_S_DRAWER_SEL = 14; +const static uint8_t TOD_PSS_MSS_STATUS_REG_00040008_SEC_M_S_TOD_SEL = 17; +const static uint8_t TOD_PSS_MSS_STATUS_REG_00040008_SEC_M_S_DRAWER_SEL = 18; +const static uint8_t TOD_FSM_REG_TOD_IS_RUNNING = 4; +const uint32_t TOD_HUID_INVALID = 0xFFFFFFFF; +const uint32_t FSP_INVALID_RID = 0x0; + +/** + * @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 TodDrawer class, that + * basically provides a grouping of the TodProc 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 + * TodProc 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 p9_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 p9_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 p9_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 TodDrawer pointers, empty in case of error + * + * @return N/A + */ + void getDrawers(const p9_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 TodProc pointer corresponding to the MDMT. NULL if error. + * + * @return Pointer to the data member iv_todConfig[i_config].iv_mdmt + */ + TodProc* getMDMT(const p9_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 p9_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 p9_tod_setup_tod_sel i_config) const + { + return iv_todConfig[i_config].iv_isConfigured; + } + + /** + * @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 p9_tod_setup_tod_sel i_config); + + //Temporary method for bringup + //Issue 132460 -- This method is temporarily provided for bringup + + //errlHndl_t writeTodProcDataFromBuffer(std::vector<TodChipData>& + // i_todChipDataVector ); + + /** + * + * @brief Getter method for iv_todChipDataVector + * + * @return Constant reference to vector<TodChipData> that will carry + * back iv_todChipDataVector + * + */ + const TodChipDataContainer& getTodChipDataVector()const + { + return iv_todChipDataVector; + } + + /** + * + * @brief This method will determine if the input processor target is + * available in the precessor blacklist or not. + * + * @param[in] i_procTarget + * The input processor target. + * The input target must not be NULL, and it must be of the processor + * type only. + * + * @return bool + * True if input processor target is blacklisted false otherwise + * + */ + bool isProcBlackListed ( + TARGETING::ConstTargetHandle_t i_procTarget + )const; + /** + * + * @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)and the MDMT belonging + * to active configuration. + * Calling code should ensure that it does not modifies active + * configuration when TOD HW is running. + * + * @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 TOD HW logic is running + * or not? + * + * @param[out] o_mdmtOnActiveTopology, target pointer of MDMT on active + * topology. In case of error or TOD HW logic is not running then this + * parameter will be NULL. + * + * @param[in] i_determineTodRunningState, This is a boolean variable that + * will determine if this method determines the TOD running state or + * not, this is done to reduce the number of SCOM operations in those + * flows where knowledge of running state is not required. Defaults to + * true i.e. determine the running state. + * + * @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( p9_tod_setup_tod_sel& o_activeConfig, + bool& o_isTodRunning, + TARGETING::Target*& o_mdmtOnActiveTopology, + bool i_determineTodRunningState=true) 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 For the input config fills up iv_todConfig with MDMT and OSC + * info. Input proc is set as the master and the input drawer as the + * master drawer. Will also ask the proc to pick an OSC from which it + * can receive signals. Caller can provide an i_avoidOscHUID, this + * will help choose a redundant OSC for the redundant topology. + * + * @param[in] i_config + * Indicates the primary/secondary topology + * + * @param[in] i_proc + * TodProc pointer, must not be NULL. + * + * @param[in] i_drawer + * TodDrawer pointer, must not be NULL. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if the MDMT was set + * @retval !NULL if MDMT couldn't be set + * + * 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 setMdmt(const p9_tod_setup_tod_sel i_config, + TodProc* i_proc, + TodDrawer* i_drawer); + + /** + * @brief This method is has similar functionality as setMdmt except that + * it will presume that OSC has already been configured for the + * processor chip that is going to be designated as MDMT. + * + * @par Detailed Description: + * The use case for this method is when we need to use the already + * configured values of MDMT and the OSC source for it. This may + * happen when TOD service gets a request for re-configuring the + * backup topology after RR because of which the in memory copy of + * active topology no longer exists. + * + * @param[in] i_config + * Indicates the primary/secondary topology + * + * @param[in] i_proc + * TodProc pointer, must not be NULL. + * + * @param[in] i_drawer + * TodDrawer pointer + * + * @return NA + * + */ + void setMdmtOfActiveConfig( const p9_tod_setup_tod_sel i_config, + TodProc* i_proc, + TodDrawer* i_drawer); + + /** + * @brief This method will collect gard records from system model and keep + * the HUIDs of garded targets on the system in local cache. + * It is done with the aim of avoiding repeated requests to the + * system model DB for checking the garded state of processors and + * OSCs, which can be time taking. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if gard records could be retrieved successfully from + * system model. + * @retval !NULL if this method failed to build the local data structure + * of the garded targets on the system. + * + */ + errlHndl_t buildGardedTargetsList(); + + /** + * @brief Given a target this method will tell whether it is garded or + * not. This method will look into local cache it that was already + * initialized else it will go and look into the system model. + * + * @param[in] i_target Input target whose gard status needs to be + * determined. + * @param[out] o_isTargetGarded Boolean parameter to return the gard + * status of the input target to the caller. + * + * @return Error log handle indicating the status of the request. + * @retval NULL if gard gard status of the input target could be + * successfully determined. + * @retval !NULL if this method failed to build the local data structure + * of the garded targets on the system. + * + */ + errlHndl_t checkGardStatusOfTarget( + TARGETING::ConstTargetHandle_t i_target, + bool& o_isTargetGarded); + + /** + * + * @brief Interface to clear the local list of garded targets on the + * system. + * + * @return NA + */ + void clearGardedTargetsList() + { + TOD_INF("Clearing the list of garded targets"); + iv_gardedTargets.clear(); + iv_gardListInitialized = false; + } + +protected: + /** + * @brief Constructor for the TodControls object. + */ + TodControls(); + + /** + * @brief Destructor for the TodControls object. + */ + ~TodControls(); + + +private: + + /** + * + * @brief Add new target to the processor blacklist + * + * @param[in] i_ProcTarget + * Processor target that needs to be added to blacklist of + * processors. + * Caller must ensure that the input target is neither + * NULL nor of non-processor type. + * + * @return NA + * + */ + void addProcToBlackList(TARGETING::ConstTargetHandle_t i_procTarget) + { + if ( !i_procTarget ) + { + TOD_ERR_ASSERT("Input target cannot be NULL for " + "addProcToBlackList"); + } + + if ( + ( GETCLASS(i_procTarget) != TARGETING::CLASS_CHIP ) + || + ( GETTYPE(i_procTarget) != TARGETING::TYPE_PROC)) + { + TOD_ERR_ASSERT(" Only processor target allowed as input for " + " addProcToBlackList"); + } + + iv_BlackListedProcs.push_back(i_procTarget); + } + + /** + * @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; + +public: + /** + * @brief Given the MDMT for TOD config alternate to i_config, + * picks the MDMT for i_config based on the following criteria + * + * @par Detailed Description: + * Whenever there is an existing MDMT for the opposite configuration + * following criteria will decide the MDMT for this configuration + * + * First of all we'll look only at TOD drawers having at least one + * proc with OSC input. Of all such procs across TOD drawers, we'll + * pick the one with max no of cores + * + * We'll run the below algorithm twice, first time we'll try to pick + * an MDMT with redundant OSC. + * If we don't find one, we'll run it again witout the redundant OSC + * constraint. + * That way we'll maximise reliability : best case we'll find the + * MDMT connected to a redundant OSC on some other node. + * + * 1.MDMT will be chosen from a node other that the node on which + * this MDMT exists, in case of multinode systems. + * 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 + * + * @param[in] i_otherConfigMdmt + * TodProc pointer to the MDMT of the config alternate to i_config + * + * @param[in] i_config + * Indicates the primary/secondary topology, alternate to the one in + * which i_otherConfigMdmt is the MDMT + * + * @param[in] i_setMdmt + * Represents an special case where the method will find the MDMT but + * not set it, this case will be used when some part of code just + * wants to validate if MDMT can be found under given constraints or + * not. + * + * @return TodProc pointer to new MDMT, NULL if couldn't be chosen + */ + + TodProc* pickMdmt(const TodProc* i_otherConfigMdmt, + const p9_tod_setup_tod_sel& i_config, + const bool i_setMdmt = true); + +private: + + //Datastructure for a TOD topology : + //A list of TOD drawers (which will contain a list of TodProc'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]; + + //TodChipData for the whole system (in ordinal order) + TodChipDataContainer iv_todChipDataVector; + + //Black listed processors that should not be considered as MDMT + BlacListedProcContainer iv_BlackListedProcs; + + //List of garded targets on the system + GardedTargetsContainer iv_gardedTargets; + + //Boolean value to indicate whether container iv_gardedTargets is + //initialized or not + bool iv_gardListInitialized; + + /* @brief enum for disable or Enable of Nag */ + enum NagUpdateAction{ + ENABLE_NAG = 0x0, + DISABLE_NAG = 0x1, + NAG_INVALID = 0x2, + }; + + + //NOTE:Extended mod ids have PLACEHOLDER MODID which needs to be used + //first when one is required. + enum ExtendedModId + { + EMOD_TOD_BUILD_BLACKLIST = 0x132, + EMOD_TOD_INIT = 0x10E, + EMOD_TOD_INIT_HWP = 0x10F, + }; + + /** + * @brief struct for returning gard records + * + */ + struct GardedUnit_t{ + TARGETING::ATTR_HUID_type iv_huid; //HUID of garded unit + TARGETING::ATTR_HUID_type iv_nodeHuid; //Node containing the unit + uint32_t iv_errlogId; //Garded Error log + HWAS::GARD_ErrorType iv_errType; //Type of gard error + TARGETING::CDM_DOMAIN iv_domain; //CDM Domain of the unit + TARGETING::ATTR_TYPE_type iv_type; //Type of the unit + TARGETING::ATTR_CLASS_type iv_class; //Class of the unit + uint32_t iv_rid; //RID of the unit + NagUpdateAction iv_nagDisabled; // Default to NAG enable + GardedUnit_t() : iv_huid(TOD_HUID_INVALID), + iv_nodeHuid(TOD_HUID_INVALID), + iv_errlogId(0), + iv_errType(HWAS::GARD_NULL), + iv_domain(TARGETING::CDM_DOMAIN_NONE), + iv_type(TARGETING::TYPE_NA), + iv_class(TARGETING::CLASS_NA), + iv_rid(FSP_INVALID_RID), + iv_nagDisabled(ENABLE_NAG) + { + } + + }; + typedef std::list<GardedUnit_t> GardedUnitList_t; + + /** + * @brief - This function returns all gard records in a system + * or node based on input huid + * + * @param[in] i_pTarget Target pointer to node or system, cannot be NULL + * @param[out] o_gardedUnitList List of garded records + * + * @return Error log handle indicating the status of the request + * @retval NULL on success + * @retval !NULL Error log handle, on failure + * + * @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 gardGetGardedUnits( + const TARGETING::Target* const i_pTarget, + GardedUnitList_t &o_gardedUnitList); + + /** + * @brief Return the physical path as string + * + * @param[in] i_path + * The physical path of a target + * + * + * @return string contains the string format of the path + */ + + const char * getPhysicalPathString( + const TARGETING::ATTR_PHYS_PATH_type &i_path); + + /** + * @brief Get Target based on the PHYSICAL Path + * + * @param[in] i_path + * Supplied PHYSICAL PATH + * + * @param[out] o_Target + * Pointer to Target + * + * assert if supplied physical path is not valid + */ + + void getTargetFromPhysicalPath( + const TARGETING::ATTR_PHYS_PATH_type &i_path, + TARGETING::Target*& o_pTarget); + + /** + * @brief Get parent of input CLASS for a Target + * + * @par Description: + * Given a target, gets first target higher in the containment hierarchy + * whose class matches the specified class. + * + * @param[in] i_pTarget + * Input target pointer. Must not be NULL (otherwise call will return an + * error log). Must be a valid target from the system blueprint. + * + * @param[in] i_class + * Class which constrains the search result. CLASS_NA is not enforced, + * but it will never find a matching parent. Also note that if search + * is for a chip parent of a chip, or other illogical searches, it will + * not find a matching parent. See attributeenums.H for class values. + * + * @param[out] o_parent_target + * Parent Target; ignore on error. Note: points to a blueprint target + * which may or may not actually be present (source target must be + * present to have assurances about presence of parent) + * + * @return errlHndl_t Error log handle indicating the status of the + * operation + * @retval NULL Success, returned target is valid + * @retval !NULL Failure; returned target is invalid. Primary SRC + * reason codes + * may be set to the following (others may be possible): + * TOD_UTIL_REASON_NULL_TG: Supplied target is NULL + * TOD_UTIL_REASON_PARENT_NOT_FOUND: Parent target of specified class + * was not found + */ + + errlHndl_t getParent(const TARGETING::Target *i_pTarget, + const TARGETING::CLASS i_class, + TARGETING::Target *& o_parent_target); + + +}; + +// Wrapper function for TodControls::getDrawers instance +void getDrawers(const p9_tod_setup_tod_sel i_config, + TodDrawerContainer& o_drawerList); + +// Wrapper function for TodControls::isProcBlackListed instance +bool isProcBlackListed(TARGETING::ConstTargetHandle_t i_procTarget); + +// Wrapper function for TodControls::getMDMT instance +TodProc* getMDMT(const p9_tod_setup_tod_sel i_config); + +// Wrapper function for TodControls::pickMdmt instance +errlHndl_t pickMdmt(const p9_tod_setup_tod_sel i_config); + +// Wrapper function for TodControls::isTodRunning instance +errlHndl_t isTodRunning(bool& o_isTodRunning); + +// Wrapper function for TodControls::checkGardStatusOfTarget instance +errlHndl_t checkGardStatusOfTarget( + TARGETING::ConstTargetHandle_t i_target, + bool& o_isTargetGarded); + +// Wrapper function for TodControls::destroy instance +void destroy(const p9_tod_setup_tod_sel i_config); + +// Wrapper function for TodControls::buildTodDrawers instance +errlHndl_t buildTodDrawers(const p9_tod_setup_tod_sel i_config); + +// Wrapper function for TodControls::buildGardedTargetsList instance +errlHndl_t buildGardedTargetsList(); + +// Wrapper function for TodControls::setConfigStatus instance +void setConfigStatus(const p9_tod_setup_tod_sel i_config, + const bool i_isConfigured ); + +// Wrapper function for TodControls::getConfiguredMdmt instance +errlHndl_t getConfiguredMdmt(TARGETING::Target*& o_primaryMdmt, + TARGETING::Target*& o_secondaryMdmt); + +// Wrapper function for TodControls::writeTodProcData instance +errlHndl_t writeTodProcData(const p9_tod_setup_tod_sel i_config); + +// Wrapper function for TodControls::clearGardedTargetsList instance +void clearGardedTargetsList(); + +// Wrapper function for TodControls::queryActiveConfig instance +errlHndl_t queryActiveConfig(p9_tod_setup_tod_sel& o_activeConfig, + bool& o_isTodRunning, + TARGETING::Target*& o_mdmtOnActiveTopology, + bool i_determineTodRunningState); + +// Wrapper function for TodControls::setMdmtOfActiveConfig instance +void setMdmtOfActiveConfig(const p9_tod_setup_tod_sel i_config, + TodProc* i_proc, + TodDrawer* i_drawer); + +// Wrapper function for TodControls::getConfigStatus instance +bool getConfigStatus(const p9_tod_setup_tod_sel i_config); + +} //end of namespace + +#endif //TODCONTROLS_H diff --git a/src/usr/isteps/tod/TodDrawer.C b/src/usr/isteps/tod/TodDrawer.C new file mode 100644 index 000000000..567e30b5e --- /dev/null +++ b/src/usr/isteps/tod/TodDrawer.C @@ -0,0 +1,297 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodDrawer.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 + */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +//Targeting support +#include <targeting/common/commontargeting.H> +#include <targeting/common/util.H> +#include <attributeenums.H> + +#include "TodControls.H" +#include "TodProc.H" +#include "TodDrawer.H" +#include "TodUtils.H" +#include <hwas/common/deconfigGard.H> +//Standard library +#include <list> +#include "TodUtils.H" +#include <isteps/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) +{ + do + { + if (!iv_parentNodeTarget) + { + TOD_ERR_ASSERT(0, "Error creating TOD drawer with id 0x%.2X," + "parent node pointer passed as NULL", + i_drawerId); + break; + } + TOD_ENTER("Created TOD drawer with id 0x%.2X, parent node 0x%.8X", + i_drawerId, + i_parentNode->getAttr<TARGETING::ATTR_HUID>()); + } while (0); + TOD_EXIT(); +} + +//****************************************************************************** +// TodDrawer::~TodDrawer +//****************************************************************************** +TodDrawer::~TodDrawer() +{ + TOD_ENTER(); + + for(TodProcContainer::iterator l_itr = iv_todProcList.begin(); + l_itr != iv_todProcList.end(); + ++l_itr) + { + delete (*l_itr); + } + iv_todProcList.clear(); + TOD_EXIT(); +} + +//****************************************************************************** +// TodDrawer::getProcWithMaxCores +//****************************************************************************** +void TodDrawer::getProcWithMaxCores( + const TodProc* i_procToIgnore, + TodProc*& o_pTodProc, + uint32_t& o_coreCount, + TodProcContainer* i_pProcList) 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; + + const TodProcContainer &l_procList = + i_pProcList ? *i_pProcList : iv_todProcList; + for(TodProcContainer::const_iterator l_procIter = + l_procList.begin(); + l_procIter != l_procList.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 0x%2X, processor 0x%08X " + "has maximum cores count = %d ", + iv_todDrawerId, + l_pSelectedTarget->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_maxCores); + } + + }while(0); + + TOD_EXIT(); +} + + +//****************************************************************************** +// TodDrawer::findMasterProc +//****************************************************************************** +errlHndl_t TodDrawer::findMasterProc(TodProc*& o_drawerMaster) const +{ + TOD_ENTER(); + + 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 + * @moduleid TOD_FIND_MASTER_PROC + * @reasoncode TOD_NO_MASTER_PROC + * @userdata1 TOD drawer id + * @devdesc No master proc set for this drawer + * @custdesc Service Processor Firmware couldn't detect any + * functional master processor required to boot the + * host + */ + + const bool hbSwError = true; + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_FIND_MASTER_PROC, + TOD_NO_MASTER_PROC, + iv_todDrawerId, + hbSwError); + } + }while(0); + + o_drawerMaster = l_pMasterProc; + + TOD_EXIT(); + + return l_errHdl; +} + +//****************************************************************************** +// TodDrawer::addProc +//****************************************************************************** +void TodDrawer::addProc(TodProc* i_proc) +{ + if(i_proc) + { + iv_todProcList.push_back(i_proc); + } + else + { + TOD_ERR_ASSERT("Code bug! Null Proc Target passed!"); + } +} + +//****************************************************************************** +// TodDrawer::getPotentialMdmts +//****************************************************************************** +void TodDrawer::getPotentialMdmts( + TodProcContainer& o_procList) const +{ + TOD_ENTER("TodDrawer::getPotentialMdmts"); + bool l_isGARDed = false; + errlHndl_t l_errHdl = NULL; + + const TARGETING::Target* l_procTarget = NULL; + + for(const auto & l_procItr : iv_todProcList) + { + + l_procTarget = l_procItr->getTarget(); + + //Check if the target is not black listed + if ( !(TOD::isProcBlackListed(l_procTarget)) ) + { + //Check if the target is not garded + l_errHdl = TOD::checkGardStatusOfTarget(l_procTarget, + l_isGARDed); + + if(l_errHdl) + { + TOD_ERR("Failed in checkGardStatusOfTarget() to get the " + " GARD state for the target 0x%.8x", + GETHUID(l_procTarget)); + + errlCommit(l_errHdl, TOD_COMP_ID); + + //Ignore this target as the gard status for this target + //could not be obtained. + continue; + } + + TARGETING::ATTR_HWAS_STATE_type l_state = + l_procTarget->getAttr<TARGETING::ATTR_HWAS_STATE>(); + + if ( (!l_isGARDed) || + (l_state.deconfiguredByEid == + HWAS::DeconfigGard::CONFIGURED_BY_RESOURCE_RECOVERY) ) + { + o_procList.push_back(l_procItr); + } + else + { + TOD_INF("PROC target 0x%.8x cannot be choosen as MDMT as" + "its garded",GETHUID(l_procTarget)); + } + } + else + { + TOD_INF("PROC target 0x%.8x cannot be choosen as MDMT as it" + "is backlisted",GETHUID(l_procTarget)); + } + l_isGARDed = false; + + }//End of for loop + TOD_EXIT(); +} + +}//end of namespace diff --git a/src/usr/isteps/tod/TodDrawer.H b/src/usr/isteps/tod/TodDrawer.H new file mode 100644 index 000000000..c574e6593 --- /dev/null +++ b/src/usr/isteps/tod/TodDrawer.H @@ -0,0 +1,290 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodDrawer.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 + * + */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +//Targeting support +#include <attributetraits.H> +#include "TodSvcUtil.H" +#include "TodProc.H" + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Forward declarations +//------------------------------------------------------------------------------ +class TodDrawer; +class TodControls; +class TodProc; + +//------------------------------------------------------------------------------ +//Typedefs +//------------------------------------------------------------------------------ +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 TodProc 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 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 TodProc + * 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. + * + * @param[in] i_pProcList If non NULL, this will be our input set instead of + * the set of all procs on this drawer. Useful if caller has already + * identified the set of procs on this drawer for which the one with max + * no. of cores is to be determined. + * + * @return N/A + */ + void getProcWithMaxCores( + const TodProc * i_procToIgnore, + TodProc *& o_pTodProc, + uint32_t& o_coreCount, + TodProcContainer* i_pProcList = NULL) 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 TodProc pointer correspnding to the proc to be added. + * + * @return N/A + */ + void addProc(TodProc* 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_GROUP_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; + } + + /** + * @brief Returns a list of procs on this drawer that can potentially be + * MDMT + * + * @par Detailed Description: + * For a processor to be a potential MDMT it has to fulfill the + * following criteria. + * 1) Processor should not be garded and it should not be on the + * blacklist. + * 2) Processor should be connected to OSC that is neither garded not + * present on the blacklist. + * 3) Processor should not be connected to the oscillator that is acting + * as MDMT source on an existing alternate toplogy. The + * Such oscillator target will be provided as input to this method. + * + * @param[out] o_procList list of procs + * + * @return N/A + */ + void getPotentialMdmts(TodProcContainer& o_procList)const; + +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_GROUP_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_GROUP_ID + TARGETING::ATTR_FABRIC_GROUP_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/tod/TodHwpIntf.C b/src/usr/isteps/tod/TodHwpIntf.C new file mode 100644 index 000000000..b20e42d7c --- /dev/null +++ b/src/usr/isteps/tod/TodHwpIntf.C @@ -0,0 +1,231 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodHwpIntf.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 + */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +#include <fapi2/target.H> +#include "TodTrace.H" +#include "TodControls.H" +#include "TodUtils.H" +#include "TodProc.H" +#include "TodHwpIntf.H" +#include "TodSvcUtil.H" +#include <devicefw/userif.H> + +//HWPF +#include <plat_hwp_invoker.H> +#include <p9_tod_setup.H> +#include <p9_tod_save_config.H> +#include <p9_tod_init.H> +#include <isteps/tod_init_reasoncodes.H> + +namespace TOD + +{ + +errlHndl_t todSetupHwp(const p9_tod_setup_tod_sel i_topologyType) +{ + TOD_ENTER(); + + errlHndl_t l_errHdl = NULL; + + do + { + //Get the MDMT + TodProc* l_pMDMT = + TOD::getMDMT(i_topologyType); + + p9_tod_setup_osc_sel l_selectedOsc = TOD_OSC_0; + TOD_INF("For topology 0x%08X Passing OSC 0x%08X to " + " p9_tod_setup ",i_topologyType,l_selectedOsc); + + //Invoke the HWP by passing the topology tree (rooted at MDMT) + FAPI_INVOKE_HWP(l_errHdl, + p9_tod_setup, + l_pMDMT->getTopologyNode(), + i_topologyType, + l_selectedOsc); + if(l_errHdl) + { + TOD_ERR("Error in call to p9_tod_setup. " + "Topology type 0x%.8X. " + "MDMT's HUID is 0x%.8X. " + "MDMT Master type : 0x%.8X. " + "MDMT Bus RX 0x%.8X, Bus TX 0x%.8X.", + i_topologyType, + l_pMDMT->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_pMDMT->getMasterType(), + l_pMDMT->getBusIn(), l_pMDMT->getBusOut()); + + break; + } + }while(0); + + TOD_EXIT(); + + return l_errHdl; +} + + +errlHndl_t todSaveRegsHwp(const p9_tod_setup_tod_sel i_topologyType) +{ + TOD_ENTER(); + + errlHndl_t l_errHdl = NULL; + do + { + //Get the MDMT + TodProc* l_pMDMT = + TOD::getMDMT(i_topologyType); + if(NULL == l_pMDMT) + { + TOD_ERR("MDMT not found for topology type 0x%.8X", + i_topologyType); + /*@ + * @errortype + * @moduleid TOD_SAVEREGS_HWP + * @reasoncode TOD_NO_VALID_MDMT_FOUND + * @userdata1 Topology type (primary/secondary) + * @devdesc MDMT could not be found + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + const bool hbSwError = true; + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_SAVEREGS_HWP, + TOD_NO_VALID_MDMT_FOUND, + i_topologyType, + hbSwError); + break; + } + + //Invoke the HWP by passing the topology tree (rooted at MDMT) + FAPI_INVOKE_HWP(l_errHdl, + p9_tod_save_config, + l_pMDMT->getTopologyNode()); + if(l_errHdl) + { + TOD_ERR("Error in call to p9_tod_save_config. " + "Topology type 0x%.8X. " + "MDMT's HUID is 0x%.8X. " + "MDMT Master type : 0x%.8X. " + "MDMT Bus RX 0x%.8X, Bus TX 0x%.8X.", + i_topologyType, + l_pMDMT->getTarget()->getAttr<TARGETING::ATTR_HUID>(), + l_pMDMT->getMasterType(), + l_pMDMT->getBusIn(), l_pMDMT->getBusOut()); + + break; + } + }while(0); + + TOD_EXIT(); + return l_errHdl; +} + +//***************************************************************************** +//todInitHwp +//***************************************************************************** +errlHndl_t todInitHwp() +{ + TOD_ENTER(); + errlHndl_t l_errHdl = NULL; + do + { + + //Get the MDMT + TodProc* l_pMDMT = + TOD::getMDMT(TOD_PRIMARY); + + if( NULL == l_pMDMT ) + { + TOD_ERR("Valid MDMT not found in the primary TOD topology"); + /*@ + * @errortype + * @moduleid TOD_INIT_HWP + * @reasoncode TOD_NO_VALID_MDMT_FOUND + * @userdata1 EMOD_TOD_INIT_HWP + * @userdata2 PRIMARY topology type + * @devdesc No MDMT present on the system + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + const bool hbSwError = true; + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_INIT_HWP, + TOD_NO_VALID_MDMT_FOUND, + EMOD_TOD_INIT_HWP, + TOD_PRIMARY, + hbSwError); + break; + } + + TARGETING::Target* l_failingTodProc = NULL; + fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> + l_fapiFailingProcTarget(l_failingTodProc); + + //Invoke the HWP by passing the reference to the topology + FAPI_INVOKE_HWP(l_errHdl, + p9_tod_init, + l_pMDMT->getTopologyNode(), + &l_fapiFailingProcTarget); + + if(l_errHdl) + { + TOD_ERR("Error in call to p9_tod_init. " + "MDMT's HUID is 0x%.8X. " + "MDMT Master type : 0x%.8X. ", + GETHUID(l_pMDMT->getTarget()), + l_pMDMT->getMasterType()); + + l_failingTodProc = reinterpret_cast<TARGETING::Target*>( + l_fapiFailingProcTarget.get()); + + break; + } + else + { + TOD_INF("Successfully completed p9_tod_init. " + "MDMT's HUID is 0x%.8X. " + "MDMT Master type : 0x%.8X. ", + GETHUID(l_pMDMT->getTarget()), + l_pMDMT->getMasterType()); + } + + }while(0); + + TOD_EXIT(); + return l_errHdl; +}//todInitHwp + +} diff --git a/src/usr/isteps/tod/TodHwpIntf.H b/src/usr/isteps/tod/TodHwpIntf.H new file mode 100644 index 000000000..b4f574257 --- /dev/null +++ b/src/usr/isteps/tod/TodHwpIntf.H @@ -0,0 +1,127 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodHwpIntf.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 + * + */ + + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +#include "TodProc.H" +#include <p9_tod_utils.H> +#include <errl/errlentry.H> +namespace TOD +{ + +class TodProc; +class TodControls; + +/** + * @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 p9_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 p9_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 p9_tod_setup_tod_sel i_topologyType); + +/** + * @brief Invokes the TOD Initialization hardware procedure + * + * @note Detailed Description: + * This interface invokes the procedure which initializes the + * time of day logic on the functional P8 processors to running + * state. + * + * @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(); + +} +#endif //TODHWPINTF_H diff --git a/src/usr/isteps/tod/TodProc.C b/src/usr/isteps/tod/TodProc.C new file mode 100644 index 000000000..51860b441 --- /dev/null +++ b/src/usr/isteps/tod/TodProc.C @@ -0,0 +1,613 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodProc.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 +//------------------------------------------------------------------------------ +//Standard library +#include <list> +//Targeting support +#include <targeting/common/targetservice.H> +#include <targeting/common/utilFilter.H> +#include <isteps/tod_init_reasoncodes.H> +#include "TodDrawer.H" +#include "TodProc.H" +#include <isteps/tod/TodTypes.H> +#include "TodControls.H" +#include <hwas/common/deconfigGard.H> +#include "TodAssert.H" +#include "TodTrace.H" +//HWPF +#include <fapi2_target.H> +#include <target_types.H> +#include "TodUtils.H" + +extern "C" { + +using namespace fapi2; + +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_ENTER(); + + do + { + if(!iv_procTarget) + { + TOD_ERR_ASSERT("Target input i_procTarget is NULL "); + break; + } + if(!iv_parentDrawer) + { + TOD_ERR_ASSERT("TOD drawer input iv_parentDrawer is NULL "); + break; + } + + TOD_ENTER("Created proc 0x%.8X on drawer 0x%.2X", + iv_procTarget->getAttr<TARGETING::ATTR_HUID>(), + iv_parentDrawer->getId()); + init(); + } while (0); + + 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; + TOD_IMP("Proc 0X%.8X is the drawer master for TOD drawer 0x%.2X", + GETHUID(iv_procTarget), iv_parentDrawer->getId()); + if(TOD_MASTER == i_masterType) + { + TOD_IMP("Proc 0X%.8X is a TOD master", + GETHUID(iv_procTarget)); + 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 + fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP> + (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 + + //Predicates tp look for a functional proc who's HUID is same as + //that of i_destination. This predicate will be applied as a result + //filter to getPeerTargets to determine the connected proc. + TARGETING::PredicateCTM + l_procFilter(TARGETING::CLASS_CHIP,TARGETING::TYPE_PROC); + TARGETING::PredicateIsFunctional l_funcFilter; + TARGETING::PredicateAttrVal<TARGETING::ATTR_HUID> + l_huidFilter( + i_destination->getTarget()->getAttr<TARGETING::ATTR_HUID>()); + TARGETING::PredicatePostfixExpr l_resFilter; + l_resFilter. + push(&l_procFilter). + push(&l_funcFilter). + And(). + push(&l_huidFilter). + And(); + + TARGETING::TargetHandleList l_procList; + TARGETING::TargetHandleList l_busList; + + TARGETING::TargetHandleList::iterator l_busIter = (*l_pBusList).begin(); + for(;l_busIter != (*l_pBusList).end() ; ++l_busIter) + { + l_procList.clear(); + l_busList.clear(); + + //Need this call without result filter to get a handle to the + //peer (bus). I need to access its HUID and chip unit. + TARGETING::getPeerTargets( + l_busList, + *l_busIter, + NULL, + NULL); + + //The call below is to determine the connected proc + TARGETING::getPeerTargets( + l_procList, + *l_busIter, + NULL, + //result filter to get the connected proc + &l_resFilter); + + if(l_procList.size()) + { + if(l_busList.empty()) + { + //This is unlikely, since the proc list is not empty, + //we should have also found a bus, but just a safety check. + TOD_ERR_ASSERT(0, + "Couldn't find a peer for bus 0x%.8X on proc 0x%.8X", + (*l_busIter)->getAttr<TARGETING::ATTR_HUID>(), + iv_procTarget->getAttr<TARGETING::ATTR_HUID>()); + break; + } + //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 + p9_tod_setup_bus l_busOut = NONE; + p9_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); + } + else + { + //Should not be hitting this path if HW procedure is + //correctly defining all the bus types and ports + TOD_ERR("p9_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, + p9_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 7: + o_busPort = XBUS7; + 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) + { + 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. + * @custdesc Service Processor Firmware encountered an internal error + */ + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_MOD_LOG_UNSUPPORTED_BUSTYPE, + TOD_UNSUPPORTED_BUSTYPE, + i_busChipUnitType); +} + +//****************************************************************************** +//TodProc::logUnsupportedBusPort +//****************************************************************************** +void TodProc::logUnsupportedBusPort( + const int32_t i_busPort, + const int32_t i_busChipUnitType, + errlHndl_t& io_errHdl) const +{ + /*@ + * @errortype + * @moduleid TOD_LOG_UNSUPPORTED_BUSPORT + * @reasoncode TOD_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. + * @custdescoff Service Processor Firmware encountered an internal error + */ + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_MOD_LOG_UNSUPPORTED_BUSTYPE, + 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(p9_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 +{ + p9_tod_setup_conf_regs& l_todRegs = iv_tod_node_data->o_todRegs; + + o_todChipData.header.chipID = iv_procTarget-> + getAttr<TARGETING::ATTR_ORDINAL_ID>(); + + o_todChipData.header.flags |= TOD_FUNC; + + fapi2::variable_buffer l_regData((uint32_t)64); + + l_regData.set(l_todRegs.tod_m_path_ctrl_reg(), 0); + o_todChipData.regs.mpcr = l_regData.get<uint32_t>(0); + + l_regData.set(l_todRegs.tod_pri_port_0_ctrl_reg(), 0); + o_todChipData.regs.pcrp0 = l_regData.get<uint32_t>(0); + + l_regData.set(l_todRegs.tod_pri_port_1_ctrl_reg(), 0); + o_todChipData.regs.pcrp1 = l_regData.get<uint32_t>(0); + + l_regData.set(l_todRegs.tod_sec_port_0_ctrl_reg(), 0); + o_todChipData.regs.scrp0 = l_regData.get<uint32_t>(0); + + l_regData.set(l_todRegs.tod_sec_port_1_ctrl_reg(), 0); + o_todChipData.regs.scrp1 = l_regData.get<uint32_t>(0); + + l_regData.set(l_todRegs.tod_s_path_ctrl_reg(), 0); + o_todChipData.regs.spcr = l_regData.get<uint32_t>(0); + + l_regData.set(l_todRegs.tod_i_path_ctrl_reg(), 0); + o_todChipData.regs.ipcr = l_regData.get<uint32_t>(0); + + l_regData.set(l_todRegs.tod_pss_mss_ctrl_reg(), 0); + o_todChipData.regs.psmscr = l_regData.get<uint32_t>(0); + + l_regData.set(l_todRegs.tod_chip_ctrl_reg(), 0); + o_todChipData.regs.ccr = l_regData.get<uint32_t>(0); +} + +}//end of namespace + +} diff --git a/src/usr/isteps/tod/TodProc.H b/src/usr/isteps/tod/TodProc.H new file mode 100644 index 000000000..a89d445cb --- /dev/null +++ b/src/usr/isteps/tod/TodProc.H @@ -0,0 +1,415 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodProc.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 + */ + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +//HWPF - For TOD constants +#include <p9_tod_utils.H> +#include "TodSvcUtil.H" +#include "TodAssert.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 specified + * 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 p9_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 , p9_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, + p9_tod_setup_bus& o_busId) const; + + /** + * @brief Method to create an errlHndl_t object for + * 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 + * 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 : p9_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(p9_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 p9_tod_setup_bus bus type and port + */ + p9_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 p9_tod_setup_bus bus type and port + */ + p9_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 p9_tod_setup_bus i_parentBusOut, + const p9_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 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/tod/TodSvc.C b/src/usr/isteps/tod/TodSvc.C new file mode 100644 index 000000000..543eb93d1 --- /dev/null +++ b/src/usr/isteps/tod/TodSvc.C @@ -0,0 +1,613 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodSvc.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 + */ + + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +//Service Processor components outside +//#include <mboxclientlib.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> +#include "TodSvc.H" +#include "TodControls.H" +#include "TodProc.H" +#include "TodTopologyManager.H" +#include "TodTrace.H" + +#include "TodHwpIntf.H" +#include "TodSvcUtil.H" + +#include <p9_tod_utils.H> +#include <isteps/tod_init_reasoncodes.H> +#include "TodUtils.H" + +//HWP +#include <p9_perv_scom_addresses.H> + +namespace TOD +{ + +TodSvc & TodSvc::getTheInstance() +{ + return Singleton<TodSvc>::instance(); +} + +//****************************************************************************** +//TodSvc::todSetup +//****************************************************************************** +errlHndl_t TodSvc::todSetup() +{ + TOD_ENTER("TodSvc::todSetup"); + + errlHndl_t l_errHdl = NULL; + bool l_isTodRunning = false; + TodTopologyManager l_primary(TOD_PRIMARY); + + do + { + bool l_inMPIPLPath = false; + l_errHdl = isMPIPL(l_inMPIPLPath); + if (l_errHdl) + { + TOD_ERR("Failed to check if in MPIPL path or not"); + break; + } + if (false == l_inMPIPLPath) + { + l_errHdl = + 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 + * @moduleid TOD_SETUP + * @reasoncode TOD_INVALID_ACTION + * @userdata1 ChipTOD logic HW state, 1=running, + * zero otherwise + * @devdesc Error: Creation of TOD topology required when + * TOD HW is running + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_SETUP, + TOD_INVALID_ACTION, + l_isTodRunning); + + break; + + } + } + + TOD::destroy(TOD_PRIMARY); + TOD::destroy(TOD_SECONDARY); + + //Build the list of garded TOD targets + l_errHdl = TOD::buildGardedTargetsList(); + if ( l_errHdl ) + { + TOD_ERR("Call to buildGardedTargetsList failed"); + break; + } + + //Build a set of datastructures to setup creation of the TOD topology + + //We're going to setup TOD for this IPL + //1) Build a set of datastructures to setup creation of the TOD + //topologies. + l_errHdl = 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 + TOD::setConfigStatus(TOD_PRIMARY,true); + + //Build datastructures for secondary topology + l_errHdl = 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 + 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 here 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 = TOD::writeTodProcData(TOD_PRIMARY); + if(l_errHdl) + { + TOD_ERR("TOD setup failure:Failed to write topology register data" + " to the file."); + } + } + + TOD::clearGardedTargetsList(); + TOD_EXIT(); + + return l_errHdl; +} + + +//****************************************************************************** +//TodSvc::readTod +//****************************************************************************** +errlHndl_t TodSvc::readTod(uint64_t& o_todValue) const +{ + TOD_ENTER("readTod"); + + errlHndl_t l_errHdl = NULL; + do + { + TARGETING::Target* l_mdmtOnActiveTopology = NULL; + bool l_isTodRunning = false; + bool l_getTodRunningStatus = false; + p9_tod_setup_tod_sel l_activeConfig = TOD_PRIMARY; + + //Get the currently active TOD configuration + //Don't bother about the TOD runing state, caller should have asked for + //readTOD in correct state. + l_errHdl = TOD::queryActiveConfig( + l_activeConfig,l_isTodRunning, + l_mdmtOnActiveTopology, + l_getTodRunningStatus); + if ( l_errHdl ) + { + TOD_ERR("Call to queryActiveConfig failed "); + break; + } + + TOD_INF(" Active topology %d, HUID of MDMT 0x%08X ", + l_activeConfig, + GETHUID(l_mdmtOnActiveTopology)); + + + //SCOM the TOD value reg + fapi2::variable_buffer o_todValueBuf(64); + l_errHdl = todGetScom(l_mdmtOnActiveTopology, + PERV_TOD_VALUE_REG, + o_todValueBuf); + + if(l_errHdl) + { + TOD_ERR("TOD read error: failed to SCOM TOD value register " + "address 0x%.16llX on MDMT 0x%.8X.", + PERV_TOD_VALUE_REG, + GETHUID(l_mdmtOnActiveTopology)); + break; + } + o_todValue = o_todValueBuf.get<int32_t>(0); + }while(0); + + TOD_EXIT(); + + return l_errHdl; +} + +//****************************************************************************** +//TodSvc::TodSvc +//****************************************************************************** +TodSvc::TodSvc() +{ + TOD_ENTER(); + + TOD_EXIT(); +} + +//****************************************************************************** +//TodSvc::~TodSvc +//****************************************************************************** +TodSvc::~TodSvc() +{ + TOD_ENTER(); + + //Free up held memory + TOD::destroy(TOD_PRIMARY); + TOD::destroy(TOD_SECONDARY); + + TOD_EXIT(); +} + +//****************************************************************************** +//TodSvc::todInit +//****************************************************************************** +errlHndl_t TodSvc::todInit() +{ + TOD_ENTER(); + errlHndl_t l_errHdl = NULL; + bool l_isTodRunning = false; + do + { + //Check if the Chip TOD logic is already Running + l_errHdl = TOD::isTodRunning(l_isTodRunning); + if ( l_errHdl ) + { + TOD_INF("Call to isTodRunning() failed , cannot initialize the" + "Chip TOD logic "); + break; + } + + if ( l_isTodRunning ) + { + TOD_ERR("Cannot initialize the TOD logic while the Chip TOD logic" + "is already running"); + /*@ + * @errortype + * @moduleid TOD_INIT_ALREADY_RUNNING + * @reasoncode TOD_INVALID_ACTION + * @userdata1 EMOD_TOD_INIT + * @userdata2 ChipTOD logic HW state, 1=running, + * zero otherwise + * @devdesc Error: Initialization of chip TOD logic cannot be + * done when its already in the running state + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_INIT_ALREADY_RUNNING, + TOD_INVALID_ACTION, + EMOD_TOD_INIT, + l_isTodRunning); + + break; + + } + + //Call the hardware procedure to initialize the Chip TOD logic to the + //running state using the PRIMARY TOD topology. + l_errHdl = todInitHwp(); + if( l_errHdl ) + { + TOD_ERR("TOD initialization failed for primary topology : HWP"); + l_errHdl->setSev(ERRORLOG::ERRL_SEV_UNRECOVERABLE); + errlCommit(l_errHdl, TOD_COMP_ID); + break; + } + + }while(0); + TOD_EXIT(); + return l_errHdl; +} + +//****************************************************************************** +//TodSvc::setActiveMdmtForResetBackup +//****************************************************************************** +errlHndl_t TodSvc::setActiveMdmtForResetBackup( + const p9_tod_setup_tod_sel i_activeConfig) +{ + TOD_ENTER("setActiveMdmtForResetBackup"); + errlHndl_t l_errHdl = NULL; + + //While doing a resetBackup it was found that in memory copy of active + //topology is not present, (system has done a RR ) + //In order to ensure redundancy of processor and oscillator source on the + //backup topology we needed to have the copy of active topology in memory. + + //However we may not need to recreate the complete active topology from + //the persistant topology information file. + //It would be just sufficient if we have the todControls built and MDMT set + + do{ + + l_errHdl = TOD::buildTodDrawers(i_activeConfig); + if ( l_errHdl ) + { + TOD_ERR("Failed to build TOD drawers for %s", + (TOD::TodSvcUtil:: + topologyTypeToString(i_activeConfig))); + break; + } + + TARGETING::Target* l_primaryMdmt = NULL; + TARGETING::Target* l_secondaryMdmt = NULL; + + //Read the HW to get the configured MDMT's + l_errHdl = TOD::getConfiguredMdmt(l_primaryMdmt, + l_secondaryMdmt); + if ( l_errHdl ) + { + TOD_ERR("Failed to get the configured MDMTs "); + break; + } + + TARGETING::Target* l_mdmtOnActiveTopology = NULL; + l_mdmtOnActiveTopology = ( i_activeConfig == TOD_PRIMARY )? + l_primaryMdmt : l_secondaryMdmt; + + if ( !l_mdmtOnActiveTopology ) //Big problem--This should not happen + + { + TOD_ERR("TOD HW logic is already running but we cannot locate" + "MDMT for the %s , that is active", + (TOD::TodSvcUtil:: + topologyTypeToString(i_activeConfig))); + /*@ + * @errortype + * @moduleid TOD_MDMT_TOPOLOGY + * @reasoncode TOD_NO_VALID_MDMT_FOUND + * @userdata1 EMOD_TOD_SET_ACTIVE_MDMT + * @userdata2 Topology type on which MDMT was searched + * @devdesc Error: Could not find MDMT on active topology + * even though TOD HW logic is running + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_MDMT_TOPOLOGY, + TOD_NO_VALID_MDMT_FOUND, + EMOD_TOD_SET_ACTIVE_MDMT, + i_activeConfig); + break; + + } + + //We have the valid MDMT target now, find the TodProc object + //corresponding to it and also figure out the TodDrawer object to + //which this processor belongs + + //To do so get the TodProc object whose HUID matches with the HUID + //of the active topology's MDMT, and also get the TOD drawer to which + //this TodProc object belongs + TodDrawer* l_masterDrawer = NULL; + TodProc* l_masterProc = NULL; + std::list<TodDrawer*> l_drawerList; + TOD::getDrawers(i_activeConfig, l_drawerList); + + bool l_drawerFound = false; + + for(std::list<TodDrawer*>::iterator l_drawerItr = + l_drawerList.begin(); + ((l_drawerItr != l_drawerList.end()) && !l_drawerFound); + ++l_drawerItr) + { + const std::list<TodProc*>& l_procsList = + (*l_drawerItr)->getProcs(); + for(std::list<TodProc*>::const_iterator l_procItr = + l_procsList.begin(); + ((l_procItr != l_procsList.end()) && !l_drawerFound); + ++l_procItr) + { + if ( + (*l_procItr)->getTarget() + == + l_mdmtOnActiveTopology) + { + l_masterProc = *l_procItr; + l_masterDrawer = *l_drawerItr; + l_drawerFound = true; + } + + } + + } + + if ( !l_masterProc || !l_masterDrawer ) + { + + //This should never happen unless we have goofed up big time + + TOD_ERR("Could not find TOD objects for the configured " + "MDMT 0x%08X on %s", + GETHUID(l_mdmtOnActiveTopology), + (TOD::TodSvcUtil:: + topologyTypeToString(i_activeConfig))); + + //FIX_ME_BEFORE_PRODUCTION_Q1 + bool l_masterProcNotFound = ( !l_masterProc )? true : false; + bool l_masterDrawerNotFound = ( !l_masterDrawer )? true : false; + + /*@ + * @errortype + * @moduleid TOD_FIND_MASTER_PROC + * @reasoncode TOD_MASTER_TARGET_NOT_FOUND + * @userdata1[32:64] 1 = Master proc was not found , zero otherwise + * @userdata1[32:63] 1 = Master drawer was not found, zero otherwise + * @userdata2[0:31] EMOD_TOD_SET_ACTIVE_MDMT + * @userdata2[32:64] Active topology + * @devdesc Either processor or drawer object was not found for + * the MDMT found by reading the processor registers. + * @custdesc Service Processor Firmware encountered an internal + * error + */ + + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_FIND_MASTER_PROC, + TOD_MASTER_TARGET_NOT_FOUND, + TWO_UINT32_TO_UINT64( + l_masterProcNotFound, + l_masterDrawerNotFound), + TWO_UINT32_TO_UINT64( + EMOD_TOD_SET_ACTIVE_MDMT, + i_activeConfig)); + break; + + } + + //Now we have the all the objects required to set the MDMT + (void) TOD::setMdmtOfActiveConfig( + i_activeConfig, + l_masterProc, + l_masterDrawer); + + }while(0); + + TOD_EXIT(); + return l_errHdl; +} + +errlHndl_t TodSvc::isMPIPL( bool& o_mpIPL ) +{ + TOD_ENTER("isMPIPL"); + + errlHndl_t l_errHdl = NULL; + o_mpIPL = false; + + do{ + // Get the top level (system) target handle to check if MPIPL + TARGETING::Target* l_pTopLevelTarget = NULL; + (void)TARGETING::targetService().getTopLevelTarget(l_pTopLevelTarget); + if(NULL == l_pTopLevelTarget) + { + /*@ + * @errortype + * @moduleid TOD_IS_MPIPL + * @reasoncode TOD_TOP_LEVEL_TARGET_NOT_FOUND + * @devdesc Top level Target not found + * @custdesc Service Processor Firmware encountered an internal + * error + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_IS_MPIPL, + TOD_TOP_LEVEL_TARGET_NOT_FOUND); + + TOD_ERR_ASSERT("Error getting top level target"); + break; + } + if(true == l_pTopLevelTarget->getAttr<TARGETING::ATTR_IS_MPIPL_HB>()) + { + TOD_INF("In MPIPL path"); + o_mpIPL = true; + } + }while(0); + + TOD_EXIT( "Output Params - o_mpIPL: %d", o_mpIPL ); + + return l_errHdl; +} + +// Wrapper function for TodSvc::todInit instance +errlHndl_t todInit() +{ + return Singleton<TodSvc>::instance().todInit(); +} + +// Wrapper function for TodSvc::todInit instance +errlHndl_t todSetup() +{ + return Singleton<TodSvc>::instance().todSetup(); +} + +} //namespace TOD diff --git a/src/usr/isteps/tod/TodSvc.H b/src/usr/isteps/tod/TodSvc.H new file mode 100644 index 000000000..c935eac06 --- /dev/null +++ b/src/usr/isteps/tod/TodSvc.H @@ -0,0 +1,261 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodSvc.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 + * + */ + + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ + +#include <util/singleton.H> +#include <targeting/common/targetservice.H> + +#include <p9_tod_utils.H> +#include <sys/time.h> + +namespace TOD +{ + +class TodControls; +//Use "theTodSvc_t::Instance()" to access the singleton via reference +class TodSvc; +typedef Singleton<TodSvc> theTodSvc_t; + +/** + * @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 P9 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) 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 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; + + /** + * @brief This interface should be called during IPL to initialize the + * time of day logic on the P9 processors to running state. + * + * @par Detailed Description: + * Once the TOD topology is setup on the system , the todinit is called + * to initialize the time of day logic on the P9 processors to running + * state. FSPFW needs to do this initialization explicitly for the + * Manufacturing AVP tests to pass. Once the FSP reaches runtime PHYP + * re-initializes it to the 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. + * + * @note This initialization should be called only by the istep after the + * tod is setup. + * + */ + errlHndl_t todInit(); + +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: + + /** + * @brief This is a helper method to resetBackup and will be called to find + * out from HW the MDMT on active topology, and set it in TOD controls. + * + * @par Detailed Description: + * During resetBackup it may happen that FSP has done a RR before + * resetBackup was called in such circumstance the in memory copy of + * topology would have been lost. In order to re-configure the backup + * with adequate redundancy we want to have MDMT of active topology + * configured in TOD controls. + * + * @param[in] i_activeConfig + * Indicates the TOD configuration ( primary/secondary ) for which the + * MDMT is to be set + * + * @return Error log handle indicating the status of the request + * @retval NULL Indicates success + * !NULL means failed to set the MDMT for the active topology + * + */ + errlHndl_t setActiveMdmtForResetBackup( + const p9_tod_setup_tod_sel i_activeConfig); + + //Disabled copy constructor and assignment operator + TodSvc(const TodSvc& rhs); + TodSvc& operator=(const TodSvc& rhs); + + /** + * @brief This method checks if in MPIPL path using attribue ATTR_IS_MPIPL + * + * @param[out] o_mpIPL + * Boolean which indicates if in MPIPL path + * TRUE if MPIPL. FALSE if not. + * + * @return Error log handle indicating the status of the request + * @retval NULL Successfully checked if system in MPIPL path or not + * @retval !NULL Error checking if system in MPIPL path or not + * 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 isMPIPL( bool& o_mpIPL ); + +}; + +// Wrapper function for TodSvc::todInit instance +errlHndl_t todInit(); + +// Wrapper function for TodSvc::todSetup instance +errlHndl_t todSetup(); + +} //namespace TOD + +#endif //TODSVC_H diff --git a/src/usr/isteps/tod/TodSvcUtil.C b/src/usr/isteps/tod/TodSvcUtil.C new file mode 100644 index 000000000..84061181e --- /dev/null +++ b/src/usr/isteps/tod/TodSvcUtil.C @@ -0,0 +1,311 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodSvcUtil.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 The file implements methods of common utility across TOD service + * + */ + + + +//targeting support +#include <targeting/common/commontargeting.H> +#include <targeting/common/util.H> +#include <attributeenums.H> +#include <errl/errlmanager.H> + +#include "TodSvcUtil.H" +#include "TodUtils.H" +#include "TodDrawer.H" +#include "TodTrace.H" +#include "TodAssert.H" +#include <isteps/tod_init_reasoncodes.H> + +namespace TOD + +{ + +//Namespace for containing the utility methods +namespace TodSvcUtil{ + +//****************************************************************************** +//calloutTodEndPoint +//****************************************************************************** +void calloutTodEndPoint( const TARGETING::Target* const i_pTodEndPoint, + errlHndl_t& io_errHdl ) +{ + + /*@ + * @errortype + * @moduleid TOD_ENDPOINT_CALLOUT + * @reasoncode TOD_MASTER_PATH_ERROR + * @userdata1 TOD_ENDPOINT_CALLOUT + * @userdata2 HUID of the TOD end point that is not receiving signal + * @devdesc This TOD end point target on processor is not receiving + * signal from the OSC. + * @custdesc There was a problem in configuring Time Of Day on the Host + * processor. + * + */ + + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_ENDPOINT_CALLOUT, + TOD_MASTER_PATH_ERROR, + EMOD_CALLOUT_TOD_ENDPOINT, + GETHUID(i_pTodEndPoint)); + + io_errHdl->addHwCallout( + i_pTodEndPoint, + HWAS::SRCI_PRIORITY_HIGH, + HWAS::DECONFIG, + HWAS::GARD_Fatal); + + //Get the PEER TOD end point on the OSC and callout as low + io_errHdl->addProcedureCallout( + HWAS::EPUB_PRC_TOD_CLOCK_ERR, + HWAS::SRCI_PRIORITY_LOW); + + //Get the PEER TOD end point on the OSC and callout as low + TARGETING::PredicateCTM l_todEndPointPred( + TARGETING::CLASS_UNIT,TARGETING::TYPE_TODCLK); + + TARGETING::PredicatePostfixExpr l_funcTodEndPointPred; + TARGETING::PredicateHwas l_hwasFunc; + l_hwasFunc.functional(true); + + l_funcTodEndPointPred.push(&l_todEndPointPred). + push(&l_hwasFunc).And(); + + TARGETING::TargetHandleList l_todEndPointList; + + TARGETING::getPeerTargets(l_todEndPointList,//output list + i_pTodEndPoint, //Peer for this TOD end point + NULL, + &l_funcTodEndPointPred);//Destination predicate + + + if ( l_todEndPointList.size() > 1 ) + { + TOD_ERR_ASSERT(0, "More than one PEER TOD end point returned" + " for the target 0x%08X ", + GETHUID(i_pTodEndPoint)); + } + + if ( !l_todEndPointList.empty()) + { + io_errHdl->addHwCallout((*l_todEndPointList.begin()), + HWAS::SRCI_PRIORITY_LOW, + HWAS::DECONFIG, + HWAS::GARD_Fatal); + + } + +} +//****************************************************************************** +//logInvalidTodConfig +//****************************************************************************** +void logInvalidTodConfig( + const uint32_t i_config, + errlHndl_t& io_errHdl) +{ + /*@ + * @errortype + * @moduleid TOD_LOG_INVALID_CONFIG + * @reasoncode TOD_INVALID_CONFIG + * @userdata1 The problematic configuration ( Primary/Secondary) + * @devdesc Error: Erroneous TOD configuration + * Possible Causes: Programming issue + * Resolution: Development team should be contacted. + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_LOG_INVALID_CONFIG, + TOD_INVALID_CONFIG, + i_config); +} + +//****************************************************************************** +//logUnsupportedOrdinalId +//****************************************************************************** +void logUnsupportedOrdinalId( + const uint32_t i_ordinalId, + errlHndl_t& io_errHdl) +{ + /*@ + * @errortype + * @moduleid TOD_LOG_UNSUPORTED_ORDINALID + * @reasoncode TOD_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. + * @custdesc Service Processor Firmware encountered an internal error + */ + io_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_LOG_UNSUPORTED_ORDINALID, + TOD_UNSUPORTED_ORDINALID, + i_ordinalId); + +} + +//****************************************************************************** +//getMaxProcsOnSystem() +//****************************************************************************** +uint32_t getMaxProcsOnSystem() +{ + TOD_ENTER("getMaxProcsOnSystem"); + errlHndl_t l_errHdl = NULL; + // Get the max attribute values in this structure; + maxConfigParamsContainer l_maxCfgParams; + + l_errHdl = getMaxConfigParams(l_maxCfgParams); + + uint32_t l_maxProcCount = 0; + if (!l_errHdl ) + { + l_maxProcCount = l_maxCfgParams.max_compute_nodes_per_sys * + l_maxCfgParams.max_procchips_per_node; + TOD_INF("Maximum procs on system = 0x%08X", l_maxProcCount); + } + else + { + TOD_ERR("getMaxConfigParams() Failed"); + errlCommit(l_errHdl, TOD_COMP_ID); + } + + return (l_maxProcCount); +} + +//****************************************************************************** +//topologyTypeToString +//****************************************************************************** + +char const * topologyTypeToString ( const p9_tod_setup_tod_sel i_topologyType ) +{ + switch ( i_topologyType ) + { + case TOD_PRIMARY: + return "Primary Topology"; + case TOD_SECONDARY: + return "Secondary Topology"; + default: + TOD_ERR_ASSERT("Unknown Topology Type"); + return ""; + } +} + +/****************************************************************************** + * getFuncNodeTargetsOnSystem + *****************************************************************************/ + +errlHndl_t getFuncNodeTargetsOnSystem( + TARGETING::ConstTargetHandle_t i_nodeOrSysTarget, + TARGETING::TargetHandleList& o_nodeList, + const bool i_skipFuncCheck){ + + TOD_ENTER("Function Node Target On System"); + + errlHndl_t l_errHdl = NULL; + + o_nodeList.clear(); + + TARGETING::ATTR_CLASS_type l_class = GETCLASS(i_nodeOrSysTarget); + TARGETING::ATTR_TYPE_type l_type = GETTYPE(i_nodeOrSysTarget); + + do{ + if(NULL == i_nodeOrSysTarget) + { + TOD_ERR("NULL target node passed in"); + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_BUILD_TOD_DRAWERS, + TOD_NULL_INPUT_TARGET, + 0); + break; + } + + //Check if the target is node or system + TARGETING::PredicateCTM l_isNode(TARGETING::CLASS_ENC, + TARGETING::TYPE_NODE); + TARGETING::PredicateCTM l_isSys(TARGETING::CLASS_SYS, + TARGETING::TYPE_SYS); + if((false == l_isNode(i_nodeOrSysTarget)) && + (false == l_isSys(i_nodeOrSysTarget))) + { + TOD_ERR("Target 0x%.8X with class %s, type %s isn't node or sys", + GETHUID(i_nodeOrSysTarget), + TARGETING::attrToString<TARGETING::ATTR_CLASS>(l_class), + TARGETING::attrToString<TARGETING::ATTR_TYPE>(l_type)); + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD_BUILD_TOD_DRAWERS, + TOD_INVALID_TARGET, + GETHUID(i_nodeOrSysTarget)); + break; + } + + if(TARGETING::TYPE_SYS == l_type) //sys target + { + //Use PredicateIsFunctional to filter only functional nodes + TARGETING::PredicateIsFunctional l_isFunctional; + TARGETING::PredicatePostfixExpr l_funcNodeFilter; + l_funcNodeFilter. + push(&l_isNode).push(&l_isFunctional).And(); + + TARGETING::targetService().getAssociated( + o_nodeList, + i_nodeOrSysTarget , + TARGETING::TargetService::CHILD, + TARGETING::TargetService::IMMEDIATE, + i_skipFuncCheck ? + static_cast<TARGETING::PredicateBase*>(&l_isNode) : + static_cast<TARGETING::PredicateBase*>(&l_funcNodeFilter)); + } + else //node target + { + if(i_skipFuncCheck || + (isFunctional(i_nodeOrSysTarget))) + { + o_nodeList.push_back( + const_cast<TARGETING::TargetHandle_t>(i_nodeOrSysTarget)); + } + } + }while(0); + + return l_errHdl; +} + + +}//End of namespace TodSvcUtil + +}//End of namespace TOD diff --git a/src/usr/isteps/tod/TodSvcUtil.H b/src/usr/isteps/tod/TodSvcUtil.H new file mode 100644 index 000000000..32a09a0da --- /dev/null +++ b/src/usr/isteps/tod/TodSvcUtil.H @@ -0,0 +1,168 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodSvcUtil.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 TODSVCUTIL_H +#define TODSVCUTIL_H + +/** + * @file TodSvcUtil.H + * + * @brief Provides definition of functions that are of common use across TOD + * todService + */ + +//Targeting includes +#include <targeting/common/target.H> +#include <p9_tod_setup.H> +#include <string.h> +#include "TodUtils.H" + +namespace TOD +{ + +typedef std::vector<TARGETING::ATTR_HUID_type> + TodEndPointContainer; + +namespace TodSvcUtil{ + + /** + * @brief This method should be called to do a callout on input TOD end + * point target on processor. + * + * @par Detailed Description: + * The method will do the followin + * + * HW callout + * Target | Priority | Deconfig | Gard + * TOD end point on + * Processor High Yes Yes + * + * Tod end point on + * OSC Low Yes Yes + * + * Procedure callout + * EPUB_PRC_TOD_CLOCK_ERR Low + * + * @param[in] i_pTodEndPoint, Input TOD end point target for calling out. + * point target connects. + * + * @param[inout] 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 calloutTodEndPoint( const TARGETING::Target* i_pTodEndPoint, + errlHndl_t& io_errHdl); + + /** + * @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 + * TodChipData structures that will be written in the file + * shared between TOD and HDAT. + * Each TodChipData 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 Return the topology type as string + * + * @param[in] i_topoloyType, The topology type for which its string + * equivalent needs to be returned. + * + * @return String equivalent of the topology type passed as input. + * Method will assert if unsupported topology type is passed as input. + */ + + char const * topologyTypeToString ( + const p9_tod_setup_tod_sel i_topologyType); + + errlHndl_t getFuncNodeTargetsOnSystem( + TARGETING::ConstTargetHandle_t i_nodeOrSysTarget, + TARGETING::TargetHandleList& o_nodeList, + const bool i_skipFuncCheck); + +}//End of namespace TodSvcUtil + +}//End of namespace TOD + +#endif diff --git a/src/usr/isteps/tod/TodTopologyManager.C b/src/usr/isteps/tod/TodTopologyManager.C new file mode 100644 index 000000000..dd53a39f1 --- /dev/null +++ b/src/usr/isteps/tod/TodTopologyManager.C @@ -0,0 +1,712 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodTopologyManager.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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. + */ + + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ +//#include <buffer.H> + +//TARGETING +#include <targeting/common/target.H> +#include <targeting/common/targetservice.H> +#include "TodUtils.H" +#include "TodTopologyManager.H" +#include "TodControls.H" +#include "TodDrawer.H" +#include "TodProc.H" +#include "TodTrace.H" +#include <p9_tod_utils.H> +#include <isteps/tod_init_reasoncodes.H> + +extern "C" { + +using namespace fapi2; + +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"; + +//****************************************************************************** +//TodTopologyManager::TodTopologyManager +//****************************************************************************** +TodTopologyManager::TodTopologyManager( + const p9_tod_setup_tod_sel i_topologyType) : + iv_topologyType(i_topologyType) +{ + TOD_ENTER("Topology type 0X%.8X", i_topologyType); + + TOD_EXIT(); +} +//****************************************************************************** +//TodTopologyManager::~TodTopologyManager +//****************************************************************************** +TodTopologyManager::~TodTopologyManager() +{ + TOD_ENTER(); + + TOD_EXIT(); +} + +//****************************************************************************** +//TodTopologyManager::create +//****************************************************************************** +errlHndl_t TodTopologyManager::create() +{ + TOD_ENTER("TodTopologyManager::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 = + TOD::pickMdmt(iv_topologyType); + if(l_errHdl) + { + TOD_ERR("Couldn't pick MDMT."); + break; + } + + //Get the TOD drawers + TodDrawerContainer l_todDrwList; + TOD::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 + * @moduleid TOD_TOPOLOGY_CREATE + * @reasoncode TOD_CREATION_ERR + * @userdata1 Topology type : primary/secondary + * @devdesc TOD master drawer not found + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + 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(); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::wireProcs +//****************************************************************************** +errlHndl_t TodTopologyManager::wireProcs(const TodDrawer* i_pTodDrawer) +{ + TOD_ENTER(); + + errlHndl_t l_errHdl = NULL; + + do + { + if(NULL == i_pTodDrawer) + { + TOD_ERR("TOD drawer not specified"); + /*@ + * @errortype + * @moduleid TOD_WIRE_PROCS + * @reasoncode TOD_INVALID_PARAM + * @userdata1 Topology type : primary/secondary + * @devdesc TOD drawer not specified + * @custdesc Service Processor Firmware encountered an internal + * error + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_PROCS, + TOD_INVALID_PARAM, + iv_topologyType); + break; + } + + TOD_INF("TOD drawer id 0x%.2X", 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<TARGETING::ATTR_HUID>(), + (*l_sourceItr)->getTarget()-> + getAttr<TARGETING::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<TARGETING::ATTR_HUID>()); + + /*@ + * @errortype + * @moduleid TOD_WIRE_PROCS + * @reasoncode TOD_CREATION_ERR + * @userdata1[0:31] Topology type : primary/secondary + * @userdata1[32:63] TOD drawer id + * @userdata2 HUID of first disconnected proc + * @devdesc TOD drawer has one or more disconnected procs + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_PROCS, + TOD_CREATION_ERR, + TWO_UINT32_TO_UINT64( + iv_topologyType, + i_pTodDrawer->getId()), + (*(l_targetsList.begin()))->getTarget()-> + getAttr<TARGETING::ATTR_HUID>()); + break; + } + }while(0); + + TOD_EXIT(); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::wireTodDrawer +//****************************************************************************** +errlHndl_t TodTopologyManager::wireTodDrawer(TodDrawer* i_pTodDrawer) +{ + TOD_ENTER("wireTodDawer"); + + errlHndl_t l_errHdl = NULL; + + do + { + if(NULL == i_pTodDrawer) + { + TOD_ERR("TOD drawer not specified"); + /*@ + * @errortype + * @moduleid TOD_WIRE_DRAWERS + * @reasoncode TOD_INVALID_PARAM + * @userdata1 Topology type : primary/secondary + * @devdesc TOD drawer not specified + * @custdesc Service Processor Firmware encountered an internal + * error + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_INVALID_PARAM, + iv_topologyType); + break; + } + + TOD_INF("TOD drawer id 0x%.2X", 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 = TOD::getMDMT(iv_topologyType); + if(NULL == l_pMDMT) + { + TOD_ERR("MDMT not found for topology type 0X%.8X", + iv_topologyType); + /*@ + * @errortype + * @moduleid TOD_WIRE_DRAWERS + * @reasoncode TOD_MASTER_TARGET_NOT_FOUND + * @userdata1 Topology type : primary/secondary + * @devdesc MDMT could not be found + * @custdesc Service Processor Firmware couldn't detect any + * functional master processor required to boot the + * host + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_MASTER_TARGET_NOT_FOUND, + 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<TARGETING::ATTR_HUID>(), + l_pMDMT->getTarget()->getAttr<TARGETING::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 + * @moduleid TOD_WIRE_DRAWERS + * @reasoncode TOD_CREATION_ERR + * @userdata1 Topology type : primary/secondary + * @userdata2 TOD drawer id + * @devdesc TOD drawer couldn't be wired + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_CREATION_ERR, + iv_topologyType, + i_pTodDrawer->getId()); + break; + } + }while(0); + + TOD_EXIT(); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::dumpTopology +//****************************************************************************** +void TodTopologyManager::dumpTopology() const +{ + TOD_ENTER("dumpTopology"); + + static const char* busnames[BUS_MAX+1] = {0}; + busnames[NONE] = NO_BUS; + busnames[XBUS0] = X_BUS_0; + busnames[XBUS1] = X_BUS_1; + busnames[XBUS2] = X_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; + TOD::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---bus out---bus in---child"); + TodProcContainer::const_iterator l_procItr = + l_procList.begin(); + //FIX_ME_BEFORE_PRODUCTION_TASK32 + //bool l_ecmdTargetFound = false; + while(l_procList.end() != l_procItr) + { + if(TodProc::TOD_MASTER == (*l_procItr)->getMasterType()) + { + TOD_INF("Proc 0x%.8X is the MDMT", + (*l_procItr)->getTarget()->getAttr<TARGETING::ATTR_HUID>()); + } + + 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<TARGETING::ATTR_HUID>(), + busnames[(*l_childItr)->getBusIn()], + busnames[(*l_childItr)->getBusOut()], + (*l_childItr)->getTarget()->getAttr<TARGETING::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(); + + 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]); + + fapi2::variable_buffer l_regData(64); + //Get the TOD drawers + TodDrawerContainer l_todDrwList; + TOD::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<TARGETING::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"); + } + p9_tod_setup_conf_regs l_todRegs; + (*l_procItr)->getTodRegs(l_todRegs); + l_regData.set(l_todRegs.tod_m_path_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> MASTER PATH CONTROL REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + l_regData.set(l_todRegs.tod_pri_port_0_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> PORT 0 PRIMARY CONFIG REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + l_regData.set(l_todRegs.tod_pri_port_1_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> PORT 1 PRIMARY CONFIG REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + l_regData.set(l_todRegs.tod_sec_port_0_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> PORT 0 SECONDARY CONFIG REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + l_regData.set(l_todRegs.tod_sec_port_1_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> PORT 1 SECONDARY CONFIG REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + l_regData.set(l_todRegs.tod_s_path_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> SLAVE PATH CONTROL REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + l_regData.set(l_todRegs.tod_i_path_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> INTERNAL PATH CONTROL REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + l_regData.set(l_todRegs.tod_pss_mss_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> PRIMARY/SECONDARY MASTER/SLAVE CONTROL" + " REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + l_regData.set(l_todRegs.tod_chip_ctrl_reg(), 0); + TOD_INF("TOD REGDUMP> CHIP CONTROL REG 0x%.16llX", + l_regData.get<uint32_t>(0)); + ++l_procItr; + } + ++l_drwItr; + } + TOD_INF("TOD REGDUMP> End"); + }while(0); + + TOD_EXIT(); +} + +//****************************************************************************** +//TodTopologyManager::wireProcsInSmpWrapMode +//****************************************************************************** +errlHndl_t TodTopologyManager::wireProcsInSmpWrapMode( + TodProcContainer& io_sourcesList, + TodProcContainer& io_targetsList) +{ + TOD_ENTER(); + + errlHndl_t l_errHdl = NULL; + + do + { + TodProcContainer::iterator l_sourceItr = io_sourcesList.begin(); + TodProcContainer::iterator l_targetItr; + bool l_connected = false; + while((NULL == l_errHdl) && (io_sourcesList.end() != l_sourceItr)) + { + for(l_targetItr = io_targetsList.begin(); + l_targetItr != io_targetsList.end();) + { + l_errHdl = (*l_sourceItr)->connect(*l_targetItr, + TARGETING::TYPE_ABUS, + l_connected); + if(l_errHdl) + { + TOD_ERR("Error tying to connect target 0x%.8X " + "to source 0x%.8X.", + (*l_targetItr)->getTarget()-> + getAttr<TARGETING::ATTR_HUID>(), + (*l_sourceItr)->getTarget()-> + getAttr<TARGETING::ATTR_HUID>()); + break; + } + if(l_connected) + { + io_sourcesList.push_back(*l_targetItr); + (*l_sourceItr)->addChild(*l_targetItr); + l_targetItr = io_targetsList.erase(l_targetItr); + } + else + { + ++l_targetItr; + } + } + ++l_sourceItr; + } + }while(0); + + TOD_EXIT(); + + return l_errHdl; +} + +} //namespace TOD + +} diff --git a/src/usr/isteps/tod/TodTopologyManager.H b/src/usr/isteps/tod/TodTopologyManager.H new file mode 100644 index 000000000..dfd653c92 --- /dev/null +++ b/src/usr/isteps/tod/TodTopologyManager.H @@ -0,0 +1,211 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodTopologyManager.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2012,2017 */ +/* [+] 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 + */ + + +//------------------------------------------------------------------------------ +//Includes +//------------------------------------------------------------------------------ + +#include "TodProc.H" + +//HWPF - For TOD constants +#include <p9_tod_utils.H> + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Forward declarations +//------------------------------------------------------------------------------ +class TodDrawer; +class TodControls; + +/** + * @class TodSvc + * + * @brief Creates TOD topologies + */ +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 p9_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 TodDrawer + * + * @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); + + /** + * @brief Wires, or sets the A bus connection paths between + * intra-drawer processors. Such connections exist in the + * wrap test mode. + * + * @param[in/out] io_sourcesList + * List of procs that may be connected to. List grows as we + * connect procs, each newly connected proc is a potential + * source. + * + * @param[in/out] io_targetsList + * List of procs that need to be connected. Once a proc is + * connected, it is removed from this list. + * + * @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 wireProcsInSmpWrapMode( + TodProcContainer& io_sourcesList, + TodProcContainer& io_targetsList); + + //Holds the type of the topology this manager is working on : + //primary/secondary + p9_tod_setup_tod_sel iv_topologyType; + +}; + +} //namespace TOD +#endif //#define TODTOPOLOGYMANAGER_H diff --git a/src/usr/isteps/tod/TodTrace.H b/src/usr/isteps/tod/TodTrace.H new file mode 100644 index 000000000..b3ce42260 --- /dev/null +++ b/src/usr/isteps/tod/TodTrace.H @@ -0,0 +1,61 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodTrace.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] 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> +#include <initservice/isteps_trace.H> + +namespace TOD +{ + +// field traces ------------------- + +#define TOD_TRAC(args...) TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + " TOD:: " args) +#define TOD_ENTER(args...) TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + ENTER_MRK" TOD:: " args) +#define TOD_EXIT(args...) TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + EXIT_MRK" TOD:: " args) +#define TOD_ERR(args...) TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + ERR_MRK" TOD:: " args) +#define TOD_INF(args...) TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + INFO_MRK" TOD:: " args) +#define TOD_IMP(args...) TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + INFO_MRK" TOD:: " args) + +// debug traces ------------------- + +#define TOD_DTRAC(args...) TRACDCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + " TOD:: " args) +#define TOD_DENTER(args...) TRACDCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + ENTER_MRK" TOD:: " args) +#define TOD_DEXIT(args...) TRACDCOMP(ISTEPS_TRACE::g_trac_isteps_trace,\ + EXIT_MRK" TOD:: " args) + +} + +#endif + diff --git a/src/usr/isteps/tod/TodUtils.C b/src/usr/isteps/tod/TodUtils.C new file mode 100644 index 000000000..a1a1ede63 --- /dev/null +++ b/src/usr/isteps/tod/TodUtils.C @@ -0,0 +1,181 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodUtils.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] 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 */ + +// Includes +// /***********************************************************************/ + +#include "TodAssert.H" +#include "TodUtils.H" +#include <devicefw/userif.H> +#include <isteps/tod_init_reasoncodes.H> +#include <errl/errlentry.H> +#include <errl/errlmanager.H> + +namespace TOD + +{ + +//****************************************************************************** +// isFunctional +//****************************************************************************** + +bool isFunctional(const TARGETING::Target* i_pTarget) +{ + //-------------------------------------------------------------------------- + // Local Variables + //-------------------------------------------------------------------------- + + errlHndl_t l_errl = NULL; + bool l_isFunctional = false; + + //-------------------------------------------------------------------------- + // Code + //-------------------------------------------------------------------------- + + if(i_pTarget) + { + // For now return true if state is FUNCTIONAL else false. + // There are total 4 HWAS functional states can exist: + // NON FUNCTIONAL,FUNCTIONAL,CM FUNCTIONAL and DUMP FUNCTIONAL. + // In-order to consider CM & DUMP FUNCTIONAL states we need to check + // whether system is in CM/DUMP mode. Since the CM/DUMP mode support + // is not available, we'll continue using FUNCTIONAL state only. + // Later we need to check for appropriate mode and state. + // @TODO via RTC: 69925 + l_isFunctional = + i_pTarget->getAttr<TARGETING::ATTR_HWAS_STATE>().functional; + } + else + { + // If i_pTarget is NULL then create an error log + TOD_ERR("Input Target handle is null"); + + //Create error + /*@ + * @errortype + * @moduleid TOD_FUNCTIONAL_TARGET + * @reasoncode TOD_INVALID_TARGET + * @devdesc NULL Target is supplied as an input + * @custdesc Service Processor Firmware encountered an internal + * error + */ + l_errl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_FUNCTIONAL_TARGET, + TOD_INVALID_TARGET); + + errlCommit(l_errl, TOD_COMP_ID); + } + + return l_isFunctional; +} + + + +//****************************************************************************** +//todGetScom() +//****************************************************************************** +errlHndl_t todGetScom(const TARGETING::Target * i_target, + const uint64_t i_address, + fapi2::variable_buffer & o_data) +{ + 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)); + + return l_err; +} + + +/*****************************************************************************/ +// getMaxConfigParams +/*****************************************************************************/ +errlHndl_t getMaxConfigParams( + maxConfigParamsContainer& o_maxConfigParams) +{ + TOD_ENTER("getMaxConfigParams"); + errlHndl_t l_err = NULL; + + do + { + //Get the top level (system) target handle + TARGETING::Target* l_pTopLevel = NULL; + (void)TARGETING::targetService().getTopLevelTarget(l_pTopLevel); + + // Assert on failure getting system target + if(NULL == l_pTopLevel) + { + TOD_ERR_ASSERT("NULL top level target found"); + break; + + } + // Top level target successfully retrieved. Now get attributes + + o_maxConfigParams.max_procchips_per_node = l_pTopLevel->getAttr + < TARGETING::ATTR_MAX_PROC_CHIPS_PER_NODE > (); + + o_maxConfigParams.max_exs_per_procchip = l_pTopLevel->getAttr + < TARGETING::ATTR_MAX_EXS_PER_PROC_CHIP > (); + + o_maxConfigParams.max_dimms_per_mbaport = l_pTopLevel->getAttr + < TARGETING::ATTR_MAX_DIMMS_PER_MBA_PORT > (); + + o_maxConfigParams.max_mbaports_per_mba = l_pTopLevel->getAttr + < TARGETING::ATTR_MAX_MBA_PORTS_PER_MBA > (); + + o_maxConfigParams.max_mbas_per_membuf = l_pTopLevel->getAttr + < TARGETING::ATTR_MAX_MBAS_PER_MEMBUF_CHIP > (); + + o_maxConfigParams.max_chiplets_per_proc = l_pTopLevel->getAttr + < TARGETING::ATTR_MAX_CHIPLETS_PER_PROC > (); + + o_maxConfigParams.max_mcs_per_sys = l_pTopLevel->getAttr + < TARGETING::ATTR_MAX_MCS_PER_SYSTEM > (); + + // TODO RTC 181481: attribute ATTR_MAX_COMPUTE_NODES_PER_SYSTEM is + // currently not implemented as needed to do this assignment. I was + // assured (10/2017) that HB only supports one node, so I am defaulting + // this to 1. In the future HB will need to be multi-node aware and + // TARGETING::ATTR_MAX_COMPUTE_NODES_PER_SYSTEM implemented. + o_maxConfigParams.max_compute_nodes_per_sys = 1; +// o_maxConfigParams.max_compute_nodes_per_sys = l_pTopLevel->getAttr +// < TARGETING::ATTR_MAX_COMPUTE_NODES_PER_SYSTEM > (); + + } while(0); + + TOD_EXIT(); + + return l_err; +} + +}//end of TOD namespace + diff --git a/src/usr/isteps/tod/TodUtils.H b/src/usr/isteps/tod/TodUtils.H new file mode 100644 index 000000000..3ddd6998c --- /dev/null +++ b/src/usr/isteps/tod/TodUtils.H @@ -0,0 +1,212 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/TodUtils.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2010,2017 */ +/* [+] 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_HOSTBOOT_H +#define __TOD_HOSTBOOT_H + + +#include <attributeenums.H> +#include <errl/errlentry.H> +#include <fapi2.H> +#include "TodTrace.H" +#include <util/utilmem.H> + +//FIX_ME_BEFORE_PRODUCTION_Q12 Update these + +//moved from mboxclientlib.H +/** @enum mboxTodTopologyAction + * Values used to determine whether to enable, disable or switch TOD + * topologies. + */ +enum mboxTodTopologyAction +{ + MBOX_DISABLE_TOPOLOGY = 0, + MBOX_ENABLE_TOPOLOGY = 1, + MBOX_SWITCH_TOPOLOGY = 99 +}; // end mboxTodTopologyAction + +/** @enum mboxTopologyValue + * Values used to determine whether to enable, disable or switch TOD + * topologies. + */ +enum mboxTopologyValue +{ + MBOX_PRIMARY_TOPOLOGY = 0, + MBOX_SECONDARY_TOPOLOGY = 1 +}; // end mboxTopologyValue + +/** + * Retrieve the CLASS of the target, or return NA if the target is NULL + */ +#define GETCLASS(pTarget) (((pTarget) == NULL) ? (TARGETING::CLASS_NA) : \ + ((pTarget)->getAttr<TARGETING::ATTR_CLASS>())) + +/** + * * Retrieve the TYPE of the target, or return NA if the target is NULL + * */ +#define GETTYPE(pTarget) (((pTarget) == NULL) ? (TARGETING::TYPE_NA) : \ + ((pTarget)->getAttr<TARGETING::ATTR_TYPE>())) + + +namespace TOD +{ + +struct maxConfigParams +{ + uint8_t max_procchips_per_node; // This will contain the maximum proc + // chips per Node available on the system + uint8_t max_exs_per_procchip; // This will contain the maximum cores per + // proc chip on the system + uint8_t max_dimms_per_mbaport; // This will contain the maximum dimms per + // MBA Port available on the system + uint8_t max_mbaports_per_mba; // This will contain the maximum MBA Ports + // per MBA available on the system + uint8_t max_mbas_per_membuf; // This will contain the maximum MBA per + // Memory Buffer available on the system + uint8_t max_psilinks_per_fsp; // This will contain the maximum psi links + // per fsp which is same on all Systems + uint8_t min_psilinks_per_fsp; // This will contain minimum number of psi + // links per fsp present in the system + uint8_t max_chiplets_per_proc; // This will contain the maximum chiplets + // per proc available on the System + uint8_t max_mcs_per_sys; // This will contain max mcs + // present in the system + uint8_t max_compute_nodes_per_sys; // This will contain max compute + // nodes present in the system + uint8_t max_exs_per_procchip_archlimit; // This will contain max + // Architecture limit of max exs + // per proc chip + + /** + * @brief Copies the data from maxConfigParams structure into the buffer + * @par Detailed Description + * Copies the data from maxConfigParams structure into the buffer + * + * @param[out] o_utilBuf + * Output buffer in which the data from the structure will be copied + * This buffer will be cleared and data will be written from beginning of + * the stream. After the data is updated ,the buffer pointer will be + * pointing to the end of the inserted data + * + * @return Error log handle indicating the status of the request + * + * @retval NULL Successfully copied the data from maxConfigParams structure + * into the buffer + * @retval !NULL Failed to copy the data from maxConfigParams structure + * into the buffer + * + * 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 flatten(UtilMem& o_utilBuf )const ; + + + /** + * @brief Copies the data from the input buffer to the maxConfigParams + * structure + * @par Detailed Description + * Copies the data from the input buffer to the maxConfigParams + * structure + * + * @param[in] i_utilBuf + * Input buffer from which the data will be copied to the structure + * @note Input buffer must contain only the maxConfigParams info and + * the buffer pointer must be pointing to index 0 of the buffer. + * The call will not alter any error in the existing input stream + * + * @return Error log handle indicating the status of the request + * + * @retval NULL Successfully copied the data from buffer into the + * maxConfigParams structure + * @retval !NULL Failed to copy the data from buffer into the + * maxConfigParams structure + * + * 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 unflatten(const UtilMem& i_utilBuf); + + + /** + * @brief Returns the Size of data which is held in the maxConfigParams + * structure + * @par Detailed Description + * Returns the size of data which is held in the maxConfigParams structure + * + * + * @return + * Returns the size of data which is held in the maxConfigParams structure + */ + + uint32_t flattenSize(void) const; +}; + +typedef maxConfigParams maxConfigParamsContainer; + + +errlHndl_t getMaxConfigParams(maxConfigParamsContainer& o_maxConfigParams); + +#define GETHUID(pTarget) (((pTarget) == NULL) ? (0) : \ + ((pTarget)->getAttr<TARGETING::ATTR_HUID>())) + +//moved from fapi_sbe_common.H +#define CONST_UINT64_T(name, expr) const uint64_t name = (expr); +#define ULL(x) x##ull +//moved from p8_scom_addresses.H +CONST_UINT64_T( TOD_PSS_MSS_STATUS_REG_00040008 , ULL(0x00040008) ); + +//****************************************************************************** +// isFunctional +//****************************************************************************** + +bool isFunctional(const TARGETING::Target* i_pTarget); + + +//moved from TodSvcUtil.C from open powervm p8 +//****************************************************************************** +// todGetScom +//****************************************************************************** +errlHndl_t todGetScom(const TARGETING::Target * i_target, + const uint64_t i_address, + fapi2::variable_buffer & o_data); +}// end of namespace + +#endif //end of .H file diff --git a/src/usr/isteps/tod/makefile b/src/usr/isteps/tod/makefile new file mode 100644 index 000000000..aaad0b413 --- /dev/null +++ b/src/usr/isteps/tod/makefile @@ -0,0 +1,39 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/isteps/tod/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2016,2017 +# [+] 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 + +OBJS += TodControls.o +OBJS += TodDrawer.o +OBJS += TodProc.o +OBJS += TodSvc.o +OBJS += TodHwpIntf.o +OBJS += TodTopologyManager.o + +SUBDIRS += runtime.d + +include tod.mk diff --git a/src/usr/isteps/tod/runtime/makefile b/src/usr/isteps/tod/runtime/makefile new file mode 100644 index 000000000..5c65fd3ff --- /dev/null +++ b/src/usr/isteps/tod/runtime/makefile @@ -0,0 +1,37 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/isteps/tod/runtime/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2016,2017 +# [+] 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 + +HOSTBOOT_RUNTIME = 1 + +ROOTPATH = ../../../../.. + +MODULE = tod_rt + +EXTRAINCDIR += ${ROOTPATH}/src/usr/isteps/tod +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/isteps/ + +OBJS += rt_todintf.o + +include ../tod.mk diff --git a/src/usr/isteps/tod/runtime/rt_todintf.C b/src/usr/isteps/tod/runtime/rt_todintf.C new file mode 100644 index 000000000..c79419604 --- /dev/null +++ b/src/usr/isteps/tod/runtime/rt_todintf.C @@ -0,0 +1,753 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/tod/runtime/rt_todintf.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2014,2017 */ +/* [+] 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 */ + +#include <isteps/tod/runtime/rt_todintf.H> +#include <TodTrace.H> // TOD_ENTER, TOD_EXIT +#include <TodUtils.H> // GETHUID +#include <TodSvcUtil.H> // getMaxProcsOnSystem + +#include <runtime/interface.h> // g_hostInterfaces +#include <tod_init_reasoncodes.H> // TOD_RT_TOPOLOGY_RESET_BACKUP, etc + +namespace TOD +{ + +const size_t MSG_OSC_ORDINAL_ID_LOC = 0; +const size_t MSG_OSC_ORDINAL_NODE_HUID_LOC = 1; +const size_t MSG_OSC_HUIDS_LOC = 2; +const size_t MSG_OSC_SIZE_OF_DETAILS = 2; + +//***************************************************************************** +// resetBackupTopology +//***************************************************************************** +errlHndl_t resetBackupTopology( + uint32_t i_oscPos, + const TARGETING::TargetHandle_t& i_procOscTgt, + const TARGETING::TargetHandleList& i_badChipList, + bool i_informPhyp) +{ + TOD_ENTER("resetBackupTopology"); + errlHndl_t l_err = nullptr; + + // Put the handle to the firmware request out here + // so it is easier to free later + hostInterfaces::hbrt_fw_msg *l_req_fw_msg = nullptr; + + do + { + if ((nullptr == g_hostInterfaces) || + (nullptr == g_hostInterfaces->firmware_request)) + { + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid TOD::TOD_RT_TOPOLOGY_RESET_BACKUP + * @reasoncode TOD::TOD_RT_NULL_FIRMWARE_REQUEST_PTR + * @devdesc Host interfaces are not initialized + * @custdesc An internal error occurred. This will force the + * Time of Day function to run with complete + * redundancy. + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD::TOD_RT_TOPOLOGY_RESET_BACKUP, + TOD::TOD_RT_NULL_FIRMWARE_REQUEST_PTR, + 0, 0, true); + + break; + } + + // First, I'll present the format of the data + // to help with the understanding of the code that follows + // The format of the data to be sent, according to the document + // "Handle PRD Request for resetting backup TOD topology" is as follows + // Ordinal ID - 0xFFFFFFFF means no OSC to be avoided + // HUID of the node - This field should be considered only if Ordinal + // ID is NOT set to 0xFFFFFFFF otherwise it is set + // to 0 + // HUID of the first processor + // HUID of the second processor, etc + + // Flag to determine if the OSC data will be added to the data + bool l_addOscData = (0xFFFFFFFF != i_oscPos) && + (nullptr != i_procOscTgt); + + // Calculate the size of the data that is being added to the + // generic struct + size_t l_data_size = 0; + + // Add to the size iff there is data needing to be passed + if (i_badChipList.size() > 0) + { + // if the bad chip list has any items then increase size to + // accommodate for an ordinal ID and a HUID, regardless if + // they have relevant data or not, because they are expected + // before the HUID list. + l_data_size += (MSG_OSC_SIZE_OF_DETAILS * sizeof(uint32_t)) + + (i_badChipList.size() * sizeof(uint32_t)); + } + else if (l_addOscData) + { + // if there is a valid OSC then accommodate for an ordinal ID + // and HUID of node, but don't need space for HUID list because, + // if we are here, the list is empty + l_data_size += (MSG_OSC_SIZE_OF_DETAILS * sizeof(uint32_t)); + } + + // Update the data size with the size of the generic msg struct + if (l_data_size < sizeof(hostInterfaces::hbrt_fw_msg::generic_msg.data)) + { + // If the current size of the data is less than the size of the + // data within the generic message (GenericFspMboxMessage_t.data), + // then default the data size to just the generic message because + // the size of the data to be passed in + // GenericFspMboxMessage_t.dataSize has be at the minimum - the + // size of the generic message (sizeof(GenericFspMboxMessage_t)). + l_data_size = sizeof(hostInterfaces::hbrt_fw_msg::generic_msg); + } + else + { + // If the current size of the data is greater than the size of the + // data within the generic message (GenericFspMboxMessage_t.data), + // then add the size of the generic message minus the size of + // generic message's data. + l_data_size += sizeof(hostInterfaces::hbrt_fw_msg::generic_msg) - + sizeof(hostInterfaces::hbrt_fw_msg::generic_msg.data); + } + + // At last. Calculate the TOTAL size of hostInterfaces::hbrt_fw_msg + // which means only adding hostInterfaces::HBRT_FW_MSG_BASE_SIZE to + // the previous calculated data size + size_t l_req_fw_msg_size = hostInterfaces::HBRT_FW_MSG_BASE_SIZE + + l_data_size; + + // Create the firmware request structure to carry the TOD data + l_req_fw_msg =(hostInterfaces::hbrt_fw_msg *)malloc(l_req_fw_msg_size); + + // Set the data for the request + l_req_fw_msg->io_type = hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ; + l_req_fw_msg->generic_msg.initialize(); + l_req_fw_msg->generic_msg.dataSize = l_data_size; + l_req_fw_msg->generic_msg.msgq = MBOX::FSP_TOD_MSGQ; + l_req_fw_msg->generic_msg.msgType = (false == i_informPhyp ? + GFMM_MSG_TOD_BACKUP_RESET: + GFMM_MSG_TOD_BACKUP_RESET_INFORM_PHYP); + l_req_fw_msg->generic_msg.__req = GFMM_REQUEST; + l_req_fw_msg->generic_msg.__onlyError = GFMM_NOT_ERROR_ONLY; + + // A convenient way to populate the data + uint32_t* l_dataPtr = (uint32_t*)&(l_req_fw_msg->generic_msg.data); + + if (i_badChipList.size() > 0) + { + // set the ordinal ID + l_dataPtr[MSG_OSC_ORDINAL_ID_LOC] = i_oscPos; + + // attach the HUIDs from bad chip list to end of structure + size_t i = MSG_OSC_HUIDS_LOC; + for (auto l_target : i_badChipList) + { + l_dataPtr[i++] = GETHUID(l_target); + } + } + + // Set the HUID of the ordinal node if need be + if (l_addOscData) + { + // set the ordinal ID + l_dataPtr[MSG_OSC_ORDINAL_ID_LOC] = i_oscPos; + + // Get the parent node target + TARGETING::TargetHandleList l_list; + TARGETING::targetService().getAssociated(l_list, + i_procOscTgt, + TARGETING::TargetService::PARENT, + TARGETING::TargetService::IMMEDIATE); + + if (l_list.size() == 1) + { + l_dataPtr[MSG_OSC_ORDINAL_NODE_HUID_LOC] = GETHUID(l_list[0]); + } + else + { + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid TOD::TOD_RT_TOPOLOGY_RESET_BACKUP + * @reasoncode TOD::TOD_INVALID_TARGET + * @devdesc No parent for processor osc target + * @custdesc An internal error occurred. This will force + * the Time of Day function to run with complete + * redundancy. + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD::TOD_RT_TOPOLOGY_RESET_BACKUP, + TOD::TOD_INVALID_TARGET, + 0, 0, true); + + break; + } + } + + // No data is returning from the call, just capture any errors + hostInterfaces::hbrt_fw_msg l_resp_fw_msg; + size_t l_resp_fw_msg_size = sizeof(l_resp_fw_msg); + + // Clear the response structure + memset(&l_resp_fw_msg, 0, l_resp_fw_msg_size); + + // Send the data via a firmware request + size_t rc = g_hostInterfaces->firmware_request( + l_req_fw_msg_size, l_req_fw_msg, + &l_resp_fw_msg_size, &l_resp_fw_msg); + + // Error log id + uint32_t l_errPlid(0); + + // Create a useful structure to get to the PLID + // The PLID is expected to be in the first 4 bytes of the data + // if it exists + struct hbrtFspRespData_t + { + uint32_t plid; + uint32_t otherData; + } PACKED ; + + hbrtFspRespData_t *l_hbrtFspRespData = + (hbrtFspRespData_t*)&(l_resp_fw_msg.generic_msg.data); + + // Capture the error log ID if any + // The return code (rc) may return OK, but there still may be an issue + // with the HWSV code on the FSP. + if ((hostInterfaces::HBRT_FW_MSG_HBRT_FSP_RESP + == l_resp_fw_msg.io_type) && + (GFMM_ERROR_ONLY == l_resp_fw_msg.generic_msg.__onlyError) && + (0 != l_hbrtFspRespData->plid) ) + { + l_errPlid = l_hbrtFspRespData->plid; + } + + // Gather up the error data and create an error log out of it + if (rc || l_errPlid) + { + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid TOD::TOD_RT_TOPOLOGY_RESET_BACKUP + * @reasoncode TOD::TOD_RT_TOPOLOGY_RESET_BACKUP_ERR + * @userdata1[0..31] Hypervisor return code + * @userdata1[32:63] HWSV error log id (if any) + * @userdata2[0:31] MBOX message type + * @userdata2[32:63] TOD message type + * @devdesc TOD reset backup topology failed + * @custdesc An internal error occurred. This will force + * the Time of Day function to run with complete + * redundancy. + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD::TOD_RT_TOPOLOGY_RESET_BACKUP, + TOD::TOD_RT_TOPOLOGY_RESET_BACKUP_ERR, + TWO_UINT32_TO_UINT64(rc, l_errPlid), + TWO_UINT32_TO_UINT64( + l_req_fw_msg->generic_msg.msgq, + l_req_fw_msg->generic_msg.msgType), + true); + + l_err->addFFDC( ISTEP_COMP_ID, + &l_resp_fw_msg, + l_resp_fw_msg_size, + 0, 0, false ); + + if (sizeof(l_req_fw_msg) > 0) + { + l_err->addFFDC( ISTEP_COMP_ID, + l_req_fw_msg, + sizeof(l_req_fw_msg), + 0, 0, false ); + } + + l_err->collectTrace( "TOD", 256); + + if (l_errPlid) + { + l_err->plid(l_errPlid); + } + + break; + } + } + while (0); + + // The firmware request message is no longer needed - free the data + free(l_req_fw_msg); + + TOD_EXIT("resetBackupTopology"); + return l_err; + +} // end resetBackupTopology + + +//***************************************************************************** +// readTodProcDataFromFile +//***************************************************************************** +errlHndl_t readTodProcDataFromFile(TodChipDataContainer& o_todChipData) +{ + TOD_ENTER("readTodProcDataFromFile"); + errlHndl_t l_err = nullptr; + + // Put the handle to the firmware response out here + // so it is easier to free later + hostInterfaces::hbrt_fw_msg *l_resp_fw_msg = nullptr; + + do + { + // clear the out data, regardless of the code to follow + o_todChipData.clear(); + + if ((nullptr == g_hostInterfaces) || + (nullptr == g_hostInterfaces->firmware_request)) + { + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid TOD::TOD_RT_TOPOLOGY_DATA + * @reasoncode TOD::TOD_RT_NULL_FIRMWARE_REQUEST_PTR + * @devdesc Host interfaces are not initialized + * @custdesc An internal error occurred. This will force the + * Time of Day function to run with complete + * redundancy. + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD::TOD_RT_TOPOLOGY_DATA, + TOD::TOD_RT_NULL_FIRMWARE_REQUEST_PTR, + 0, 0, true); + + break; + } + + // Create the firmware request structure. No data is being + // passed via this structure so this step may be moot. + // Maybe just passing size of 0 and a null pointer would be better? + hostInterfaces::hbrt_fw_msg l_req_fw_msg; + size_t l_req_fw_msg_size = sizeof(l_req_fw_msg); + + // Set the data for the request + l_req_fw_msg.io_type = hostInterfaces::HBRT_FW_MSG_HBRT_FSP_REQ; + l_req_fw_msg.generic_msg.initialize(); + l_req_fw_msg.generic_msg.msgq = MBOX::FSP_TOD_MSGQ; + l_req_fw_msg.generic_msg.msgType = GFMM_MSG_TOD_TOPOLOGY_DATA; + l_req_fw_msg.generic_msg.__req = GFMM_REQUEST; + l_req_fw_msg.generic_msg.__onlyError = GFMM_NOT_ERROR_ONLY; + + // Calculate the size of the response - the number + // of TodChipData items that will be returned. + uint32_t l_nTodChips = TodSvcUtil::getMaxProcsOnSystem(); + + // Calculate the size of the data that is being added to the + // generic struct + size_t l_data_size = (l_nTodChips * sizeof(TodChipData)); + + // Update the data size with the size of the generic msg struct + if (l_data_size < sizeof(hostInterfaces::hbrt_fw_msg::generic_msg.data)) + { + // If the current size of the data is less than the size of the + // data within the generic message (GenericFspMboxMessage_t.data), + // then default the data size to just the generic message because + // the size of the data to be passed in + // GenericFspMboxMessage_t.dataSize has be at the minimum - the + // size of the generic message (sizeof(GenericFspMboxMessage_t)). + l_data_size = sizeof(hostInterfaces::hbrt_fw_msg::generic_msg); + } + else + { + // If the current size of the data is greater than the size of the + // data within the generic message (GenericFspMboxMessage_t.data), + // then add the size of the generic message minus the size of + // generic message's data. + l_data_size += sizeof(hostInterfaces::hbrt_fw_msg::generic_msg) - + sizeof(hostInterfaces::hbrt_fw_msg::generic_msg.data); + } + + // At last. Calculate the TOTAL size of hostInterfaces::hbrt_fw_msg + // which means only adding hostInterfaces::HBRT_FW_MSG_BASE_SIZE to + // the previous calculated data size + size_t l_resp_fw_msg_size = hostInterfaces::HBRT_FW_MSG_BASE_SIZE + + l_data_size; + + // Create the firmware response structure to return the data + l_resp_fw_msg = + (hostInterfaces::hbrt_fw_msg *)malloc(l_resp_fw_msg_size); + + // Clear the response structure + memset(l_resp_fw_msg, 0, l_resp_fw_msg_size); + + // Send the data via a firmware request + size_t rc = g_hostInterfaces->firmware_request( + l_req_fw_msg_size, &l_req_fw_msg, + &l_resp_fw_msg_size, l_resp_fw_msg); + + // Error log id + uint32_t l_errPlid(0); + + // Create a useful structure to get to the PLID + // The PLID is expected to be in the first 4 bytes of the data + struct hbrtFspRespData_t + { + uint32_t plid; + uint32_t otherData; + } PACKED ; + + hbrtFspRespData_t *l_hbrtFspRespData = + (hbrtFspRespData_t*)&(l_resp_fw_msg->generic_msg.data); + + // Capture the error log ID if any + // The return code (rc) may return OK, but there still may be an issue + // with the HWSV code on the FSP. + if ((hostInterfaces::HBRT_FW_MSG_HBRT_FSP_RESP + == l_resp_fw_msg->io_type) && + (GFMM_ERROR_ONLY == l_resp_fw_msg->generic_msg.__onlyError) && + (0 != l_hbrtFspRespData->plid) ) + { + l_errPlid = l_hbrtFspRespData->plid; + } + + // Gather up the error data and create an error log out of it + if (rc || l_errPlid) + { + /*@ + * @errortype + * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE + * @moduleid TOD::TOD_RT_TOPOLOGY_DATA + * @reasoncode TOD::TOD_RT_TOPOLOGY_DATA_ERR + * @userdata1[0..31] Hypervisor return code + * @userdata1[32:63] HWSV error log id (if any) + * @userdata2[0:31] MBOX message type + * @userdata2[32:63] TOD message type + * @devdesc TOD read proc data failed + * @custdesc An internal error occurred. This will force + * the Time of Day function to run with complete + * redundancy. + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + TOD::TOD_RT_TOPOLOGY_DATA, + TOD::TOD_RT_TOPOLOGY_DATA_ERR, + TWO_UINT32_TO_UINT64(rc, l_errPlid), + TWO_UINT32_TO_UINT64( + l_req_fw_msg.generic_msg.msgq, + l_req_fw_msg.generic_msg.msgType), + true); + + if (l_resp_fw_msg_size > 0) + { + l_err->addFFDC( ISTEP_COMP_ID, + l_resp_fw_msg, + l_resp_fw_msg_size, + 0, 0, false ); + } + + l_err->addFFDC( ISTEP_COMP_ID, + &l_req_fw_msg, + sizeof(l_req_fw_msg), + 0, 0, false ); + + l_err->collectTrace( "TOD", 256); + + if (l_errPlid) + { + l_err->plid(l_errPlid); + } + + break; + } + + // If we are here, then this was no error retrieving the data. Now, + // just get the data from the returned struct and pass back to caller + // Get a pointer to the data + TodChipData* l_todChipData = + (TodChipData*)(&(l_resp_fw_msg->generic_msg.data)); + + // Gather the data into the container provided + for (size_t i = 0; i < l_nTodChips; ++i) + { + o_todChipData.push_back(l_todChipData[i]); + } + } + while (0); + + // Free the memory associated with the response + free(l_resp_fw_msg); + + TOD_EXIT("readTodProcDataFromFile"); + return l_err; +} // end readTodProcDataFromFile + +// This code was ported over from the FIPS code - +// /esw/fips910/Builds/b1005a_1742.910/ +// src/hwsv/server/services/todservice/hwsvTodSvc.C +// It was decided that a port of the code is not needed but to hold onto +// the code since the majority of it has been ported. +// There are few places below that do not have a direct port from the FIPS code +// that need to be resolved. I did not resolve them, because the port was +// abandoned and I did not want to waste any more time on it. +// In particular the call to mboxControlTodTopology() and the use of +// util::ScopeLock + +#if 0 +errlHndl_t resetBackupTopologyPortedCoded( + const TARGETING::TargetHandleList& i_badChipList, + bool i_informPhyp) +{ + TOD_ENTER("resetBackupTopology"); + + errlHndl_t l_err = nullptr; + bool l_deleteOnFailure = false; + + // l_backupConfig will be set again after determining the non-active + // topology from register values + p9_tod_setup_tod_sel l_backupConfig = TOD_SECONDARY; + +// NOTE: Not sure if this is needed - no direct port +// util::ScopeLock l_lock(iv_mutexTodAccess); + do + { + p9_tod_setup_tod_sel l_activeConfig = TOD_PRIMARY; + bool l_isTodRunning = false; + TARGETING::Target* l_mdmtOnActiveTopology = NULL; + bool l_getTodRunningStatus = true; + + // Get the currently active TOD configuration + l_err = TOD::queryActiveConfig(l_activeConfig, + l_isTodRunning, + l_mdmtOnActiveTopology, + l_getTodRunningStatus); + + if ( l_err ) + { + TOD_ERR("Call to queryActiveConfig failed "); + break; + } + + if ( !l_isTodRunning ) + { + TOD_ERR("TOD HW logic is not running,only use case of " + " resetBackup is when TOD is already running "); + /*@ + * @errortype + * @moduleid TOD::TOD_RESET_BACKUP + * @reasoncode TOD::TOD_INVALID_ACTION + * @userdata1 ChipTOD logic HW state, 1 means running, zero + * otherwise + * @devdesc Error: TOD HW logic is not running, only use case + * of resetBackup is when TOD is already running + * @custdesc Host failed to boot because there was a problem + * configuring Time Of Day on the Host processors + */ + l_err = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_RESET_BACKUP, + TOD_INVALID_ACTION, + l_isTodRunning); + break; + } + + l_backupConfig = (( l_activeConfig == TOD_PRIMARY) ? + TOD_SECONDARY : TOD_PRIMARY ); + + TOD_INF("Currently active topology ==> %s, and inactive ==> %s", + TodSvcUtil::topologyTypeToString(l_activeConfig), + TodSvcUtil::topologyTypeToString(l_backupConfig) ); + + // PHYP needs to be informed that it won't have a + // backup available for failover while we are reconfiguring it. + // Not all the cases will require HWSV to inform PHYP because in some + // of the case PHYP would have already initiated a failover before + // PRD asks HWSV to reconfigure backup. + // This indication is sent by PRD after the analysis of TOD error + // If this method is initiated by PHYP's message to MBOX to reset the + // backup topology this parameter will be always false. + if ( i_informPhyp ) + { + TOD_INF("Sending request to PHYP to disable the %s", + TodSvcUtil::topologyTypeToString(l_backupConfig)); + +// NOTE: Not sure if this is needed - no direct port +// l_err = mboxControlTodTopology(MBOX_DISABLE_TOPOLOGY, +// (( l_backupConfig == TOD_PRIMARY)? +// MBOX_PRIMARY_TOPOLOGY : MBOX_SECONDARY_TOPOLOGY)); + + if ( l_err ) + { + TOD_ERR("Request to PHYP for disabling the %s,that is " + "currently inactive failed", + TodSvcUtil::topologyTypeToString(l_backupConfig)); + break; + } + + TOD_INF("Got response from PHYP, for the request to disable" + "inactive topology "); + } + + + // Mark configured state to false + TOD::setConfigStatus(l_backupConfig,false); + + // Destroy the backup topology in case it exists, this is copy of + // topology in volatile memory so it won't matter even if we fail + // somewhere + TOD::destroy(l_backupConfig); + + // Build blacklist information + l_err = TOD::buildBlackList(i_badChipList); + if ( l_err ) + { + TOD_ERR("Call to buildBlackList failed "); + break; + } + + //Build the list of garded TOD targets + l_err = TOD::buildGardedTargetsList(); + if ( l_err ) + { + TOD_ERR("Call to buildGardedTargetsList failed"); + break; + } + + // Build a set of datastructures to setup creation of the TOD topology + l_err = TOD::buildTodDrawers(l_backupConfig); + if ( l_err ) + { + TOD_ERR("TOD setup failure: failed to build TOD drawers " + "for %s", + TodSvcUtil::topologyTypeToString(l_backupConfig)); + break; + } + + // From here on if resetBackup failed, we will do the cleanup at the end + l_deleteOnFailure = true; + + //Before we ask HwsvTodTopologyManager to create a new backup + //topology let us make sure that we have MDMT set in TOD Controls for + //the active topology, if there was RR then the copy of + //topology in main memory would have got erased + //MDMT of the active topology should be avoided while choosing MDMT for + //backup + if ( !(TOD::getConfigStatus(l_activeConfig)) && + TOD::getMDMT(l_activeConfig) ) + { + l_err = Singleton<TodSvc>::instance(). + setActiveMdmtForResetBackup(l_activeConfig); + + if ( l_err ) + { + TOD_ERR("setActiveMdmtForResetBackup failed for " + " %s", + TodSvcUtil::topologyTypeToString(l_activeConfig)); + break; + } + } + + + // Ask the topology manager to setup the backup topology + TodTopologyManager l_backupTopology(l_backupConfig); + l_err = l_backupTopology.create(); + + if ( l_err ) + { + TOD_ERR("TOD setup failure: failed to create %s", + TodSvcUtil::topologyTypeToString(l_backupConfig)); + break; + } + + l_backupTopology.dumpTopology(); + + //Call hardware procedures to configure the TOD hardware logic for + //the backup topology and to fill up the TOD regs. + l_err = TOD::todSetupHwp(l_backupConfig); + if ( l_err ) + { + TOD_ERR("TOD setup failure: secondary topology setup HWP."); + break; + } + + // Save the TOD registers into the local data structures + l_err = todSaveRegsHwp(l_backupConfig); + if ( l_err ) + { + TOD_ERR("todSaveRegsHwp failed for the %s", + TodSvcUtil::topologyTypeToString(l_backupConfig)); + break; + } + l_backupTopology.dumpTodRegs(); + + // Sending request to PHYP to enable the inactive + TOD_INF("Sending request to PHYP to enable the inactive %s", + TodSvcUtil::topologyTypeToString(l_backupConfig)); + + // Inform PHYP about the availability of backup topology +// NOTE: Not sure if this is needed - no direct port +// l_err = mboxControlTodTopology(MBOX_ENABLE_TOPOLOGY, +// ( l_backupConfig == TOD_PRIMARY)? MBOX_PRIMARY_TOPOLOGY +// : MBOX_SECONDARY_TOPOLOGY ); + if ( l_err ) + { + TOD_ERR("Request to PHYP for disabling the %s,that is curently" + "backup, failed ", + TodSvcUtil::topologyTypeToString(l_backupConfig)); + break; + + } + TOD_INF("Got response from PHYP, for the request to enable" + "inactive topology "); + + // Write this information to the persistant file + l_err = TOD::writeTodProcData(l_backupConfig); + if( l_err ) + { + TOD_ERR("TOD setup failure:Failed to write topology register data" + " to the file."); + break; + } + + // Backup successfully configured + TOD::setConfigStatus(l_backupConfig, true); + } + while (0); + + if ( l_err && l_deleteOnFailure ) + { + TOD::destroy(l_backupConfig); + } + TOD::clearGardedTargetsList(); + + TOD_EXIT("resetBackupTopology"); + + return l_err; +} // end resetBackupTopologyPortedCoded +#endif + +} // end namespace TOD diff --git a/src/usr/isteps/tod/tod.mk b/src/usr/isteps/tod/tod.mk new file mode 100644 index 000000000..15ee98a28 --- /dev/null +++ b/src/usr/isteps/tod/tod.mk @@ -0,0 +1,43 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/isteps/tod/tod.mk $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2016,2017 +# [+] 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 + +# Define common TOD objects +OBJS += TodSvcUtil.o +OBJS += TodUtils.o + +# Define common include paths +PROCEDURES_PATH = ${ROOTPATH}/src/import/chips/p9/procedures/hwp/nest +## support for Targeting and fapi +EXTRAINCDIR += ${PROCEDURES_PATH} +EXTRAINCDIR += ${ROOTPATH}/src/import/hwpf/fapi2/include +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/fapi2 +EXTRAINCDIR += ${ROOTPATH}/src/import/chips/p9/utils/imageProcs +EXTRAINCDIR += ${ROOTPATH}/src/import/chips/common/utils/imageProcs + +VPATH += ../ + +# include common mk files +include ${ROOTPATH}/procedure.rules.mk +include $(ROOTPATH)/config.mk |