diff options
Diffstat (limited to 'src/usr/isteps/istep18/TodTopologyManager.C')
-rwxr-xr-x | src/usr/isteps/istep18/TodTopologyManager.C | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/src/usr/isteps/istep18/TodTopologyManager.C b/src/usr/isteps/istep18/TodTopologyManager.C new file mode 100755 index 000000000..4a7d09435 --- /dev/null +++ b/src/usr/isteps/istep18/TodTopologyManager.C @@ -0,0 +1,619 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/isteps/istep18/TodTopologyManager.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/** + * @file TodTopologyManager.C + * + * @brief TOD Topology Manager class implementation. Responsible for + * creating/modifying the primary and secondary topologies. + * + * HWP_IGNORE_VERSION_CHECK + * + */ + +#include <targeting/common/target.H> +#include <targeting/common/targetservice.H> +#include <tod_init/tod_init_reasoncodes.H> +#include "TodTopologyManager.H" +#include "TodControls.H" +#include "TodDrawer.H" +#include "TodProc.H" +#include "TodTrace.H" + +using namespace TARGETING; + +namespace TOD +{ + +//------------------------------------------------------------------------------ +//Global defines +//------------------------------------------------------------------------------ +//Strings used in topology/register dump to fsp-trace +static const char* TOD_PRIMARY_TOPOLOGY = "PRIMARY"; +static const char* TOD_SECONDARY_TOPOLOGY = "SECONDARY"; +static const char* NO_BUS = "NONE"; +static const char* X_BUS_0 = "XBUS0"; +static const char* X_BUS_1 = "XBUS1"; +static const char* X_BUS_2 = "XBUS2"; +static const char* X_BUS_3 = "XBUS3"; +static const char* A_BUS_0 = "ABUS0"; +static const char* A_BUS_1 = "ABUS1"; +static const char* A_BUS_2 = "ABUS2"; + +//****************************************************************************** +//TodTopologyManager::TodTopologyManager +//****************************************************************************** +TodTopologyManager::TodTopologyManager( + const proc_tod_setup_tod_sel i_topologyType) : + iv_topologyType(i_topologyType) +{ + TOD_ENTER("Topology type 0X%.8X", i_topologyType); + + TOD_EXIT("TodTopologyManager constructor"); +} + +//****************************************************************************** +//TodTopologyManager::~TodTopologyManager +//****************************************************************************** +TodTopologyManager::~TodTopologyManager() +{ + TOD_ENTER("TodTopologyManager destructor"); + + TOD_EXIT("TodTopologyManager destructor"); +} + +//****************************************************************************** +//TodTopologyManager::create +//****************************************************************************** +errlHndl_t TodTopologyManager::create() +{ + TOD_ENTER("create"); + + errlHndl_t l_errHdl = NULL; + + //The topology creation algorithm goes as follows : + //1)Pick the MDMT. + //2)In the master TOD drawer (the one in which MDMT lies), + //wire the procs together. + //3)Connect the MDMT to one processor in each of the slave TOD drawers + //(the TOD drawers other than the master TOD drawer) + //4)Wire the procs in the slave TOD drawers. + do + { + //1) Pick the MDMT. + l_errHdl = TodControls::getTheInstance().pickMdmt(iv_topologyType); + if(l_errHdl) + { + TOD_ERR("Couldn't pick MDMT."); + break; + } + + //Get the TOD drawers + TodDrawerContainer l_todDrwList; + TodControls::getTheInstance().getDrawers(iv_topologyType, + l_todDrwList); + //Find the TOD system master drawer (the one in which the MDMT lies) + TodDrawer* l_pMasterDrawer = NULL; + for(TodDrawerContainer::const_iterator l_itr = l_todDrwList.begin(); + l_itr != l_todDrwList.end(); + ++l_itr) + { + if((*l_itr)->isMaster()) + { + l_pMasterDrawer = *l_itr; + TOD_INF("TOD drawer(0x%.2X) is the master drawer", + l_pMasterDrawer->getId()); + break; + } + } + if(NULL == l_pMasterDrawer) + { + TOD_ERR("TOD master drawer not found"); + /*@ + * @errortype + * @reasoncode TOD_CREATION_ERR + * @moduleid TOD_TOPOLOGY_CREATE + * @userdata1 Topology type : primary/secondary + * @devdesc TOD master drawer not found + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_TOPOLOGY_CREATE, + TOD_CREATION_ERR, + iv_topologyType ); + break; + } + + //2)In the master TOD drawer, wire the procs together. + l_errHdl = wireProcs(l_pMasterDrawer); + if(l_errHdl) + { + TOD_ERR("Couldn't wire one or more processors for " + "the master TOD drawer(0x%.2X)", + l_pMasterDrawer->getId()); + break; + } + + //3)Connect the MDMT to one processor in each of the TOD drawers + //other than the master TOD drawer. + for(TodDrawerContainer::iterator l_itr = l_todDrwList.begin(); + l_itr != l_todDrwList.end(); + ++l_itr) + { + if((*l_itr)->isMaster()) + { + //This is the master TOD drawer, we are connecting other + //TOD drawers to this. + continue; + } + l_errHdl = wireTodDrawer(*l_itr); + if(l_errHdl) + { + TOD_ERR("Couldn't wire TOD drawer(0x%.2X) to MDMT.", + (*l_itr)->getId()); + break; + } + } + if(l_errHdl) + { + break; + } + + //4)Wire the procs in the other TOD drawers (i.e other than the master) + for(TodDrawerContainer::const_iterator l_itr = + l_todDrwList.begin(); + l_itr != l_todDrwList.end(); + ++l_itr) + { + if((*l_itr)->isMaster()) + { + //We've done this already for the master TOD drawer + continue; + } + l_errHdl = wireProcs(*l_itr); + if(l_errHdl) + { + TOD_ERR("Couldn't wire one or more processors for " + "TOD drawer(0x%.2X).", + (*l_itr)->getId()); + break; + } + } + if(l_errHdl) + { + break; + } + }while(0); + + TOD_EXIT("create. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::wireProcs +//****************************************************************************** +errlHndl_t TodTopologyManager::wireProcs(const TodDrawer* i_pTodDrawer) +{ + TOD_ENTER("wireProcs"); + + errlHndl_t l_errHdl = NULL; + + do + { + if(NULL == i_pTodDrawer) + { + TOD_ERR("TOD drawer not specified"); + /*@ + * @errortype + * @reasoncode TOD_CREATION_ERR_NO_DRAWER + * @moduleid TOD_WIRE_PROCS + * @userdata1 Topology type : primary/secondary + * @devdesc TOD drawer not specified + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_PROCS, + TOD_CREATION_ERR_NO_DRAWER, + iv_topologyType ); + break; + } + + TOD_INF("TOD drawer id %d", i_pTodDrawer->getId()); + + //The algorithm to wire procs in a TOD drawer goes as follows : + /* + Have a "sources" list which initially has only the drawer master + Have a "targets" list which has all the other procs. + While the sources list isn't empty, for each source "s" in sources + For each target "t" in targets + If s connects t via X bus + Remove t from targets and add it to sources, + since it's now a potential source + If targets isn't empty, we couldn't wire one or more procs + */ + + //Get the targets + TodProcContainer l_targetsList = i_pTodDrawer->getProcs(); + + //Check if we have procs to wire in the first place + if(l_targetsList.empty()) + { + TOD_INF("Nothing to wire on TOD drawer(0x%.2X)", + i_pTodDrawer->getId()); + break; + } + + //Push the drawer master onto the sources list + TodProc* l_pDrawerMaster = NULL; + l_errHdl = i_pTodDrawer->findMasterProc(l_pDrawerMaster); + if(l_errHdl) + { + TOD_ERR("Master TOD proc not set for TOD drawer(0x%.2X)", + i_pTodDrawer->getId()); + break; + } + TodProcContainer l_sourcesList; + l_sourcesList.push_back(l_pDrawerMaster); + + //Start connecting targets to sources + TodProcContainer::iterator l_sourceItr = l_sourcesList.begin(); + TodProcContainer::iterator l_targetItr; + bool l_connected = false; + while((NULL == l_errHdl) && (l_sourcesList.end() != l_sourceItr)) + { + for(l_targetItr = l_targetsList.begin(); + l_targetItr != l_targetsList.end();) + { + l_errHdl = (*l_sourceItr)->connect(*l_targetItr, + TARGETING::TYPE_XBUS, + l_connected); + if(l_errHdl) + { + TOD_ERR("Error tying to connect target 0x%.8X " + "to source 0x%.8X.", + (*l_targetItr)->getTarget()->getAttr<ATTR_HUID>(), + (*l_sourceItr)->getTarget()->getAttr<ATTR_HUID>()); + break; + } + if(l_connected) + { + //Prefer push_back to push_front since in case of multiple + //X bus path alternatives, the paths and hence the TOD + //delays will be shorter. + l_sourcesList.push_back(*l_targetItr); + (*l_sourceItr)->addChild(*l_targetItr); + l_targetItr = l_targetsList.erase(l_targetItr); + } + else + { + ++l_targetItr; + } + } + ++l_sourceItr; + } + if(l_errHdl) + { + break; + } + if(false == l_targetsList.empty()) + { + //We couldn't connect one or more procs in this drawer + TOD_ERR("TOD drawer(0x%.2X) has one or more procs not connected. " + "0x%.8X is the first such proc.", + i_pTodDrawer->getId(), + (*(l_targetsList.begin()))->getTarget()->getAttr<ATTR_HUID>()); + /*@ + * @errortype + * @reasoncode TOD_CREATION_ERR + * @moduleid TOD_WIRE_PROCS + * @userdata1 DrawerId = bit[0:31], Topology type = bit[32:63] + * @userdata2 HUID of first disconnected proc + * @devdesc TOD drawer has one or more disconnected procs + */ + uint64_t l_data = i_pTodDrawer->getId(); + l_data <<= 32; + l_data |= iv_topologyType; + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_PROCS, + TOD_CREATION_ERR, + l_data, + (*(l_targetsList.begin()))->getTarget()-> + getAttr<ATTR_HUID>()); + break; + } + }while(0); + + TOD_EXIT("wireProcs. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::wireTodDrawer +//****************************************************************************** +errlHndl_t TodTopologyManager::wireTodDrawer(TodDrawer* i_pTodDrawer) +{ + TOD_ENTER("wireTodDrawer"); + + errlHndl_t l_errHdl = NULL; + + do + { + if(NULL == i_pTodDrawer) + { + TOD_ERR("TOD drawer not specified"); + /*@ + * @errortype + * @reasoncode TOD_CREATION_ERR + * @moduleid TOD_WIRE_DRAWERS + * @userdata1 Topology type : primary/secondary + * @devdesc TOD drawer not specified + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_CREATION_ERR, + iv_topologyType); + break; + } + + TOD_INF("TOD drawer id %d", i_pTodDrawer->getId()); + + //The algorithm to wire the slave TOD drawers to the mater TOD + //drawer (to the MDMT to be specific) goes as follows : + /* + For each slave TOD drawer "d" + For each proc "p" in d + If MDMT connects p via A bus + we are done, exit + */ + + //Get the MDMT + TodProc* l_pMDMT = + TodControls::getTheInstance().getMDMT(iv_topologyType); + if(NULL == l_pMDMT) + { + TOD_ERR("MDMT not found for topology type 0X%.8X", + iv_topologyType); + /*@ + * @errortype + * @reasoncode TOD_NO_MASTER_PROC + * @moduleid TOD_WIRE_DRAWERS + * @userdata1 Topology type : primary/secondary + * @devdesc MDMT could not be found + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_NO_MASTER_PROC, + iv_topologyType); + break; + } + + //Get the procs in this TOD drawer + TodProcContainer l_procs = i_pTodDrawer->getProcs(); + + //Check if we have procs + if(l_procs.empty()) + { + TOD_INF("Nothing to wire on TOD drawer(0x%.2X)", + i_pTodDrawer->getId()); + break; + } + + //Find a proc which connects to the MDMT via A bus + bool l_connected = false; + TodProcContainer::iterator l_itr; + for(l_itr = l_procs.begin(); + l_itr != l_procs.end(); + ++l_itr) + { + l_errHdl = l_pMDMT->connect(*l_itr, + TARGETING::TYPE_ABUS, + l_connected); + if(l_errHdl) + { + TOD_ERR("Error tying to connect target 0x%.4X " + "to MDMT 0x%.8X.", + (*l_itr)->getTarget()->getAttr<ATTR_HUID>(), + l_pMDMT->getTarget()->getAttr<ATTR_HUID>()); + break; + } + if(l_connected) + { + //Found a proc, designate this as the SDMT for this TOD drawer. + l_pMDMT->addChild(*l_itr); + (*l_itr)->setMasterType(TodProc::DRAWER_MASTER); + break; + } + } + if(l_errHdl) + { + break; + } + if(l_procs.end() == l_itr) + { + TOD_ERR("TOD drawer(0x%.2X) couldn't be wired", + i_pTodDrawer->getId()); + /*@ + * @errortype + * @reasoncode TOD_CANNOT_WIRE_DRAWER + * @moduleid TOD_WIRE_DRAWERS + * @userdata1 Topology type : primary/secondary + * @userdata2 TOD drawer id + * @devdesc TOD drawer couldn't be wired + */ + l_errHdl = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_INFORMATIONAL, + TOD_WIRE_DRAWERS, + TOD_CANNOT_WIRE_DRAWER, + iv_topologyType, + i_pTodDrawer->getId()); + break; + } + }while(0); + + TOD_EXIT("wireTodDrawer. errHdl = %p", l_errHdl); + + return l_errHdl; +} + +//****************************************************************************** +//TodTopologyManager::dumpTopology +//****************************************************************************** +void TodTopologyManager::dumpTopology() const +{ + TOD_ENTER("dumpTopology"); + + static const char* busnames[8] = {0}; + busnames[NONE] = NO_BUS; + busnames[XBUS0] = X_BUS_0; + busnames[XBUS1] = X_BUS_1; + busnames[XBUS2] = X_BUS_2; + busnames[XBUS3] = X_BUS_3; + busnames[ABUS0] = A_BUS_0; + busnames[ABUS1] = A_BUS_1; + busnames[ABUS2] = A_BUS_2; + + static const char* topologynames[2] = {0}; + topologynames[TOD_PRIMARY] = TOD_PRIMARY_TOPOLOGY; + topologynames[TOD_SECONDARY] = TOD_SECONDARY_TOPOLOGY; + + do + { + //Dump the inter and intra TOD drawer connections + TOD_INF("TOPOLOGY DUMP> Start, topology type %s", + topologynames[iv_topologyType]); + //Get the TOD drawers + TodDrawerContainer l_todDrwList; + TodControls::getTheInstance().getDrawers(iv_topologyType, l_todDrwList); + TodDrawerContainer::const_iterator l_drwItr = l_todDrwList.begin(); + while(l_todDrwList.end() != l_drwItr) + { + TOD_INF("TOPOLOGY DUMP> TOD Drawer(0x%.2X)",(*l_drwItr)->getId()); + //Get the procs on this drawer + TodProcContainer l_procList = (*l_drwItr)->getProcs(); + + TOD_INF("TOPOLOGY DUMP> " + "parent_huid---bus out---bus in---child_huid"); + TodProcContainer::const_iterator l_procItr = l_procList.begin(); + while(l_procList.end() != l_procItr) + { + //Get the children for this TOD proc + TodProcContainer l_childList; + (*l_procItr)->getChildren(l_childList); + TodProcContainer::const_iterator l_childItr = + l_childList.begin(); + while(l_childList.end() != l_childItr) + { + TOD_INF("TOPOLOGY DUMP> 0x%08X---%s---%s---0x%08X", + (*l_procItr)->getTarget()->getAttr<ATTR_HUID>(), + busnames[(*l_childItr)->getBusIn()], + busnames[(*l_childItr)->getBusOut()], + (*l_childItr)->getTarget()->getAttr<ATTR_HUID>()); + ++l_childItr; + } + ++l_procItr; + } + ++l_drwItr; + } + TOD_INF("TOPOLOGY DUMP> End"); + }while(0); + + TOD_EXIT("dumpTopology"); +} + +//****************************************************************************** +//TodTopologyManager::dumpTodRegs +//****************************************************************************** +void TodTopologyManager::dumpTodRegs() const +{ + TOD_ENTER("dumpTodRegs"); + + static const char* topologynames[2] = {0}; + topologynames[TOD_PRIMARY] = TOD_PRIMARY_TOPOLOGY; + topologynames[TOD_SECONDARY] = TOD_SECONDARY_TOPOLOGY; + + do + { + TOD_INF("TOD REGDUMP> Start, topology type %s", + topologynames[iv_topologyType]); + //Get the TOD drawers + TodDrawerContainer l_todDrwList; + TodControls::getTheInstance().getDrawers(iv_topologyType, l_todDrwList); + TodDrawerContainer::const_iterator l_drwItr = l_todDrwList.begin(); + while(l_todDrwList.end() != l_drwItr) + { + TOD_INF("TOD REGDUMP> TOD Drawer(0x%.2X)",(*l_drwItr)->getId()); + //Get the procs on this drawer + TodProcContainer l_procList = (*l_drwItr)->getProcs(); + TodProcContainer::const_iterator l_procItr = l_procList.begin(); + while(l_procList.end() != l_procItr) + { + TOD_INF("TOD REGDUMP> Proc HUID 0x%.8X", + (*l_procItr)->getTarget()->getAttr<ATTR_HUID>()); + if(TodProc::TOD_MASTER == (*l_procItr)->getMasterType()) + { + TOD_INF("TOD REGDUMP> This proc is the MDMT"); + } + else if(TodProc::DRAWER_MASTER == (*l_procItr)->getMasterType()) + { + TOD_INF("TOD REGDUMP> This proc is the SDMT " + " for this drawer"); + } + proc_tod_setup_conf_regs l_todRegs; + (*l_procItr)->getTodRegs(l_todRegs); + TOD_INF("TOD REGDUMP> MASTER PATH CONTROL REG 0x%.16llX", + l_todRegs.tod_m_path_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PORT 0 PRIMARY CONFIG REG 0x%.16llX", + l_todRegs.tod_pri_port_0_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PORT 1 PRIMARY CONFIG REG 0x%.16llX", + l_todRegs.tod_pri_port_1_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PORT 0 SECONDARY CONFIG REG 0x%.16llX", + l_todRegs.tod_sec_port_0_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PORT 1 SECONDARY CONFIG REG 0x%.16llX", + l_todRegs.tod_sec_port_1_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> SLAVE PATH CONTROL REG 0x%.16llX", + l_todRegs.tod_s_path_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> INTERNAL PATH CONTROL REG 0x%.16llX", + l_todRegs.tod_i_path_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> PRIMARY/SECONDARY MASTER/SLAVE CONTROL" + " REG 0x%.16llX", + l_todRegs.tod_pss_mss_ctrl_reg.getDoubleWord(0)); + TOD_INF("TOD REGDUMP> CHIP CONTROL REG 0x%.16llX", + l_todRegs.tod_chip_ctrl_reg.getDoubleWord(0)); + ++l_procItr; + } + ++l_drwItr; + } + TOD_INF("TOD REGDUMP> End"); + }while(0); + + TOD_EXIT("dumpTodRegs"); +} + +} //namespace TOD |