/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/chips/p9/procedures/hwp/io/p9_io_erepairGetFailedLanesHwp.H $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] 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 p9_io_erepairGetFailedLanesHwp.H /// @brief FW Team HWP that accesses the fail lanes of Fabric and Memory buses. /// //---------------------------------------------------------------------------- // *HWP HWP Owner : Chris Steffen // *HWP HWP Backup Owner: Gary Peterson // *HWP FW Owner : Sumit Kumar // *HWP Team : IO // *HWP Level : 2 // *HWP Consumed by : FSP:HB //---------------------------------------------------------------------------- #ifndef P9_IO_EREPAIRGETFAILEDLANESHWP_H_ #define P9_IO_EREPAIRGETFAILEDLANESHWP_H_ #include #include #include #include /****************************************************************************** * Accessor HWP *****************************************************************************/ /** * @brief Function to check if the system has Custom DIMM type (CDIMM). * Attribute ATTR_EFF_CUSTOM_DIMM is read to determine the type. * @param[in] i_target Reference to X-Bus or O-Bus or DMI target * @param[o] o_customDimm Return value - ENUM_ATTR_EFF_CUSTOM_DIMM_NO * or ENUM_ATTR_EFF_CUSTOM_DIMM_YES * @return ReturnCode */ template fapi2::ReturnCode getDimmType( const fapi2::Target < K >& i_target, uint8_t& o_customDimm) { fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; std::vector> l_mbaChiplets; fapi2::Target l_mbaTarget; std::vector> l_target_dimm_array; o_customDimm = fapi2::ENUM_ATTR_CEN_SPD_CUSTOM_NO; // Get the connected MBA chiplet and determine whether we have CDIMM l_mbaChiplets = i_target.template getChildren (fapi2::TARGET_STATE_FUNCTIONAL); FAPI_ASSERT( 0 != l_mbaChiplets.size(), fapi2::P9_EREPAIR_CHILD_MBA_TARGETS_ERR() .set_VAL_CHIPLET(l_mbaChiplets), "ERROR: During get child MBA targets"); l_mbaTarget = l_mbaChiplets[0]; l_target_dimm_array = l_mbaTarget.getChildren (fapi2::TARGET_STATE_FUNCTIONAL); if(0 != l_target_dimm_array.size()) { FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CEN_SPD_CUSTOM, l_target_dimm_array[0], o_customDimm)); } else { o_customDimm = fapi2::ENUM_ATTR_CEN_SPD_CUSTOM_NO; } fapi_try_exit: return l_rc; } /** * @brief Function called by the HWP that parses the data read from VPD. * This function scans through failBit field bit pattern and checks * for all bits that are set. For bits SET the corresponding bit positions * marks the failed lane number and is copied into * the respective failLane vectors to be returned to the caller. * * @param[in] i_target Reference to X-Bus or O-Bus or DMI target type * @param[in] i_busInterface Reference to target sub interface * @param[in] i_failBit This is the failBit field from the eRepair records * read from the VPD * @param[o] o_FailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Rx/Tx sub-interface. * * @return ReturnCode */ template fapi2::ReturnCode decodeFailedLanes( const fapi2::Target < K >& i_target, uint8_t i_busInterface, uint32_t i_failBit, std::vector& o_FailLanes) { fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; uint8_t loop; uint8_t maxBusLanes = 0; uint32_t checkBitPosition = (0x00800000); // fail bits[0:23] maps to bits[8:31] FAPI_INF(">> decodeFailedLanes - IF:0x%x FailBit:0x%x ", i_busInterface, i_failBit); // Check for target type and corresponding sub interface // to get max lanes supported per interface if(i_target.getType() == fapi2::TARGET_TYPE_OBUS) { maxBusLanes = EREPAIR::OBUS_MAX_LANE_WIDTH; //OBUS } else if(i_target.getType() == fapi2::TARGET_TYPE_XBUS) { maxBusLanes = EREPAIR::XBUS_MAX_LANE_WIDTH; //XBUS } else if((i_target.getType() == fapi2::TARGET_TYPE_MEMBUF_CHIP) || (i_target.getType() == fapi2::TARGET_TYPE_DMI)) { if( (i_busInterface == EREPAIR::DMI_MCS_RECEIVE) || (i_busInterface == EREPAIR::DMI_MEMBUF_DRIVE) ) { maxBusLanes = EREPAIR::DMIBUS_UPSTREAM_MAX_LANE_WIDTH; } else if( (i_busInterface == EREPAIR::DMI_MCS_DRIVE) || (i_busInterface == EREPAIR::DMI_MEMBUF_RECEIVE) ) { maxBusLanes = EREPAIR::DMIBUS_DNSTREAM_MAX_LANE_WIDTH; } } //Check for all the failed bit SET in the bit stream and update the vector //And print the failed lanes FAPI_INF("decodeFailedLanes: Failed Lane(s):"); for( loop = 0; loop < maxBusLanes; loop++ ) { if( i_failBit & ( checkBitPosition >> loop ) ) { o_FailLanes.push_back(loop); FAPI_INF("%d", loop); } } FAPI_DBG("<< decodeFailedLanes"); return l_rc; } /** * @brief Function called by the FW Team HWP that parses the data read from * Field VPD. This function matches each eRepair record read from the VPD * and matches it against the attributes of the passed target. * If a match is found, the corresponding eRepair record is copied into * the respective failLane vectors to be returned to the caller. * (For Proc) * @param[in] i_target Reference to X-Bus or O-Bus target * @param[in] i_buf This is the buffer that has the eRepair records * read from the VPD * @param[in] i_bufSz This is the size of passed buffer in terms of bytes * @param[in] i_clkGroup Specifies clock group 0:[XOA, X1A,..] 1:[X0B, X1B,..] * @param[o] o_txFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Tx sub-interface. * @param[o] o_rxFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Rx sub-interface. * * @return ReturnCode */ template fapi2::ReturnCode determineRepairLanesProc( const fapi2::Target < K >& i_target, uint8_t* i_buf, uint32_t i_bufSz, const uint8_t i_clkGroup, EREPAIR::erepairVpdType i_vpdType, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { uint32_t l_numRepairs = 0; uint8_t* l_vpdPtr = NULL; eRepairHeader* l_vpdHeadPtr = NULL; uint32_t l_loop = 0; uint32_t l_bytesParsed = 0; const uint32_t l_fabricRepairDataSz = sizeof(eRepairPowerBus); fapi2::Target l_chipTarget; fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; fapi2::ATTR_CHIP_UNIT_POS_Type l_busNum; fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; fapi2::MvpdRecord l_vpdRecord = fapi2::MVPD_RECORD_VWML; FAPI_INF(">> determineRepairLanesProc - BufSize:%d ClkGrp:%d ", i_bufSz, i_clkGroup); if(i_vpdType == EREPAIR::EREPAIR_VPD_MNFG) { l_vpdRecord = fapi2::MVPD_RECORD_MER0; } // Get the parent chip target l_chipTarget = i_target.template getParent(); // Get the chip position uint32_t l_chipPosition; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POS, l_chipTarget, l_chipPosition)); // Read the header and count information l_vpdPtr = i_buf; // point to the start of header data l_vpdHeadPtr = reinterpret_cast (l_vpdPtr); l_numRepairs = l_vpdHeadPtr->availNumRecord; l_bytesParsed = sizeof(eRepairHeader); // we've read the header data l_vpdPtr += sizeof(eRepairHeader); // point to the start of repair data // Parse for Power bus data { eRepairPowerBus* l_fabricBus; // Read Power bus eRepair data and get the failed lane numbers for(l_loop = 0; l_loop < l_numRepairs; l_loop++, (l_vpdPtr += l_fabricRepairDataSz)) { FAPI_INF("Loop data:Numrepair:%d Bytesparse:%d ", l_numRepairs, l_bytesParsed); // Make sure we are not parsing more data than the passed size l_bytesParsed += l_fabricRepairDataSz; if(l_bytesParsed > i_bufSz) { FAPI_INF("Size:Byteparsed:%d BufSize:%d ", l_bytesParsed, i_bufSz); break; } l_fabricBus = reinterpret_cast(l_vpdPtr); #ifndef _BIG_ENDIAN // We are on a Little Endian system. // Need to swap the nibbles of the structure - eRepairPowerBus uint8_t l_temp = l_vpdPtr[2]; l_fabricBus->type = (l_temp >> 4); l_fabricBus->interface = (l_temp & 0x0F); #endif // Check if we have the matching the Fabric Bus types //if((l_tgtType == fapi2::TARGET_TYPE_OBUS) && // (l_fabricBus->type != PROCESSOR_OPT)) //{ // continue; //} // Get fabric unit position FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, l_busNum)); FAPI_INF("ChipPos:%d ProcId:%d ", l_chipPosition, l_fabricBus->device.processor_id); FAPI_INF("BusNum:%d Channel:%d ", l_busNum, l_fabricBus->device.fabricBus); FAPI_INF("Type:%d IF:%d ", l_fabricBus->type, l_fabricBus->interface); // Check if we have the correct Proc ID if( (l_chipPosition != l_fabricBus->device.processor_id) && (l_fabricBus->type == EREPAIR::PROCESSOR_EDIP) ) { FAPI_INF("Invalidate Fabric vpd record"); // Reset lane value to invalidate record and // update number of records accordingly l_fabricBus->failBit = 0; l_vpdHeadPtr->availNumRecord--; FAPI_INF("Set VPD data:RC:0x%x KW:0x%x BS:%d ", l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, i_bufSz); /*** Write the updated eRepair buffer back to MVPD ***/ FAPI_TRY( setMvpdField( l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, l_chipTarget, i_buf, i_bufSz), "Update erepair fabric data to VPD failed w/rc=0x%x", static_cast(fapi2::current_err) ); continue; } if( (l_fabricBus->type != EREPAIR::PROCESSOR_EDIP) || (l_fabricBus->device.fabricBus != ((i_clkGroup << 4) | l_busNum)) ) { continue; } // Copy the fail lane numbers in the vectors FAPI_INF("Decode:IF:0x%x FailBit:%d ", l_fabricBus->interface, l_fabricBus->failBit); if(l_fabricBus->interface == EREPAIR::PBUS_DRIVER) { decodeFailedLanes(i_target, l_fabricBus->interface, l_fabricBus->failBit, o_txFailLanes); } else if(l_fabricBus->interface == EREPAIR::PBUS_RECEIVER) { decodeFailedLanes(i_target, l_fabricBus->interface, l_fabricBus->failBit, o_rxFailLanes); } } // end of for loop } // end of if(l_tgtType is XBus or OBus) FAPI_INF("<< No.of Fail Lanes: tx: %llu, rx: %llu", o_txFailLanes.size(), o_rxFailLanes.size()); fapi_try_exit: return fapi2::current_err; } /** * @brief Function called by the FW Team HWP that parses the data read from * Field VPD. This function matches each eRepair record read from the VPD * and matches it against the attributes of the passed target. * If a match is found, the corresponding eRepair record is copied into * the respective failLane vectors to be returned to the caller. * (For MemBuf) * @param[in] i_target Reference to MEMBUF target * @param[in] i_buf This is the buffer that has the eRepair records * read from the VPD * @param[in] i_bufSz This is the size of passed buffer in terms of bytes * @param[in] i_vpdType Specifies which VPD (MNFG or Field) to access. * @param[o] o_txFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Tx sub-interface. * @param[o] o_rxFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Rx sub-interface. * * @return ReturnCode */ template fapi2::ReturnCode determineRepairLanesMemBuf( const fapi2::Target < K >& i_target, uint8_t* i_buf, uint32_t i_bufSz, EREPAIR::erepairVpdType i_vpdType, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { uint32_t l_numRepairs = 0; uint8_t* l_vpdPtr = NULL; uint32_t l_loop = 0; uint32_t l_bytesParsed = 0; uint8_t l_customDimm = 0xFF; //Initialized to invalid value fapi2::Target l_dmiTarget; fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; fapi2::ATTR_CHIP_UNIT_POS_Type l_busNum; fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; fapi2::MBvpdRecord l_vpdRecord = fapi2::MBVPD_RECORD_VEIR; size_t l_mBufSize = 0; FAPI_INF(">> determineRepairLanesMemBuf - BufSize:%d ", i_bufSz); if(i_vpdType == EREPAIR::EREPAIR_VPD_MNFG) { l_vpdRecord = fapi2::MBVPD_RECORD_MER0; } // Get buf size l_mBufSize = i_bufSz; // Get the Centaur chip position uint32_t l_chipPosition; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POS, i_target, l_chipPosition)); // Check whether we have CDIMM l_rc = getDimmType(i_target, l_customDimm); FAPI_ASSERT(static_cast(l_rc) == 0x0, fapi2::P9_EREPAIR_DIMM_TYPE_CHECK_ERR() .set_ERROR(l_rc), "ERROR: DIMM type check"); FAPI_INF("CustomDimm:(%d)%s ", l_customDimm, (l_customDimm == fapi2::ENUM_ATTR_CEN_SPD_CUSTOM_NO ? "CEN_SPD_CUSTOM_NO" : "CEN_SPD_CUSTOM_YES")); // For Memory riser based centaur if(l_customDimm == fapi2::ENUM_ATTR_CEN_SPD_CUSTOM_NO) { eRepairHeader* l_vpdHeadPtr = NULL; // Read the header and count information l_vpdPtr = i_buf; // point to the start of header data l_vpdHeadPtr = reinterpret_cast (l_vpdPtr); l_numRepairs = l_vpdHeadPtr->availNumRecord; l_bytesParsed = sizeof(eRepairHeader); // we've read the header data l_vpdPtr += sizeof(eRepairHeader); // point to the start of repair data // Parse for Memory bus data eRepairMemBus* l_memBus; l_dmiTarget = i_target.template getParent(); // Read Power bus eRepair data and get the failed lane numbers for(l_loop = 0; l_loop < l_numRepairs; l_loop++, (l_vpdPtr += sizeof(eRepairMemBus))) { FAPI_INF("Loop data:Numrepair:%d Bytesparse:%d ", l_numRepairs, l_bytesParsed); // Make sure we are not parsing more data than the passed size l_bytesParsed += sizeof(eRepairMemBus); if(l_bytesParsed > i_bufSz) { FAPI_INF("Size:Byteparsed:%d BufSize:%d ", l_bytesParsed, i_bufSz); break; } l_memBus = reinterpret_cast(l_vpdPtr); #ifndef _BIG_ENDIAN // We are on a Little Endian system. // Need to swap the nibbles of the structure - eRepairMemBus uint8_t l_temp = l_vpdPtr[2]; l_memBus->type = (l_temp >> 4); l_memBus->interface = (l_temp & 0x0F); #endif // Get DMI chip unit position FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_dmiTarget, l_busNum)); FAPI_INF("ChipPos:%d CentaurId:%d ", l_chipPosition, l_memBus->device.proc_centaur_id); FAPI_INF("BusNum:%d Channel:%d ", l_busNum, l_memBus->device.memChannel); // Check if we have the correct Centaur ID // NOTE: We do not prefer to make the check of Centaur ID if the // system is known to have CDIMMs. This check is applicable // only for systems with ISDIMM because in the ISDIMM systems // the Lane eRepair data for multiple Centaurs is maintained in // a common VPD. // DMI<-->MemBuf uniquely identify the bus if( (l_chipPosition != l_memBus->device.proc_centaur_id) || (l_busNum != l_memBus->device.memChannel) ) { continue; } FAPI_INF("Type:%d IF:%d ", l_memBus->type, l_memBus->interface); // Check if we have the matching the Memory Bus types if(l_memBus->type != EREPAIR::MEMORY_EDIP) { continue; } // Copy the fail lane numbers in the vectors FAPI_INF("Decode:IF:0x%x FailBit:0x%x ", l_memBus->interface, l_memBus->failBit); if(l_memBus->interface == EREPAIR::DMI_MEMBUF_DRIVE) { decodeFailedLanes(i_target, l_memBus->interface, l_memBus->failBit, o_txFailLanes); } else if(l_memBus->interface == EREPAIR::DMI_MEMBUF_RECEIVE) { decodeFailedLanes(i_target, l_memBus->interface, l_memBus->failBit, o_rxFailLanes); } } // end of for loop } else // For CDIMM { eRepairHeader_cdimm* l_vpdHeadPtr = NULL; l_vpdPtr = i_buf; // point to the start of header data l_vpdHeadPtr = reinterpret_cast (l_vpdPtr); l_numRepairs = l_vpdHeadPtr->numRecords; l_bytesParsed = sizeof(eRepairHeader_cdimm); // we've read the header data l_vpdPtr += sizeof(eRepairHeader_cdimm); // point to the start of repair data // Parse for Memory bus data eRepairMemBus_cdimm* l_memBus; l_dmiTarget = i_target.template getParent(); // Read Power bus eRepair data and get the failed lane numbers for(l_loop = 0; l_loop < l_numRepairs; l_loop++, (l_vpdPtr += sizeof(eRepairMemBus_cdimm))) { FAPI_INF("Loop data:Numrepair:%d Bytesparse:%d ", l_numRepairs, l_bytesParsed); // Make sure we are not parsing more data than the passed size l_bytesParsed += sizeof(eRepairMemBus_cdimm); if(l_bytesParsed > i_bufSz) { FAPI_INF("Size:Byteparsed:%d BufSize:%d ", l_bytesParsed, i_bufSz); break; } l_memBus = reinterpret_cast(l_vpdPtr); #ifndef _BIG_ENDIAN // We are on a Little Endian system. // Need to swap the nibbles of the structure - eRepairMemBus_cdimm uint8_t l_temp = l_vpdPtr[2]; l_memBus->type = (l_temp >> 4); l_memBus->interface = (l_temp & 0x0F); #endif // Get DMI chip unit position FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, l_dmiTarget, l_busNum)); FAPI_INF("ChipPos:%d CentaurId:%d ", l_chipPosition, l_memBus->device.proc_centaur_id); FAPI_INF("BusNum:%d Channel:%d ", l_busNum, l_memBus->device.memChannel); // Check if we have the correct Centaur ID and matching DMI bus i/f. // DMI<-->MemBuf uniquely identify the bus if( (l_chipPosition != l_memBus->device.proc_centaur_id) || (l_busNum != l_memBus->device.memChannel) ) { FAPI_INF("Invalidate Centaur vpd record"); // Set lane value as 0xFF to invalidate record and // update number of records accordingly l_memBus->failBit = EREPAIR::INVALID_FAIL_LANE_NUMBER; l_vpdHeadPtr->numRecords--; FAPI_INF("Set VPD data:RC:0x%x KW:0x%x BS:%d ", l_vpdRecord, fapi2::MBVPD_KEYWORD_PDI, l_mBufSize); /*** Write the updated eRepair buffer back to Centaur FRU VPD ***/ FAPI_TRY( setMBvpdField( l_vpdRecord, fapi2::MBVPD_KEYWORD_PDI, i_target, i_buf, l_mBufSize), "Update erepair centaur data to VPD failed w/rc=0x%x", static_cast(fapi2::current_err) ); continue; } FAPI_INF("Type:%d IF:%d ", l_memBus->type, l_memBus->interface); // Check if we have the matching the Memory Bus types if(l_memBus->type != EREPAIR::MEMORY_EDIP) { continue; } // Copy the fail lane numbers in the vectors FAPI_INF("Decode:IF:0x%x FailBit:0x%x ", l_memBus->interface, l_memBus->failBit); if(l_memBus->interface == EREPAIR::DMI_MEMBUF_DRIVE) { o_txFailLanes.push_back(l_memBus->failBit); } else if(l_memBus->interface == EREPAIR::DMI_MEMBUF_RECEIVE) { o_rxFailLanes.push_back(l_memBus->failBit); } } // end of for loop } // for l_customDimm FAPI_INF("<< No.of Fail Lanes: tx: %llu, rx: %llu", o_txFailLanes.size(), o_rxFailLanes.size()); fapi_try_exit: return fapi2::current_err; } /** * @brief Function called by the FW Team HWP that parses the data read from * Field VPD. This function matches each eRepair record read from the VPD * and matches it against the attributes of the passed target. * If a match is found, the corresponding eRepair record is copied into * the respective failLane vectors to be returned to the caller. * (For Memory) * @param[in] i_target Reference to DMI target * @param[in] i_buf This is the buffer that has the eRepair records * read from the VPD * @param[in] i_bufSz This is the size of passed buffer in terms of bytes * @param[o] o_txFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Tx sub-interface. * @param[o] o_rxFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Rx sub-interface. * * @return ReturnCode */ template fapi2::ReturnCode determineRepairLanesDMI( const fapi2::Target < K >& i_target, uint8_t* i_buf, uint32_t i_bufSz, EREPAIR::erepairVpdType i_vpdType, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { uint32_t l_numRepairs = 0; uint8_t* l_vpdPtr = NULL; eRepairHeader* l_vpdHeadPtr = NULL; uint32_t l_loop = 0; uint32_t l_bytesParsed = 0; const uint32_t l_memRepairDataSz = sizeof(eRepairMemBus); fapi2::Target l_chipTarget; fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; fapi2::ATTR_CHIP_UNIT_POS_Type l_busNum; fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; fapi2::MvpdRecord l_vpdRecord = fapi2::MVPD_RECORD_VWML; FAPI_INF(">> determineRepairLanesMemDMI - BufSize:%d ", i_bufSz); if(i_vpdType == EREPAIR::EREPAIR_VPD_MNFG) { l_vpdRecord = fapi2::MVPD_RECORD_MER0; } // Get the parent chip target l_chipTarget = i_target.template getParent(); // Get the chip position uint32_t l_chipPosition; FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_POS, l_chipTarget, l_chipPosition)); // Read the header and count information l_vpdPtr = i_buf; // point to the start of header data l_vpdHeadPtr = reinterpret_cast (l_vpdPtr); l_numRepairs = l_vpdHeadPtr->availNumRecord; l_bytesParsed = sizeof(eRepairHeader); // we've read the header data l_vpdPtr += sizeof(eRepairHeader); // point to the start of repair data // Parse for Memory bus data { eRepairMemBus* l_memBus; // Read Power bus eRepair data and get the failed lane numbers for(l_loop = 0; l_loop < l_numRepairs; l_loop++, (l_vpdPtr += l_memRepairDataSz)) { FAPI_INF("Loop data:Numrepair:%d Bytesparse:%d ", l_numRepairs, l_bytesParsed); // Make sure we are not parsing more data than the passed size l_bytesParsed += l_memRepairDataSz; if(l_bytesParsed > i_bufSz) { FAPI_INF("Size:Byteparsed:%d BufSize:%d ", l_bytesParsed, i_bufSz); break; } l_memBus = reinterpret_cast(l_vpdPtr); #ifndef _BIG_ENDIAN // We are on a Little Endian system. // Need to swap the nibbles of the structure - eRepairMemBus uint8_t l_temp = l_vpdPtr[2]; l_memBus->type = (l_temp >> 4); l_memBus->interface = (l_temp & 0x0F); #endif // Get DMI chip unit position FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, l_busNum)); FAPI_INF("ChipPos:%d ProcId:%d ", l_chipPosition, l_memBus->device.proc_centaur_id); FAPI_INF("BusNum:%d Channel:%d ", l_busNum, l_memBus->device.memChannel); FAPI_INF("Type:%d IF:%d ", l_memBus->type, l_memBus->interface); // Check if we have the correct Proc ID if( (l_chipPosition != l_memBus->device.proc_centaur_id) && (l_memBus->type == EREPAIR::MEMORY_EDIP) ) { FAPI_INF("Invalidate DMI vpd record"); // Reset lane value to invalidate record and // update number of records accordingly l_memBus->failBit = 0; l_vpdHeadPtr->availNumRecord--; FAPI_INF("Set VPD data:RC:0x%x KW:0x%x BS:%d ", l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, i_bufSz); /*** Write the updated eRepair buffer back to MVPD ***/ FAPI_TRY( setMvpdField( l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, l_chipTarget, i_buf, i_bufSz), "Update erepair dmi data to VPD failed w/rc=0x%x", static_cast(fapi2::current_err) ); continue; } // Check if we have the matching the Memory Bus types if( (l_busNum != l_memBus->device.memChannel) || (l_memBus->type != EREPAIR::MEMORY_EDIP) ) { continue; } // Copy the fail lane numbers in the vectors FAPI_INF("Decode:IF:0x%x FailBit:%d ", l_memBus->interface, l_memBus->failBit); if(l_memBus->interface == EREPAIR::DMI_MCS_DRIVE) { decodeFailedLanes(i_target, l_memBus->interface, l_memBus->failBit, o_txFailLanes); } else if(l_memBus->interface == EREPAIR::DMI_MCS_RECEIVE) { decodeFailedLanes(i_target, l_memBus->interface, l_memBus->failBit, o_rxFailLanes); } } // end of for loop } // end of if(l_tgtType is DMI) FAPI_INF("<< No.of Fail Lanes: tx: %llu, rx: %llu", o_txFailLanes.size(), o_rxFailLanes.size()); fapi_try_exit: return fapi2::current_err; } /** * @brief Function called by the FW Team HWP that reads the data from Field VPD. * This function makes the actual calls to read the VPD * It determines the size of the buffer to be read, allocates memory * of the determined size, calls fapiGetMvpdField to read the eRepair * records. This buffer is further passed to another routine for * parsing. (For Proc) * * @param[in] i_target Reference to X-Bus or O-Bus target * @param[in] i_vpdType Specifies which VPD (MNFG or Field) to access. * @param[in] i_clkGroup Specifies clock group 0:[XOA, X1A,..] 1:[X0B, X1B,..] * @param[o] o_txFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Tx sub-interface. * @param[o] o_rxFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Rx sub-interface. * * @return ReturnCode */ template fapi2::ReturnCode retrieveRepairDataProc( const fapi2::Target < K >& i_target, EREPAIR::erepairVpdType i_vpdType, const uint8_t i_clkGroup, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; uint8_t* l_retBuf = NULL; uint8_t* l_serialBuf = NULL; uint32_t l_bufSize = 0; uint32_t l_serialNum = 0; fapi2::Target l_procTarget; FAPI_INF(">> retrieveRepairDataProc: vpdType:%s", (i_vpdType == EREPAIR::EREPAIR_VPD_MNFG ? "MNFG" : "FIELD")); // Determine the Processor target l_procTarget = i_target.template getParent(); fapi2::MvpdRecord l_vpdRecord = fapi2::MVPD_RECORD_VWML; if(i_vpdType == EREPAIR::EREPAIR_VPD_MNFG) { l_vpdRecord = fapi2::MVPD_RECORD_MER0; } // Determine the serial number to uniquely identify the proc FAPI_TRY( getMvpdField( fapi2::MVPD_RECORD_VINI, fapi2::MVPD_KEYWORD_SN, l_procTarget, NULL, l_serialNum), "Serial number size read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("Serial number size:0x%08x ", l_serialNum); if( l_serialNum ) { // Allocate memory for buffer l_serialBuf = new uint8_t[l_serialNum](); // Retrieve the serial number data from the MVPD FAPI_TRY( getMvpdField( fapi2::MVPD_RECORD_VINI, fapi2::MVPD_KEYWORD_SN, l_procTarget, l_serialBuf, l_serialNum), "Serial number read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("Serial Number: "); for(uint32_t i = 0; i < l_serialNum; i++) { FAPI_INF("%02x ", *(l_serialBuf + i)); } } // Determine the size of the eRepair data in the VPD FAPI_TRY( getMvpdField( l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, l_procTarget, NULL, l_bufSize), "VPD size read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("retrieveRepairDataProc:VPD data:RC:0x%x KW:0x%x BS:%d ", l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, l_bufSize); if((l_bufSize == 0) || ((i_vpdType == EREPAIR::EREPAIR_VPD_FIELD) && (l_bufSize > EREPAIR::EREPAIR_P9_MODULE_VPD_FIELD_SIZE)) || ((i_vpdType == EREPAIR::EREPAIR_VPD_MNFG) && (l_bufSize > EREPAIR::EREPAIR_P9_MODULE_VPD_MNFG_SIZE))) { FAPI_ASSERT(false, fapi2::P9_EREPAIR_ACCESSOR_HWP_INVALID_FABRIC_VPD_SIZE_ERR() .set_VAL_BUF_SIZE(l_bufSize) .set_ERROR(fapi2::current_err), "ERROR: Invalid Fabric VPD size"); } // Allocate memory for buffer l_retBuf = new uint8_t[l_bufSize](); FAPI_ASSERT(l_retBuf != NULL, fapi2::P9_EREPAIR_ACCESSOR_HWP_MEMORY_ALLOC_FAIL_ERR() .set_BUF_SIZE(l_bufSize), "ERROR: Failed to allocate memory size"); // Retrieve the Field eRepair data from the PNOR FAPI_TRY( getMvpdField( l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, l_procTarget, l_retBuf, l_bufSize), "VPD read failed w/rc=0x%x", static_cast(fapi2::current_err) ); // Parse the buffer to determine eRepair lanes and copy the // fail lane numbers to the return vector FAPI_TRY( determineRepairLanesProc( i_target, l_retBuf, l_bufSize, i_clkGroup, i_vpdType, o_txFailLanes, o_rxFailLanes), "Call to determineRepairLanesProc failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_DBG("<< retrieveRepairDataProc"); fapi_try_exit: // Delete the buffer which has Field eRepair data delete[] l_retBuf; delete[] l_serialBuf; return fapi2::current_err; } /** * @brief Function called by the FW Team HWP that reads the data from Field VPD. * This function makes the actual calls to read the VPD * It determines the size of the buffer to be read, allocates memory * of the determined size, calls fapiGetMBvpdField to read the eRepair * records. This buffer is further passed to another routine for * parsing. (For Memory) * * @param[in] i_target Reference to MEMBUF or DMI target * @param[in] i_vpdType Specifies which VPD (MNFG or Field) to access. * @param[o] o_txFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Tx sub-interface. * @param[o] o_rxFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Rx sub-interface. * * @return ReturnCode */ template fapi2::ReturnCode retrieveRepairDataMemBuf( const fapi2::Target < K >& i_target, EREPAIR::erepairVpdType i_vpdType, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; uint8_t* l_retBuf = NULL; uint8_t* l_serialBuf = NULL; size_t l_serialNum = 0; size_t l_bufSize = 0; FAPI_INF(">> retrieveRepairDataMemBuf: vpdType:%s", (i_vpdType == EREPAIR::EREPAIR_VPD_MNFG ? "MNFG" : "FIELD")); fapi2::MBvpdRecord l_vpdRecord = fapi2::MBVPD_RECORD_VEIR; if(i_vpdType == EREPAIR::EREPAIR_VPD_MNFG) { l_vpdRecord = fapi2::MBVPD_RECORD_MER0; } // Determine the serial number to uniquely identify centaur vpd FAPI_TRY( getMBvpdField( fapi2::MBVPD_RECORD_VINI, fapi2::MBVPD_KEYWORD_SN, i_target, NULL, l_serialNum), "Serial number size read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("Serial number size:0x%08x ", l_serialNum); if( l_serialNum ) { // Allocate memory for buffer l_serialBuf = new uint8_t[l_serialNum](); // Retrieve the serial number data from the MVPD FAPI_TRY( getMBvpdField( fapi2::MBVPD_RECORD_VINI, fapi2::MBVPD_KEYWORD_SN, i_target, l_serialBuf, l_serialNum), "Serial number read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("Serial Number: "); for(size_t i = 0; i < l_serialNum; i++) { FAPI_INF("%02x ", *(l_serialBuf + i)); } } // Determine the size of the eRepair data in the VPD FAPI_TRY( getMBvpdField( l_vpdRecord, fapi2::MBVPD_KEYWORD_PDI, i_target, NULL, l_bufSize), "VPD size read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("retrieveRepairDataMemBuf:VPD data:RC:0x%x KW:0x%x BS:%d ", l_vpdRecord, fapi2::MBVPD_KEYWORD_PDI, l_bufSize); // Check for buf size FAPI_ASSERT(l_bufSize > 0, fapi2::P9_EREPAIR_ACCESSOR_HWP_INVALID_MEM_VPD_SIZE_ERR() .set_VAL_BUF_SIZE(l_bufSize) .set_ERROR(l_rc), "ERROR: Invalid MEM VPD size"); // Allocate memory for buffer l_retBuf = new uint8_t[l_bufSize](); FAPI_ASSERT(l_retBuf != NULL, fapi2::P9_EREPAIR_ACCESSOR_HWP_MEMORY_ALLOC_FAIL_ERR() .set_BUF_SIZE(l_bufSize), "ERROR: Failed to allocate memory size"); // Retrieve the Field eRepair data from the PNOR FAPI_TRY( getMBvpdField( l_vpdRecord, fapi2::MBVPD_KEYWORD_PDI, i_target, l_retBuf, l_bufSize), "VPD read failed w/rc=0x%x", static_cast(fapi2::current_err) ); // Parse the buffer to determine eRepair lanes and copy the // fail lane numbers to the return vector FAPI_TRY( determineRepairLanesMemBuf( i_target, l_retBuf, l_bufSize, i_vpdType, o_txFailLanes, o_rxFailLanes), "Call to determineRepairLanesMemBuf failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_DBG("<< retrieveRepairDataMemBuf"); fapi_try_exit: // Delete the buffer which has Field eRepair data delete[] l_retBuf; delete[] l_serialBuf; return fapi2::current_err; } /** * @brief Function called by the FW Team HWP that reads the data from Field VPD. * This function makes the actual calls to read the VPD * It determines the size of the buffer to be read, allocates memory * of the determined size, calls fapiGetMvpdField to read the eRepair * records. This buffer is further passed to another routine for * parsing. (For DMI) * * @param[in] i_target Reference to DMI target * @param[in] i_vpdType Specifies which VPD (MNFG or Field) to access. * @param[o] o_txFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Tx sub-interface. * @param[o] o_rxFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Rx sub-interface. * * @return ReturnCode */ template fapi2::ReturnCode retrieveRepairDataDMI( const fapi2::Target < K >& i_target, EREPAIR::erepairVpdType i_vpdType, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { fapi2::ReturnCode l_rc = fapi2::FAPI2_RC_SUCCESS; fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; uint8_t* l_retBuf = NULL; uint8_t* l_serialBuf = NULL; uint32_t l_bufSize = 0; uint32_t l_serialNum = 0; fapi2::Target l_procTarget; FAPI_INF(">> retrieveRepairDataDMI: vpdType:%s", (i_vpdType == EREPAIR::EREPAIR_VPD_MNFG ? "MNFG" : "FIELD")); // Determine the Processor target l_procTarget = i_target.template getParent(); fapi2::MvpdRecord l_vpdRecord = fapi2::MVPD_RECORD_VWML; if(i_vpdType == EREPAIR::EREPAIR_VPD_MNFG) { l_vpdRecord = fapi2::MVPD_RECORD_MER0; } // Determine the serial number to uniquely identify the proc FAPI_TRY( getMvpdField( fapi2::MVPD_RECORD_VINI, fapi2::MVPD_KEYWORD_SN, l_procTarget, NULL, l_serialNum), "Serial number size read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("Serial number size:0x%08x ", l_serialNum); if( l_serialNum ) { // Allocate memory for buffer l_serialBuf = new uint8_t[l_serialNum](); // Retrieve the serial number data from the MVPD FAPI_TRY( getMvpdField( fapi2::MVPD_RECORD_VINI, fapi2::MVPD_KEYWORD_SN, l_procTarget, l_serialBuf, l_serialNum), "Serial number read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("Serial Number: "); for(uint32_t i = 0; i < l_serialNum; i++) { FAPI_INF("%02x ", *(l_serialBuf + i)); } } // Determine the size of the eRepair data in the VPD FAPI_TRY( getMvpdField( l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, l_procTarget, NULL, l_bufSize), "VPD size read failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_INF("retrieveRepairDataDMI:VPD data:RC:0x%x KW:0x%x BS:%d ", l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, l_bufSize); if((l_bufSize == 0) || ((i_vpdType == EREPAIR::EREPAIR_VPD_FIELD) && (l_bufSize > EREPAIR::EREPAIR_P9_MODULE_VPD_FIELD_SIZE)) || ((i_vpdType == EREPAIR::EREPAIR_VPD_MNFG) && (l_bufSize > EREPAIR::EREPAIR_P9_MODULE_VPD_MNFG_SIZE))) { FAPI_ASSERT(false, fapi2::P9_EREPAIR_ACCESSOR_HWP_INVALID_FABRIC_VPD_SIZE_ERR() .set_VAL_BUF_SIZE(l_bufSize) .set_ERROR(fapi2::current_err), "ERROR: Invalid Fabric VPD size (DMI)"); } // Allocate memory for buffer l_retBuf = new uint8_t[l_bufSize](); FAPI_ASSERT(l_retBuf != NULL, fapi2::P9_EREPAIR_ACCESSOR_HWP_MEMORY_ALLOC_FAIL_ERR() .set_BUF_SIZE(l_bufSize), "ERROR: Failed to allocate memory size (DMI)"); // Retrieve the Field eRepair data from the PNOR FAPI_TRY( getMvpdField( l_vpdRecord, fapi2::MVPD_KEYWORD_PDI, l_procTarget, l_retBuf, l_bufSize), "VPD read failed w/rc=0x%x", static_cast(fapi2::current_err) ); // Parse the buffer to determine eRepair lanes and copy the // fail lane numbers to the return vector FAPI_TRY( determineRepairLanesDMI( i_target, l_retBuf, l_bufSize, i_vpdType, o_txFailLanes, o_rxFailLanes), "Call to determineRepairLanesDMI failed w/rc=0x%x", static_cast(fapi2::current_err) ); FAPI_DBG("<< retrieveRepairDataDMI"); fapi_try_exit: // Delete the buffer which has Field eRepair data delete[] l_retBuf; delete[] l_serialBuf; return fapi2::current_err; } /** * @brief Function called by the FW Team HWP that reads the failed lanes * from VPD. This function calls the retrieveRepairData() that makes * the actual calls to read the VPD and perform the necessary actions. * * @param[in] i_target Reference to X-Bus or O-Bus or DMI target * @param[in] i_vpdType Specifies which VPD (MNFG or Field) to access. * @param[in] i_clkGroup Specifies clock group 0:[XOA, X1A,..] 1:[X0B, X1B,..] * @param[o] o_txFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Tx sub-interface. * @param[o] o_rxFailLanes Reference to a vector that will hold eRepair fail * lane numbers of the Rx sub-interface. * * @return ReturnCode */ fapi2::ReturnCode p9_io_erepairGetFailedLanesHwp( const fapi2::Target < fapi2::TARGET_TYPE_XBUS >& i_target, EREPAIR::erepairVpdType i_vpdType, const uint8_t i_clkGroup, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; FAPI_INF(">> erepairGetFailedLanesHwp - XBUS"); o_txFailLanes.clear(); o_rxFailLanes.clear(); // Retrieve the Field eRepair lane numbers from the VPD FAPI_TRY( retrieveRepairDataProc( i_target, i_vpdType, i_clkGroup, o_txFailLanes, o_rxFailLanes), "retrieveRepairDataProc() failed w/rc=0x%x", (uint64_t)fapi2::current_err ); fapi_try_exit: return fapi2::current_err; } fapi2::ReturnCode p9_io_erepairGetFailedLanesHwp( const fapi2::Target < fapi2::TARGET_TYPE_MEMBUF_CHIP >& i_target, EREPAIR::erepairVpdType i_vpdType, const uint8_t i_clkGroup, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; FAPI_INF(">> erepairGetFailedLanesHwp - MemBuf"); o_txFailLanes.clear(); o_rxFailLanes.clear(); // Retrieve the Field eRepair lane numbers from the VPD FAPI_TRY( retrieveRepairDataMemBuf( i_target, i_vpdType, o_txFailLanes, o_rxFailLanes), "retrieveRepairDataMemBuf() failed w/rc=0x%x", (uint64_t)fapi2::current_err ); fapi_try_exit: return fapi2::current_err; } fapi2::ReturnCode p9_io_erepairGetFailedLanesHwp( const fapi2::Target < fapi2::TARGET_TYPE_DMI >& i_target, EREPAIR::erepairVpdType i_vpdType, const uint8_t i_clkGroup, std::vector& o_txFailLanes, std::vector& o_rxFailLanes) { fapi2::current_err = fapi2::FAPI2_RC_SUCCESS; FAPI_INF(">> erepairGetFailedLanesHwp - DMI"); o_txFailLanes.clear(); o_rxFailLanes.clear(); // Retrieve the Field eRepair lane numbers from the VPD FAPI_TRY( retrieveRepairDataDMI( i_target, i_vpdType, o_txFailLanes, o_rxFailLanes), "retrieveRepairDataDMI() failed w/rc=0x%x", (uint64_t)fapi2::current_err ); fapi_try_exit: return fapi2::current_err; } #endif