From 25a05966a93786736212b4f35aa84929423a48e4 Mon Sep 17 00:00:00 2001 From: Zane Shelley Date: Sat, 27 Apr 2013 22:12:56 -0500 Subject: PRD: TD controller for MDIA Change-Id: I6453a1fef37cbd7f9d3c105af8349688ad62c0c2 RTC: 22866 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/4248 Tested-by: Jenkins Server Reviewed-by: A. Patrick Williams III Reviewed-by: Zane Shelley Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/4935 --- src/usr/diag/mdia/mdiasm.C | 8 +- src/usr/diag/prdf/common/framework/rule/prdrpp | 6 +- .../framework/service/prdfPlatServices_common.C | 84 +- .../framework/service/prdfPlatServices_common.H | 37 +- src/usr/diag/prdf/common/plat/pegasus/Mba.rule | 24 +- .../prdf/common/plat/pegasus/Membuf_regs_NEST.rule | 32 + .../prdf/common/plat/pegasus/prdfCalloutUtil.C | 20 + .../prdf/common/plat/pegasus/prdfCalloutUtil.H | 20 +- .../diag/prdf/common/plat/pegasus/prdfCenConst.H | 6 + .../prdf/common/plat/pegasus/prdfCenDqBitmap.C | 36 + .../prdf/common/plat/pegasus/prdfCenDqBitmap.H | 8 + src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C | 76 +- .../plat/pegasus/prdfCenMbaDataBundle_common.H | 11 +- .../prdf/common/plat/pegasus/prdfCenMbaExtraSig.H | 48 + .../common/plat/pegasus/prdfCenMbaTdCtlr_common.C | 104 ++ .../common/plat/pegasus/prdfCenMbaTdCtlr_common.H | 212 ++++ .../diag/prdf/common/plat/pegasus/prdfCenSymbol.C | 40 +- .../diag/prdf/common/plat/pegasus/prdfCenSymbol.H | 15 +- .../diag/prdf/common/plat/pegasus/prdfMemoryMru.C | 3 +- .../diag/prdf/common/plat/pegasus/prdfMemoryMru.H | 3 + src/usr/diag/prdf/common/prd_pegasus.mk | 10 +- .../diag/prdf/framework/service/prdfPlatServices.C | 36 +- .../diag/prdf/framework/service/prdfPlatServices.H | 12 + .../diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H | 6 +- src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C | 1342 ++++++++++++++++++++ src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H | 174 +++ src/usr/diag/prdf/test/prdfTest_Mba.H | 22 +- 27 files changed, 2252 insertions(+), 143 deletions(-) create mode 100644 src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H create mode 100644 src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C create mode 100644 src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H create mode 100644 src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C create mode 100644 src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H diff --git a/src/usr/diag/mdia/mdiasm.C b/src/usr/diag/mdia/mdiasm.C index 512a20265..893fffcda 100644 --- a/src/usr/diag/mdia/mdiasm.C +++ b/src/usr/diag/mdia/mdiasm.C @@ -585,8 +585,12 @@ errlHndl_t StateMachine::doMaintCommand(WorkFlowProperties & i_wfp) uint64_t timeout = 60000000000; errlHndl_t err = NULL; - uint64_t stopCondition = mss_MaintCmd::STOP_ON_END_ADDRESS - | mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION; + uint64_t stopCondition = + mss_MaintCmd::STOP_END_OF_RANK | + mss_MaintCmd::STOP_ON_MPE | + mss_MaintCmd::STOP_ON_UE | + mss_MaintCmd::STOP_ON_END_ADDRESS | + mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION; uint64_t workItem; bool restart; diff --git a/src/usr/diag/prdf/common/framework/rule/prdrpp b/src/usr/diag/prdf/common/framework/rule/prdrpp index 058e5f4b5..fab66e381 100755 --- a/src/usr/diag/prdf/common/framework/rule/prdrpp +++ b/src/usr/diag/prdf/common/framework/rule/prdrpp @@ -50,11 +50,15 @@ sub read_file open_file($include); print ".end_included\n"; } + elsif ( $line =~ m{/\*[^\*].*\*/} ) + { + # Skip C-style (/* */) comments. This is needed to avoid prologs + # added to the extra signature .H files. + } else { print $line; } - } } diff --git a/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C b/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C index 20a4cdea8..0d77d3aaa 100755 --- a/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C +++ b/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.C @@ -59,6 +59,14 @@ namespace PRDF namespace PlatServices { +//############################################################################## +//## Forward references +//############################################################################## + +int32_t getMemAddrRange( TargetHandle_t i_mba, uint8_t i_rank, + ecmdDataBufferBase & o_startAddr, + ecmdDataBufferBase & o_endAddr ); + //############################################################################## //## Utility Functions (for this file only) //############################################################################## @@ -289,22 +297,25 @@ int32_t setBadDqBitmap( TargetHandle_t i_mba, const CenRank & i_rank, int32_t o_rc = SUCCESS; - const uint8_t (&data)[PORT_SLCT_PER_MBA][DIMM_DQ_RANK_BITMAP_SIZE] + if ( !areDramRepairsDisabled() ) + { + const uint8_t (&data)[PORT_SLCT_PER_MBA][DIMM_DQ_RANK_BITMAP_SIZE] = i_bitmap.getData(); - for ( int32_t ps = 0; ps < PORT_SLCT_PER_MBA; ps++ ) - { - errlHndl_t errl = NULL; - PRD_FAPI_TO_ERRL( errl, dimmSetBadDqBitmap, getFapiTarget(i_mba), - ps, i_rank.getDimmSlct(), i_rank.getRankSlct(), - data[ps] ); - if ( NULL != errl ) + for ( int32_t ps = 0; ps < PORT_SLCT_PER_MBA; ps++ ) { - PRDF_ERR( PRDF_FUNC"dimmSetBadDqBitmap() failed: MBA=0x%08x " - "ps=%d ds=%d rs=%d", getHuid(i_mba), ps, - i_rank.getDimmSlct(), i_rank.getRankSlct() ); - PRDF_COMMIT_ERRL( errl, ERRL_ACTION_REPORT ); - o_rc = FAIL; + errlHndl_t errl = NULL; + PRD_FAPI_TO_ERRL( errl, dimmSetBadDqBitmap, getFapiTarget(i_mba), + ps, i_rank.getDimmSlct(), i_rank.getRankSlct(), + data[ps] ); + if ( NULL != errl ) + { + PRDF_ERR( PRDF_FUNC"dimmSetBadDqBitmap() failed: MBA=0x%08x " + "ps=%d ds=%d rs=%d", getHuid(i_mba), ps, + i_rank.getDimmSlct(), i_rank.getRankSlct() ); + PRDF_COMMIT_ERRL( errl, ERRL_ACTION_REPORT ); + o_rc = FAIL; + } } } @@ -445,6 +456,48 @@ int32_t mssSetSteerMux( TargetHandle_t i_mba, const CenRank & i_rank, //------------------------------------------------------------------------------ +int32_t getMemAddrRange( TargetHandle_t i_mba, CenAddr & o_startAddr, + CenAddr & o_endAddr ) +{ + ecmdDataBufferBase startAddr(64), endAddr(64); + int32_t o_rc = getMemAddrRange( i_mba, MSS_ALL_RANKS, startAddr, endAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( "[PlatServices::getMemAddrRange] failed: i_mba=0x%08x", + getHuid(i_mba) ); + } + else + { + o_startAddr = CenAddr::fromMaintStartAddr( startAddr.getDoubleWord(0) ); + o_endAddr = CenAddr::fromMaintEndAddr( endAddr.getDoubleWord(0) ); + } + + return o_rc; +} + +//------------------------------------------------------------------------------ + +int32_t getMemAddrRange( TargetHandle_t i_mba, const CenRank & i_rank, + CenAddr & o_startAddr, CenAddr & o_endAddr ) +{ + ecmdDataBufferBase startAddr(64), endAddr(64); + int32_t o_rc = getMemAddrRange(i_mba, i_rank.flatten(), startAddr, endAddr); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( "[PlatServices::getMemAddrRange] failed: i_mba=0x%08x " + "i_rank=%d", getHuid(i_mba), i_rank.flatten() ); + } + else + { + o_startAddr = CenAddr::fromMaintStartAddr( startAddr.getDoubleWord(0) ); + o_endAddr = CenAddr::fromMaintEndAddr( endAddr.getDoubleWord(0) ); + } + + return o_rc; +} + +//------------------------------------------------------------------------------ + /* TODO - Get the memory buffer raw card type (i.e. R/C A). This is needed for the DRAM site locations for buffered DIMMs. Should be able to get this from an attribute but doesn't look like this is available yet. @@ -673,8 +726,9 @@ mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType, //------------------------------------------------------------------------------ mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType, - TargetHandle_t i_mba, uint32_t i_stopCond, - bool i_isFastSpeed, const CenRank & i_rank ) + TargetHandle_t i_mba, + const CenRank & i_rank, uint32_t i_stopCond, + bool i_isFastSpeed ) { mss_MaintCmdWrapper * o_cmd = NULL; diff --git a/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H b/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H index 24d975b38..51fb8c1b9 100755 --- a/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H +++ b/src/usr/diag/prdf/common/framework/service/prdfPlatServices_common.H @@ -55,6 +55,7 @@ namespace PRDF { +class CenAddr; class CenDqBitmap; class CenMark; class CenRank; @@ -208,6 +209,7 @@ int32_t getBadDqBitmap( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank, * @param i_mbaTarget A MBA target. * @param i_rank Target rank. * @param i_bitmap DQ bitmap container. + * @note This is a no-op if DRAM Repairs are disabled in manufacturing. * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. */ int32_t setBadDqBitmap( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank, @@ -270,6 +272,28 @@ int32_t mssGetSteerMux( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank, int32_t mssSetSteerMux( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank, const CenSymbol & i_symbol, bool i_x4EccSpare ); +/** + * @brief Returns the start and end maintenance address of the given MBA. + * @param i_mba Target MBA. + * @param o_startAddr The return start address. + * @param o_endAddr The return end address. + * @return Non-SUCCESS in internal function fails, SUCCESS otherwise. + */ +int32_t getMemAddrRange( TARGETING::TargetHandle_t i_mba, CenAddr & o_startAddr, + CenAddr & o_endAddr ); + +/** + * @brief Returns the start and end maintenance address of the given rank. + * @param i_mba Target MBA. + * @param i_rank Target rank. + * @param o_startAddr The return start address. + * @param o_endAddr The return end address. + * @return Non-SUCCESS in internal function fails, SUCCESS otherwise. + */ +int32_t getMemAddrRange( TARGETING::TargetHandle_t i_mba, + const CenRank & i_rank, CenAddr & o_startAddr, + CenAddr & o_endAddr ); + /** * @brief Returns the memory buffer raw card type (i.e. R/C A). * @param i_memTarget A memory buffer, MBA, or DIMM. @@ -362,7 +386,7 @@ class mss_MaintCmdWrapper * @param i_cmdType Maintenance command type which we want to create. * @param i_mba An MBA target. * @param i_stopCond Bit mask for conditions in which to stop command. - * @param i_isFastSpeed false = slow (12 H), true = fast. + * @param i_isFastSpeed false = slow (12 H), true = fast (default). * @return A mss_MaintCmdWrapper object, NULL if an internal function failed. * @note This function allocates memory on heap for mss_MaintCmdWrapper * object. It is the caller's responsibilty to delete this object. @@ -370,16 +394,17 @@ class mss_MaintCmdWrapper */ mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType, TARGETING::TargetHandle_t i_mba, - uint32_t i_stopCond, bool i_isFastSpeed ); + uint32_t i_stopCond, + bool i_isFastSpeed = true ); /** * @brief Create a maintenance command object that will run on all memory * behind the given rank. * @param i_cmdType Maintenance command type which we want to create. + * @param i_rank The target rank. * @param i_mba An MBA target. * @param i_stopCond Bit mask for conditions in which to stop command. - * @param i_isFastSpeed false = slow (12 H), true = fast. - * @param i_rank The target rank. + * @param i_isFastSpeed false = slow (12 H), true = fast (default). * @return A mss_MaintCmdWrapper object, NULL if an internal function failed. * @note This function allocates memory on heap for mss_MaintCmdWrapper * object. It is the caller's responsibilty to delete this object. @@ -387,8 +412,8 @@ mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType, */ mss_MaintCmdWrapper * createMssCmd( mss_MaintCmdWrapper::CmdType i_cmdType, TARGETING::TargetHandle_t i_mba, - uint32_t i_stopCond, bool i_isFastSpeed, - const CenRank & i_rank ); + const CenRank & i_rank, uint32_t i_stopCond, + bool i_isFastSpeed = true ); } // end namespace PlatServices diff --git a/src/usr/diag/prdf/common/plat/pegasus/Mba.rule b/src/usr/diag/prdf/common/plat/pegasus/Mba.rule index d09d63997..438f483be 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/Mba.rule +++ b/src/usr/diag/prdf/common/plat/pegasus/Mba.rule @@ -44,6 +44,8 @@ chip Mba dump DUMP_CONTENT_HWSUPERNOVA; scomlen 64; +.include "prdfCenMbaExtraSig.H"; + ############################################################################# # # # ###### # @@ -120,6 +122,13 @@ chip Mba capture group FirRegs; }; + register MBADDRPHYFIR_AND + { + name "DPHY01.PHY01_DDRPHY_FIR_REG_AND"; + scomaddr 0x800200910301143F; + capture group never; + }; + register MBADDRPHYFIR_MASK { name "DPHY01.PHY01_DDRPHY_FIR_MASK_REG"; @@ -190,11 +199,17 @@ chip Mba name "MBU.MBA01.MBA_MCBIST.SCOMFIR.MBSPAQ"; scomaddr 0x03010611; reset (&, 0x03010612); - #FIXME : There is no OR register for mask. Is it right to use mask register value mask (|, 0x03010614); capture group FirRegs; }; + register MBASPA_AND + { + name "MBU.MBA01.MBA_MCBIST.SCOMFIR.MBSPAQ_AND"; + scomaddr 0x03010612; + capture group never; + }; + register MBASPA_MASK { name "MBU.MBA01.MBA_MCBIST.SCOMFIR.MBSPAMSKQ"; @@ -221,7 +236,6 @@ chip Mba capture group CerrRegs; }; - register DDRPHY_APB_FIR_ERR0_P0 { name "DPHY01.DDRPHY_APB_FIR_ERR0_P0"; @@ -796,5 +810,9 @@ group gMbaSpa attntype SPECIAL filter singlebit ################################################################################ /** Analyze maintenance command complete */ -actionclass analyzeMaintCmdComplete { funccall("MaintCmdComplete"); }; +actionclass analyzeMaintCmdComplete +{ + funccall("MaintCmdComplete"); # Must be called last so return code can be + # passed on to rule code. +}; 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 668f49be3..7bf027415 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 @@ -228,6 +228,13 @@ capture group FirRegs; }; + register MBSECC01FIR_AND + { + name "MBU.MBS.ECC01.MBECCFIR_AND"; + scomaddr 0x02011441; + capture group never; + }; + register MBSECC01FIR_MASK { name "MBU.MBS.ECC01.MBECCFIR_MASK"; @@ -269,6 +276,13 @@ capture group FirRegs; }; + register MBSECC23FIR_AND + { + name "MBU.MBS.ECC23.MBECCFIR_AND"; + scomaddr 0x02011481; + capture group never; + }; + register MBSECC23FIR_MASK { name "MBU.MBS.ECC23.MBECCFIR_MASK"; @@ -599,3 +613,21 @@ capture group default; }; + ############################################################################ + # NEST Chiplet memory scrub/read threshold register + ############################################################################ + + register MBSTR_0 + { + name "MBU.MBS.MCBISTS01.SCOMFIR.MBSTRQ"; + scomaddr 0x02011655; + capture group default; + }; + + register MBSTR_1 + { + name "MBU.MBS.MCBISTS23.SCOMFIR.MBSTRQ"; + scomaddr 0x02011755; + capture group default; + }; + diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C index 39917a826..a7ca03cb7 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.C @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -49,6 +50,25 @@ void defaultError( STEP_CODE_DATA_STRUCT & i_sc ) //------------------------------------------------------------------------------ +void calloutMark( TargetHandle_t i_mba, const CenRank & i_rank, + const CenMark & i_mark, STEP_CODE_DATA_STRUCT & io_sc, + PRDpriority i_priority ) +{ + if ( i_mark.getCM().isValid() ) + { + MemoryMru memmru ( i_mba, i_rank, i_mark.getCM() ); + io_sc.service_data->SetCallout( memmru, i_priority ); + } + + if ( i_mark.getSM().isValid() ) + { + MemoryMru memmru ( i_mba, i_rank, i_mark.getSM() ); + io_sc.service_data->SetCallout( memmru, i_priority ); + } +} + +//------------------------------------------------------------------------------ + TargetHandleList getConnectedDimms( TargetHandle_t i_mba, const CenRank & i_rank ) { diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H index ff4f97baf..0bf1a6863 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCalloutUtil.H @@ -24,15 +24,18 @@ #ifndef prdfCalloutUtil_H #define prdfCalloutUtil_H -#include - /** @file prdfCalloutUtil.H * @brief Utility functions for common, non-trivial callouts. */ +#include + +#include + namespace PRDF { +class CenMark; class CenRank; struct STEP_CODE_DATA_STRUCT; @@ -47,6 +50,19 @@ namespace CalloutUtil */ void defaultError( STEP_CODE_DATA_STRUCT & i_sc ); +/** + * @brief Will add a MemoryMru to the callout list for the chip mark and symbol + * mark, if they exist. + * @param i_mba Target MBA. + * @param i_rank Target rank. + * @param i_mark Target mark. + * @param io_sc The step code data struct. + * @param i_priority Callout priority (default MRU_MED). + */ +void calloutMark( TARGETING::TargetHandle_t i_mba, const CenRank & i_rank, + const CenMark & i_mark, STEP_CODE_DATA_STRUCT & io_sc, + PRDpriority i_priority = MRU_MED ); + /** * @param i_mba The target MBA. * @param i_rank The target rank. diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H index 8d31d928b..4360da5b2 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenConst.H @@ -48,6 +48,12 @@ enum SYMBOLS_PER_BYTE = 4, DQS_PER_SYMBOL = 2, DQS_PER_BYTE = SYMBOLS_PER_BYTE * DQS_PER_SYMBOL, + + SYMBOLS_PER_X8DRAM = 4, + SYMBOLS_PER_X4DRAM = 2, + + X8DRAMS_PER_RANK = SYMBOLS_PER_RANK / SYMBOLS_PER_X8DRAM, + X4DRAMS_PER_RANK = SYMBOLS_PER_RANK / SYMBOLS_PER_X4DRAM, }; } // end namespace PRDF diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C index 8b0e920d8..48ea97c00 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.C @@ -228,6 +228,42 @@ int32_t CenDqBitmap::setEccSpare( uint8_t i_pins ) //------------------------------------------------------------------------------ +int32_t CenDqBitmap::isDramSpareAvailable( uint8_t i_portSlct, + bool & o_available ) +{ + #define PRDF_FUNC "[CenDqBitmap::isDramSpareAvailable] " + + int32_t o_rc = SUCCESS; + + o_available = false; + + do + { + if ( PORT_SLCT_PER_MBA <= i_portSlct ) + { + PRDF_ERR( PRDF_FUNC"Invalid parameter: i_portSlct=%d", i_portSlct ); + o_rc = FAIL; break; + } + + if ( isDramWidthX4(iv_mba) ) + { + // TODO: RTC 68096 Need to add x4 ECC support. + } + else + { + o_available = + ( 0 == iv_data[i_portSlct][DIMM_DQ_RANK_BITMAP_SIZE-1] ); + } + + } while (0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + void CenDqBitmap::getCaptureData( CaptureData & o_cd ) const { uint8_t rank = iv_rank.flatten(); diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H index 834c3bb01..4762caecd 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenDqBitmap.H @@ -113,6 +113,14 @@ class CenDqBitmap */ int32_t setEccSpare( uint8_t i_pins ); + /** + * @brief Queries for DRAM spare status. + * @param i_portSlct The target port. + * @param o_available TRUE if the spare is available, FALSE if it is used. + * @return Non-SUCCESS if an internal function failed, SUCCESS otherwise. + */ + int32_t isDramSpareAvailable( uint8_t i_portSlct, bool & o_available ); + /** * @brief Adds the bitmaps for both ports to the capture data. * @param o_cd Capture data struct. diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C index 0d03876ab..c73efc43f 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMba.C @@ -22,19 +22,22 @@ /* IBM_PROLOG_END_TAG */ /** @file prdfCenMba.C - * @brief Contains all the plugin code for the PRD Centaur MBA + * @brief Contains all common plugin code for the Centaur MBA */ +// Framework includes #include -#include #include #include #include -#include +// Pegasus includes +#include #include #include +using namespace TARGETING; + namespace PRDF { @@ -78,71 +81,32 @@ int32_t MaintCmdComplete( ExtensibleChip * i_mbaChip, { #define PRDF_FUNC "[Mba::MaintCmdComplete] " - using namespace TARGETING; - int32_t l_rc = SUCCESS; - TargetHandle_t mbaTarget = i_mbaChip->GetChipHandle(); - - do - { - #ifdef __HOSTBOOT_MODULE - - if ( isInMdiaMode() ) - { - // Immediately inform mdia that the command - // has finished. - - l_rc = mdiaSendEventMsg( mbaTarget, MDIA::RESET_TIMER ); - - if(l_rc) - { - PRDF_ERR( PRDF_FUNC"PlatServices::mdiaSendEventMsg() failed" ); - // keep going - } - - // Determine for mdia whether or not the command - // finished at the end of the last rank or if - // the command will need to be restarted. - // Tuck this away until PostAnalysis. - - CenAddr startAddr, endAddr; - l_rc = getCenMaintStartAddr( i_mbaChip, startAddr ); - l_rc |= getCenMaintEndAddr( i_mbaChip, endAddr ); - if ( SUCCESS != l_rc ) - { - PRDF_ERR( PRDF_FUNC"cenGetMbaAddr() failed" ); - break; - } - - CenMbaDataBundle * mbadb = getMbaDataBundle( i_mbaChip ); - mbadb->iv_sendCmdCompleteMsg = true; - mbadb->iv_cmdCompleteMsgData = - startAddr == endAddr ? MDIA::COMMAND_COMPLETE - : MDIA::COMMAND_STOPPED; - - // Do not commit error log for a successful command complete. - if ( MDIA::COMMAND_COMPLETE == mbadb->iv_cmdCompleteMsgData ) - i_sc.service_data->DontCommitErrorLog(); - } - - #endif // __HOSTBOOT_MODULE - - // Get DRAM repairs capture data - CenMbaCaptureData::addDramRepairsData( mbaTarget, i_sc ); - } while (0); + TargetHandle_t mbaTarget = i_mbaChip->GetChipHandle(); + CenMbaDataBundle * mbadb = getMbaDataBundle( i_mbaChip ); + // Tell the TD controller that a maintenance command complete occurred. + l_rc = mbadb->iv_tdCtlr.handleCmdCompleteEvent( i_sc ); if ( SUCCESS != l_rc ) { - PRDF_ERR( PRDF_FUNC"failed on MBA 0x%08x", getHuid(mbaTarget) ); + PRDF_ERR( PRDF_FUNC"Failed: i_mbaChip=0x%08x", getHuid(mbaTarget) ); CalloutUtil::defaultError( i_sc ); } - return l_rc; + // Gather capture data even if something failed above. + // NOTE: There is no need to capture if the maintenance command complete was + // successful with no errors because the error log will not be + // committed. + if ( !i_sc.service_data->IsDontCommitErrl() ) + CenMbaCaptureData::addDramRepairsData( mbaTarget, i_sc ); + + return PRD_NO_CLEAR_FIR_BITS; // FIR bits are cleared by this plugin #undef PRDF_FUNC } PRDF_PLUGIN_DEFINE( Mba, MaintCmdComplete ); } // end namespace Mba + } // end namespace PRDF 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 a239ad48d..fe2eb5c4c 100644 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaDataBundle_common.H @@ -28,11 +28,15 @@ * @brief Contains the common data bundle for a Centaur MBA object. */ +// Framework includes #include #include #include #include +// Pegasus includes +#include + namespace PRDF { @@ -48,7 +52,7 @@ class CenMbaDataBundleCommon : public DataBundle * @param i_mbaChip The MBA chip. */ explicit CenMbaDataBundleCommon( ExtensibleChip * i_mbaChip ) : - iv_mbaChip(i_mbaChip), iv_membChip(NULL) + iv_mbaChip(i_mbaChip), iv_membChip(NULL), iv_tdCtlr(i_mbaChip) {} /** @@ -83,6 +87,11 @@ class CenMbaDataBundleCommon : public DataBundle ExtensibleChip * iv_mbaChip; ///< This MBA chip ExtensibleChip * iv_membChip; ///< The connected MEMBUF chip + + public: // instance variables + + CenMbaTdCtlr iv_tdCtlr; ///< Targeted Diagnostics Controller + }; } // end namespace PRDF diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H new file mode 100644 index 000000000..3fa49f259 --- /dev/null +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.H @@ -0,0 +1,48 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaExtraSig.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 __prdfCenMbaExtraSig_H +#define __prdfCenMbaExtraSig_H + +#include + +PRDR_ERROR_SIGNATURE(MaintCmdComplete_ERROR, 0xeeee0000, "", + "ERROR: maint cmd complete analysis failed" ); + +PRDR_ERROR_SIGNATURE(StartVcmPhase1, 0xffff0000, "", "Starting VCM phase 1"); +PRDR_ERROR_SIGNATURE(StartVcmPhase2, 0xffff0001, "", "Starting VCM phase 2"); +PRDR_ERROR_SIGNATURE(StartDsdPhase1, 0xffff0002, "", "Starting DSD phase 1"); +PRDR_ERROR_SIGNATURE(StartDsdPhase2, 0xffff0003, "", "Starting DSD phase 2"); + +PRDR_ERROR_SIGNATURE(MaintUE, 0xffff0010, "", "Maintenance UE"); + +PRDR_ERROR_SIGNATURE(VcmVerified, 0xffff0020, "", "VCM: verified"); +PRDR_ERROR_SIGNATURE(VcmFalseAlarm, 0xffff0021, "", "VCM: false alarm"); +PRDR_ERROR_SIGNATURE(VcmBadSpare, 0xffff0022, "", "VCM: bad DRAM spare"); +PRDR_ERROR_SIGNATURE(VcmMarksUnavail, 0xffff0023, "", + "VCM: No more marks available"); + +PRDR_ERROR_SIGNATURE(DsdDramSpared, 0xffff0030, "", "DSD: DRAM spared"); +PRDR_ERROR_SIGNATURE(DsdBadSpare, 0xffff0031, "", "DSD: DRAM spare is bad"); + +#endif // __prdfCenMbaExtraSig_H diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C new file mode 100644 index 000000000..1e7a0ed7c --- /dev/null +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.C @@ -0,0 +1,104 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.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 + +using namespace TARGETING; + +namespace PRDF +{ + +using namespace PlatServices; + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlrCommon::cleanupPrevCmd() +{ + #define PRDF_FUNC "[CenMbaTdCtlrCommon::cleanupPrevCmd] " + + int32_t o_rc = SUCCESS; + + // Clean up the current maintenance command. This must be done whenever + // maintenance command will no longer be executed. + if ( NULL != iv_mssCmd ) + { + o_rc = iv_mssCmd->cleanupCmd(); + if ( SUCCESS != o_rc ) + PRDF_ERR( PRDF_FUNC"cleanupCmd() failed" ); + + delete iv_mssCmd; iv_mssCmd = NULL; + } + + // Clear the command complete attention. This must be done before starting + // the next maintenance command. + SCAN_COMM_REGISTER_CLASS * firand = iv_mbaChip->getRegister("MBASPA_AND"); + firand->setAllBits(); + + firand->ClearBit(0); // Maintenance command complete + firand->ClearBit(8); // Maintenance command complete (DD1.0 workaround) + + int32_t l_rc = firand->Write(); + if ( SUCCESS != l_rc ) + { + PRDF_ERR( PRDF_FUNC"Write() failed on MBASPA_AND" ); + o_rc = FAIL; + } + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlrCommon::chipMarkCleanup() +{ + #define PRDF_FUNC "[CenMbaTdCtlrCommon::chipMarkCleanup] " + + int32_t o_rc = SUCCESS; + + do + { + SCAN_COMM_REGISTER_CLASS * ddrPhyAndFir = + iv_mbaChip->getRegister( "MBADDRPHYFIR_AND" ); + ddrPhyAndFir->setAllBits(); + + ddrPhyAndFir->ClearBit(50); // Calibration Error RE 0 + ddrPhyAndFir->ClearBit(58); // Calibration Error RE 1 + + o_rc = ddrPhyAndFir->Write(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"Write() failed on MBADDRPHYFIR_AND" ); + break; + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +} // end namespace PRDF + diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H new file mode 100644 index 000000000..5107dc7f5 --- /dev/null +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.H @@ -0,0 +1,212 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/common/plat/pegasus/prdfCenMbaTdCtlr_common.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 */ + +/** @file prdfCenMbaTdCtlr_common.H + * @brief The common implementation of the MBA TD Controller. + */ + +#ifndef __prdfCenMbaTdCtlr_common_H +#define __prdfCenMbaTdCtlr_common_H + +// Framework includes +#include +#include +#include + +// Pegasus includes +#include +#include +#include +#include + +namespace PRDF +{ + +class ExtensibleChip; + +/** + * @brief A state machine for memory targeted diagnostics. + */ +class CenMbaTdCtlrCommon +{ + public: // functions + + /** + * @brief Constructor + * + * This constructor will be called in the MBA data bundle code. Therefore, + * no register reads/writes can be done in this constructor. Anything needed + * to initialize the instance variables that requires register reads/writes + * or is non-trivial should be done in initialize(). + * + * @param i_mbaChip An MBA chip. + */ + explicit CenMbaTdCtlrCommon( ExtensibleChip * i_mbaChip ) : + iv_mbaChip(i_mbaChip), iv_initialized(false), iv_rank(), iv_mark(), + iv_mssCmd(NULL) + {} + + /** @brief Destructor */ + ~CenMbaTdCtlrCommon() + { + delete iv_mssCmd; iv_mssCmd = NULL; + } + + /** + * @brief Determines and executes the next course of action after a + * maintenance command complete attention. + * @note Initializes the TD controller, if needed. + * @param io_sc The step code data struct. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t handleCmdCompleteEvent( STEP_CODE_DATA_STRUCT & io_sc ) = 0; + + protected: // functions + + /** + * @brief Initializes the TD controller and sets appropriate information + * in the hardware, if needed. + * + * Since the TD controller constructor will only be called in the MBA data + * bundle, register reads/writes can NOT be done in the constructor. + * Instead, anything needed to initialize the instance variables that + * requires register reads/writes or is non-trivial should be done in + * this function. + * + * @note Should be called at the beginning of every public function to + * ensure the TD controller is initialized. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t initialize() = 0; + + /** + * @brief Analyzes a non-TD command complete event. + * + * A maintenance command has completed but no TD are in progress. This + * function will check for any ECC errors, unverified chip marks from a + * reset/reload, etc. and starts any TD procedures, if necessary. + * + * @param io_sc The step code data struct. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t analyzeCmdComplete( STEP_CODE_DATA_STRUCT & io_sc ) = 0; + + /** + * @brief Analyzes VCM Phase 1 results and moves state machine. + * @param io_sc The step code data struct. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t analyzeVcmPhase1( STEP_CODE_DATA_STRUCT & io_sc ) = 0; + + /** + * @brief Analyzes VCM Phase 2 results and moves state machine. + * @param io_sc The step code data struct. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t analyzeVcmPhase2( STEP_CODE_DATA_STRUCT & io_sc ) = 0; + + /** + * @brief Analyzes DSD Phase 1 results and moves state machine. + * @param io_sc The step code data struct. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t analyzeDsdPhase1( STEP_CODE_DATA_STRUCT & io_sc ) = 0; + + /** + * @brief Analyzes DSD Phase 2 results and moves state machine. + * @param io_sc The step code data struct. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t analyzeDsdPhase2( STEP_CODE_DATA_STRUCT & io_sc ) = 0; + + /** + * @brief Starts VCM Phase 1. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t startVcmPhase1() = 0; + + /** + * @brief Starts VCM Phase 2. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t startVcmPhase2() = 0; + + /** + * @brief Starts DSD Phase 1. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t startDsdPhase1() = 0; + + /** + * @brief Starts DSD Phase 2. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t startDsdPhase2() = 0; + + /** + * @return TRUE if currently running a targeted diagnositics procedure, + * FALSE otherwise. + */ + virtual bool isInTdMode() = 0; + + /** + * @brief Calls the cleanupCmd() function of the command that had just + * completed. + * @note This function will clear the maintenance command complete + * attention. So for FSP attentions, the SDC needs to be synched + * before calling this function just in case there is a + * reset/reload. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t cleanupPrevCmd(); + + /** + * @brief Clears FIR bits that may have been a side-effect of a chip mark + * placed by hardware. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + virtual int32_t chipMarkCleanup(); + + protected: // instance variables + + /** The memory controller chip that this TD controller acts on. */ + ExtensibleChip * iv_mbaChip; + + /** Indicates if TD controller is initialized. */ + bool iv_initialized; + + /** The current rank that is being targeted for diagnostics. */ + CenRank iv_rank; + + /** The current mark that is being targeted for diagnostics. */ + CenMark iv_mark; + + /** Current maintenance command */ + PlatServices::mss_MaintCmdWrapper * iv_mssCmd; + +}; // CenMbaTdCtlrCommon + +} // end namespace PRDF + +#endif // __prdfCenMbaTdCtlr_common_H + diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C index 38edaea21..57eaf1322 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.C @@ -60,29 +60,17 @@ CenSymbol CenSymbol::fromSymbol( TargetHandle_t i_mba, const CenRank & i_rank, break; } - if ( SYMBOLS_PER_RANK <= i_symbol ) - { - PRDF_ERR( PRDF_FUNC"i_symbol is invalid" ); - break; - } - if ( BOTH_SYMBOL_DQS < i_pins ) { PRDF_ERR( PRDF_FUNC"i_pins is invalid" ); break; } - o_symbol = CenSymbol ( i_mba, i_rank, wiringType, i_symbol, i_pins ); + o_symbol = CenSymbol ( i_mba, i_rank, wiringType, i_symbol, i_pins, + isDramWidthX4(i_mba) ); } while (0); - if ( !o_symbol.isValid() ) - { - PRDF_ERR( PRDF_FUNC"Failed: i_mba=0x%08x i_rank=%d i_symbol=%d " - "i_pins=%d", getHuid(i_mba), i_rank.flatten(), i_symbol, - i_pins ); - } - return o_symbol; #undef PRDF_FUNC @@ -124,17 +112,11 @@ CenSymbol CenSymbol::fromDimmDq( TargetHandle_t i_mba, const CenRank & i_rank, uint8_t pins = (0 == (i_dimmDq & ODD_SYMBOL_DQ)) ? EVEN_SYMBOL_DQ : ODD_SYMBOL_DQ; - o_symbol = CenSymbol ( i_mba, i_rank, wiringType, symbol, pins ); + o_symbol = CenSymbol ( i_mba, i_rank, wiringType, symbol, pins, + isDramWidthX4(i_mba) ); } while (0); - if ( !o_symbol.isValid() ) - { - PRDF_ERR( PRDF_FUNC"Failed: i_mba=0x%08x i_rank=%d i_dimmDq=%d " - "i_portSlct=%d", getHuid(i_mba), i_rank.flatten(), i_dimmDq, - i_portSlct ); - } - return o_symbol; #undef PRDF_FUNC @@ -205,6 +187,20 @@ uint8_t CenSymbol::symbol2PortSlct( uint8_t i_symbol ) //------------------------------------------------------------------------------ +uint8_t CenSymbol::symbol2Dram( uint8_t i_symbol, bool isX4Dram ) +{ + uint8_t dram = isX4Dram ? X4DRAMS_PER_RANK : X8DRAMS_PER_RANK; + + if ( SYMBOLS_PER_RANK > i_symbol ) + { + dram = i_symbol / (isX4Dram ? SYMBOLS_PER_X4DRAM : SYMBOLS_PER_X8DRAM); + } + + return dram; +} + +//------------------------------------------------------------------------------ + int32_t CenSymbol::getSymbol( const CenRank & i_rank, WiringType i_wiringType, uint8_t i_dimmDq, uint8_t i_portSlct, uint8_t & o_symbol ) diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H index 0bfc86dfd..a43700e87 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfCenSymbol.H @@ -81,9 +81,10 @@ class CenSymbol * @brief Constructor from components */ CenSymbol( TARGETING::TargetHandle_t i_mba, CenRank i_rank, - WiringType i_wiringType, uint8_t i_symbol, uint8_t i_pins ) : + WiringType i_wiringType, uint8_t i_symbol, uint8_t i_pins, + bool i_x4Dram ) : iv_mbaTarget(i_mba), iv_rank(i_rank), iv_wiringType(i_wiringType), - iv_symbol(i_symbol), iv_pins(i_pins) + iv_symbol(i_symbol), iv_pins(i_pins), iv_x4Dram(i_x4Dram) {} public: // functions @@ -148,6 +149,12 @@ class CenSymbol /** @return The port select for this symbol. */ uint8_t getPortSlct() const { return symbol2PortSlct( iv_symbol ); } + /** @return The DRAM index for this symbol. */ + uint8_t getDram() const { return symbol2Dram( iv_symbol, iv_x4Dram ); } + + /** @return TRUE this symbol is on a x4 DRAM, FALSE otherwise. */ + bool isX4Dram() const { return iv_x4Dram; } + /** @return The symbol of the given Centaur DQ and port select. */ static uint8_t cenDq2Symbol( uint8_t i_CenDq, uint8_t i_ps ); @@ -157,6 +164,9 @@ class CenSymbol /** @return The port select for given symbol. */ static uint8_t symbol2PortSlct( uint8_t i_symbol ); + /** @return The DRAM index for the given symbol. */ + static uint8_t symbol2Dram( uint8_t i_symbol, bool isX4Dram ); + /** * @brief Overrides the '<' operator. * @param i_symbol The symbol to compare with. @@ -199,6 +209,7 @@ class CenSymbol WiringType iv_wiringType; ///< This symbol's wiring type. uint8_t iv_symbol; ///< This symbol's numerical value. uint8_t iv_pins; ///< See enum DqMask. + bool iv_x4Dram; ///< TRUE x4 DRAM, FALSE x8 DRAM. }; } // end namespace PRDF diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C b/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C index 177a64d91..6c4e7a736 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.C @@ -203,8 +203,7 @@ MemoryMru::MemoryMru( TARGETING::TargetHandle_t i_mbaTarget, iv_memMruMeld.s.rank = iv_rank.flatten(); iv_memMruMeld.s.symbol = iv_symbol.getSymbol(); iv_memMruMeld.s.pins = iv_symbol.getPins(); - //TODO: RTC 68096 Add support for DRAM spare - iv_memMruMeld.s.dramSpared = 0; + iv_memMruMeld.s.dramSpared = 0; // manually set by setDramSpared() iv_memMruMeld.s.wiringType = iv_symbol.getWiringType(); // If the code gets to this point the MemoryMru is valid. diff --git a/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H b/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H index a1cb63ab0..448649385 100755 --- a/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H +++ b/src/usr/diag/prdf/common/plat/pegasus/prdfMemoryMru.H @@ -71,6 +71,9 @@ class MemoryMru MemoryMru( TARGETING::TargetHandle_t i_mbaTarget, const CenRank & i_rank, MemoryMruData::Callout i_specialCallout ); + /** @brief Indicates that the symbol actually resides on the DRAM spare. */ + void setDramSpared() { iv_memMruMeld.s.dramSpared = 1; } + public: // functions /** @return The 32-bit representation of this MemoryMru. */ diff --git a/src/usr/diag/prdf/common/prd_pegasus.mk b/src/usr/diag/prdf/common/prd_pegasus.mk index ade450c4b..6279d7afd 100755 --- a/src/usr/diag/prdf/common/prd_pegasus.mk +++ b/src/usr/diag/prdf/common/prd_pegasus.mk @@ -41,10 +41,12 @@ prd_pegasus_specific = \ prdfCalloutUtil.o \ prdfCenAddress.o \ prdfCenDqBitmap.o \ + prdfCenMbaCaptureData.o \ + prdfCenMbaTdCtlr.o \ + prdfCenMbaTdCtlr_common.o \ prdfCenSymbol.o \ + prdfLaneRepair.o \ prdfLineDelete.o \ - prdfPegasusConfigurator.o \ - prdfCenMbaCaptureData.o \ prdfMemoryMru.o \ - prdfRegisterData.o \ - prdfLaneRepair.o + prdfPegasusConfigurator.o \ + prdfRegisterData.o diff --git a/src/usr/diag/prdf/framework/service/prdfPlatServices.C b/src/usr/diag/prdf/framework/service/prdfPlatServices.C index c6477ca85..81564e53a 100644 --- a/src/usr/diag/prdf/framework/service/prdfPlatServices.C +++ b/src/usr/diag/prdf/framework/service/prdfPlatServices.C @@ -36,6 +36,9 @@ #include #include +#include +#include + #include #include #include @@ -44,8 +47,6 @@ using namespace TARGETING; -//------------------------------------------------------------------------------ - namespace PRDF { @@ -200,6 +201,37 @@ int32_t mssRestoreDramRepairs( TargetHandle_t i_mbaTarget, return o_rc; } +//------------------------------------------------------------------------------ + +int32_t mssIplUeIsolation( TargetHandle_t i_mba, const CenRank & i_rank, + CenDqBitmap & o_bitmap ) +{ + #define PRDF_FUNC "[PlatServices::mssIplUeIsolation] " + + int32_t o_rc = SUCCESS; + + uint8_t data[PORT_SLCT_PER_MBA][DIMM_DQ_RANK_BITMAP_SIZE]; + + errlHndl_t errl = NULL; + PRD_FAPI_TO_ERRL( errl, mss_IPL_UE_isolation, getFapiTarget(i_mba), + i_rank.flatten(), data ); + if ( NULL != errl ) + { + PRDF_ERR( PRDF_FUNC"mss_IPL_UE_isolation() failed: MBA=0x%08x " + "rank=%d", getHuid(i_mba), i_rank.flatten() ); + PRDF_COMMIT_ERRL( errl, ERRL_ACTION_REPORT ); + o_rc = FAIL; + } + else + { + o_bitmap = CenDqBitmap ( i_mba, i_rank, data ); + } + + return o_rc; + + #undef PRDF_FUNC +} + } // end namespace PlatServices } // end namespace PRDF diff --git a/src/usr/diag/prdf/framework/service/prdfPlatServices.H b/src/usr/diag/prdf/framework/service/prdfPlatServices.H index 8395d8619..41e489152 100644 --- a/src/usr/diag/prdf/framework/service/prdfPlatServices.H +++ b/src/usr/diag/prdf/framework/service/prdfPlatServices.H @@ -86,6 +86,18 @@ int32_t mssRestoreDramRepairs( TARGETING::TargetHandle_t i_mbaTarget, uint8_t & o_repairedRankMask, uint8_t & o_badDimmMask ); +/** + * @brief Invokes the mss_IPL_UE_isolation hardware procedure. + * This function will identify the bits that caused the UE. + * @param i_mba Target MBA. + * @param i_rank Target rank. + * @param o_bitmap DQ bitmap container. + * @return Non-SUCCESS in internal function fails, SUCCESS otherwise. + */ +int32_t mssIplUeIsolation( TARGETING::TargetHandle_t i_mba, + const CenRank & i_rank, + CenDqBitmap & o_bitmap ); + } // end namespace PlatServices } // end namespace PRDF diff --git a/src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H index ffa254849..c6dcf5ccc 100644 --- a/src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H +++ b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaDataBundle.H @@ -38,7 +38,7 @@ namespace PRDF { /** - * @brief The P7 Centaur MBA data bundle. + * @brief Centaur MBA data bundle. */ class CenMbaDataBundle : public CenMbaDataBundleCommon { @@ -56,9 +56,7 @@ class CenMbaDataBundle : public CenMbaDataBundleCommon /** * @brief Destructor. */ - ~CenMbaDataBundle() - { - } + ~CenMbaDataBundle() {} private: // functions diff --git a/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C new file mode 100644 index 000000000..40f7b51a4 --- /dev/null +++ b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.C @@ -0,0 +1,1342 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.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 + +// Framework includes +#include +#include +#include +#include +#include +#include +#include + +// Pegasus includes +#include +#include +#include +#include +#include +#include + +// TODO: RTC 68096 Currently we are only supporting x8 DRAM. Once support for x4 +// DRAM is available, it will have impact on DRAM spare. + +using namespace TARGETING; + +namespace PRDF +{ + +using namespace PlatServices; + +enum EccErrorMask +{ + NO_ERROR = 0, ///< No ECC errors found + UE = 0x80, ///< UE + MPE = 0x40, ///< Chip mark placed + RCE = 0x20, ///< Retry CE + MCE = 0x10, ///< CE on chip mark +}; + +//------------------------------------------------------------------------------ +// Class Variables +//------------------------------------------------------------------------------ + +CenMbaTdCtlr::CMD_COMPLETE_FUNCS CenMbaTdCtlr::cv_cmdCompleteFuncs[] = +{ + &CenMbaTdCtlr::analyzeCmdComplete, // NO_OP + &CenMbaTdCtlr::analyzeVcmPhase1, // VCM_PHASE_1 + &CenMbaTdCtlr::analyzeVcmPhase2, // VCM_PHASE_2 + &CenMbaTdCtlr::analyzeDsdPhase1, // DSD_PHASE_1 + &CenMbaTdCtlr::analyzeDsdPhase2, // DSD_PHASE_2 +}; + +//------------------------------------------------------------------------------ +// Public Functions +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::handleCmdCompleteEvent( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::handleCmdCompleteEvent] " + + int32_t o_rc = SUCCESS; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( !isInMdiaMode() ) + { + PRDF_ERR( PRDF_FUNC"A hostboot maintenance command complete " + "attention occurred while MDIA was not running." ); + o_rc = FAIL; + break; + } + + o_rc = initialize(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"initialize() failed" ); + break; + } + + // Immediately inform MDIA that the command has finished. + o_rc = mdiaSendEventMsg( mba, MDIA::RESET_TIMER ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"mdiaSendEventMsg(RESET_TIMER) failed" ); + break; + } + + o_rc = (this->*cv_cmdCompleteFuncs[iv_tdState])( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"Failed to continue analysis" ); + break; + } + + // Do some cleanup if the TD procedure is complete. + if ( !isInTdMode() ) + { + o_rc = exitTdSequence(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"exitTdSequence() failed" ); + break; + } + } + + } while(0); + + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"iv_mbaChip:0x%08x iv_initialized:%c iv_tdState:%d " + "iv_rank:%d iv_mark:%2d %2d", getHuid(mba), + iv_initialized ? 'T' : 'F', iv_tdState, iv_rank.flatten(), + iv_mark.getCM().getSymbol(), iv_mark.getSM().getSymbol() ); + + int32_t l_rc = cleanupPrevCmd(); // Just in case. + if ( SUCCESS != l_rc ) + PRDF_ERR( PRDF_FUNC"cleanupPrevCmd() failed" ); + + l_rc = mdiaSendEventMsg( mba, MDIA::SKIP_MBA ); + if ( SUCCESS != l_rc ) + PRDF_ERR( PRDF_FUNC"mdiaSendEventMsg(SKIP_MBA) failed" ); + + io_sc.service_data->SetErrorSig( PRDFSIG_MaintCmdComplete_ERROR ); + io_sc.service_data->SetServiceCall(); + + // There may have been a code bug, callout 2nd level support. + io_sc.service_data->SetCallout( NextLevelSupport_ENUM, MRU_HIGH ); + + // Callout the mark. If nothing was added to the callout list (no valid + // marks), callout the MBA. + CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc ); + if ( 1 == io_sc.service_data->GetMruList().size() ) + io_sc.service_data->SetCallout( mba ); + + // Just in case it was a legitimate maintenance command complete (error + // log not committed) but something else failed. + io_sc.service_data->ClearFlag(ServiceDataCollector::DONT_COMMIT_ERRL); + } + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ +// Private Functions +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::initialize() +{ + #define PRDF_FUNC "[CenMbaTdCtlr::initialize] " + + int32_t o_rc = SUCCESS; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( iv_initialized ) break; // nothing to do + + // Check for valid MBA. + if ( TYPE_MBA != getTargetType(mba) ) + { + PRDF_ERR( PRDF_FUNC"iv_mbaChip is not TYPE_MBA" ); + o_rc = FAIL; break; + } + + iv_initialized = true; + + } while (0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::analyzeCmdComplete( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::analyzeCmdComplete] " + + int32_t o_rc = SUCCESS; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( NO_OP != iv_tdState ) + { + PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" ); + o_rc = FAIL; break; + } + + // Get the rank on which maintenance command stopped + CenAddr addr; + o_rc = getCenMaintStartAddr( iv_mbaChip, addr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"cenGetMaintAddr() failed" ); + break; + } + iv_rank = CenRank( addr.getRank() ); + + // Get error condition which caused command to stop + uint8_t eccErrorMask = NO_ERROR; + o_rc = checkEccErrors( eccErrorMask ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" ); + break; + } + + if ( eccErrorMask & UE ) + { + // Handle UE. Highest priority + o_rc = handleUE( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"handleUE() failed" ); + break; + } + } + else if ( eccErrorMask & MPE ) + { + // Get the current marks in hardware. + o_rc = mssGetMarkStore( mba, iv_rank, iv_mark ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"mssGetMarkStore() failed"); + break; + } + + if ( !iv_mark.getCM().isValid() ) + { + PRDF_ERR( PRDF_FUNC"No valid chip mark to verify"); + o_rc = FAIL; break; + } + + io_sc.service_data->SetErrorSig( PRDFSIG_StartVcmPhase1 ); + + CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc ); + + // Start VCM procedure + o_rc = startVcmPhase1(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"startVcmPhase1() failed" ); + break; + } + } + else + { + // If maint cmd completed with no error, don't commit error log. + io_sc.service_data->DontCommitErrorLog(); + } + + } while (0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::analyzeVcmPhase1( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::analyzeVcmPhase1] " + + int32_t o_rc = SUCCESS; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( VCM_PHASE_1 != iv_tdState ) + { + PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" ); + o_rc = FAIL; break; + } + + // Get error condition which caused command to stop + uint8_t eccErrorMask = NO_ERROR; + o_rc = checkEccErrors( eccErrorMask ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" ); + break; + } + + if ( (eccErrorMask & UE) || (eccErrorMask & RCE) ) + { + // Handle UE. Highest priority + o_rc = handleUE( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"handleUE() failed" ); + break; + } + } + else + { + io_sc.service_data->SetErrorSig( PRDFSIG_StartVcmPhase2 ); + + CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc ); + + // Start VCM Phase 2 + o_rc = startVcmPhase2(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"startVcmPhase2() failed" ); + break; + } + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::analyzeVcmPhase2( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::analyzeVcmPhase2] " + + int32_t o_rc = SUCCESS; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( VCM_PHASE_2 != iv_tdState ) + { + PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" ); + o_rc = FAIL; break; + } + + // Get error condition which caused command to stop + uint8_t eccErrorMask = NO_ERROR; + o_rc = checkEccErrors( eccErrorMask ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" ); + break; + } + + if ( eccErrorMask & UE ) + { + // Handle UE. Highest priority + o_rc = handleUE( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"handleUE() failed" ); + break; + } + } + else if ( eccErrorMask & MCE ) + { + // Chip mark is verified. + + // Do callouts, VPD updates, and start DRAM sparing, if possible. + o_rc = handleMCE_VCM2( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"handleMCE_VCM2() failed" ); + break; + } + } + else + { + // Chip mark verification failed. + + iv_tdState = NO_OP; // Abort the TD procedure. + + io_sc.service_data->SetErrorSig( PRDFSIG_VcmFalseAlarm ); + + CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc ); + + // In the field, this error log will be recoverable for now, but we + // may have to add thresholding later if they become a problem. In + // manufacturing, this error log will be predictive. + + if ( areDramRepairsDisabled() ) + io_sc.service_data->SetServiceCall(); + + // Remove chip mark from hardware. + iv_mark.clearCM(); + bool junk; + o_rc = mssSetMarkStore( mba, iv_rank, iv_mark, junk ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"mssSetMarkStore() failed" ); + break; + } + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::analyzeDsdPhase1( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::analyzeDsdPhase1] " + + int32_t o_rc = SUCCESS; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( DSD_PHASE_1 != iv_tdState ) + { + PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" ); + o_rc = FAIL; break; + } + + // Get error condition which caused command to stop + uint8_t eccErrorMask = NO_ERROR; + o_rc = checkEccErrors( eccErrorMask ); + if ( SUCCESS != o_rc) + { + PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" ); + break; + } + + if ( ( eccErrorMask & UE) || ( eccErrorMask & RCE ) ) + { + // Handle UE. Highest priority + o_rc = handleUE( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"handleUE() failed" ); + break; + } + } + else + { + io_sc.service_data->SetErrorSig( PRDFSIG_StartDsdPhase2 ); + + CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc ); + + // Start DSD Phase 2 + startDsdPhase2(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"startDsdPhase2() failed" ); + break; + } + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::analyzeDsdPhase2( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::analyzeDsdPhase2] " + + int32_t o_rc = SUCCESS; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( DSD_PHASE_2 != iv_tdState ) + { + PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" ); + o_rc = FAIL; break; + } + + // Get error condition which caused command to stop + uint8_t eccErrorMask = NO_ERROR; + o_rc = checkEccErrors( eccErrorMask ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"checkEccErrors() failed" ); + break; + } + + if ( eccErrorMask & UE) + { + // Handle UE. Highest priority + o_rc = handleUE( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"handleUE() failed" ); + break; + } + } + else if ( eccErrorMask & MCE ) + { + // The spare is bad. + + // Do callouts and VPD updates. + o_rc = handleMCE_DSD2( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"handleMCE_DSD2() failed" ); + break; + } + } + else + { + // The chip mark has successfully been steered to the spare. + + io_sc.service_data->SetErrorSig( PRDFSIG_DsdDramSpared ); + + CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc ); + + // Remove chip mark from hardware. + iv_mark.clearCM(); + bool junk; + o_rc = mssSetMarkStore( mba, iv_rank, iv_mark, junk ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"mssSetMarkStore() failed" ); + break; + } + } + + iv_tdState = NO_OP; // The TD procedure is complete. + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::startVcmPhase1() +{ + #define PRDF_FUNC "[CenMbaTdCtlr::startVcmPhase1] " + + int32_t o_rc = SUCCESS; + + iv_tdState = VCM_PHASE_1; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + o_rc = prepareNextCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" ); + break; + } + + // Start phase 1. + uint32_t stopCond = ( mss_MaintCmd::STOP_END_OF_RANK | + mss_MaintCmd::STOP_ON_END_ADDRESS | + mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION ); + + iv_mssCmd = createMssCmd( mss_MaintCmdWrapper::TIMEBASE_STEER_CLEANUP, + mba, iv_rank, stopCond ); + if ( NULL == iv_mssCmd ) + { + PRDF_ERR( PRDF_FUNC"createMssCmd() failed"); + o_rc = FAIL; break; + } + + o_rc = iv_mssCmd->setupAndExecuteCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setupAndExecuteCmd() failed" ); + break; + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::startVcmPhase2() +{ + #define PRDF_FUNC "[CenMbaTdCtlr::startVcmPhase2] " + + int32_t o_rc = SUCCESS; + + iv_tdState = VCM_PHASE_2; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + o_rc = prepareNextCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" ); + break; + } + + // Start phase 2. + uint32_t stopCond = ( mss_MaintCmd::STOP_END_OF_RANK | + mss_MaintCmd::STOP_ON_END_ADDRESS | + mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION ); + + iv_mssCmd = createMssCmd( mss_MaintCmdWrapper::SUPERFAST_READ, + mba, iv_rank, stopCond ); + if ( NULL == iv_mssCmd ) + { + PRDF_ERR( PRDF_FUNC"createMssCmd() failed"); + o_rc = FAIL; break; + } + + o_rc = iv_mssCmd->setupAndExecuteCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setupAndExecuteCmd() failed" ); + break; + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::startDsdPhase1() +{ + #define PRDF_FUNC "[CenMbaTdCtlr::startDsdPhase1] " + + int32_t o_rc = SUCCESS; + + iv_tdState = DSD_PHASE_1; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + o_rc = prepareNextCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" ); + break; + } + + // Set the steer mux + o_rc = mssSetSteerMux( mba, iv_rank, iv_mark.getCM(), false ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"mssSetSteerMux() failed" ); + break; + } + + // Start phase 1. + uint32_t stopCond = ( mss_MaintCmd::STOP_END_OF_RANK | + mss_MaintCmd::STOP_ON_END_ADDRESS | + mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION ); + + iv_mssCmd = createMssCmd( mss_MaintCmdWrapper::TIMEBASE_STEER_CLEANUP, + mba, iv_rank, stopCond ); + if ( NULL == iv_mssCmd ) + { + PRDF_ERR( PRDF_FUNC"createMssCmd() failed"); + o_rc = FAIL; break; + } + + o_rc = iv_mssCmd->setupAndExecuteCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setupAndExecuteCmd() failed" ); + break; + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::startDsdPhase2() +{ + #define PRDF_FUNC "[CenMbaTdCtlr::startDsdPhase2] " + + int32_t o_rc = SUCCESS; + + iv_tdState = DSD_PHASE_2; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + o_rc = prepareNextCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" ); + break; + } + + // Start phase 2. + uint32_t stopCond = ( mss_MaintCmd::STOP_END_OF_RANK | + mss_MaintCmd::STOP_ON_END_ADDRESS | + mss_MaintCmd::ENABLE_CMD_COMPLETE_ATTENTION ); + + iv_mssCmd = createMssCmd( mss_MaintCmdWrapper::SUPERFAST_READ, + mba, iv_rank, stopCond ); + if ( NULL == iv_mssCmd ) + { + PRDF_ERR( PRDF_FUNC"createMssCmd() failed"); + o_rc = FAIL; break; + } + + o_rc = iv_mssCmd->setupAndExecuteCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setupAndExecuteCmd() failed" ); + break; + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +bool CenMbaTdCtlr::isInTdMode() +{ + return ( (NO_OP != iv_tdState) && (MAX_TD_STATE > iv_tdState) ); +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::checkEccErrors( uint8_t & o_eccErrorMask ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::checkEccErrors] " + + int32_t o_rc = SUCCESS; + + o_eccErrorMask = NO_ERROR; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + CenMbaDataBundle * mbadb = getMbaDataBundle( iv_mbaChip ); + ExtensibleChip * membChip = mbadb->getMembChip(); + if ( NULL == membChip ) + { + PRDF_ERR( PRDF_FUNC"getMembChip() failed: MBA=0x%08x", + getHuid(mba) ); + o_rc = FAIL; break; + } + + const char * reg_str = ( 0 == getTargetPosition(mba) ) + ? "MBSECC01FIR" : "MBSECC23FIR"; + SCAN_COMM_REGISTER_CLASS * mbsEccFir = membChip->getRegister( reg_str ); + + o_rc = mbsEccFir->Read(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"Read() failed on %s", reg_str ); + break; + } + + if ( mbsEccFir->IsBitSet(20 + iv_rank.flatten()) ) + { + o_eccErrorMask |= MPE; + + // Clean up side-effect FIRs that may be set due to the chip mark. + o_rc = chipMarkCleanup(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"chipMarkCleanup() failed" ); + break; + } + } + + if ( mbsEccFir->IsBitSet(38) ) o_eccErrorMask |= MCE; + if ( mbsEccFir->IsBitSet(41) ) o_eccErrorMask |= UE; + if ( mbsEccFir->IsBitSet(42) ) o_eccErrorMask |= RCE; + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::handleUE( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::handleUE] " + + using namespace CalloutUtil; + + int32_t o_rc = SUCCESS; + + iv_tdState = NO_OP; // Abort the TD procedure. + + io_sc.service_data->SetErrorSig( PRDFSIG_MaintUE ); + io_sc.service_data->SetServiceCall(); + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + // Clean up the maintenance command. This is needed just in case the UE + // isolation procedure is modified to use maintenance commands. + o_rc = cleanupPrevCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"cleanupPrevCmd() failed" ); + break; + } + + // Look for all failing bits on this rank. + CenDqBitmap bitmap; + o_rc = mssIplUeIsolation( mba, iv_rank, bitmap ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"mssIplUeIsolation() failed" ); + break; + } + + // Add UE data to capture data. + bitmap.getCaptureData( io_sc.service_data->GetCaptureData() ); + + // Callout the failing DIMMs. + TargetHandleList callouts; + for ( int32_t ps = 0; ps < PORT_SLCT_PER_MBA; ps++ ) + { + bool badDqs = false; + o_rc = bitmap.badDqs( ps, badDqs ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"badDqs(%d) failed", ps ); + break; + } + + if ( !badDqs ) continue; // nothing to do. + + TargetHandleList dimms = getConnectedDimms( mba, iv_rank, ps ); + if ( 0 == dimms.size() ) + { + PRDF_ERR( PRDF_FUNC"getConnectedDimms(%d) failed", ps ); + o_rc = FAIL; break; + } + + callouts.insert( callouts.end(), dimms.begin(), dimms.end() ); + } + if ( SUCCESS != o_rc ) break; + + if ( 0 == callouts.size() ) + { + // It is possible the scrub counters have rolled over to zero due to + // a known DD1.0 hardware bug. In this case, the best we can do is + // callout both DIMMs, because at minimum we know there was a UE, we + // just don't know where. + // NOTE: If this condition happens because of a DD2.0+ bug, the + // mssIplUeIsolation procedure will callout the Centaur. + callouts = getConnectedDimms( mba, iv_rank ); + if ( 0 == callouts.size() ) + { + PRDF_ERR( PRDF_FUNC"getConnectedDimms() failed" ); + o_rc = FAIL; break; + } + } + + // Callout all DIMMs in the list. + for ( TargetHandleList::iterator i = callouts.begin(); + i != callouts.end(); i++ ) + { + io_sc.service_data->SetCallout( *i, MRU_HIGH ); + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::handleMCE_VCM2( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::handleMCE_VCM2] " + + int32_t o_rc = SUCCESS; + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( VCM_PHASE_2 != iv_tdState ) + { + PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" ); + o_rc = FAIL; break; + } + + io_sc.service_data->SetErrorSig( PRDFSIG_VcmVerified ); + + CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc ); + + if ( areDramRepairsDisabled() ) + { + iv_tdState = NO_OP; // The TD procedure is complete. + + io_sc.service_data->SetServiceCall(); + + break; // nothing else to do. + } + + bool startDsdProcedure = false; + + // Read VPD. + CenDqBitmap bitmap; + o_rc = getBadDqBitmap( mba, iv_rank, bitmap ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"getBadDqBitmap() failed" ); + break; + } + + // The chip mark is considered verified, so set it in VPD. + // NOTE: If this chip mark was placed on the spare, the original failing + // DRAM will have already been set in VPD so this will be + // redundant but it simplifies the rest of the logic below. + o_rc = bitmap.setDram( iv_mark.getCM().getSymbol() ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setDram() failed" ); + break; + } + + // RAS callout policies can be determined by the DIMM type. We can + // assume IS DIMMs are on low end systems and Centaur DIMMs are on + // mid/high end systems. + bool isCenDimm = false; + o_rc = isMembufOnDimm( mba, isCenDimm ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"isMembufOnDimm() failed" ); + break; + } + + if ( isCenDimm ) // Medium/high end systems + { + uint8_t ps = iv_mark.getCM().getPortSlct(); + + // It is possible that a Centaur DIMM does not have spare DRAMs. + // Check the VPD for available spares. Note that a x4 DIMM may have + // one or two spare DRAMs so check for availability on both. + // TODO: RTC 68096 Add support for x4 DRAMs. + bool dramSparePossible = false; + o_rc = bitmap.isDramSpareAvailable( ps, dramSparePossible ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"isDramSpareAvailable() failed" ); + break; + } + + if ( dramSparePossible ) + { + // Verify the spare is not already used. + CenSymbol sp0, sp1, ecc; + // TODO: RTC 68096 need to support ECC spare. + o_rc = mssGetSteerMux( mba, iv_rank, sp0, sp1, ecc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"mssGetSteerMux() failed" ); + break; + } + + if ( ((0 == ps) && !sp0.isValid()) || + ((1 == ps) && !sp1.isValid()) ) + { + // A spare DRAM is available. + startDsdProcedure = true; + } + else if ( iv_mark.getCM().getDram() == + (0 == ps ? sp0.getDram() : sp1.getDram()) ) + { + io_sc.service_data->SetErrorSig( PRDFSIG_VcmBadSpare ); + + // The chip mark was on the spare DRAM and it is bad, so + // call it out and set it in VPD. + + MemoryMru memmru ( mba, iv_rank, iv_mark.getCM() ); + memmru.setDramSpared(); + io_sc.service_data->SetCallout( memmru ); + io_sc.service_data->SetServiceCall(); + + o_rc = bitmap.setDramSpare( ps ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setDramSpare() failed" ); + break; + } + } + else + { + // Chip mark and DRAM spare are both used. + io_sc.service_data->SetErrorSig( PRDFSIG_VcmMarksUnavail ); + io_sc.service_data->SetServiceCall(); + } + } + else + { + // Chip mark is in place and sparing is not possible. + io_sc.service_data->SetErrorSig( PRDFSIG_VcmMarksUnavail ); + io_sc.service_data->SetServiceCall(); + } + } + else // Low end systems + { + // Not able to do dram sparing. If there is a symbol mark, there are + // no repairs available so call it out and set the error log to + // predictive. + if ( iv_mark.getSM().isValid() ) + { + io_sc.service_data->SetErrorSig( PRDFSIG_VcmMarksUnavail ); + io_sc.service_data->SetServiceCall(); + } + } + + // Write VPD. + o_rc = setBadDqBitmap( mba, iv_rank, bitmap ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setBadDqBitmap() failed" ); + break; + } + + // Start DSD Phase 1, if possible. + if ( startDsdProcedure ) + { + io_sc.service_data->SetErrorSig( PRDFSIG_StartDsdPhase1 ); + + o_rc = startDsdPhase1(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"startDsdPhase1() failed" ); + break; + } + } + else + { + iv_tdState = NO_OP; // The TD procedure is complete. + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::handleMCE_DSD2( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[CenMbaTdCtlr::handleMCE_DSD2] " + + int32_t o_rc = SUCCESS; + + io_sc.service_data->SetErrorSig( PRDFSIG_DsdBadSpare ); + io_sc.service_data->SetServiceCall(); + + TargetHandle_t mba = iv_mbaChip->GetChipHandle(); + + do + { + if ( DSD_PHASE_2 != iv_tdState ) + { + PRDF_ERR( PRDF_FUNC"Invalid state machine configuration" ); + o_rc = FAIL; break; + } + + // Callout mark and spare DRAM. + CalloutUtil::calloutMark( mba, iv_rank, iv_mark, io_sc ); + + MemoryMru memmru ( mba, iv_rank, iv_mark.getCM() ); + memmru.setDramSpared(); + io_sc.service_data->SetCallout( memmru ); + + // The spare DRAM is bad, so set it in VPD. At this point, the chip mark + // should have already been set in the VPD because it was recently + // verified. + + CenDqBitmap bitmap; + o_rc = getBadDqBitmap( mba, iv_rank, bitmap ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"getBadDqBitmap() failed" ); + break; + } + + o_rc = bitmap.setDramSpare( iv_mark.getCM().getPortSlct() ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setDramSpare() failed" ); + break; + } + + o_rc = setBadDqBitmap( mba, iv_rank, bitmap ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"setBadDqBitmap() failed" ); + break; + } + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::exitTdSequence() +{ + #define PRDF_FUNC "[CenMbaTdCtlr::exitTdSequence] " + + int32_t o_rc = SUCCESS; + + do + { + // Clean up the previous command + // PRD is not starting another command but MDIA might be so clear the + // counters and FIRs as well. + o_rc = prepareNextCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"prepareNextCmd() failed" ); + break; + } + + // Inform MDIA about command complete + // Note that we only want to send the command complete message if + // everything above is successful because a bad return code will result + // in a SKIP_MBA message sent. There is no need to send redundant + // messages. + o_rc = signalMdiaCmdComplete(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"signalMdiaCmdComplete() failed" ); + break; + } + + // Clear out the mark, just in case. This is so we don't accidentally + // callout this mark on another rank in an error patch scenario. + iv_mark = CenMark(); + + } while (0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::prepareNextCmd() +{ + #define PRDF_FUNC "[CenMbaTdCtlr::prepareNextCmd] " + + int32_t o_rc = SUCCESS; + + do + { + CenMbaDataBundle * mbadb = getMbaDataBundle( iv_mbaChip ); + ExtensibleChip * membChip = mbadb->getMembChip(); + if ( NULL == membChip ) + { + PRDF_ERR( PRDF_FUNC"getMembChip() failed" ); + o_rc = FAIL; break; + } + + uint32_t mbaPos = getTargetPosition( iv_mbaChip->GetChipHandle() ); + + //---------------------------------------------------------------------- + // Clean up previous command + //---------------------------------------------------------------------- + + o_rc = cleanupPrevCmd(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"cleanupPrevCmd() failed" ); + break; + } + + //---------------------------------------------------------------------- + // Clear ECC counters + //---------------------------------------------------------------------- + + const char * reg_str = ( 0 == mbaPos ) ? "MBSTR_0" : "MBSTR_1"; + SCAN_COMM_REGISTER_CLASS * mbstr = membChip->getRegister( reg_str ); + o_rc = mbstr->Read(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"Read() failed on %s", reg_str ); + break; + } + + mbstr->SetBit(53); // Setting this bit clears all counters. + + o_rc = mbstr->Write(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"Write() failed on %s", reg_str ); + break; + } + + // Hardware automatically clears bit 53, so flush this register out of + // the register cache to avoid clearing the counters again with a write + // from the out-of-date cached copy. + RegDataCache & cache = RegDataCache::getCachedRegisters(); + cache.flush( membChip, mbstr ); + + //---------------------------------------------------------------------- + // Clear ECC FIRs + //---------------------------------------------------------------------- + + reg_str = ( 0 == mbaPos ) ? "MBSECC01FIR_AND" : "MBSECC23FIR_AND"; + SCAN_COMM_REGISTER_CLASS * firand = membChip->getRegister( reg_str ); + firand->setAllBits(); + + // Clear MPE bit for this rank. + firand->ClearBit( 20 + iv_rank.flatten() ); + + // Clear NCE, SCE, MCE, RCE, SUE, UE bits (36-41) + firand->SetBitFieldJustified( 36, 6, 0 ); + + o_rc = firand->Write(); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"Write() failed on %s", reg_str ); + break; + } + + } while (0); + + return o_rc; + + #undef PRDF_FUNC +} + +//------------------------------------------------------------------------------ + +int32_t CenMbaTdCtlr::signalMdiaCmdComplete() +{ + #define PRDF_FUNC "[CenMbaTdCtlr::signalMdiaCmdComplete] " + + int32_t o_rc = SUCCESS; + + do + { + // Determine for MDIA whether or not the command finished at the end of + // the last rank or if the command will need to be restarted. + + // Get the last address of the last rank in memory. + CenAddr junk, allEndAddr; + o_rc = getMemAddrRange( iv_mbaChip->GetChipHandle(), junk, allEndAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"getMemAddrRange() failed" ); + break; + } + + // Get the address currently in the MBMEA. + CenAddr curEndAddr; + o_rc = getCenMaintEndAddr( iv_mbaChip, curEndAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC"cenGetMaintAddr() failed" ); + break; + } + + // The actual message will need to be sent in post analysis after the + // FIR bits have been cleared. + CenMbaDataBundle * mbadb = getMbaDataBundle( iv_mbaChip ); + mbadb->iv_sendCmdCompleteMsg = true; + mbadb->iv_cmdCompleteMsgData = + (allEndAddr == curEndAddr) ? MDIA::COMMAND_COMPLETE + : MDIA::COMMAND_STOPPED; + + } while(0); + + return o_rc; + + #undef PRDF_FUNC +} + +} // end namespace PRDF + diff --git a/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H new file mode 100644 index 000000000..807211e30 --- /dev/null +++ b/src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.H @@ -0,0 +1,174 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/diag/prdf/plat/pegasus/prdfCenMbaTdCtlr.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 */ + +/** @file prdfCenMbaTdCtlr.H + * @brief The Hostboot implementation of the MBA TD Controller. + */ + +#ifndef __prdfCenMbaTdCtlr_H +#define __prdfCenMbaTdCtlr_H + +#include + +namespace PRDF +{ + +/** + * @brief A state machine for memory targeted diagnostics during Hostboot MDIA. + */ +class CenMbaTdCtlr : public CenMbaTdCtlrCommon +{ + private: // constants, enums + + /** + * @brief Lists all possible states of TD controller + * @note These enums are used as array indexes to cv_cmdCompleteFuncs and + * the last entry will be used to get the size of the array. + */ + enum TdState + { + NO_OP = 0, ///< No TD procedures in place. + VCM_PHASE_1, ///< Verify Chip Mark phase 1. + VCM_PHASE_2, ///< Verify Chip Mark phase 2. + DSD_PHASE_1, ///< DRAM Spare Deploy phase 1. + DSD_PHASE_2, ///< DRAM Spare Deploy phase 2. + MAX_TD_STATE ///< The maximum number of TD states. + }; + + // Function pointers for maintenance command complete events. + typedef int32_t (CenMbaTdCtlr::*CMD_COMPLETE_FUNCS) + ( STEP_CODE_DATA_STRUCT & io_sc ); + + public: // functions + + /** + * @brief Constructor + * + * This contructor will be called in the MBA data bundle code. Therefore, + * no register reads/writes can be done in this constructor. Anything needed + * to initialize the instance variables that requires register reads/writes + * or is non-trivial should be done in initialize(). + * + * @param i_mbaChip An MBA chip. + */ + explicit CenMbaTdCtlr( ExtensibleChip * i_mbaChip ) : + CenMbaTdCtlrCommon(i_mbaChip), iv_tdState(NO_OP) + {} + + public: // Overloaded functions + + int32_t handleCmdCompleteEvent( STEP_CODE_DATA_STRUCT & io_sc ); + + private: // Overloaded functions + + int32_t initialize(); + + int32_t analyzeCmdComplete( STEP_CODE_DATA_STRUCT & io_sc ); + int32_t analyzeVcmPhase1( STEP_CODE_DATA_STRUCT & io_sc ); + int32_t analyzeVcmPhase2( STEP_CODE_DATA_STRUCT & io_sc ); + int32_t analyzeDsdPhase1( STEP_CODE_DATA_STRUCT & io_sc ); + int32_t analyzeDsdPhase2( STEP_CODE_DATA_STRUCT & io_sc ); + + int32_t startVcmPhase1(); + int32_t startVcmPhase2(); + int32_t startDsdPhase1(); + int32_t startDsdPhase2(); + + bool isInTdMode(); + + private: // functions + + /** + * @brief Checks if ECC errors have occurred during a maintenance command. + * @param o_eccErrorMask Bitwise mask indicating which ECC errors have + * occurred. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + int32_t checkEccErrors( uint8_t & o_eccErrorMask ); + + /** + * @brief Handle UEs during TD analysis. + * @param io_sc Service data collector. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + int32_t handleUE( STEP_CODE_DATA_STRUCT & io_sc ); + + /** + * @brief Handle MCE event during VCM Phase 2 + * @param io_sc Service data collector. + * @note This will update bad bits information in VPD, set callouts, and + * start the DRAM sparing procedure, if possible. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + int32_t handleMCE_VCM2( STEP_CODE_DATA_STRUCT & io_sc ); + + /** + * @brief Handle MCE event during DSD Phase 2 + * @param io_sc Service data collector. + * @note This will update bad bits information in VPD and set callouts. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + int32_t handleMCE_DSD2( STEP_CODE_DATA_STRUCT & io_sc ); + + /** + * @brief Handle cleanup when TD sequence is complete and TD state machine + * will reset. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + int32_t exitTdSequence(); + + /** + * @brief Preforms cleanup tasks that need to be done before starting the + * next maintenance command (i.e. clear scrub counter). + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + int32_t prepareNextCmd(); + + /** + * @brief Sends a message to MDIA that a maintenance command has completed. + * @note If for some reason PRD needed to do some targeted diagnotics and + * on a rank that was not the last rank behind the MBA, this + * function will need to send a message to MDIA indicating that the + * command stopped and MDIA will need to restart the pattern testing + * from the next address to the end of memory. + * @return Non-SUCCESS if an internal function fails, SUCCESS otherwise. + */ + int32_t signalMdiaCmdComplete(); + + private: // instance variables + + /** The targeted diagnostics state variable (see enum TdState). */ + TdState iv_tdState; + + /** Array of functions pointers for TD controller states. This is used to + * determine the next course of action after a maintenance command complete + * attention. + */ + static CMD_COMPLETE_FUNCS cv_cmdCompleteFuncs[MAX_TD_STATE]; + +}; // CenMbaTdCtlr + +} // end namespace PRDF + +#endif // __prdfCenMbaTdCtlr_H + diff --git a/src/usr/diag/prdf/test/prdfTest_Mba.H b/src/usr/diag/prdf/test/prdfTest_Mba.H index eae23077a..7730e88da 100644 --- a/src/usr/diag/prdf/test/prdfTest_Mba.H +++ b/src/usr/diag/prdf/test/prdfTest_Mba.H @@ -62,9 +62,8 @@ class MBAFIR:public CxxTest::TestSuite } } - void TestCheckstop(void) + void DISABLED_TestCheckstop(void) { - /* PRDS_BEGIN("MBAFIR01 Checkstop attention"); PRDS_ERROR_ENTRY("NODE{0}:MEMBUF{4}", PRDF::CHECK_STOP); PRDS_EXPECTED_SIGNATURE("NODE{0}:MEMBUF{4}:MBS{0}:MBA{0}", 0x43f10002); @@ -82,26 +81,7 @@ class MBAFIR:public CxxTest::TestSuite { TS_FAIL("Expected Signature Failed MBAFIR01 Checkstop attention"); } - */ } - void TestSpecialAttention(void) - { - PRDS_BEGIN("MBAFIR01 Special attention"); - PRDS_ERROR_ENTRY("NODE{0}:MEMBUF{4}", PRDF::SPECIAL); - PRDS_EXPECTED_SIGNATURE("NODE{0}:MEMBUF{4}:MBS{0}:MBA{0}", 0x9e8b0000); - // PRDS_EXPECTED_CALLOUT(NONE); - // GLOBAL_RE_FIR - PRDS_SCR_WRITE("NODE{0}:MEMBUF{4}", 0x570F001A, 0x1000000000000000); - // MEM_CHIPLET_CS_FIR[0] Attention from MBAFIR01 - PRDS_SCR_WRITE("NODE{0}:MEMBUF{4}", 0x03040004, 0x8000000000000000); - // set MBAFIR01[0] - PRDS_SCR_WRITE("NODE{0}:MEMBUF{4}:MBS{0}:MBA{0}", 0x03010611, 0x8000000000000000); - PRDS_START_SIM(); - if(!(PRDS_END())) - { - TS_FAIL("Expected Signature Failed MBAFIR01 Special attention"); - } - } }; #endif -- cgit v1.2.1