diff options
Diffstat (limited to 'src/usr/hwas')
-rw-r--r-- | src/usr/hwas/hwasPlat.C | 342 |
1 files changed, 142 insertions, 200 deletions
diff --git a/src/usr/hwas/hwasPlat.C b/src/usr/hwas/hwasPlat.C index a16d0fdcc..46911bca1 100644 --- a/src/usr/hwas/hwasPlat.C +++ b/src/usr/hwas/hwasPlat.C @@ -405,186 +405,65 @@ void ocmbErrlCommit(const TARGETING::TargetHandle_t& i_target, } /** - * @brief This is a small helper function that is used to translate from SPD - * to OCMB IDEC register values. + * @brief This helper function will lookup the chip id and ec levels of + * a given OCMB based on what is found in a provided SPD buffer. + * The target is passed along for trace information. * - * @param[in] i_value The value to translate + * @param[in] i_target OCMB target we are looking up IDEC for * - * @param[in] i_isID The type of value passed in. Used to search - * the corresponding map and for FFDC. + * @param[in] i_spdBuffer Buffer of at least SPD::OCMB_SPD_EFD_COMBINED_SIZE + * bytes of the given OCMB's SPD * - * @param[in] i_spdFFDCBytes Byte 1: SPD Module Revision - * Byte 2: DRAM Interface Type Presented or - * Emulated - * Byte 3: Memory Module Interface Type - * Byte 4: Unused + * @param[out] o_chipId Chip Id associated with the given OCMB + * (see src/import/chips/common/utils/chipids.H) * - * @param[out] o_translatedValue The value resulting from the map.find() + * @param[out] o_ec EC level associated with the given OCMB * - * @param[in] i_id The SPD ID used to construct the association - * map. Defaulted to 0xFFFF. This MUST be set - * when i_isID == false. - * - * @return errlHndl_t nullptr on success. Otherwise an error log - * indicating that the translation failed. + * @return nullptr if success, error log otherwise * */ -errlHndl_t ocmbTranslateSpdToIdec(const uint16_t i_value, - const bool i_isID, - const uint32_t i_spdFFDCBytes, - uint16_t& o_translatedValue, - const uint16_t i_id = 0xFFFF) +errlHndl_t getOcmbIdecFromSpd(const TARGETING::TargetHandle_t& i_target, + uint8_t * i_spdBuffer, + uint16_t& o_chipId, + uint8_t& o_ec) { + errlHndl_t l_errl = nullptr; + // These bytes are used for FFDC and verification purposes. + const size_t SPD_REVISION_OFFSET = 1; + const size_t DRAM_INTERFACE_TYPE_OFFSET = 2; + const size_t MEMORY_MODULE_INTERFACE_TYPE_OFFSET = 3; - assert((i_isID || (i_id != 0xFFFF)), "i_id must be set to a valid OCMB SPD Chip ID value when attempting to translate an SPD EC value."); - - errlHndl_t error = nullptr; - - const uint16_t OCMB_ID = i_isID ? i_value : i_id; - - const uint32_t GEMINI_EC = 0x0010; - const uint32_t GEMINI_SPD_EC = 0x0000; - const uint32_t EXPLORER_EC = 0x0010; - const uint32_t EXPLORER_SPD_EC = 0x0000; - // This map will hold the associated values between what is read from - // the OCMB's IDEC register and the SPD since they use different - // standards and thus cannot be directly compared. - std::map<uint32_t, uint32_t> OCMB_ASSOCIATION_MAP; - - if (i_isID) - { - if (DDIMM_DMB_ID::EXPLORER == OCMB_ID) - { - OCMB_ASSOCIATION_MAP[DDIMM_DMB_ID::EXPLORER] = - POWER_CHIPID::EXPLORER_16; - } - else if (DDIMM_DMB_ID::GEMINI == OCMB_ID) - { - OCMB_ASSOCIATION_MAP[DDIMM_DMB_ID::GEMINI] = - POWER_CHIPID::GEMINI_16; - } - } - else - { - if (DDIMM_DMB_ID::EXPLORER == OCMB_ID) - { - OCMB_ASSOCIATION_MAP[EXPLORER_SPD_EC] = EXPLORER_EC; - } - else if (DDIMM_DMB_ID::GEMINI == OCMB_ID) - { - OCMB_ASSOCIATION_MAP[GEMINI_SPD_EC] = GEMINI_EC; - } - } - - auto map_it = OCMB_ASSOCIATION_MAP.find(i_value); - - if (map_it == OCMB_ASSOCIATION_MAP.end()) - { - HWAS_ERR("ocmbTranslateSpdToIdec> Unable to translate " - "given %s 0x%.4X to a known OCMB IDEC register equivalent", - i_isID ? "Chip ID" : "Revision", - i_value); - - /*@ - * @errortype - * @severity ERRL_SEV_PREDICTIVE - * @moduleid MOD_OCMB_TRANSLATE_SPD_IDEC - * @reasoncode RC_OCMB_UNEXPECTED_IDEC - * @userdata1[0:7] SPD Module Revision - * @userdata1[8:15] DRAM Interface Type Presented or Emulated - * @userdata1[16:23] Memory Module Interface Type - * @userdata1[24:31] Unused - * @userdata1[32:47] The value given to the translate function - * @userdata1[48:63] 0x1 = value is Chip ID, 0x0 = value is Revision - * @devdesc The IDEC values read from the OCMB did not - * appear in the OCMB IDEC to SPD association map. - * Please update the map with new values. - * @custdesc Firmware Error - */ - error = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE, - MOD_OCMB_TRANSLATE_SPD_IDEC, - RC_OCMB_UNEXPECTED_IDEC, - TWO_UINT32_TO_UINT64(i_spdFFDCBytes, - TWO_UINT16_TO_UINT32(i_value, i_isID))); - - } - else - { - o_translatedValue = map_it->second; - } - - return error; -} - -errlHndl_t ocmbIdecPhase1(const TARGETING::TargetHandle_t& i_target) -{ - errlHndl_t error = nullptr; - - // Allocate buffer to hold SPD and init to 0 - size_t spdBufferSize = SPD::OCMB_SPD_EFD_COMBINED_SIZE; - uint8_t* spdBuffer = new uint8_t[spdBufferSize]; - memset(spdBuffer, 0, spdBufferSize); - - do { - - // Read the full SPD. - error = deviceRead(i_target, - spdBuffer, - spdBufferSize, - DEVICE_SPD_ADDRESS(SPD::ENTIRE_SPD)); - - // If unable to retrieve the SPD buffer then can't - // extract the IDEC data, so return error. - if (error != nullptr) - { - HWAS_ERR("ocmbIDEC> Error while trying to read " - "ENTIRE SPD from 0x%.08X ", - TARGETING::get_huid(i_target)); - break; - } - - // Make sure we got back the size we were expecting. - assert(spdBufferSize == SPD::OCMB_SPD_EFD_COMBINED_SIZE, - "ocmbIDEC> OCMB SPD read size %d " - "doesn't match the expected size %d", - spdBufferSize, - SPD::OCMB_SPD_EFD_COMBINED_SIZE); - - // These bytes are used for FFDC and verification purposes. - const size_t SPD_REVISION_OFFSET = 1; - const size_t DRAM_INTERFACE_TYPE_OFFSET = 2; - const size_t MEMORY_MODULE_INTERFACE_TYPE_OFFSET = 3; + // This is the value that signifies the SPD we read is for a DDIMM. + const uint8_t DDIMM_MEMORY_INTERFACE_TYPE = 0x0A; - // This is the value that signifies the SPD we read is for a DDIMM. - const uint32_t DDIMM_MEMORY_INTERFACE_TYPE = 0x0A; + const uint8_t l_spdModuleRevision = + *(i_spdBuffer + SPD_REVISION_OFFSET); - const uint8_t spdModuleRevision = - *(spdBuffer + SPD_REVISION_OFFSET); + const uint8_t l_spdDRAMInterfaceType = + *(i_spdBuffer + DRAM_INTERFACE_TYPE_OFFSET); - const uint8_t spdDRAMInterfaceType = - *(spdBuffer + DRAM_INTERFACE_TYPE_OFFSET); + const uint8_t l_spdMemoryInterfaceType = + *(i_spdBuffer + MEMORY_MODULE_INTERFACE_TYPE_OFFSET); - const uint8_t spdMemoryInterfaceType = - *(spdBuffer + MEMORY_MODULE_INTERFACE_TYPE_OFFSET); + // Byte 1 SPD Module Revision + // Byte 2 DRAM Interface Type Presented or Emulated + // Byte 3 Memory Module Interface Type + const uint32_t SPD_FFDC_BYTES = TWO_UINT16_TO_UINT32( + TWO_UINT8_TO_UINT16(l_spdModuleRevision, l_spdDRAMInterfaceType), + TWO_UINT8_TO_UINT16(l_spdMemoryInterfaceType, 0)); - // Byte 1 SPD Module Revision - // Byte 2 DRAM Interface Type Presented or Emulated - // Byte 3 Memory Module Interface Type - const uint32_t SPD_FFDC_BYTES = TWO_UINT16_TO_UINT32( - TWO_UINT8_TO_UINT16(spdModuleRevision, spdDRAMInterfaceType), - TWO_UINT8_TO_UINT16(spdMemoryInterfaceType, 0)); + do{ // Since the byte offsets used to get the IDEC info out of the SPD are // specific to the DDIMM interface type we must first verify that we // read from an SPD of that type. - if (DDIMM_MEMORY_INTERFACE_TYPE != spdMemoryInterfaceType) + if (DDIMM_MEMORY_INTERFACE_TYPE != l_spdMemoryInterfaceType) { - HWAS_ERR("ocmbIDEC> OCMB 0x%.8X memory module interface type " - "didn't match the expected type. " - "Expected 0x%.2X, Actual 0x%.2X", - TARGETING::get_huid(i_target), - DDIMM_MEMORY_INTERFACE_TYPE, - spdMemoryInterfaceType); + HWAS_ERR("getOcmbIdecFromSpd> memory module interface type " + "didn't match the expected type. " + "Expected 0x%.2X, Actual 0x%.2X", + DDIMM_MEMORY_INTERFACE_TYPE, + l_spdMemoryInterfaceType); /*@ * @errortype @@ -603,17 +482,17 @@ errlHndl_t ocmbIdecPhase1(const TARGETING::TargetHandle_t& i_target) * continue. * @custdesc Invalid or unsupported memory card installed. */ - error = hwasError(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + l_errl = hwasError(ERRORLOG::ERRL_SEV_UNRECOVERABLE, MOD_OCMB_IDEC, RC_OCMB_INTERFACE_TYPE_MISMATCH, TWO_UINT32_TO_UINT64(SPD_FFDC_BYTES, DDIMM_MEMORY_INTERFACE_TYPE), TARGETING::get_huid(i_target)); - error->addProcedureCallout(EPUB_PRC_HB_CODE, - SRCI_PRIORITY_LOW); + l_errl->addProcedureCallout(EPUB_PRC_HB_CODE, + SRCI_PRIORITY_LOW); - error->addHwCallout(i_target, + l_errl->addHwCallout(i_target, SRCI_PRIORITY_HIGH, NO_DECONFIG, GARD_NULL); @@ -625,37 +504,59 @@ errlHndl_t ocmbIdecPhase1(const TARGETING::TargetHandle_t& i_target) // SPD IDEC info is in the following three bytes const size_t SPD_ID_LEAST_SIGNIFICANT_BYTE_OFFSET = 198; const size_t SPD_ID_MOST_SIGNIFICANT_BYTE_OFFSET = 199; - const size_t SPD_EC_OFFSET = 200; + const size_t DMB_REV_OFFSET = 200; // Get the ID from the SPD and verify that it matches what we read from // the IDEC register. - uint16_t spdId = TWO_UINT8_TO_UINT16( - *(spdBuffer + SPD_ID_LEAST_SIGNIFICANT_BYTE_OFFSET), - *(spdBuffer + SPD_ID_MOST_SIGNIFICANT_BYTE_OFFSET)); + uint16_t l_spdId = TWO_UINT8_TO_UINT16( + *(i_spdBuffer + SPD_ID_LEAST_SIGNIFICANT_BYTE_OFFSET), + *(i_spdBuffer + SPD_ID_MOST_SIGNIFICANT_BYTE_OFFSET)); - uint8_t spdEc = *(spdBuffer + SPD_EC_OFFSET); + // Bytes 200 of the SPD contains the DMB Revision, this is essentially the + // OCMB manufacture's version of the chip. The manufacture can define any + // format for this field and we must add special logic to convert the + // manufacture's DMB_REV to the EC level IBM is familiar with. + uint8_t l_spdDmbRev = *(i_spdBuffer + DMB_REV_OFFSET); - if (DDIMM_DMB_ID::EXPLORER == spdId) + HWAS_INF("getOcmbIdecFromSpd> OCMB 0x%.8x l_spdId = 0x%.4X l_spdDmbRev = 0x%.2x", + TARGETING::get_huid(i_target), l_spdId, l_spdDmbRev); + + if (DDIMM_DMB_ID::EXPLORER == l_spdId) { - HWAS_INF("ocmbIdecPhase1> OCMB 0x%.8X chip type is EXPLORER", - TARGETING::get_huid(i_target)); + o_chipId = POWER_CHIPID::EXPLORER_16; + // Must convert Explorer's versioning into IBM-style EC levels. + // Explorer vendor has stated versioning will start at 0xA0 and increment + // 1st nibble for major revisions and 2nd nibble by 1 for minor revisions + // Examples : + // Version 0xA0 = EC 0x10 + // Version 0xA1 = EC 0x11 + // Version 0xB2 = EC 0x22 + + // Resulting formula from pattern in examples above is as follows: + o_ec = (l_spdDmbRev - 0x90); } - else if (DDIMM_DMB_ID::GEMINI == spdId) + else if (DDIMM_DMB_ID::GEMINI == l_spdId) { - HWAS_INF("ocmbIdecPhase1> OCMB 0x%.8X chip type is GEMINI", - TARGETING::get_huid(i_target)); + o_chipId = POWER_CHIPID::GEMINI_16; + + HWAS_ASSERT(l_spdDmbRev == 0x0, + "Invalid Gemini DMB Revision Number, expected to find 0x0 at byte 200 in Gemini SPD"); + + // 0x10 is the only valid EC level for Gemini cards. If we find 0x0 @ byte 200 in + // the Gemini SPD then we will return 0x10 as the EC level + o_ec = 0x10; } else { - HWAS_ERR("ocmbIdecPhase1> Unknown OCMB chip type discovered in SPD " - "ID=0x%.4X OCMB HUID 0x%.8X", - spdId, - TARGETING::get_huid(i_target)); + HWAS_ERR("getOcmbIdecFromSpd> Unknown OCMB chip type discovered in SPD " + "ID=0x%.4X OCMB HUID 0x%.8x", + l_spdId, + TARGETING::get_huid(i_target)); /*@ * @errortype * @severity ERRL_SEV_PREDICTIVE - * @moduleid MOD_OCMB_IDEC_PHASE_1 + * @moduleid MOD_OCMB_IDEC * @reasoncode RC_OCMB_UNKNOWN_CHIP_TYPE * @userdata1[0:7] SPD Module Revision * @userdata1[8:15] DRAM Interface Type Presented or Emulated @@ -667,46 +568,87 @@ errlHndl_t ocmbIdecPhase1(const TARGETING::TargetHandle_t& i_target) * OCMB chip types. * @custdesc Unsupported memory installed. */ - error = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE, + l_errl = hwasError(ERRORLOG::ERRL_SEV_PREDICTIVE, MOD_OCMB_IDEC_PHASE_1, RC_OCMB_UNKNOWN_CHIP_TYPE, - TWO_UINT32_TO_UINT64(SPD_FFDC_BYTES, spdId), + TWO_UINT32_TO_UINT64(SPD_FFDC_BYTES, l_spdId), TARGETING::get_huid(i_target)); - // Add callouts and commit - ocmbErrlCommit(i_target, error); - break; } - uint16_t id = 0; - uint16_t ec = 0; - bool isId = true; + }while(0); + + return l_errl; + +} + + +errlHndl_t ocmbIdecPhase1(const TARGETING::TargetHandle_t& i_target) +{ + errlHndl_t l_errl = nullptr; + + // Allocate buffer to hold SPD and init to 0 + size_t l_spdBufferSize = SPD::OCMB_SPD_EFD_COMBINED_SIZE; + uint8_t* l_spdBuffer = new uint8_t[l_spdBufferSize]; + memset(l_spdBuffer, 0, l_spdBufferSize); + uint16_t l_chipId = 0; + uint8_t l_chipEc = 0; + do { - error = ocmbTranslateSpdToIdec(spdId, isId, SPD_FFDC_BYTES, id); - if (error) + // Read the full SPD. + l_errl = deviceRead(i_target, + l_spdBuffer, + l_spdBufferSize, + DEVICE_SPD_ADDRESS(SPD::ENTIRE_SPD)); + + // If unable to retrieve the SPD buffer then can't + // extract the IDEC data, so return error. + if (l_errl != nullptr) { - ocmbErrlCommit(i_target, error); + HWAS_ERR("ocmbIdecPhase1> Error while trying to read " + "ENTIRE SPD from 0x%.08X ", + TARGETING::get_huid(i_target)); + break; } - error = ocmbTranslateSpdToIdec(spdEc, !isId, SPD_FFDC_BYTES, ec, spdId); - if (error) + // Make sure we got back the size we were expecting. + assert(l_spdBufferSize == SPD::OCMB_SPD_EFD_COMBINED_SIZE, + "ocmbIdecPhase1> OCMB SPD read size %d " + "doesn't match the expected size %d", + l_spdBufferSize, + SPD::OCMB_SPD_EFD_COMBINED_SIZE); + + l_errl = getOcmbIdecFromSpd(i_target, + l_spdBuffer, + l_chipId, + l_chipEc); + + // If we were unable to read the IDEC information from the SPD + // then break out early and do not set the associated attributes + if (l_errl != nullptr) { - ocmbErrlCommit(i_target, error); + HWAS_ERR("ocmbIdecPhase1> Error while trying to parse " + "chip id and ec values from SPD read from OCMB 0x%.08X ", + TARGETING::get_huid(i_target)); + break; } + HWAS_INF("ocmbIdecPhase1> Read Chip ID = 0x%x Chip EC = 0x%x from target 0x%.08X", + l_chipId, l_chipEc, TARGETING::get_huid(i_target) ); + // set the explorer chip EC attributes. - i_target->setAttr<TARGETING::ATTR_EC>(ec); - i_target->setAttr<TARGETING::ATTR_HDAT_EC>(ec); + i_target->setAttr<TARGETING::ATTR_EC>(l_chipEc); + i_target->setAttr<TARGETING::ATTR_HDAT_EC>(l_chipEc); // set the explorer chip id attribute. - i_target->setAttr<TARGETING::ATTR_CHIP_ID>(id); + i_target->setAttr<TARGETING::ATTR_CHIP_ID>(l_chipId); } while(0); - delete[] spdBuffer; - return error; + delete[] l_spdBuffer; + return l_errl; } |