From 8b35a2e4125b9b5d8263a6795e7e639f604ba397 Mon Sep 17 00:00:00 2001 From: Zane Shelley Date: Mon, 30 Sep 2013 15:22:47 -0500 Subject: PRD: Memory CE table support Change-Id: Ibf65bd92e9ef412876603cab63fc06861e19b7c7 RTC: 81714 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/5992 Reviewed-by: Zane Shelley Tested-by: Jenkins Server Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/6591 Reviewed-by: A. Patrick Williams III --- .../common/framework/service/prdfTargetServices.C | 2 +- .../common/framework/service/prdfTargetServices.H | 2 +- src/usr/diag/prdf/common/plat/pegasus/Membuf.rule | 2 + .../prdf/common/plat/pegasus/Membuf_acts_NEST.rule | 16 +- .../prdf/common/plat/pegasus/Membuf_regs_NEST.rule | 32 +++ .../common/plat/pegasus/prdfCenMbaCaptureData.C | 3 + .../prdf/common/plat/pegasus/prdfCenMbaCeTable.C | 237 +++++++++++++++++++++ .../prdf/common/plat/pegasus/prdfCenMbaCeTable.H | 167 +++++++++++++++ .../plat/pegasus/prdfCenMbaDataBundle_common.H | 2 + .../plat/pegasus/prdfCenMbaThresholds_common.C | 4 +- .../prdf/common/plat/pegasus/prdfCenMbaUeTable.C | 8 +- .../diag/prdf/common/plat/pegasus/prdfCenMembuf.C | 120 ++++++++++- .../common/plat/pegasus/prdfCenMembufExtraSig.H | 33 +++ .../diag/prdf/common/plat/pegasus/prdfCenSymbol.C | 82 ++++++- .../diag/prdf/common/plat/pegasus/prdfCenSymbol.H | 19 +- src/usr/diag/prdf/common/plugins/prdfCenLogParse.C | 84 ++++++++ src/usr/diag/prdf/common/plugins/prdfCenLogParse.H | 9 + .../diag/prdf/common/plugins/prdfLogParse_common.C | 4 + src/usr/diag/prdf/common/plugins/prdfParserEnums.H | 12 ++ src/usr/diag/prdf/common/prd_pegasus.mk | 1 + 20 files changed, 804 insertions(+), 35 deletions(-) create mode 100644 src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.C create mode 100644 src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.H create mode 100644 src/usr/diag/prdf/common/plat/pegasus/prdfCenMembufExtraSig.H (limited to 'src/usr/diag/prdf/common') diff --git a/src/usr/diag/prdf/common/framework/service/prdfTargetServices.C b/src/usr/diag/prdf/common/framework/service/prdfTargetServices.C index 347b5a824..ac73b98a5 100755 --- a/src/usr/diag/prdf/common/framework/service/prdfTargetServices.C +++ b/src/usr/diag/prdf/common/framework/service/prdfTargetServices.C @@ -286,7 +286,7 @@ uint8_t getChipLevel( TARGETING::TargetHandle_t i_target ) if ( !l_parentTarget->tryGetAttr(o_chipLvl) ) { PRDF_ERR( "[getChipLevel] Failed to get ATTR_EC" ); - o_chipLvl = 0xff; // Just in case + o_chipLvl = 0; // Just in case } } while (0); diff --git a/src/usr/diag/prdf/common/framework/service/prdfTargetServices.H b/src/usr/diag/prdf/common/framework/service/prdfTargetServices.H index db5d3666a..2421fc144 100755 --- a/src/usr/diag/prdf/common/framework/service/prdfTargetServices.H +++ b/src/usr/diag/prdf/common/framework/service/prdfTargetServices.H @@ -339,7 +339,7 @@ int32_t getMbaDimm( TARGETING::TargetHandle_t i_dimmTarget, uint8_t & o_dimm ); bool isDramWidthX4(TARGETING::TargetHandle_t i_mbaTarget); /** - * @brief Obtain ranks per DIMM select on an MBA. + * @brief Obtains number of ranks (including slave ranks) per DIMM select. * @param i_mbaTarget MBA target. * @param i_ds DIMM select for DIMM. * @return Number of ranks confgured per DIMM select. If internal function diff --git a/src/usr/diag/prdf/common/plat/pegasus/Membuf.rule b/src/usr/diag/prdf/common/plat/pegasus/Membuf.rule index 809e8f2a5..9fab60ab6 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/Membuf.rule +++ b/src/usr/diag/prdf/common/plat/pegasus/Membuf.rule @@ -46,6 +46,8 @@ chip Membuf dump DUMP_CONTENT_HWSUPERNOVA; scomlen 64; +.include "prdfCenMembufExtraSig.H"; + ############################################################################# # # # ###### # diff --git a/src/usr/diag/prdf/common/plat/pegasus/Membuf_acts_NEST.rule b/src/usr/diag/prdf/common/plat/pegasus/Membuf_acts_NEST.rule index a7446d857..c9110be2e 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/Membuf_acts_NEST.rule +++ b/src/usr/diag/prdf/common/plat/pegasus/Membuf_acts_NEST.rule @@ -1330,22 +1330,10 @@ actionclass analyzeFetchMpe0_7 { funccall("AnalyzeFetchMpe0_7"); }; actionclass analyzeFetchMpe1_7 { funccall("AnalyzeFetchMpe1_7"); }; /** Analyze a fetch NCE on MBA0 */ -actionclass analyzeFetchNce0 -{ - funccall("AnalyzeFetchNce0"); - # FIXME: RTC 47289 MNFG threshold temporarily set to 32/day until we add - # actual support in the AnalyzeFetchNce plugins. - threshold( field(32 / day), mfg(32 / day) ); -}; +actionclass analyzeFetchNce0 { funccall("AnalyzeFetchNce0"); }; /** Analyze a fetch NCE on MBA1 */ -actionclass analyzeFetchNce1 -{ - funccall("AnalyzeFetchNce1"); - # FIXME: RTC 47289 MNFG threshold temporarily set to 32/day until we add - # actual support in the AnalyzeFetchNce plugins. - threshold( field(32 / day), mfg(32 / day) ); -}; +actionclass analyzeFetchNce1 { funccall("AnalyzeFetchNce1"); }; # TODO: RTC 23125 The RAS spreadsheet action is RCE is: "Threshold per rank 8/24 # make a callout of DIMM pair". Needs discussion. diff --git a/src/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule b/src/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule index 134282142..740879f5f 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule +++ b/src/usr/diag/prdf/common/plat/pegasus/Membuf_regs_NEST.rule @@ -247,6 +247,22 @@ capture group FirRegs; }; + register MBA0_MBSECCFIR_MASK_AND + { + name "MBU.MBS.ECC01.MBECCFIR_MASK_AND"; + scomaddr 0x02011444; + capture group never; + access write_only; + }; + + register MBA0_MBSECCFIR_MASK_OR + { + name "MBU.MBS.ECC01.MBECCFIR_MASK_OR"; + scomaddr 0x02011445; + capture group never; + access write_only; + }; + register MBA0_MBSECCFIR_ACT0 { name "MBU.MBS.ECC01.MBECCFIR_ACTION0"; @@ -297,6 +313,22 @@ capture group FirRegs; }; + register MBA1_MBSECCFIR_MASK_AND + { + name "MBU.MBS.ECC23.MBECCFIR_MASK_AND"; + scomaddr 0x02011484; + capture group never; + access write_only; + }; + + register MBA1_MBSECCFIR_MASK_OR + { + name "MBU.MBS.ECC23.MBECCFIR_MASK_OR"; + scomaddr 0x02011485; + capture group never; + access write_only; + }; + register MBA1_MBSECCFIR_ACT0 { name "MBU.MBS.ECC23.MBECCFIR_ACTION0"; diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCaptureData.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCaptureData.C index caf5e6aeb..d74c5da03 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCaptureData.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCaptureData.C @@ -160,6 +160,9 @@ void addMemEccData( ExtensibleChip * i_mbaChip, STEP_CODE_DATA_STRUCT & io_sc ) // Add UE table to capture data. mbadb->iv_ueTable.addCapData( mbaTarget, cd ); + // Add CE table to capture data. + mbadb->iv_ceTable.addCapData( mbaTarget, cd ); + // Add DRAM repairs data from hardware. captureDramRepairsData( mbaTarget, cd ); diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.C new file mode 100644 index 000000000..e58abb65b --- /dev/null +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.C @@ -0,0 +1,237 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.C $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* COPYRIGHT International Business Machines Corp. 2013 */ +/* */ +/* p1 */ +/* */ +/* Object Code Only (OCO) source materials */ +/* Licensed Internal Code Source Materials */ +/* IBM HostBoot Licensed Internal Code */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* Origin: 30 */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#include + +#include + +// Framwork includes +#include +#include + +// Pegasus includes +#include + +using namespace TARGETING; + +namespace PRDF +{ + +using namespace CE_TABLE; + +//------------------------------------------------------------------------------ + +bool CenMbaCeTable::addEntry( const CenAddr & i_addr, + const CenSymbol & i_symbol ) +{ + bool o_doTps = false; + + TableData data ( i_addr, i_symbol.getDram(), i_symbol.getDramPins(), + i_symbol.getPortSlct(), i_symbol.getWiringType() ); + + // First, check if the entry already exists. If so, increment its count and + // move it to the end of the queue. + CeTable::iterator it = std::find( iv_table.begin(), iv_table.end(), data ); + if ( iv_table.end() != it ) + { + // Update the count + data.count = it->count + 1; + + // Update the DRAM pins + data.dramPins |= it->dramPins; + + // Remove the old entry + iv_table.erase( it ); + } + + // Add the new entry to the end of the list. + iv_table.push_back( data ); + + // Check the new entry's count for single entry threshold. + if ( TPS_ENTRY_COUNT_TH <= data.count ) + { + o_doTps = true; + } + + // Get number of entries in this table on the same rank as the new entry and + // threshold if needed. + if ( !o_doTps ) // no point iterating the table if o_doTps is already true + { + CenRank thisRank = data.addr.getRank(); + uint32_t rankCount = 0; + for ( CeTable::iterator it = iv_table.begin(); + it != iv_table.end(); it++ ) + { + if ( it->addr.getRank() == thisRank ) + rankCount++; + } + + if ( TPS_RANK_ENTRY_TH <= rankCount ) + o_doTps = true; + } + + // Note that we intentially checked the entries-per-rank threshold before + // removing any entries, if the table is full. This is to catch the corner + // case where the oldest entry is on the same rank as the new entry. + + // If the table is full, remove the oldest inactive entry + if ( MAX_ENTRIES < iv_table.size() ) + { + for ( CeTable::iterator it = iv_table.begin(); + it != iv_table.end(); it++ ) + { + if ( !it->active ) + { + iv_table.erase( it ); + break; + } + } + } + + // If the table is still full, all entries are active. Pop off the oldest + // active entry. + if ( MAX_ENTRIES < iv_table.size() ) + iv_table.pop_front(); + + // Do TPS if the table is full. + if ( MAX_ENTRIES == iv_table.size() ) + o_doTps = true; + + return o_doTps; +} + +//------------------------------------------------------------------------------ + +void CenMbaCeTable::deactivateAll() +{ + for ( CeTable::iterator it = iv_table.begin(); it != iv_table.end(); it++ ) + it->active = false; +} + +//------------------------------------------------------------------------------ + +void CenMbaCeTable::deactivateRank( const CenRank & i_rank ) +{ + for ( CeTable::iterator it = iv_table.begin(); it != iv_table.end(); it++ ) + { + if ( it->addr.getRank() == i_rank ) + it->active = false; + } +} + +//------------------------------------------------------------------------------ + +void CenMbaCeTable::getMnfgCounts( const CenRank & i_rank, + const CenSymbol & i_symbol, + uint32_t & o_dramCount, + uint32_t & o_hrCount, + uint32_t & o_dimmCount ) +{ + o_dramCount = 0; o_hrCount = 0; o_dimmCount = 0; + + const uint32_t dram = i_symbol.getDram(); + const uint32_t ps = i_symbol.getPortSlct(); + const uint32_t ds = i_rank.getDimmSlct(); + + for ( CeTable::iterator it = iv_table.begin(); it != iv_table.end(); it++ ) + { + if ( ps != it->portSlct ) continue; + + CenRank itRank = it->addr.getRank(); + + if ( ds == itRank.getDimmSlct() ) + { + o_dimmCount++; + + if ( i_rank == itRank ) + { + o_hrCount++; + + if ( dram == it->dram ) + o_dramCount++; + } + } + } +} + +//------------------------------------------------------------------------------ + +void CenMbaCeTable::addCapData( TargetHandle_t i_mbaTrgt, CaptureData & io_cd ) +{ + static const size_t sz_word = sizeof(CPU_WORD); + + // Get the maximum capture data size and adjust the size for endianess. + static const size_t sz_maxData = ((MAX_SIZE+sz_word-1) / sz_word) * sz_word; + + // Initialize to 0. + uint8_t data[sz_maxData]; + memset( data, 0x00, sz_maxData ); + + size_t sz_actData = 0; + + for ( CeTable::iterator it = iv_table.begin(); it != iv_table.end(); it++ ) + { + uint32_t mrnk = it->addr.getRank().getMaster(); // 3-bit + uint32_t srnk = it->addr.getRank().getSlave(); // 3-bit + uint32_t svld = it->addr.getRank().isSlaveValid() ? 1 : 0; // 1-bit + uint32_t bnk = it->addr.getBank(); // 4-bit + uint32_t row = it->addr.getRow(); // 17-bit + uint32_t col = it->addr.getCol(); // 12-bit + + uint8_t row0 = (row & 0x10000) >> 16; + uint8_t row1_8 = (row & 0x0ff00) >> 8; + uint8_t row9_16 = row & 0x000ff; + + uint8_t col0_3 = (col & 0xf00) >> 8; + uint8_t col4_11 = col & 0x0ff; + + uint8_t active = it->active ? 1 : 0; + + data[sz_actData ] = it->count; + data[sz_actData+1] = it->type << 4; // 4 spare bits + data[sz_actData+2] = (active << 6) | (it->dram & 0x3f); // 1 spare bit + data[sz_actData+3] = it->dramPins; + data[sz_actData+4] = (mrnk << 5) | (srnk << 2) | (svld << 1) | row0; + data[sz_actData+5] = row1_8; + data[sz_actData+6] = row9_16; + data[sz_actData+7] = (bnk << 4) | col0_3; + data[sz_actData+8] = col4_11; + + sz_actData += ENTRY_SIZE; + } + + if ( 0 != sz_actData ) + { + // Fix endianess issues with non PPC machines. + sz_actData = ((sz_actData + sz_word-1) / sz_word) * sz_word; + for ( uint32_t i = 0; i < (sz_actData/sz_word); i++ ) + ((CPU_WORD*)data)[i] = htonl(((CPU_WORD*)data)[i]); + + // Add data to capture data. + BIT_STRING_ADDRESS_CLASS bs ( 0, sz_actData*8, (CPU_WORD *) &data ); + io_cd.Add( i_mbaTrgt, Util::hashString("MEM_CE_TABLE"), bs ); + } +} + +} // end namespace PRDF + diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.H new file mode 100644 index 000000000..64b312ce9 --- /dev/null +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.H @@ -0,0 +1,167 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaCeTable.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* COPYRIGHT International Business Machines Corp. 2013 */ +/* */ +/* p1 */ +/* */ +/* Object Code Only (OCO) source materials */ +/* Licensed Internal Code Source Materials */ +/* IBM HostBoot Licensed Internal Code */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* Origin: 30 */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef __prdfCenMbaCeTable_H +#define __prdfCenMbaCeTable_H + +/** @file prdfCenMbaCeTable.H */ + +// Framwork includes +#include +#include +#include + +// Pegasus includes +#include +#include + +// Other includes +#include + +namespace PRDF +{ + +class CenMark; + +/** + * @brief A table of memory CEs. + * @note Only one of these tables will exist per MBA. + * @note Will be used to determine when to do a TPS procedure for Targeted + * Diagnostics at runtime. Will be used for FFDC only during Hostboot. + */ +class CenMbaCeTable +{ + + private: // constants, enums + + /** @brief Table size limits. */ + enum TableTHs + { + TPS_RANK_ENTRY_TH = 8, ///< Threshold of entries per rank that + ///< triggers a TPS procedure + TPS_ENTRY_COUNT_TH = 32, ///< Entry count threshold that triggers + ///< a TPS procedure + }; + + public: // functions + + /** + * @brief Will attempt to add a new entry to the table. + * + * If an entry already exists, the entry's count is incremented. Otherwise, + * a new entry is created. Will return TRUE if the CE triggers one of the + * following TPS conditions: + * - A single entry reaches count of TPS_ENTRY_COUNT_TH. + * - A rank has an entry count of TPS_RANK_ENTRY_TH. + * - The table is full. + * + * @param i_addr The address reporting the CE. + * @param i_symbol The symbol reporting the CE. + * @return TRUE if TPS is required, FALSE otherwise. + */ + bool addEntry( const CenAddr & i_addr, const CenSymbol & i_symbol ); + + /** + * @brief Deactivates all entries in the table. + */ + void deactivateAll(); + + /** + * @brief Deactivates all entries covered by a rank. + * @param i_rank The target rank. + */ + void deactivateRank( const CenRank & i_rank ); + + /** + * @brief Iterates the entire table and returns the number of unique entries + * that exist for the target DRAM, half-rank, logical DIMM. + * @param i_rank The failing rank. + * @param i_symbol The failing symbol. + * @param o_dramCount The entry count for the target dram. + * @param o_hrCount The entry count for the target half-rank (per rank + * per port select). + * @param o_dimmCount The entry count for the target logical DIMM. + */ + void getMnfgCounts( const CenRank & i_rank, const CenSymbol & i_symbol, + uint32_t & o_dramCount, uint32_t & o_hrCount, + uint32_t & o_dimmCount ); + + /** + * @brief Gathers all table data to be stored in capture data. + * @param i_mbaTrgt An MBA target. + * @param io_cd Capture data struct. + */ + void addCapData( TARGETING::TargetHandle_t i_mbaTrgt, CaptureData & io_cd ); + + private: // structs, typedefs + + /** @brief Individual entries of iv_table. */ + struct TableData + { + bool active; ///< TRUE if this entry is active + uint8_t count; ///< Number of times this entry is detected + CenAddr addr; ///< Physical address of this entry + uint8_t dram; ///< The DRAM in which the CE was detected + uint8_t dramPins; ///< The failing pins of the DRAM + uint8_t portSlct; ///< The port select of the DRAM + CenSymbol::WiringType type; ///< The wiring type + + /** @brief Default constructor. */ + TableData() : + active(false), count(0), addr(), dram(0), dramPins(0), portSlct(0), + type(CenSymbol::WIRING_INVALID) + {} + + /** + * @brief Constructor from components. + * @param i_addr The physical address of this entry. + * @param i_dram The DRAM in which the CE was detected + * @param i_dramPins The failing pins of the DRAM + * @param i_type The wiring type (for DRAM site locations). + */ + TableData( const CenAddr & i_addr, uint8_t i_dram, uint8_t i_dramPins, + uint8_t i_portSlct, CenSymbol::WiringType i_type ) : + active(true), count(1), addr(i_addr), dram(i_dram), + dramPins(i_dramPins), portSlct(i_portSlct), type(i_type) + {} + + /** An entry is equivalent if the address and DRAM match. */ + bool operator==( const TableData & i_data ) const + { + return ( this->addr == i_data.addr && this->dram == i_data.dram ); + } + }; + + typedef std::list CeTable; + + private: // instance variables + + /** A storage container for memory fetch CE errors. */ + CeTable iv_table; + +}; + +} // end namespace PRDF + +#endif // __prdfCenMbaCeTable_H + diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H index fc6eadafa..aa40507f1 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H @@ -37,6 +37,7 @@ // Pegasus includes #include #include +#include namespace PRDF { @@ -97,6 +98,7 @@ class CenMbaDataBundleCommon : public DataBundle CenMbaTdCtlr iv_tdCtlr; ///< Targeted Diagnostics Controller CenMbaUeTable iv_ueTable; ///< UE table for FFDC + CenMbaCeTable iv_ceTable; ///< CE table for FFDC }; diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaThresholds_common.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaThresholds_common.C index 58b664863..8975618f0 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaThresholds_common.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaThresholds_common.C @@ -72,13 +72,13 @@ int32_t getMnfgMemCeTh( ExtensibleChip * i_mbaChip, const CenRank & i_rank, break; } - // Get number of ranks DIMM select. + // Get number of ranks per DIMM select. uint8_t rankCount = getRanksPerDimm( i_mbaChip->GetChipHandle(), i_rank.getDimmSlct() ); if ( 0 == rankCount ) { PRDF_ERR( PRDF_FUNC "PlatServices::getRanksPerDimm() failed" ); - break; + o_rc = FAIL; break; } // Get number of allowed CEs. diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaUeTable.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaUeTable.C index 4c8217157..0f450d9de 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaUeTable.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaUeTable.C @@ -57,12 +57,12 @@ void CenMbaUeTable::addEntry( UE_TABLE::Type i_type, const CenAddr & i_addr ) iv_table.erase( it ); } - // Pop off the oldest entry if the table is full. - if ( MAX_ENTRIES == iv_table.size() ) - iv_table.pop_front(); - // Add the new entry to the end of the list. iv_table.push_back( data ); + + // Pop off the oldest entry if the table is full. + if ( MAX_ENTRIES < iv_table.size() ) + iv_table.pop_front(); } //------------------------------------------------------------------------------ diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMembuf.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMembuf.C index f0f0c9835..124a43af2 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMembuf.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMembuf.C @@ -41,7 +41,9 @@ #include #include #include +#include #include +#include #include using namespace TARGETING; @@ -510,6 +512,7 @@ int32_t AnalyzeFetchNce( ExtensibleChip * i_membChip, PRDF_ERR( PRDF_FUNC"getMbaChip() returned NULL" ); l_rc = FAIL; break; } + TargetHandle_t mbaTrgt = mbaChip->GetChipHandle(); CenAddr addr; l_rc = getCenReadAddr( i_membChip, i_mbaPos, READ_NCE_ADDR, addr ); @@ -518,15 +521,105 @@ int32_t AnalyzeFetchNce( ExtensibleChip * i_membChip, PRDF_ERR( PRDF_FUNC"getCenReadAddr() failed" ); break; } + CenRank rank = addr.getRank(); - // FIXME: RTC 47289 Need to read MBSEVR to get the symbol. There is a - // bug in DD1.x so we can't use this register. There is a - // workaround but is it complicated. Need to check with Ken if it - // is ok to just callout the rank for DD1.x. + if ( 0x20 > getChipLevel(i_membChip->GetChipHandle()) ) + { + // There is a bug in DD1.x where the value of MBSEVR cannot be + // trusted. The workaround is too complicated for its value so + // callout the rank instead. + MemoryMru memmru ( mbaTrgt, rank, MemoryMruData::CALLOUT_RANK ); + i_sc.service_data->SetCallout( memmru ); + } + else // DD2.0+ + { + // Get the failing symbol + const char * reg_str = (0 == i_mbaPos) ? "MBA0_MBSEVR" + : "MBA1_MBSEVR"; + SCAN_COMM_REGISTER_CLASS * reg = i_membChip->getRegister(reg_str); + l_rc = reg->Read(); + if ( SUCCESS != l_rc ) + { + PRDF_ERR( PRDF_FUNC"Read() failed on %s", reg_str ); + break; + } - MemoryMru memmru ( mbaChip->GetChipHandle(), addr.getRank(), - MemoryMruData::CALLOUT_RANK ); - i_sc.service_data->SetCallout( memmru ); + uint8_t galois = reg->GetBitFieldJustified( 40, 8 ); + uint8_t mask = reg->GetBitFieldJustified( 32, 8 ); + + CenSymbol symbol = CenSymbol::fromGalois( mbaTrgt, rank, galois, + mask ); + if ( !symbol.isValid() ) + { + PRDF_ERR( PRDF_FUNC"Failed to create symbol: galois=0x%02x " + "mask=0x%02x", galois, mask ); + break; + } + + // Add the DIMM to the callout list + MemoryMru memmru ( mbaTrgt, rank, symbol ); + i_sc.service_data->SetCallout( memmru ); + + // Add to CE table + CenMbaDataBundle * mbadb = getMbaDataBundle( mbaChip ); + bool doTps = mbadb->iv_ceTable.addEntry( addr, symbol ); + + if ( mfgMode() ) + { + // Get the MNFG CE thresholds. + uint16_t dramTh, hrTh, dimmTh; + l_rc = getMnfgMemCeTh( mbaChip, rank, dramTh, hrTh, dimmTh ); + if ( SUCCESS != l_rc ) + { + PRDF_ERR( PRDF_FUNC"getMnfgMemCeTh() failed: rank=m%ds%d", + rank.getMaster(), rank.getSlave() ); + break; + } + + // Get counts from CE table. + uint32_t dramCount, hrCount, dimmCount; + mbadb->iv_ceTable.getMnfgCounts( addr.getRank(), symbol, + dramCount, hrCount, + dimmCount ); + + if ( dramTh < dramCount ) + { + i_sc.service_data->SetErrorSig( PRDFSIG_MnfgDramCte ); + i_sc.service_data->AddSignatureList( mbaTrgt, + PRDFSIG_MnfgDramCte ); + i_sc.service_data->SetServiceCall(); + } + + if ( hrTh < hrCount ) + { + i_sc.service_data->SetErrorSig( PRDFSIG_MnfgHrCte ); + i_sc.service_data->AddSignatureList( mbaTrgt, + PRDFSIG_MnfgHrCte ); + i_sc.service_data->SetServiceCall(); + } + + if ( dimmTh < dimmCount ) + { + i_sc.service_data->SetErrorSig( PRDFSIG_MnfgDimmCte ); + i_sc.service_data->AddSignatureList( mbaTrgt, + PRDFSIG_MnfgDimmCte ); + i_sc.service_data->SetServiceCall(); + } + } + + // Initiate a TPS procedure, if needed. + if ( doTps ) + { + l_rc = mbadb->iv_tdCtlr.handleTdEvent( i_sc, rank, + CenMbaTdCtlrCommon::TPS_EVENT ); + if ( SUCCESS != l_rc ) + { + PRDF_ERR( PRDF_FUNC"handleTdEvent() failed: rank=m%ds%d", + rank.getMaster(), rank.getSlave() ); + break; + } + } + } } while (0); @@ -645,16 +738,27 @@ int32_t AnalyzeFetchUe( ExtensibleChip * i_membChip, PRDF_ERR( PRDF_FUNC"getCenReadAddr() failed" ); break; } + CenRank rank = addr.getRank(); // Add address to UE table. CenMbaDataBundle * mbadb = getMbaDataBundle( mbaChip ); mbadb->iv_ueTable.addEntry( UE_TABLE::FETCH_UE, addr ); // Callout the rank. - MemoryMru memmru ( mbaChip->GetChipHandle(), addr.getRank(), + MemoryMru memmru ( mbaChip->GetChipHandle(), rank, MemoryMruData::CALLOUT_RANK ); i_sc.service_data->SetCallout( memmru ); + // Add a TPS request to the TD queue. + l_rc = mbadb->iv_tdCtlr.handleTdEvent( i_sc, rank, + CenMbaTdCtlrCommon::TPS_EVENT ); + if ( SUCCESS != l_rc ) + { + PRDF_ERR( PRDF_FUNC"handleTdEvent() failed: rank=m%ds%d", + rank.getMaster(), rank.getSlave() ); + break; + } + } while (0); // Add ECC capture data for FFDC. diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMembufExtraSig.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMembufExtraSig.H new file mode 100644 index 000000000..fed2caeca --- /dev/null +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMembufExtraSig.H @@ -0,0 +1,33 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMembufExtraSig.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* COPYRIGHT International Business Machines Corp. 2013 */ +/* */ +/* p1 */ +/* */ +/* Object Code Only (OCO) source materials */ +/* Licensed Internal Code Source Materials */ +/* IBM HostBoot Licensed Internal Code */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* Origin: 30 */ +/* */ +/* IBM_PROLOG_END_TAG */ + +#ifndef __prdfCenMembufExtraSig_H +#define __prdfCenMembufExtraSig_H + +#include + +PRDR_ERROR_SIGNATURE(MnfgDramCte, 0x44440000, "", "MNFG per DRAM CTE"); +PRDR_ERROR_SIGNATURE(MnfgHrCte, 0x44440001, "", "MNFG per half-rank CTE"); +PRDR_ERROR_SIGNATURE(MnfgDimmCte, 0x44440002, "", "MNFG per DIMM CTE"); + +#endif // __prdfCenMembufExtraSig_H diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C index 04a4aea3d..dfffc0377 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C @@ -33,6 +33,19 @@ namespace PRDF using namespace PlatServices; +static const uint8_t symbol2Galois[] = +{ + 0x80, 0xa0, 0x90, 0xf0, 0x08, 0x0a, 0x09, 0x0f, // symbols 0- 7 + 0x98, 0xda, 0xb9, 0x7f, 0x91, 0xd7, 0xb2, 0x78, // symbols 8-15 + 0x28, 0xea, 0x49, 0x9f, 0x9a, 0xd4, 0xbd, 0x76, // symbols 16-23 + 0x60, 0xb0, 0xc0, 0x20, 0x06, 0x0b, 0x0c, 0x02, // symbols 24-31 + 0xc6, 0xfb, 0x1c, 0x42, 0xca, 0xf4, 0x1d, 0x46, // symbols 32-39 + 0xd6, 0x8b, 0x3c, 0xc2, 0xcb, 0xf3, 0x1f, 0x4e, // symbols 40-47 + 0xe0, 0x10, 0x50, 0xd0, 0x0e, 0x01, 0x05, 0x0d, // symbols 48-55 + 0x5e, 0x21, 0xa5, 0x3d, 0x5b, 0x23, 0xaf, 0x3e, // symbols 56-63 + 0xfe, 0x61, 0x75, 0x5d, 0x51, 0x27, 0xa2, 0x38, // symbols 64-71 +}; + //############################################################################## // class CenSymbol //############################################################################## @@ -48,7 +61,8 @@ CenSymbol CenSymbol::fromSymbol( TargetHandle_t i_mba, const CenRank & i_rank, { if ( TYPE_MBA != getTargetType(i_mba) ) { - PRDF_ERR( PRDF_FUNC"i_mba is invalid" ); + PRDF_ERR( PRDF_FUNC"i_mba is invalid: i_mba=0x%08x", + getHuid(i_mba) ); break; } @@ -124,9 +138,60 @@ CenSymbol CenSymbol::fromDimmDq( TargetHandle_t i_mba, const CenRank & i_rank, //------------------------------------------------------------------------------ -int32_t CenSymbol::getWiringType( TARGETING::TargetHandle_t i_mba, - const CenRank & i_rank, - WiringType & o_type ) +CenSymbol CenSymbol::fromGalois( TargetHandle_t i_mba, const CenRank & i_rank, + uint8_t i_galois, uint8_t i_mask ) +{ + #define PRDF_FUNC "[CenSymbol::fromGalois] " + + CenSymbol o_symbol; // default contructor is invalid. + + do + { + if ( TYPE_MBA != getTargetType(i_mba) ) + { + PRDF_ERR( PRDF_FUNC"i_mba=0x%08x is invalid", getHuid(i_mba) ); + break; + } + + WiringType wiringType = WIRING_INVALID; + int32_t l_rc = getWiringType( i_mba, i_rank, wiringType ); + if ( SUCCESS != l_rc ) + { + PRDF_ERR( PRDF_FUNC"getWiringType() failed" ); + break; + } + + // Get symbol from Galois field. + uint8_t symbol = SYMBOLS_PER_RANK; + for ( uint32_t i = 0; i < SYMBOLS_PER_RANK; i++ ) + { + if ( symbol2Galois[i] == i_galois ) + { + symbol = i; + break; + } + } + + // Get pins from mask. + uint8_t pins = NO_SYMBOL_DQS; + if ( 0 != (i_mask & 0xaa) ) pins |= EVEN_SYMBOL_DQ; + if ( 0 != (i_mask & 0x55) ) pins |= ODD_SYMBOL_DQ; + + // Create symbol object. + o_symbol = CenSymbol ( i_mba, i_rank, wiringType, symbol, pins, + isDramWidthX4(i_mba) ); + + } while (0); + + return o_symbol; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenSymbol::getWiringType( TargetHandle_t i_mba, const CenRank & i_rank, + WiringType & o_type ) { int32_t o_rc = SUCCESS; @@ -138,6 +203,15 @@ int32_t CenSymbol::getWiringType( TARGETING::TargetHandle_t i_mba, //------------------------------------------------------------------------------ +uint8_t CenSymbol::getDramPins() const +{ + uint32_t spd = iv_x4Dram ? SYMBOLS_PER_X4DRAM : SYMBOLS_PER_X8DRAM; + + return iv_pins << (((spd - 1) - (iv_symbol % spd)) * DQS_PER_SYMBOL); +} + +//------------------------------------------------------------------------------ + uint8_t CenSymbol::cenDq2Symbol( uint8_t i_cenDq, uint8_t i_ps ) { uint8_t sym = SYMBOLS_PER_RANK; diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H index e0d3e4659..d6f12864c 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H @@ -121,6 +121,19 @@ class CenSymbol const CenRank & i_rank, uint8_t i_dimmDq, uint8_t i_portSlct ); + /** + * @brief Creates a CenSymbol from a Galois field. + * @param i_mba The MBA target. + * @param i_rank The rank this symbol is on. + * @param i_galois The Galois field. + * @param i_mask The bit mask. + * @return A CenSymbol. Must call isValid() to determine if the function was + * successful in creating a valid object. + */ + static CenSymbol fromGalois( TARGETING::TargetHandle_t i_mba, + const CenRank & i_rank, uint8_t i_galois, + uint8_t i_mask = 0 ); + /** * @brief Returns the dimm's wiring type. * @param i_mba MBA Target handle. @@ -141,7 +154,7 @@ class CenSymbol /** @return This symbol's numerical value (0-71). */ uint8_t getSymbol() const { return iv_symbol; } - /** @return The bad pins associated with this symbol. */ + /** @return The bad pins associated with this symbol (2-bits). */ uint8_t getPins() const { return iv_pins; } /** @return The even Centaur DQ of this symbol. */ @@ -153,6 +166,10 @@ class CenSymbol /** @return The DRAM index for this symbol. */ uint8_t getDram() const { return symbol2Dram( iv_symbol, iv_x4Dram ); } + /** @return The bad pins associated with this symbol in relation to the DRAM + * (x4 mode is 4-bits, x8 mode is 8-bits,). */ + uint8_t getDramPins() const; + /** @return rank associated with this symbol. */ CenRank getRank() const { return iv_rank; }; diff --git a/src/usr/diag/prdf/common/plugins/prdfCenLogParse.C b/src/usr/diag/prdf/common/plugins/prdfCenLogParse.C index 21647ccea..7c02ceeac 100644 --- a/src/usr/diag/prdf/common/plugins/prdfCenLogParse.C +++ b/src/usr/diag/prdf/common/plugins/prdfCenLogParse.C @@ -218,6 +218,90 @@ bool parseMemUeTable( uint8_t * i_buffer, uint32_t i_buflen, //------------------------------------------------------------------------------ +bool parseMemCeTable( uint8_t * i_buffer, uint32_t i_buflen, + ErrlUsrParser & i_parser ) +{ + using namespace CE_TABLE; + + bool rc = true; + + if ( NULL == i_buffer ) return false; // Something failed in parser. + + const uint32_t entries = i_buflen / ENTRY_SIZE; + + i_parser.PrintNumber( " MEM_CE_TABLE", "%d", entries ); + + const char * hh = " A Count Type"; + const char * hd = "Rank Bank Row Column DRAM Pins"; + i_parser.PrintString( hh, hd ); + hh = " - ----- -------------"; + hd = "---- ---- ------- ------ ---- ----"; + i_parser.PrintString( hh, hd ); + + for ( uint32_t i = 0; i < entries; i++ ) + { + uint32_t idx = i * ENTRY_SIZE; + + uint32_t count = i_buffer[idx ]; // 8-bit + uint32_t type = i_buffer[idx+1] >> 4; // 4-bit + + uint8_t active = (i_buffer[idx+2] >> 6) & 0x1; // 1-bit + uint8_t dram = i_buffer[idx+2] & 0x3f; // 6-bit + + uint32_t dramPins = i_buffer[idx+3]; // 8-bit + + uint32_t mrnk = (i_buffer[idx+4] >> 5) & 0x7; // 3-bit + uint32_t srnk = (i_buffer[idx+4] >> 2) & 0x7; // 3-bit + uint32_t svld = (i_buffer[idx+4] >> 1) & 0x1; // 1-bit + + uint32_t row0 = i_buffer[idx+4] & 0x1; + uint32_t row1_8 = i_buffer[idx+5]; + uint32_t row9_16 = i_buffer[idx+6]; + uint32_t row = (row0 << 16) | (row1_8 << 8) | row9_16; // 17-bit + + uint32_t bnk = i_buffer[idx+7] >> 4; // 4-bit + + uint32_t col0_3 = i_buffer[idx+7] & 0xf; + uint32_t col4_11 = i_buffer[idx+8]; + uint32_t col = (col0_3 << 8) | col4_11; // 12-bit + + char active_char = ( 1 == active ) ? 'Y':'N'; + + const char * type_str = "UNKNOWN "; // 13 characters + switch ( type ) + { + // TODO: RTC 67358 card type will be determined from wiring type. + // Also there will be string representation for dram. + // Currently we will use integer number. + default: ; + } + + char rank_str[DATA_SIZE]; // 4 characters + if ( 1 == svld ) + { + snprintf( rank_str, DATA_SIZE, "m%ds%d", mrnk, srnk ); + } + else + { + snprintf( rank_str, DATA_SIZE, "m%d ", mrnk ); + } + + char header[HEADER_SIZE] = { '\0' }; + snprintf( header, HEADER_SIZE, " %c 0x%02x %s", active_char, + count, type_str ); + + char data[DATA_SIZE] = { '\0' }; + snprintf( data, DATA_SIZE, "%s 0x%01x 0x%05x 0x%03x %2d 0x%02x", + rank_str, bnk, row, col, dram, dramPins ); + + i_parser.PrintString( header, data ); + } + + return rc; +} + +//------------------------------------------------------------------------------ + bool parseDramRepairsData( uint8_t * i_buffer, uint32_t i_buflen, ErrlUsrParser & i_parser ) { diff --git a/src/usr/diag/prdf/common/plugins/prdfCenLogParse.H b/src/usr/diag/prdf/common/plugins/prdfCenLogParse.H index c2695b10d..8a7c49391 100644 --- a/src/usr/diag/prdf/common/plugins/prdfCenLogParse.H +++ b/src/usr/diag/prdf/common/plugins/prdfCenLogParse.H @@ -61,6 +61,15 @@ bool parseMemMruData( ErrlUsrParser & i_parser, uint32_t i_memMru ); bool parseMemUeTable( uint8_t * i_buffer, uint32_t i_buflen, ErrlUsrParser & i_parser ); +/** + * @brief Parses Memory CE table. + * @param i_buffer The data buffer. + * @param i_buflen The buffer length. + * @param i_parser The error log parser. + */ +bool parseMemCeTable( uint8_t * i_buffer, uint32_t i_buflen, + ErrlUsrParser & i_parser ); + /** * @brief Parses DRAM Repairs data (actual chip/symbol marks and DRAM repairs in * hardware). diff --git a/src/usr/diag/prdf/common/plugins/prdfLogParse_common.C b/src/usr/diag/prdf/common/plugins/prdfLogParse_common.C index 3a39eb90b..71c693cb7 100644 --- a/src/usr/diag/prdf/common/plugins/prdfLogParse_common.C +++ b/src/usr/diag/prdf/common/plugins/prdfLogParse_common.C @@ -317,6 +317,10 @@ bool parseCaptureData( void * i_buffer, uint32_t i_buflen, { parseMemUeTable( sigData, sigDataSize, i_parser ); } + else if ( Util::hashString("MEM_CE_TABLE") == sigId ) + { + parseMemCeTable( sigData, sigDataSize, i_parser ); + } else if ( Util::hashString("DRAM_REPAIRS_DATA") == sigId ) { parseDramRepairsData( sigData, sigDataSize, i_parser ); diff --git a/src/usr/diag/prdf/common/plugins/prdfParserEnums.H b/src/usr/diag/prdf/common/plugins/prdfParserEnums.H index d720639f8..4d40e287b 100644 --- a/src/usr/diag/prdf/common/plugins/prdfParserEnums.H +++ b/src/usr/diag/prdf/common/plugins/prdfParserEnums.H @@ -70,6 +70,18 @@ namespace UE_TABLE } // namespace UE_TABLE +namespace CE_TABLE +{ + enum + { + MAX_ENTRIES = 32, ///< Maximum number of entries allow in table. + ENTRY_SIZE = 9, ///< Number of bytes per entry. + + MAX_SIZE = MAX_ENTRIES * ENTRY_SIZE, ///< Maximum table size. + }; + +} // namespace UE_TABLE + namespace DQ_BITMAP { enum diff --git a/src/usr/diag/prdf/common/prd_pegasus.mk b/src/usr/diag/prdf/common/prd_pegasus.mk index 9843751be..5d7577c59 100755 --- a/src/usr/diag/prdf/common/prd_pegasus.mk +++ b/src/usr/diag/prdf/common/prd_pegasus.mk @@ -44,6 +44,7 @@ prd_pegasus_specific = \ prdfCenAddress.o \ prdfCenDqBitmap.o \ prdfCenMbaCaptureData.o \ + prdfCenMbaCeTable.o \ prdfCenMbaTdCtlr.o \ prdfCenMbaTdCtlr_common.o \ prdfCenMbaThresholds_common.o \ -- cgit v1.2.1