From 8b6b1b256035236d5434760729a1263305939a1f Mon Sep 17 00:00:00 2001 From: Matt Raybuck Date: Thu, 25 Oct 2018 13:57:53 -0500 Subject: 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 Reviewed-by: Nicholas E. Bofferding Tested-by: Jenkins Server Reviewed-by: Daniel M. Crowell --- src/usr/hwas/common/pgLogic.C | 416 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 416 insertions(+) (limited to 'src/usr/hwas/common/pgLogic.C') diff --git a/src/usr/hwas/common/pgLogic.C b/src/usr/hwas/common/pgLogic.C index 6b5ea76c6..80fbacb02 100644 --- a/src/usr/hwas/common/pgLogic.C +++ b/src/usr/hwas/common/pgLogic.C @@ -22,3 +22,419 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ +#include +#include +#include +#include + +namespace PARTIAL_GOOD +{ + + // These constants are used for the applicableChipTypes in a PartialGoodRule + // A combination of them can be pushed onto applicableChipTypes' expr stack. + const TARGETING::PredicateCTM PREDICATE_NIMBUS(TARGETING::CLASS_NA, + TARGETING::TYPE_NA, + TARGETING::MODEL_NIMBUS); + + const TARGETING::PredicateCTM PREDICATE_CUMULUS(TARGETING::CLASS_NA, + TARGETING::TYPE_NA, + TARGETING::MODEL_CUMULUS); + + const TARGETING::PredicateCTM PREDICATE_AXONE(TARGETING::CLASS_NA, + TARGETING::TYPE_NA, + TARGETING::MODEL_AXONE); + + const TARGETING::PredicateCTM PREDICATE_NA(TARGETING::CLASS_NA, + TARGETING::TYPE_NA, + TARGETING::MODEL_NA); + + const predicates_t PREDICATE_P9 = {&PREDICATE_CUMULUS, &PREDICATE_NIMBUS, + &PREDICATE_AXONE}; + + // Partial Good Rule constants for Target Types + // Naming convention for masks is as follows: + // TargetType_RuleNumber_MaskType_MASK + // + // Mask Types: PG = Partial Good + // AG = All Good + // CU = Applicable Chip Units + + // Special Masks that are applicable to many rules + + // This mask is common to many rules because in most cases we are checking + // specific bits and don't care about the rest. To detect a problem with + // only those bits we provide an AG mask of all zeroes. + const uint16_t ALL_OFF_AG_MASK = 0x0000; + + // This mask is common to many rules because there are target types that + // cover a set of bits where all must checked at one time instead of just a + // subset of bits to determine functionality. + const uint16_t ALL_ON_PG_MASK = 0xFFFF; + + // Used in place of a chip unit mask to indicate that the rule is applicable + // for all values a chip unit can take. + const size_t APPLICABLE_TO_ALL = UINT64_MAX; + + // The following three masks are common among a few PG Rules and have been + // defined as special masks. Each mask applies to the chip unit that the + // name suggests. Zero bit for chip unit 0, etc. + const size_t ZERO_BIT_CU_MASK = 0x0001; + const size_t ONE_BIT_CU_MASK = 0x0002; + const size_t TWO_BIT_CU_MASK = 0x0004; + + + // Used in place of a PG index to indicate that the target's associated + // chiplet id is the correct way to index the PG vector. + const uint8_t USE_CHIPLET_ID = 0xFF; + + // Used when a target type has no applicable partial good checking logic. + // Instead of omitting that target type from the map of rules, it will have: + // pgMask == MASK_NA + // agMask == MASK_NA + // pgIndex == INDEX_NA + // This will ensure that the algorithm in isDescFunctional() will execute + // successfully and serve to enforce that all targets be defined in the + // rules map. + const uint16_t MASK_NA = 0x0000; + const uint8_t INDEX_NA = 0x00; + + // Target Type Masks + // PG Masks are created such that: + // pgData[ pgIndex ] & pgMask + // produces the AG Mask defined for that rule. They are defined to cover the + // set of bits that a target type covers. The AG masks were defined either + // by directly using the provided AG mask listed in the MVPD PG Mapping + // Table or were chosen to check the specific bits a target type covers. + + // EQ + // PG/AG Masks + const uint16_t EQ_R1_PG_MASK = 0xFC33; + const uint16_t EQ_R1_AG_MASK = 0xE001; + + // EX + // PG/AG Masks + const uint16_t EX_R1_PG_MASK = 0x0288; + const uint16_t EX_R2_PG_MASK = 0x0144; + + // Applicable Chip Units + // Rule 1 only applies to even chip unit values + const size_t EX_R1_CU_MASK = 0x5555555555555555u; + // Rule 2 only applies to odd chip unit values + const size_t EX_R2_CU_MASK = 0xAAAAAAAAAAAAAAAAu; + + // EC + // PG/AG Masks + const uint16_t EC_R1_AG_MASK = 0xE1FF; + + // MC + // PG/AG Masks + const uint16_t MC_R1_AG_MASK = 0xE0FD; + const uint16_t MC_R2_PG_MASK = 0x0040; + const uint16_t MC_R3_PG_MASK = 0x0020; + + // MCA + // PG/AG Masks + const uint16_t MCA_R1_PG_MASK = 0x0200; + const uint16_t MCA_R2_PG_MASK = 0x0100; + + // Applicable Chip Units + const size_t MCA_R2_CU_MASK = 0x00CC; + + // MCBIST + // PG/AG Masks + // There is a special rule for MCBIST targets where the first MCA (MCA0 and + // MCA4) on each MC is required to be functional for it to be functional. To + // condense that rule into a single rule the bit that needs to be checked + // has been included in the PG mask. The PG mask excluding that bit would + // have been FCFF. + const uint16_t MCBIST_R1_PG_MASK = 0xFEFF; + const uint16_t MCBIST_R1_AG_MASK = 0xE0FD; + + // MCS + // PG/AG Masks + const uint16_t MCS_R1_PG_MASK = 0x0020; + const uint16_t MCS_R2_PG_MASK = 0x0040; + const uint16_t MCS_R3_PG_MASK = 0xFEFF; + const uint16_t MCS_R4_PG_MASK = 0xFDFF; + + const uint16_t MCS_ALL_GOOD_MASK = 0xE0FD; + + // Applicable Chip Units + // Rule 1 only applies to chip units 0 & 1 + const size_t MCS_R1_CU_MASK = 0x0003; + // Rule 2 only applies to chip units 2 & 3 + const size_t MCS_R2_CU_MASK = 0x000C; + + // NPU + // PG/AG Masks + const uint16_t NPU_R1_PG_MASK = 0x0100; + + // OBUS + // PG/AG Masks + const uint16_t OBUS_R1_AG_MASK = 0xE1FD; + const uint16_t OBUS_R2_PG_MASK = 0x0100; + const uint16_t OBUS_R3_PG_MASK = 0x0080; + + // Applicable Chip Units + // Rule 3 only applies to Cumulus OBUS's 1 and 2 + const size_t OBUS_R3_CU_MASK = 0x0006; + + // PEC + // PG/AG Masks + const uint16_t PEC_R1_AG_MASK = 0xE1FD; + const uint16_t PEC_R2_AG_MASK = 0xE0FD; + const uint16_t PEC_R3_AG_MASK = 0xE07D; + + // PERV + // PG/AG Masks + const uint16_t PERV_R1_PG_MASK = 0x1000; + + // XBUS + // PG/AG Masks + const uint16_t XBUS_R1_PG_MASK = 0x0040; + const uint16_t XBUS_R2_PG_MASK = 0x0020; + const uint16_t XBUS_R3_PG_MASK = 0x0010; + + + // Partial Good Vector Indexes + const uint16_t N1_PG_INDEX = 0x03; + const uint16_t N3_PG_INDEX = 0x05; + + const specialRuleFuncPtr_t NO_SPECIAL_RULE = nullptr; + + const PartialGoodRulesTable pgTable; + + PartialGoodRulesTable::~PartialGoodRulesTable() + { + for (auto const& type : pgRules_map) + { + for (pgRules_t::const_iterator it = type.second.begin(); + it != type.second.end(); ++it) + { + delete (*it); + } + } + } + + pgLogic_t PartialGoodRulesTable::findRulesForTarget( + const TARGETING::TargetHandle_t &i_target) const + { + pgLogic_t l_targetPgLogic; + + // Lookup the Target in the PG Rules Table + auto rulesIterator = + pgRules_map.find(i_target->getAttr()); + + do { + + if (rulesIterator == pgRules_map.end()) + { + // Target is missing from the table. Return an empty vector. + break; + } + + pgRules_t l_allRules = rulesIterator->second; + + // Since many targets don't have ATTR_MODEL filled in, lookup + // the master proc and use that to verify if this chip type is + // applicable for the target. + TARGETING::TargetService& ts = TARGETING::targetService(); + TARGETING::TargetHandle_t masterProc; + ts.masterProcChipTargetHandle(masterProc); + + // Iterate through all of the pg rules and compose a list of + // applicable rules based on chip unit and chip type. + for (pgRules_t::const_iterator pgRule = l_allRules.begin(); + pgRule != l_allRules.end(); ++pgRule) + { + TARGETING::ATTR_CHIP_UNIT_type targetCU = + i_target->getAttr(); + + // Compare the pgRule's chip type to the target. Encode the + // target's chip unit and see if it is a match for this rule. + if ((*pgRule)->iv_applicableChipTypes(masterProc) + && (*pgRule)->isApplicableToChipUnit(targetCU)) + { + // Current PG Rule is applicable to this target so create + // logic for it and add it to the list of logic for this + // target. + PartialGoodLogic pgLogic; + pgLogic.iv_pgMask = (*pgRule)->iv_pgMask; + pgLogic.iv_agMask = (*pgRule)->iv_agMask; + pgLogic.iv_pgIndex = (*pgRule)->iv_pgIndex; + pgLogic.iv_specialRule = (*pgRule)->iv_specialRule; + + // Check if the chiplet id of the target is a valid index + // for this rule. + if ((*pgRule)->useChipletIdAsIndex()) + { + pgLogic.iv_pgIndex = + i_target->getAttr(); + } + + // Add it to list of pg logic for this target. + l_targetPgLogic.push_back(pgLogic); + } + } + + } while(0); + + return l_targetPgLogic; + } + + + PartialGoodRule::PartialGoodRule() : iv_pgMask(MASK_NA), + iv_agMask(MASK_NA), + iv_pgIndex(INDEX_NA), + iv_applicableChipUnits(APPLICABLE_TO_ALL), + iv_specialRule(NO_SPECIAL_RULE) + { + iv_applicableChipTypes.push(&PREDICATE_NA); + }; + + PartialGoodRule::PartialGoodRule + ( + predicates_t i_preds, + uint16_t i_pgMask, uint16_t i_agMask, + uint8_t i_pgIndex, size_t i_appChipUnits, + specialRuleFuncPtr_t rule + ) + : iv_pgMask(i_pgMask), iv_agMask(i_agMask), iv_pgIndex(i_pgIndex), + iv_applicableChipUnits(i_appChipUnits), iv_specialRule(rule) + { + + // First push all predicates onto the expr stack. + for (predicates_t::const_iterator it = i_preds.begin(); + it != i_preds.end(); ++it) + { + iv_applicableChipTypes.push(*it); + } + + // If there were more than one predicate pushed on the expr stack then + // add n - 1 Or() predicates to the expr stack + if (i_preds.size() > 1) + { + for (size_t i = 0; i < (i_preds.size() - 1); ++i) + { + iv_applicableChipTypes.Or(); + } + } + } + + bool PartialGoodRule::isApplicableToChipUnit(uint8_t i_chipUnit) const + { + // The encoded chip unit has the value of zero represented as the + // farthest right bit. + size_t l_encodedChipUnit = 0x0001; + + // Left shift the encoded value a number of times equal to the value + // of i_chipUnit. This puts the ON bit under the correct position to + // be compared against the chip unit mask. + l_encodedChipUnit <<= i_chipUnit; + + bool result = false; + + // A PartialGoodRule is applicable for a chip unit if the result of + // the bit-wise & results in the encoded chip unit value. This + // allows the special chip unit mask APPLICABLE_TO_ALL to function + // correctly. + if ((iv_applicableChipUnits & l_encodedChipUnit) == + l_encodedChipUnit) + { + result = true; + } + + return result; + } + + bool PartialGoodRule::useChipletIdAsIndex() const + { + return iv_pgIndex == USE_CHIPLET_ID; + } + + //////////////////////////////////////////////////////////////////////////// + // Special Rules + //////////////////////////////////////////////////////////////////////////// + + + bool PervSpecialRule(const TARGETING::TargetHandle_t &i_desc, + const uint16_t i_pgData[]) + { + HWAS_ASSERT((i_desc->getAttr() + == TARGETING::TYPE_PERV), + "PervSpecialRule: i_desc type != TYPE_PERV"); + + // The chip unit number of the perv target is the index into the PG data + auto indexPERV = i_desc->getAttr(); + + // Set the local attribute copy of this data + TARGETING::ATTR_PG_type l_pg = i_pgData[indexPERV]; + i_desc->setAttr(l_pg); + + return true; + } + + bool ObusBrickSpecialRule(const TARGETING::TargetHandle_t &i_desc, + const uint16_t i_pgData[]) + { + HWAS_ASSERT((i_desc->getAttr() + == TARGETING::TYPE_OBUS_BRICK), + "ObusBrickSpecialRule: i_desc type != TYPE_OBUS_BRICK"); + + bool l_descFunctional = true; + auto obusType = TARGETING::TYPE_OBUS; + TARGETING::Target* l_obus_ptr = getParent(i_desc, obusType); + + //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() + != TARGETING::OPTICS_CONFIG_MODE_SMP) + && ((i_pgData[N3_PG_INDEX] & NPU_R1_PG_MASK) != ALL_OFF_AG_MASK)) + { + TRACFCOMP(HWAS::g_trac_imp_hwas, + "pDesc 0x%.8X - OBUS_BRICK pgData[%d]: " + "actual 0x%04X, expected 0x%04X - bad", + i_desc->getAttr(), + N3_PG_INDEX, + i_pgData[N3_PG_INDEX], + ALL_OFF_AG_MASK); + + l_descFunctional = false; + } + + return l_descFunctional; + } + + bool EQSpecialRule(const TARGETING::TargetHandle_t &i_desc, + const uint16_t i_pgData[]) + { + + HWAS_ASSERT((i_desc->getAttr() + == TARGETING::TYPE_EQ), + "EQSpecialRule: i_desc target type != TYPE_EQ"); + + bool l_valid = false; + + // This rule only looks at specific bits in the partial good vector. + // These bits can be found by using EQ chiplet id's value as an index + // into the vector. + auto EQChipletId = i_desc->getAttr(); + uint16_t l_pgData = i_pgData[EQChipletId]; + + // For this rule, we check the triplets associated with EX targets. + // Those are the L3, L2, and REFR units. In order for this rule to + // be validated, only values of all 0 or all 1 are permitted in those + // three bit positions. + if ((((l_pgData & EX_R1_PG_MASK) == 0) + || ((l_pgData & EX_R1_PG_MASK) == EX_R1_PG_MASK)) + && (((l_pgData & EX_R2_PG_MASK) == 0) + || ((l_pgData & EX_R2_PG_MASK) == EX_R2_PG_MASK))) + { + l_valid = true; + } + + return l_valid; + + } + +} -- cgit v1.2.1