diff options
Diffstat (limited to 'src/usr/diag/prdf/plat/mem/prdfMemVcm.C')
-rw-r--r-- | src/usr/diag/prdf/plat/mem/prdfMemVcm.C | 214 |
1 files changed, 198 insertions, 16 deletions
diff --git a/src/usr/diag/prdf/plat/mem/prdfMemVcm.C b/src/usr/diag/prdf/plat/mem/prdfMemVcm.C index e0feeb362..5009b6aa6 100644 --- a/src/usr/diag/prdf/plat/mem/prdfMemVcm.C +++ b/src/usr/diag/prdf/plat/mem/prdfMemVcm.C @@ -112,10 +112,169 @@ uint32_t VcmEvent<TYPE_MBA>::rowRepair( STEP_CODE_DATA_STRUCT & io_sc, { #define PRDF_FUNC "[VcmEvent::rowRepair] " + PRDF_ASSERT( iv_rowRepairEnabled ) + uint32_t o_rc = SUCCESS; do { + // get port select + uint8_t l_ps = iv_mark.getSymbol().getPortSlct(); + + // get if the spares are available + bool l_spAvail, l_eccAvail; + o_rc = PlatServices::isSpareAvailable<TYPE_MBA>( iv_chip->getTrgt(), + iv_rank, l_ps, l_spAvail, l_eccAvail ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "isChipMarkOnSpare(0x%08x) failed", + iv_chip->getHuid() ); + break; + } + + // get dimm + TARGETING::TargetHandle_t l_dimm = + PlatServices::getConnectedDimm( iv_chip->getTrgt(), iv_rank, + l_ps ); + + // If scrub stops on first MCE, and static row repair + // not supported or both spare and chip mark used + if ( 1 == iv_mceCount && ( !l_spAvail && !l_eccAvail ) ) + { + // Record bad DQs in VPD - done when verified() + // No need to continue scrubbing, VCM verified, VCM done. + o_done = true; + } + // Else if scrub stops on first MCE and static row repair + // supported + else if ( 1 == iv_mceCount ) + { + MemRowRepair l_rowRepair; + o_rc = getRowRepairData<TYPE_MBA>( l_dimm, iv_rank, l_rowRepair ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getRowRepairData(0x%08x, 0x%02x)", + PlatServices::getHuid(l_dimm), iv_rank.getKey() ); + break; + } + + // If the port, dimm, master rank has previous row repair in VPD + if ( l_rowRepair.isValid() ) + { + // If previous repair for same DRAM + if ( l_rowRepair.getRowRepairDram() == + iv_mark.getSymbol().getDram() ) + { + // Clear previous row repair from VPD + o_rc = clearRowRepairData<TYPE_MBA>( l_dimm, iv_rank ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "clearRowRepairData" + "(0x%08x, 0x%02x) failed", + PlatServices::getHuid(l_dimm), + iv_rank.getKey() ); + break; + } + + // Record bad DQs in VPD - done when verified() + // Signature: "VCM: verified: previous PPR on same DRAM" + io_sc.service_data->setSignature( iv_chip->getHuid(), + PRDFSIG_VcmVerSameDram ); + + // No need to continue scrubbing, VCM verified, VCM done + o_done = true; + } + // Else if previous repair for different DRAM + else + { + // Leave previous row repair in VPD + // Record bad DQs in VPD - done when verified() + // Signature:"VCM: verified: previous PPR on + // different DRAM" + io_sc.service_data->setSignature( iv_chip->getHuid(), + PRDFSIG_VcmVerDiffDram ); + + // No need to continue scrubbing, VCM verified, VCM done + o_done = true; + } + } + // Else if no previous row repair + else + { + // Signature: "VCM: verified: first MCE" + io_sc.service_data->setSignature( iv_chip->getHuid(), + PRDFSIG_VcmVerFirstMce ); + + // Record bad DQs in VPD - done when verified() + // Remember address + MemAddr l_addr; + o_rc = getMemMaintAddr<TYPE_MBA>( iv_chip, + iv_rowRepairFailAddr ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "getMemMaintAddr(0x%08x) failed", + iv_chip->getHuid() ); + break; + } + + // Continue scrub, don't set procedure to done + } + } + // Else if scrub stops on second MCE + else if ( iv_mceCount > 1 ) + { + // Since at least 2 bad rows, don't bother with row repair + // No need to continue scrubbing, VCM verified, VCM done + o_done = true; + + // Signature: "VCM: verified: second MCE" + io_sc.service_data->setSignature( iv_chip->getHuid(), + PRDFSIG_VcmVerSecMce ); + } + + } while (0); + + return o_rc; + + #undef PRDF_FUNC +} + +template<> +uint32_t VcmEvent<TYPE_MBA>::rowRepairEndRank( STEP_CODE_DATA_STRUCT & io_sc ) +{ + #define PRDF_FUNC "[VcmEvent::rowRepairEndRank] " + + PRDF_ASSERT( !iv_canResumeScrub ); + PRDF_ASSERT( iv_rowRepairEnabled ); + PRDF_ASSERT( 0 != iv_mceCount ); + + uint32_t o_rc = SUCCESS; + + do + { + // get dimm + uint8_t l_ps = iv_mark.getSymbol().getPortSlct(); + TARGETING::TargetHandle_t l_dimm = + PlatServices::getConnectedDimm( iv_chip->getTrgt(), iv_rank, + l_ps ); + + // If scrub gets to the end of the master rank with an MCE + // Update VPD with row repair + o_rc = setRowRepairData<TYPE_MBA>( l_dimm, iv_rank, + iv_rowRepairFailAddr, iv_mark.getSymbol().getDram() ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "setRowRepairData(0x%08x, 0x%02x) " + "failed", PlatServices::getHuid(l_dimm), + iv_rank.getKey() ); + break; + } + + // Signature: "VCM: verified: common row fail" + io_sc.service_data->setSignature( iv_chip->getHuid(), + PRDFSIG_VcmVerRowFail ); + + // VCM verified, VCM done } while (0); @@ -196,41 +355,64 @@ uint32_t VcmEvent<TYPE_MBA>::handlePhaseComplete( const uint32_t & i_eccAttns, { if ( i_eccAttns & MAINT_MCE ) { - if ( iv_rowRepairEnabled ) + iv_mceCount++; + + // Only need to call verified on the first mce we hit + if ( 1 == iv_mceCount ) { - o_rc = rowRepair( io_sc, o_done ); + o_rc = verified( io_sc ); if ( SUCCESS != o_rc ) { - PRDF_ERR( PRDF_FUNC "rowRepair() failed on 0x%08x", + PRDF_ERR( PRDF_FUNC "verified() failed on 0x%08x", iv_chip->getHuid() ); break; } } - else + + if ( iv_rowRepairEnabled ) { - o_rc = verified( io_sc ); + o_rc = rowRepair( io_sc, o_done ); if ( SUCCESS != o_rc ) { - PRDF_ERR( PRDF_FUNC "verified() failed on 0x%08x", + PRDF_ERR( PRDF_FUNC "rowRepair() failed on 0x%08x", iv_chip->getHuid() ); break; } - + if ( o_done ) break; + } + else + { o_done = true; // Procedure is complete. + break; } } - else if ( !iv_canResumeScrub ) + + if ( !iv_canResumeScrub ) { - // The chip mark is not verified and the command has reached the - // end of the rank. So this is a false alarm. - o_rc = falseAlarm( io_sc ); - if ( SUCCESS != o_rc ) + // If row repair is enabled, we reached the end of the rank, and + // we got an MCE, we need to apply the row repair. + if ( iv_rowRepairEnabled && 0 != iv_mceCount ) { - PRDF_ERR( PRDF_FUNC "falseAlarm() failed on 0x%08x", - iv_chip->getHuid() ); - break; + o_rc = rowRepairEndRank( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "rowRepairEndRank() failed on " + "0x%08x", iv_chip->getHuid() ); + break; + } + } + else + { + // The chip mark is not verified and the command has reached + // the end of the rank. So this is a false alarm. + o_rc = falseAlarm( io_sc ); + if ( SUCCESS != o_rc ) + { + PRDF_ERR( PRDF_FUNC "falseAlarm() failed on 0x%08x", + iv_chip->getHuid() ); + break; + } } - o_done = true; // Procedure is complete. } } |