summaryrefslogtreecommitdiffstats
path: root/src/usr/hwas/common/hwas.C
diff options
context:
space:
mode:
authorMatt Raybuck <mraybuc@us.ibm.com>2018-10-25 13:57:53 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-12-03 12:33:22 -0600
commit8b6b1b256035236d5434760729a1263305939a1f (patch)
tree4674a7415f369b36dfb885eb119b066aef47e66e /src/usr/hwas/common/hwas.C
parenteb8d14930c5e77bc2d0d0ef9f6861514c04d775d (diff)
downloadtalos-hostboot-8b6b1b256035236d5434760729a1263305939a1f.tar.gz
talos-hostboot-8b6b1b256035236d5434760729a1263305939a1f.zip
Remove hardcoding of partial good logic (2/2)
The original pg logic was a hard-coded criss-crossed jumble of logic that was difficult to understand. It has now been generalized to an algorithm that applies the correct logic based on a set of rules kept in a table. This should make it easier to understand and maintain going forward. Change-Id: I51435cc2ca6bbfa9ebc8a3d52d4ebf23b5bd2730 RTC:193270 CMVC-Prereq: 1072559 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/68232 Reviewed-by: Ilya Smirnov <ismirno@us.ibm.com> Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/hwas/common/hwas.C')
-rw-r--r--src/usr/hwas/common/hwas.C851
1 files changed, 235 insertions, 616 deletions
diff --git a/src/usr/hwas/common/hwas.C b/src/usr/hwas/common/hwas.C
index 851ad897e..3939cc06c 100644
--- a/src/usr/hwas/common/hwas.C
+++ b/src/usr/hwas/common/hwas.C
@@ -37,6 +37,7 @@
/******************************************************************************/
#include <stdint.h>
#include <algorithm>
+#include <map>
#ifdef __HOSTBOOT_MODULE
#include <config.h>
#include <initservice/initserviceif.H>
@@ -48,6 +49,7 @@
#include <hwas/common/hwas.H>
#include <hwas/common/hwasCommon.H>
#include <hwas/common/hwasError.H>
+#include <hwas/common/pgLogic.H>
#include <hwas/common/deconfigGard.H>
#include <hwas/common/hwas_reasoncodes.H>
@@ -71,6 +73,7 @@ TRAC_INIT(&g_trac_dbg_hwas, "HWAS", 1024 );
TRAC_INIT(&g_trac_imp_hwas, "HWAS_I", 1024 );
#endif
+
// SORT functions that we'll use for PR keyword processing
bool compareProcGroup(procRestrict_t t1, procRestrict_t t2)
{
@@ -153,83 +156,71 @@ void enableHwasState(Target *i_target,
i_target->setAttr<ATTR_HWAS_STATE>( hwasState );
}
-
-
/**
- * @brief simple helper fn to check L3/L2/REFR triplets in PG EPx data
+ * @brief This is a helper function for
+ * isDescFunctional. The name for it is slightly
+ * misleading because this function will only
+ * mark children non-functional if the passed-in
+ * parent is non-functional. Therefore, if a
+ * parent is passed in that is functional this
+ * function behaves as a NOOP. This function will
+ * propagate a parent's non-functional status
+ * down to all children since children cannot be
+ * considered functional if they have
+ * non-functional parents.
*
- * @param[in] i_pgData EPx data from PG keyword VPD
+ * @param[in] i_desc Pointer to the parent target we're looking
+ * at. Must not be nullptr.
*
- * @return bool triplets are valid
+ * @param[in] i_pgData Reference to area holding the PG keyword read
+ * from VPD; must be malloc'ed by the caller, and
+ * must be VPD_CP00_PG_DATA_ENTRIES in size.
+ *
+ * @param[in] io_targetStates Reference to the pgState_map that will to
+ * be updated by this function.
*
*/
-bool areL3L2REFRtripletsValid(uint16_t i_pgData)
+void markChildrenNonFunctional(const TARGETING::TargetHandle_t &i_parent,
+ const uint16_t (&i_pgData)
+ [VPD_CP00_PG_DATA_ENTRIES],
+ pgState_map &io_targetStates)
{
- bool l_valid = true;
- // Check that triplets are valid, that is, all good or all bad
- for (uint8_t l_triplet = 0;
- l_triplet <= 1;
- l_triplet++)
+ // Get the state for the parent.
+ auto parentState_it = io_targetStates.find(i_parent);
+
+ if (!parentState_it->second)
{
- // Check if all are good in the triplet
- if ((i_pgData & VPD_CP00_PG_EPx_L3L2REFR[l_triplet]) == 0)
- {
- continue;
- }
+ // Parent is non-functional. So get the list of all children
+ // and mark them non-functional as well.
+ TargetHandleList l_pDescChildren;
+ targetService().getAssociated(l_pDescChildren, i_parent,
+ TargetService::CHILD,
+ TargetService::ALL);
- // Check if all are bad in the triplet
- if ((i_pgData & VPD_CP00_PG_EPx_L3L2REFR[l_triplet]) ==
- VPD_CP00_PG_EPx_L3L2REFR[l_triplet])
+ for(TargetHandleList::const_iterator child_it =
+ l_pDescChildren.begin();
+ child_it != l_pDescChildren.end(); ++child_it)
{
- continue;
- }
+ TargetHandle_t child = *child_it;
- l_valid = false;
- break;
- }
-
- return l_valid;
-}
+ auto childState_it = io_targetStates.find(child);
-/**
- * @brief simple helper fn to check core data for rollup
- *
- * @param[in] i_firstCore First core to look at
- * @param[in] i_numCoresToCheck number of cores to check from first one
- * @param[in] i_pgData PG keyword VPD
- *
- * @return bool All ECxx domains were marked bad
- *
- */
-bool allCoresBad(const uint8_t & i_firstCore,
- const uint8_t & i_numCoresToCheck,
- const uint16_t i_pgData[])
-{
- bool coresBad = true;
- uint8_t coreNum = 0;
- do
- {
- // don't look outside of EC core entries
- if ((i_firstCore + coreNum) >= VPD_CP00_PG_ECxx_MAX_ENTRIES)
- {
- HWAS_INF("allCoresBad: requested %d cores beginning at %d, "
- "but only able to check %d cores",
- i_numCoresToCheck, i_firstCore, coreNum);
- break;
- }
- if (i_pgData[VPD_CP00_PG_EC00_INDEX + i_firstCore + coreNum] ==
- VPD_CP00_PG_ECxx_GOOD)
- {
- coresBad = false;
+ if(childState_it != io_targetStates.end())
+ {
+ childState_it->second = false;
+ }
+ else
+ {
+ // Child is missing from the targetStates map. Insert it and
+ // mark it non-functional.
+ io_targetStates[child] = false;
+ }
}
- coreNum++;
}
- while (coresBad && (coreNum < i_numCoresToCheck));
-
- return coresBad;
}
+
/**
* @brief disable obuses in wrap config.
* Due to fabric limitations, we can only have 2 parallel OBUS
@@ -704,7 +695,7 @@ errlHndl_t discoverTargets()
bool chipPresent = true;
bool chipFunctional = true;
uint32_t errlEid = 0;
- uint16_t pgData[VPD_CP00_PG_DATA_LENGTH / sizeof(uint16_t)];
+ uint16_t pgData[VPD_CP00_PG_DATA_ENTRIES];
bzero(pgData, sizeof(pgData));
if( (pTarget->getAttr<ATTR_CLASS>() == CLASS_CHIP) &&
@@ -770,25 +761,57 @@ errlHndl_t discoverTargets()
pTarget->getAttr<ATTR_HUID>(),
chipFunctional ? "" : "NOT ");
- // now need to mark all of this target's
- // physical descendants as present and functional as appropriate
+ // now need to mark all of this target's physical descendants as
+ // present and functional as appropriate
TargetHandleList pDescList;
targetService().getAssociated( pDescList, pTarget,
TargetService::CHILD, TargetService::ALL);
+
+ // A map that will keep track of what has already been checked to
+ // eliminate re-checking targets. It also holds functional state.
+ pgState_map targetStates;
+
+ // by default, the descendant's functionality is 'inherited'
+ bool descFunctional = chipFunctional;
+
+ if (chipFunctional)
+ {
+ // Check all of the descendants before moving onto setting
+ // hwasState. They must be checked before the next loop since a
+ // descendant's state can be changed multiple times before
+ // arriving at the final state. The reason for that is that a
+ // descendant could be marked functional until its parent is
+ // checked and then later be updated if the parent is determined
+ // to be non-functional.
+ for (TargetHandleList::const_iterator pDesc_it =
+ pDescList.begin();
+ pDesc_it != pDescList.end();
+ ++pDesc_it)
+ {
+ isDescFunctional(*pDesc_it, pgData, targetStates);
+ }
+ }
+
+
for (TargetHandleList::const_iterator pDesc_it = pDescList.begin();
pDesc_it != pDescList.end();
++pDesc_it)
{
+
TargetHandle_t pDesc = *pDesc_it;
- // by default, the descendant's functionality is 'inherited'
- bool descFunctional = chipFunctional;
if (chipFunctional)
- { // if the chip is functional, then look through the
- // partialGood vector to see if its chiplets
- // are functional
+ {
+ // if the chip is functional, then look through the
+ // partialGood vector to see if its chiplets
+ // are functional.
+ //
+ // The descendant has been checked already, it will
+ // not be checked again here. The result will be returned
+ // instead.
descFunctional = isDescFunctional(pDesc,
- pgData);
+ pgData,
+ targetStates);
}
if (pDesc->getAttr<ATTR_TYPE>() == TYPE_PERV)
@@ -814,6 +837,7 @@ errlHndl_t discoverTargets()
}
}
+
// set HWAS state to show CHIP is present, functional per above
enableHwasState(pTarget, chipPresent, chipFunctional, errlEid);
@@ -1015,587 +1039,182 @@ bool isChipFunctional(const TARGETING::TargetHandle_t &i_target,
return l_chipFunctional;
} // isChipFunctional
-// Checks the passed in target for functionality. This function assumes
-// that the passed in target is of TYPE_OBUS. Returns true if the target
-// is functional; false otherwise.
-bool isObusFunctional(const TARGETING::TargetHandle_t &i_desc,
- const uint16_t i_pgData[])
-{
- bool l_isFunctional = true;
-
- ATTR_CHIP_UNIT_type indexOB = i_desc->getAttr<ATTR_CHIP_UNIT>();
- // Check all bits in OBUSx entry
- if (i_pgData[VPD_CP00_PG_OB0_INDEX + indexOB] != VPD_CP00_PG_OBUS_GOOD)
- {
- HWAS_INF("pDesc %.8X - OB%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexOB,
- VPD_CP00_PG_OB0_INDEX + indexOB,
- i_pgData[VPD_CP00_PG_OB0_INDEX + indexOB],
- VPD_CP00_PG_OBUS_GOOD);
- l_isFunctional = false;
- }
- else
- // Check PBIOO0 bit in N1 entry
- // Rule 3 / Rule 4 PBIOO0 to be good with Nimbus and Cumulus except
- // Nimbus Sforza (without optics and NVLINK), so is
- // associated with all OBUS entries
- if ((i_pgData[VPD_CP00_PG_N1_INDEX] & VPD_CP00_PG_N1_PBIOO0) != 0)
- {
- HWAS_INF("pDesc %.8X - OB%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexOB,
- VPD_CP00_PG_N1_INDEX,
- i_pgData[VPD_CP00_PG_N1_INDEX],
- (i_pgData[VPD_CP00_PG_N1_INDEX] &
- ~VPD_CP00_PG_N1_PBIOO0));
- l_isFunctional = false;
- }
- else
- // Check PBIOO1 bit in N1 entry if second or third OBUS
- // Rule 4 PBIOO1 to be associated with OBUS1 and OBUS2 which only are
- // valid on a Cumulus
- if (((1 == indexOB) || (2 == indexOB)) && ((i_pgData[VPD_CP00_PG_N1_INDEX] &
- VPD_CP00_PG_N1_PBIOO1) != 0))
- {
- HWAS_INF("pDesc %.8X - OB%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexOB,
- VPD_CP00_PG_N1_INDEX,
- i_pgData[VPD_CP00_PG_N1_INDEX],
- (i_pgData[VPD_CP00_PG_N1_INDEX] &
- ~VPD_CP00_PG_N1_PBIOO1));
- l_isFunctional = false;
- }
-
- return l_isFunctional;
-}
-
bool isDescFunctional(const TARGETING::TargetHandle_t &i_desc,
- const uint16_t i_pgData[])
+ const uint16_t (&i_pgData)[VPD_CP00_PG_DATA_ENTRIES],
+ pgState_map &io_targetStates)
{
- bool l_descFunctional = true;
+ bool l_functional = false;
+ TargetHandleList l_pDescChildren;
+ targetService().getAssociated(l_pDescChildren, i_desc,
+ TargetService::CHILD,
+ TargetService::IMMEDIATE);
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_XBUS)
- {
- ATTR_CHIP_UNIT_type indexXB =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
- // Check bits in XBUS entry
- if ((i_pgData[VPD_CP00_PG_XBUS_INDEX] &
- VPD_CP00_PG_XBUS_IOX[indexXB]) != 0)
- {
- HWAS_INF("pDesc %.8X - XBUS%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexXB,
- VPD_CP00_PG_XBUS_INDEX,
- i_pgData[VPD_CP00_PG_XBUS_INDEX],
- (i_pgData[VPD_CP00_PG_XBUS_INDEX] &
- ~VPD_CP00_PG_XBUS_IOX[indexXB]));
- l_descFunctional = false;
- }
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_OBUS)
- {
- l_descFunctional = isObusFunctional(i_desc, i_pgData);
- }
- else
- if ((i_desc->getAttr<ATTR_TYPE>() == TYPE_PEC)
- || (i_desc->getAttr<ATTR_TYPE>() == TYPE_PHB))
- {
- Target * l_targ = NULL;
+ do {
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_PHB)
+ // There is a chance that this target has been checked already. Since
+ // descendant list isn't ordered.
+ auto selfState_it = io_targetStates.find(i_desc);
+ if (selfState_it != io_targetStates.end())
{
- //First get Parent PEC target as there are no PG bits for PHB
- TargetHandleList pParentPECList;
- getParentAffinityTargetsByState(pParentPECList, i_desc,
- CLASS_UNIT, TYPE_PEC, UTIL_FILTER_ALL);
- HWAS_ASSERT((pParentPECList.size() == 1),
- "isDescFunctional(): pParentPECList != 1");
- l_targ = pParentPECList[0];
+ // This target has been seen, return.
+ l_functional = selfState_it->second;
+ break;
}
- else
+
+ // First, if a target has children at least one must be functional for
+ // this target to be considered functional.
+ if (l_pDescChildren.size() == 0)
{
- l_targ = const_cast<TARGETING::Target*>(i_desc);
+ // Target has no children. So, set l_functional to true so that the
+ // check after the loop won't cause the function to exit with a
+ // potentially incorrect result.
+ l_functional = true;
}
- ATTR_CHIP_UNIT_type indexPCI =
- l_targ->getAttr<ATTR_CHIP_UNIT>();
- // Check all bits in PCIx entry
- if (i_pgData[VPD_CP00_PG_PCI0_INDEX + indexPCI] !=
- VPD_CP00_PG_PCIx_GOOD[indexPCI])
- {
- HWAS_INF("pDesc %.8X - PCI%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexPCI,
- VPD_CP00_PG_PCI0_INDEX + indexPCI,
- i_pgData[VPD_CP00_PG_PCI0_INDEX + indexPCI],
- VPD_CP00_PG_PCIx_GOOD[indexPCI]);
- l_descFunctional = false;
- }
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_EQ)
- {
- ATTR_CHIP_UNIT_type indexEP =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
- // Check bits in EPx entry, validating triplets in partial good region
- if (((i_pgData[VPD_CP00_PG_EP0_INDEX + indexEP]
- & ~VPD_CP00_PG_EPx_PG_MASK) !=
- VPD_CP00_PG_EPx_GOOD) ||
- (!areL3L2REFRtripletsValid(i_pgData[VPD_CP00_PG_EP0_INDEX +
- indexEP])))
- {
- HWAS_INF("pDesc %.8X - EQ%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexEP,
- VPD_CP00_PG_EP0_INDEX + indexEP,
- i_pgData[VPD_CP00_PG_EP0_INDEX + indexEP],
- VPD_CP00_PG_EPx_GOOD);
- l_descFunctional = false;
- }
- else
+ // Iterate through the list of children and look them up in the
+ // io_targetStates map. If at least one is functional then the algorithm
+ // will move onto the next set of checks to determine functionality for
+ // this target.
+ for(TargetHandleList::const_iterator child_it = l_pDescChildren.begin();
+ child_it != l_pDescChildren.end(); ++child_it)
{
- // Look for a rollup bad status
- // Either both EXs are bad or all 4 EC's are bad
-
- // index of first EX of 2 EXs under this EQ
- uint8_t indexEX = (uint8_t)indexEP * 2;
+ TargetHandle_t child = *child_it;
- // index of first EC of 4 ECs under this EQ
- uint8_t indexEC = indexEX * 2;
- uint8_t coresToCheck = 4;
+ auto childState = io_targetStates.find(child);
- // check if both EX's are bad
- if (((i_pgData[VPD_CP00_PG_EP0_INDEX + indexEP] &
- VPD_CP00_PG_EPx_L3L2REFR[0]) != 0) &&
- ((i_pgData[VPD_CP00_PG_EP0_INDEX + indexEP] &
- VPD_CP00_PG_EPx_L3L2REFR[1]) != 0))
+ if (childState == io_targetStates.end())
{
- HWAS_INF("pDesc %.8X - EQ%d marked bad because its EXs "
- "(%d and %d) are both bad",
- i_desc->getAttr<ATTR_HUID>(),
- indexEP,
- indexEX, indexEX+1);
-
- l_descFunctional = false;
+ // The child was not added to the map. This means that it hasn't
+ // been checked yet. So, check it before continuing with this
+ // target.
+ isDescFunctional(child, i_pgData, io_targetStates);
+ childState = io_targetStates.find(child);
}
- else
- // check if child cores are bad
- if (allCoresBad(indexEC, coresToCheck, i_pgData))
+
+ if (childState->second)
{
- HWAS_INF("pDesc %.8X - EQ%d marked bad because its %d CORES "
- "(EC%d - EC%d) are all bad",
- i_desc->getAttr<ATTR_HUID>(),
- indexEP,
- coresToCheck, indexEC, indexEC+3);
- l_descFunctional = false;
+ // One child of this target is functional. So far, that
+ // indicates that this target is functional.
+ l_functional = true;
+ break;
}
}
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_EX)
- {
- ATTR_CHIP_UNIT_type indexEX =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
- // 2 EX chiplets per EP/EQ chiplet
- size_t indexEP = indexEX / 2;
- // 2 L3/L2/REFR triplets per EX chiplet
- size_t indexL3L2REFR = indexEX % 2;
- // 2 EC children per EX
- uint8_t indexEC = indexEX * 2;
- uint8_t allCoresToCheck = 2; // 2 CORES per EX
-
- // Check triplet of bits in EPx entry
- if ((i_pgData[VPD_CP00_PG_EP0_INDEX + indexEP] &
- VPD_CP00_PG_EPx_L3L2REFR[indexL3L2REFR]) != 0)
- {
- HWAS_INF("pDesc %.8X - EX%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexEX,
- VPD_CP00_PG_EP0_INDEX + indexEP,
- i_pgData[VPD_CP00_PG_EP0_INDEX + indexEP],
- (i_pgData[VPD_CP00_PG_EP0_INDEX + indexEP] &
- ~VPD_CP00_PG_EPx_L3L2REFR[indexL3L2REFR]));
- l_descFunctional = false;
- }
- else
- // Check that EX does not have 2 bad CORE children
- if (allCoresBad(indexEC, allCoresToCheck, i_pgData))
- {
- HWAS_INF("pDesc %.8X - EX%d marked bad since it has no good cores",
- i_desc->getAttr<ATTR_HUID>(), indexEX);
- HWAS_INF("(core %d: actual 0x%04X, expected 0x%04X) "
- "(core %d: actual 0x%04X, expected 0x%04X)",
- indexEC, i_pgData[VPD_CP00_PG_EC00_INDEX + indexEC],
- VPD_CP00_PG_ECxx_GOOD,
- indexEC+1, i_pgData[VPD_CP00_PG_EC00_INDEX + indexEC+1],
- VPD_CP00_PG_ECxx_GOOD);
- l_descFunctional = false;
- }
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_CORE)
- {
- ATTR_CHIP_UNIT_type indexEC =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
- // Check all bits in ECxx entry
- if (i_pgData[VPD_CP00_PG_EC00_INDEX + indexEC] !=
- VPD_CP00_PG_ECxx_GOOD)
- {
- HWAS_INF("pDesc %.8X - CORE/EC%2.2d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexEC,
- VPD_CP00_PG_EC00_INDEX + indexEC,
- i_pgData[VPD_CP00_PG_EC00_INDEX + indexEC],
- VPD_CP00_PG_ECxx_GOOD);
- l_descFunctional = false;
- }
- }
- else // MCBIST is found on Nimbus chips
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_MCBIST)
- {
- ATTR_CHIP_UNIT_type indexMCBIST =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
- // 2 MCS chiplets per MCBIST / MCU
- size_t indexMCS = indexMCBIST * 2;
-
- // Check MCS01 bit in N3 entry if first MCBIST / MCU
- if ((0 == indexMCBIST) &&
- ((i_pgData[VPD_CP00_PG_N3_INDEX] &
- VPD_CP00_PG_N3_MCS01) != 0))
- {
- HWAS_INF("pDesc %.8X - MCBIST%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMCBIST,
- VPD_CP00_PG_N3_INDEX,
- i_pgData[VPD_CP00_PG_N3_INDEX],
- (i_pgData[VPD_CP00_PG_N3_INDEX] &
- ~VPD_CP00_PG_N3_MCS01));
- l_descFunctional = false;
- }
- else
- // Check MCS23 bit in N1 entry if second MCBIST / MCU
- if ((1 == indexMCBIST) &&
- ((i_pgData[VPD_CP00_PG_N1_INDEX] &
- VPD_CP00_PG_N1_MCS23) != 0))
- {
- HWAS_INF("pDesc %.8X - MCBIST%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMCBIST,
- VPD_CP00_PG_N1_INDEX,
- i_pgData[VPD_CP00_PG_N1_INDEX],
- (i_pgData[VPD_CP00_PG_N1_INDEX] &
- ~VPD_CP00_PG_N1_MCS23));
- l_descFunctional = false;
- }
- else
- // Check bits in MCxx entry except those in partial good region
- if ((i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]]
- & ~VPD_CP00_PG_MCxx_PG_MASK) !=
- VPD_CP00_PG_MCxx_GOOD)
- {
- HWAS_INF("pDesc %.8X - MCBIST%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMCBIST,
- VPD_CP00_PG_MCxx_INDEX[indexMCS],
- i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]],
- VPD_CP00_PG_MCxx_GOOD);
- l_descFunctional = false;
- }
- else
- // One MCA (the first one = mca0 or mca4) on each MC must be functional
- // for zqcal to work on any of the MCAs on that side
- if ( (i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]] &
- VPD_CP00_PG_MCA_MAGIC_PORT_MASK) != 0 )
- {
- HWAS_INF("pDesc %.8X - MCBIST%d pgData[%d]: "
- "0x%04X marked bad because of bad magic MCA port (0x%04X)",
- i_desc->getAttr<ATTR_HUID>(), indexMCBIST,
- VPD_CP00_PG_MCxx_INDEX[indexMCS],
- i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]],
- VPD_CP00_PG_MCA_MAGIC_PORT_MASK);
- l_descFunctional = false;
- }
- }
- else // MCS is found on Nimbus chips
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_MCS)
- {
- ATTR_CHIP_UNIT_type indexMCS =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
- // Check MCS01 bit in N3 entry if first or second MCS
- if (((0 == indexMCS) || (1 == indexMCS)) &&
- ((i_pgData[VPD_CP00_PG_N3_INDEX] &
- VPD_CP00_PG_N3_MCS01) != 0))
- {
- HWAS_INF("pDesc %.8X - MCS%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMCS,
- VPD_CP00_PG_N3_INDEX,
- i_pgData[VPD_CP00_PG_N3_INDEX],
- (i_pgData[VPD_CP00_PG_N3_INDEX] &
- ~VPD_CP00_PG_N3_MCS01));
- l_descFunctional = false;
- }
- else
- // Check MCS23 bit in N1 entry if third or fourth MCS
- if (((2 == indexMCS) || (3 == indexMCS)) &&
- ((i_pgData[VPD_CP00_PG_N1_INDEX] &
- VPD_CP00_PG_N1_MCS23) != 0))
- {
- HWAS_INF("pDesc %.8X - MCS%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMCS,
- VPD_CP00_PG_N1_INDEX,
- i_pgData[VPD_CP00_PG_N1_INDEX],
- (i_pgData[VPD_CP00_PG_N1_INDEX] &
- ~VPD_CP00_PG_N1_MCS23));
- l_descFunctional = false;
- }
- else
- // Check bits in MCxx entry including specific IOM bit,
- // but not other bits in partial good region
- if ((i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]]
- & ~(VPD_CP00_PG_MCxx_PG_MASK
- & ~VPD_CP00_PG_MCxx_IOMyy[indexMCS])) !=
- VPD_CP00_PG_MCxx_GOOD)
- {
- HWAS_INF("pDesc %.8X - MCS%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMCS,
- VPD_CP00_PG_MCxx_INDEX[indexMCS],
- i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]],
- (i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]] &
- ~VPD_CP00_PG_MCxx_IOMyy[indexMCS]));
- l_descFunctional = false;
- }
- else
- // One MCA (the first one = mca0 or mca4) on each MC must be functional
- // for zqcal to work on any of the MCAs on that side
- if ( (i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]] &
- VPD_CP00_PG_MCA_MAGIC_PORT_MASK) != 0 )
- {
- HWAS_INF("pDesc %.8X - MCS%d pgData[%d]: "
- "0x%04X marked bad because of bad magic MCA port (0x%04X)",
- i_desc->getAttr<ATTR_HUID>(), indexMCS,
- VPD_CP00_PG_MCxx_INDEX[indexMCS],
- i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]],
- VPD_CP00_PG_MCA_MAGIC_PORT_MASK);
- l_descFunctional = false;
- }
- }
- else // MCA is found on Nimbus chips
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_MCA)
- {
- ATTR_CHIP_UNIT_type indexMCA =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
- // 2 MCA chiplets per MCS
- size_t indexMCS = indexMCA / 2;
- // Check IOM bit in MCxx entry
- if ((i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]]
- & VPD_CP00_PG_MCxx_IOMyy[indexMCS]) != 0)
- {
- HWAS_INF("pDesc %.8X - MCA%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMCA,
- VPD_CP00_PG_MCxx_INDEX[indexMCS],
- i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]],
- (i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]] &
- ~VPD_CP00_PG_MCxx_IOMyy[indexMCS]));
- l_descFunctional = false;
- }
- else
- // One MCA (the first one = mca0 or mca4) on each MC must be functional
- // for zqcal to work on any of the MCAs on that side
- if ( (i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]] &
- VPD_CP00_PG_MCA_MAGIC_PORT_MASK) != 0 )
- {
- HWAS_INF("pDesc %.8X - MCA%d pgData[%d]: "
- "0x%04X marked bad because of bad magic MCA port (0x%04X)",
- i_desc->getAttr<ATTR_HUID>(), indexMCA,
- VPD_CP00_PG_MCxx_INDEX[indexMCS],
- i_pgData[VPD_CP00_PG_MCxx_INDEX[indexMCS]],
- VPD_CP00_PG_MCA_MAGIC_PORT_MASK);
- l_descFunctional = false;
+ if (!l_functional)
+ {
+ // No functional children of this target were found. Target is
+ // considered not functional.
+ HWAS_INF("pDesc 0x%.8X - marked bad because all of "
+ "its children were bad.",
+ i_desc->getAttr<ATTR_HUID>());
+ break;
}
- }
- // MC/MI/DMI is found on Cumulus chips
- else // MC/MI/MCC/OMI/OMIC is found on Axone chips
- if ((i_desc->getAttr<ATTR_TYPE>() == TYPE_MC) ||
- (i_desc->getAttr<ATTR_TYPE>() == TYPE_MI) ||
- (i_desc->getAttr<ATTR_TYPE>() == TYPE_DMI) ||
- (i_desc->getAttr<ATTR_TYPE>() == TYPE_MCC) ||
- (i_desc->getAttr<ATTR_TYPE>() == TYPE_OMIC) ||
- (i_desc->getAttr<ATTR_TYPE>() == TYPE_OMI))
- {
- ATTR_CHIP_UNIT_type index =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
- // ** Cumulus **
- // 2 MCs/chip, 2 MIs/MC, 2 DMIs/MI
- // ** Axone **
- // 2 MCs/chip, 2 MIs/MC, 2 MCCs/MI, 2 OMIs/MCC
- // 3 OMICs/MC
- size_t indexMC = 0;
+ // Since the target has at least one functional child (or no children),
+ // next we must apply the correct partial good rules to determine
+ // functionality.
+ //
+ // Lookup the correct partial good logic for the given target. To avoid
+ // errors of omission, the lookup must return at least one pg logic
+ // struct. If a target has no associated rules then an NA rule will be
+ // returned that was created by the default constructor which will cause
+ // the next for loop to succeed.
+ PARTIAL_GOOD::pgLogic_t descPgLogic = PARTIAL_GOOD::pgTable
+ .findRulesForTarget(i_desc);
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_MC)
- {
- indexMC = index;
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_MI)
- {
- indexMC = index / 2;
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_DMI)
- {
- indexMC = index / 4;
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_MCC)
- {
- indexMC = index / 4;
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_OMIC)
- {
- indexMC = index / 3;
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_OMI)
+ if (descPgLogic.size() == 0)
{
- indexMC = index / 8;
- }
+ // If descPgLogic is empty then the PgTable was not updated when a
+ // new target was added. This is not allowed. So create an error.
+ HWAS_ERR("isDescFunctional: No rules for target type 0x%X were"
+ " found in the PG rules table. At least one must exist."
+ " HUID 0x%X",
+ i_desc->getAttr<ATTR_TYPE>(), get_huid(i_desc));
- // if indexMC == 1 , then use MC23 PG Index
- // if indexMC == 0 , then use MC01 PG Index
- size_t mcPgIndex = indexMC ? VPD_CP00_PG_MC23_INDEX : VPD_CP00_PG_MC01_INDEX;
-
- // Check MCS01 bit in N3 entry if first MC
- if ((0 == indexMC) &&
- ((i_pgData[VPD_CP00_PG_N3_INDEX] &
- VPD_CP00_PG_N3_MCS01) != 0))
- {
- HWAS_INF("pDesc %.8X - MC%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMC,
- VPD_CP00_PG_N3_INDEX,
- i_pgData[VPD_CP00_PG_N3_INDEX],
- (i_pgData[VPD_CP00_PG_N3_INDEX] &
- ~VPD_CP00_PG_N3_MCS01));
- l_descFunctional = false;
- }
- else
- // Check MCS23 bit in N1 entry if second MC
- if ((1 == indexMC) &&
- ((i_pgData[VPD_CP00_PG_N1_INDEX] &
- VPD_CP00_PG_N1_MCS23) != 0))
- {
- HWAS_INF("pDesc %.8X - MC%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMC,
- VPD_CP00_PG_N1_INDEX,
- i_pgData[VPD_CP00_PG_N1_INDEX],
- (i_pgData[VPD_CP00_PG_N1_INDEX] &
- ~VPD_CP00_PG_N1_MCS23));
- l_descFunctional = false;
- }
- else
- // Check bits in MCxx entry except those in partial good region
- if (i_pgData[mcPgIndex] !=
- VPD_CP00_PG_MCxx_GOOD)
- {
- HWAS_INF("pDesc %.8X - MC%d pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(), indexMC,
- mcPgIndex,
- i_pgData[mcPgIndex],
- VPD_CP00_PG_MCxx_GOOD);
- l_descFunctional = false;
- }
+ /*@
+ * @errortype
+ * @severity ERRL_SEV_UNRECOVERABLE
+ * @moduleid MOD_IS_DESCENDANT_FUNCTIONAL
+ * @reasoncode RC_NO_PG_LOGIC
+ * @devdesc To enforce all target types have partial good
+ * rules and logic, all targets must be included in
+ * the PartialGoodRulesTable. A combination of
+ * target type, chip type, and chip unit produced
+ * an empty set of logic for the target.
+ * @custdesc A problem occured during IPL of the system:
+ * Internal Firmware Error
+ * @userdata1 target type attribute
+ * @userdata2 HUID of the target
+ */
+ errlHndl_t l_errl = hwasError(ERRL_SEV_UNRECOVERABLE,
+ MOD_IS_DESCENDANT_FUNCTIONAL,
+ RC_NO_PG_LOGIC,
+ i_desc->getAttr<ATTR_TYPE>(),
+ get_huid(i_desc));
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_OBUS_BRICK)
- {
- auto obusType = TARGETING::TYPE_OBUS;
- TARGETING::Target* l_obus_ptr = getParent(i_desc, obusType);
+ errlCommit(l_errl, HWAS_COMP_ID);
- //If NPU is bad and OBUS is non-SMP, then mark them bad
- // Bit does not matter unless not in SMP mode
- if ((l_obus_ptr->getAttr<ATTR_OPTICS_CONFIG_MODE>()
- != OPTICS_CONFIG_MODE_SMP) &&
- ((i_pgData[VPD_CP00_PG_N3_INDEX] & VPD_CP00_PG_N3_NPU) != 0))
- {
- HWAS_INF("pDesc %.8X - OBUS_BRICK pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(),
- VPD_CP00_PG_N3_INDEX,
- i_pgData[VPD_CP00_PG_N3_INDEX],
- (i_pgData[VPD_CP00_PG_N3_INDEX] &
- ~VPD_CP00_PG_N3_NPU));
- l_descFunctional = false;
}
- // If the target is functional at this point, check its parent
- // to make sure it is also functional. Then mark the target
- // not functional if its parent is not functional.
- if(l_descFunctional)
- {
- l_descFunctional = isObusFunctional(l_obus_ptr, i_pgData);
- }
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_NPU)
- {
- // Check NPU bit in N3 entry
- if ((i_pgData[VPD_CP00_PG_N3_INDEX] &
- VPD_CP00_PG_N3_NPU) != 0)
+ // Iterate through the list of partial good logic for this target. If
+ // any of them fail then the target is non-functional.
+ for(PARTIAL_GOOD::pgLogic_t::const_iterator pgLogic_it =
+ descPgLogic.begin();
+ pgLogic_it != descPgLogic.end(); ++pgLogic_it)
{
- HWAS_INF("pDesc %.8X - NPU pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(),
- VPD_CP00_PG_N3_INDEX,
- i_pgData[VPD_CP00_PG_N3_INDEX],
- (i_pgData[VPD_CP00_PG_N3_INDEX] &
- ~VPD_CP00_PG_N3_NPU));
- l_descFunctional = false;
- }
- }
- else
- if (i_desc->getAttr<ATTR_TYPE>() == TYPE_PERV)
- {
- // The chip unit number of the perv target
- // is the index into the PG data
- ATTR_CHIP_UNIT_type indexPERV =
- i_desc->getAttr<ATTR_CHIP_UNIT>();
-
- // Check VITAL bit in the entry
- if ((i_pgData[indexPERV]
- & VPD_CP00_PG_xxx_VITAL) != 0)
- {
- HWAS_INF("pDesc %.8X - PERV pgData[%d]: "
- "actual 0x%04X, expected 0x%04X - bad",
- i_desc->getAttr<ATTR_HUID>(),
- indexPERV,
- i_pgData[indexPERV],
- (i_pgData[indexPERV] &
- ~VPD_CP00_PG_xxx_VITAL));
- l_descFunctional = false;
+ PARTIAL_GOOD::PartialGoodLogic pgLogic = *pgLogic_it;
+
+ if ((i_pgData[pgLogic.iv_pgIndex]
+ & pgLogic.iv_pgMask) != pgLogic.iv_agMask)
+ {
+ HWAS_INF("pDesc 0x%.8X - pgData[%d]: "
+ "actual 0x%04X, expected 0x%04X - bad",
+ i_desc->getAttr<ATTR_HUID>(),
+ pgLogic.iv_pgIndex,
+ i_pgData[pgLogic.iv_pgIndex] & pgLogic.iv_pgMask,
+ pgLogic.iv_agMask);
+ l_functional = false;
+ break;
+ }
+
+ // The final check is to see if there is any additional logic
+ // that cannot be generically included in this loop. If there is
+ // special logic it will be included in a function that is
+ // hard-coded for that particular target and a function pointer will
+ // point to it.
+ //
+ // Any of the structs in the vector could have a pointer to a
+ // special rule so this check is included in the iteration.
+ if (pgLogic.iv_specialRule != nullptr)
+ {
+ // This pgLogic struct has a special rule. Call it to determine
+ // functionality.
+ l_functional = pgLogic.iv_specialRule(i_desc, i_pgData);
+
+ if (!l_functional)
+ {
+ break;
+ }
+ }
}
- // Set the local attribute copy of this data
- ATTR_PG_type l_pg = i_pgData[indexPERV];
- i_desc->setAttr<ATTR_PG>(l_pg);
+ } while(0);
+
+ // Record the result in the targetStates map for later use.
+ io_targetStates[i_desc] = l_functional;
+
+ if ((!l_functional) && (l_pDescChildren.size() != 0))
+ {
+ // Since this target isn't functional and it's a parent,
+ // mark the children as non-functional.
+ markChildrenNonFunctional(i_desc, i_pgData, io_targetStates);
}
- return l_descFunctional;
+ return l_functional;
} // isDescFunctional
+
void forceEcExEqDeconfig(const TARGETING::TargetHandle_t i_core,
const bool i_present,
const uint32_t i_deconfigReason)
OpenPOWER on IntegriCloud