summaryrefslogtreecommitdiffstats
path: root/src/usr/isteps/tod
diff options
context:
space:
mode:
authorRoland Veloz <rveloz@us.ibm.com>2017-10-10 10:55:09 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2017-12-20 17:47:47 -0500
commita69cb64611f39c3320e71a025cc612690305926d (patch)
treedebcc9b99e0c0f0fc5fafa47c9f0efbb20c38765 /src/usr/isteps/tod
parentf0db3bed83349756e9182077b02c1c73e473a569 (diff)
downloadtalos-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.H59
-rw-r--r--src/usr/isteps/tod/TodControls.C1821
-rw-r--r--src/usr/isteps/tod/TodControls.H936
-rw-r--r--src/usr/isteps/tod/TodDrawer.C297
-rw-r--r--src/usr/isteps/tod/TodDrawer.H290
-rw-r--r--src/usr/isteps/tod/TodHwpIntf.C231
-rw-r--r--src/usr/isteps/tod/TodHwpIntf.H127
-rw-r--r--src/usr/isteps/tod/TodProc.C613
-rw-r--r--src/usr/isteps/tod/TodProc.H415
-rw-r--r--src/usr/isteps/tod/TodSvc.C613
-rw-r--r--src/usr/isteps/tod/TodSvc.H261
-rw-r--r--src/usr/isteps/tod/TodSvcUtil.C311
-rw-r--r--src/usr/isteps/tod/TodSvcUtil.H168
-rw-r--r--src/usr/isteps/tod/TodTopologyManager.C712
-rw-r--r--src/usr/isteps/tod/TodTopologyManager.H211
-rw-r--r--src/usr/isteps/tod/TodTrace.H61
-rw-r--r--src/usr/isteps/tod/TodUtils.C181
-rw-r--r--src/usr/isteps/tod/TodUtils.H212
-rw-r--r--src/usr/isteps/tod/makefile39
-rw-r--r--src/usr/isteps/tod/runtime/makefile37
-rw-r--r--src/usr/isteps/tod/runtime/rt_todintf.C753
-rw-r--r--src/usr/isteps/tod/tod.mk43
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
OpenPOWER on IntegriCloud