<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/diag/prdf/common/plat/mem/prdfMemEccAnalysis.C $      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

#include <prdfMemEccAnalysis.H>

// Platform includes
#include <prdfMemAddress.H>
#include <prdfMemCaptureData.H>
#include <prdfP9McaDataBundle.H>
#include <prdfP9McaExtraSig.H>

using namespace TARGETING;

namespace PRDF
{

using namespace PlatServices;

namespace MemEcc
{

//------------------------------------------------------------------------------

template<TARGETING::TYPE T, typename D>
uint32_t __handleMemUe( ExtensibleChip * i_chip, const MemAddr & i_addr,
                        UE_TABLE::Type i_type, STEP_CODE_DATA_STRUCT & io_sc )
{
    #define PRDF_FUNC "[MemEcc::__handleMemUe] "

    uint32_t o_rc = SUCCESS;

    MemRank rank = i_addr.getRank();

    // Add the rank to the callout list.
    MemoryMru mm { i_chip->getTrgt(), rank, MemoryMruData::CALLOUT_RANK };
    io_sc.service_data->SetCallout( mm );

    // All memory UEs should be customer viewable.
    io_sc.service_data->setServiceCall();

    // Add entry to UE table.
    D db = static_cast<D>(i_chip->getDataBundle());
    db->iv_ueTable.addEntry( i_type, i_addr );

    #ifdef __HOSTBOOT_RUNTIME

    /* TODO RTC 136129
    // Dynamically deallocate the rank.
    o_rc = MemDealloc::rank<T>( i_chip, rank );
    if ( SUCCESS != o_rc )
    {
        PRDF_ERR( PRDF_FUNC "MemDealloc::rank<T>(0x%08x,m%ds%d) failed",
                  i_chip->getHuid(), rank.getMaster(), rank.getSlave() );
    }
    */

    #endif

    return o_rc;

    #undef PRDF_FUNC
}

template<>
uint32_t handleMemUe<TYPE_MCA>( ExtensibleChip * i_chip, const MemAddr & i_addr,
                                UE_TABLE::Type i_type,
                                STEP_CODE_DATA_STRUCT & io_sc )
{
    #define PRDF_FUNC "[MemEcc::handleMemUe] "

    PRDF_ASSERT( nullptr != i_chip );
    PRDF_ASSERT( TYPE_MCA == i_chip->getType() );

    uint32_t o_rc = SUCCESS;

    do
    {
        // First check to see if this is a side-effect UE.
        SCAN_COMM_REGISTER_CLASS * fir  = i_chip->getRegister("DDRPHYFIR");
        o_rc = fir->Read();
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "Read() failed on DDRPHYFIR: i_chip=0x%08x",
                      i_chip->getHuid() );
            break;
        }

        // Check DDRPHYFIR[54:55,57:59] to determine if this is a side-effect.
        if ( 0 != (fir->GetBitFieldJustified(54,6) & 0x37) )
        {
            // This is a side-effect. Callout the MCA.
            PRDF_TRAC( PRDF_FUNC "Memory UE is side-effect of DDRPHY error" );
            io_sc.service_data->SetCallout( i_chip->getTrgt() );
            io_sc.service_data->setServiceCall();
        }
        else
        {
            // Handle the memory UE.
            o_rc = __handleMemUe<TYPE_MCA,McaDataBundle *>( i_chip, i_addr,
                                                            i_type, io_sc );
            if ( SUCCESS != o_rc )
            {
                PRDF_ERR( PRDF_FUNC "__handleMemUe(0x%08x,%d) failed",
                          i_chip->getHuid(), i_type );
                break;
            }
        }

    } while (0);

    return o_rc;

    #undef PRDF_FUNC
}

/* TODO RTC 157888
template<>
uint32_t handleMemUe<TYPE_MBA>( ExtensibleChip * i_chip, const MemAddr & i_addr,
                                UE_TABLE::Type i_type,
                                STEP_CODE_DATA_STRUCT & io_sc )
{
    PRDF_ASSERT( nullptr != i_chip );
    PRDF_ASSERT( TYPE_MBA == i_chip->getType() );

    return __handleMemUe<TYPE_MBA,CenMbaDataBundle *>( i_chip, i_addr,
                                                       i_type, io_sc );
}
*/

//------------------------------------------------------------------------------

#ifdef __HOSTBOOT_MODULE

template<>
uint32_t maskMemPort<TYPE_MCA>( ExtensibleChip * i_chip )
{
    #define PRDF_FUNC "[MemEcc::maskMemPort<TYPE_MCA>] "

    PRDF_ASSERT( nullptr != i_chip );
    PRDF_ASSERT( TYPE_MCA == i_chip->getType() );

    uint32_t o_rc = SUCCESS;

    do
    {
        // Mask all FIRs on the port.
        SCAN_COMM_REGISTER_CLASS * c = i_chip->getRegister("MCACALFIR_MASK_OR");
        SCAN_COMM_REGISTER_CLASS * d = i_chip->getRegister("DDRPHYFIR_MASK_OR");
        SCAN_COMM_REGISTER_CLASS * e = i_chip->getRegister("MCAECCFIR_MASK_OR");

        c->setAllBits(); d->setAllBits(); e->setAllBits();

        o_rc = c->Write() | d->Write() | e->Write();
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "Write() failed on 0x%08x", i_chip->getHuid() );
            break;
        }

        #ifdef __HOSTBOOT_RUNTIME

        /* TODO RTC 136129
        // Dynamically deallocate the port.
        o_rc = MemDealloc::port<TYPE_MCA>( i_chip );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "MemDealloc::port<TYPE_MCA>(0x%08x) failed",
                      i_chip->getHuid() );
        }
        */

        #endif

    } while (0);

    return o_rc;

    #undef PRDF_FUNC
}

#endif // __HOSTBOOT_MODULE

//------------------------------------------------------------------------------

#ifdef __HOSTBOOT_RUNTIME

template<>
uint32_t iuePortFail<TYPE_MCA>( ExtensibleChip * i_chip,
                                STEP_CODE_DATA_STRUCT & io_sc )
{
    #define PRDF_FUNC "[MemEcc::iuePortFail<TYPE_MCA>] "

    PRDF_ASSERT( nullptr != i_chip );
    PRDF_ASSERT( TYPE_MCA == i_chip->getType() );

    uint32_t o_rc = SUCCESS;

    McaDataBundle * db = getMcaDataBundle( i_chip );

    // Loop through all our thresholds
    for ( auto & th : db->iv_iueTh )
    {
        // If threshold reached
        if ( th.second.thReached(io_sc) )
        {
            // trigger a port fail
            // set FARB0[59] - MBA_FARB0Q_CFG_INJECT_PARITY_ERR_CONSTANT and
            //     FARB0[40] - MBA_FARB0Q_CFG_INJECT_PARITY_ERR_ADDR5
            SCAN_COMM_REGISTER_CLASS * farb0 = i_chip->getRegister("FARB0");

            o_rc = farb0->Read();
            if ( SUCCESS != o_rc )
            {
                PRDF_ERR( PRDF_FUNC "Read() FARB0 failed: i_chip=0x%08x",
                        i_chip->getHuid() );
                continue;
            }

            farb0->SetBit(59);
            farb0->SetBit(40);

            o_rc = farb0->Write();
            if ( SUCCESS != o_rc )
            {
                PRDF_ERR( PRDF_FUNC "Write() FARB0 failed: i_chip=0x%08x",
                        i_chip->getHuid() );
                continue;
            }

            // reset thresholds to prevent issuing multiple port failures on
            // the same port
            for ( auto & resetTh : db->iv_iueTh )
            {
                resetTh.second.reset();
            }
            break;
        }
    }

    return o_rc;

    #undef PRDF_FUNC
}

#endif // __HOSTBOOT_RUNTIME

//------------------------------------------------------------------------------

#ifdef __HOSTBOOT_MODULE

template<TARGETING::TYPE T, typename D>
uint32_t addVcmEvent( ExtensibleChip * i_chip, const MemRank & i_rank,
                      const MemMark & i_mark, STEP_CODE_DATA_STRUCT & io_sc )
{
    PRDF_ASSERT( T == i_chip->getType() );

    D db = static_cast<D>(i_chip->getDataBundle());

    TdEntry * entry = new VcmEvent<T>( i_chip, i_rank, i_mark );

    return db->getTdCtlr()->handleTdEvent( io_sc, entry );
}

template
uint32_t addVcmEvent<TYPE_MCA, McaDataBundle *>( ExtensibleChip * i_chip,
                                                 const MemRank & i_rank,
                                                 const MemMark & i_mark,
                                                 STEP_CODE_DATA_STRUCT & io_sc);

#endif

//------------------------------------------------------------------------------

#ifdef __HOSTBOOT_MODULE

template<TARGETING::TYPE T, typename D>
uint32_t addTpsEvent( ExtensibleChip * i_chip, const MemRank & i_rank,
                      STEP_CODE_DATA_STRUCT & io_sc, bool i_banTps )
{
    PRDF_ASSERT( T == i_chip->getType() );

    D db = static_cast<D>(i_chip->getDataBundle());

    TdEntry * entry = new TpsEvent<T>( i_chip, i_rank, i_banTps );

    return db->getTdCtlr()->handleTdEvent( io_sc, entry );
}

template
uint32_t addTpsEvent<TYPE_MCA, McaDataBundle *>( ExtensibleChip * i_chip,
                                                 const MemRank & i_rank,
                                                 STEP_CODE_DATA_STRUCT & io_sc,
                                                 bool i_banTps );

#endif

//------------------------------------------------------------------------------

template<TARGETING::TYPE T, typename D>
uint32_t analyzeFetchMpe( ExtensibleChip * i_chip, const MemRank & i_rank,
                          STEP_CODE_DATA_STRUCT & io_sc )
{
    #define PRDF_FUNC "[MemEcc::analyzeFetchMpe] "

    PRDF_ASSERT( T == i_chip->getType() );

    uint32_t o_rc = SUCCESS;

    #ifndef __HOSTBOOT_RUNTIME // IPL

    PRDF_ERR( PRDF_FUNC "Mainline MPE attns should be masked during IPL" );
    PRDF_ASSERT(false); // HWP bug.

    #else // runtime

    do
    {
        // Get the address of the failure.
        MemAddr addr;
        o_rc = getMemReadAddr<T>( i_chip, MemAddr::READ_MPE_ADDR, addr );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "getMemReadAddr(0x%08x, READ_MPE_ADDR) failed",
                      i_chip->getHuid() );
            break;
        }

        // There is only one address register and it will contain the latest
        // chip mark placed. So it is possible this address will be out of sync
        // with the rank that reported the attention. In this case, we will
        // simply fake an address with the correct rank and move on.
        if ( i_rank != addr.getRank() )
        {
            addr = MemAddr ( i_rank, 0, 0, 0 );
        }

        // Add address to UE table.
        D db = static_cast<D>(i_chip->getDataBundle());
        db->iv_ueTable.addEntry( UE_TABLE::FETCH_MPE, addr );

        // Read the chip mark from markstore.
        MemMark chipMark;
        o_rc = MarkStore::readChipMark<T>( i_chip, i_rank, chipMark );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "readChipMark<T>(0x%08x,%d) failed",
                      i_chip->getHuid(), i_rank.getMaster() );
            break;
        }

        // If the chip mark is not valid, then somehow the chip mark was placed
        // on a rank other than the rank with the attention. This would most
        // likely be a code bug.
        PRDF_ASSERT( chipMark.isValid() );

        // Add the mark to the callout list.
        MemoryMru mm { i_chip->getTrgt(), i_rank, chipMark.getSymbol() };
        io_sc.service_data->SetCallout( mm );

        // Add a VCM request to the TD queue.
        o_rc = addVcmEvent<T,D>( i_chip, i_rank, chipMark, io_sc );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "addVcmEvent() failed: i_chip=0x%08x "
                      "i_rank=%d,%d", i_chip->getHuid(), i_rank.getMaster(),
                      i_rank.getSlave() );
            break;
        }

    } while (0);

    // Add ECC capture data for FFDC.
    MemCaptureData::addEccData<T>( i_chip, io_sc );

    #endif // __HOSTBOOT_RUNTIME

    return o_rc;

    #undef PRDF_FUNC
}

// To resolve template linker errors.
template
uint32_t analyzeFetchMpe<TYPE_MCA, McaDataBundle *>( ExtensibleChip * i_chip,
                                                const MemRank & i_rank,
                                                STEP_CODE_DATA_STRUCT & io_sc );

//------------------------------------------------------------------------------

template<TARGETING::TYPE T, typename D>
uint32_t handleMemCe( ExtensibleChip * i_chip, const MemAddr & i_addr,
                      const MemSymbol & i_symbol, bool & o_doTps,
                      STEP_CODE_DATA_STRUCT & io_sc, bool i_isHard )
{
    #define PRDF_FUNC "[MemEcc::handleMemCe] "

    uint32_t o_rc = SUCCESS;

    o_doTps = i_isHard; // Do TPS on every hard CE.

    TargetHandle_t trgt = i_chip->getTrgt();
    MemRank        rank = i_addr.getRank();

    // Add the DIMM to the callout list
    MemoryMru memmru ( trgt, rank, i_symbol );
    io_sc.service_data->SetCallout( memmru, MRU_MEDA );
<commit_msg>PRD: do TPS only on threshold, not for all hard CEs<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/diag/prdf/common/plat/mem/prdfMemEccAnalysis.C $      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

#include <prdfMemEccAnalysis.H>

// Platform includes
#include <prdfMemAddress.H>
#include <prdfMemCaptureData.H>
#include <prdfP9McaDataBundle.H>
#include <prdfP9McaExtraSig.H>

using namespace TARGETING;

namespace PRDF
{

using namespace PlatServices;

namespace MemEcc
{

//------------------------------------------------------------------------------

template<TARGETING::TYPE T, typename D>
uint32_t __handleMemUe( ExtensibleChip * i_chip, const MemAddr & i_addr,
                        UE_TABLE::Type i_type, STEP_CODE_DATA_STRUCT & io_sc )
{
    #define PRDF_FUNC "[MemEcc::__handleMemUe] "

    uint32_t o_rc = SUCCESS;

    MemRank rank = i_addr.getRank();

    // Add the rank to the callout list.
    MemoryMru mm { i_chip->getTrgt(), rank, MemoryMruData::CALLOUT_RANK };
    io_sc.service_data->SetCallout( mm );

    // All memory UEs should be customer viewable.
    io_sc.service_data->setServiceCall();

    // Add entry to UE table.
    D db = static_cast<D>(i_chip->getDataBundle());
    db->iv_ueTable.addEntry( i_type, i_addr );

    #ifdef __HOSTBOOT_RUNTIME

    /* TODO RTC 136129
    // Dynamically deallocate the rank.
    o_rc = MemDealloc::rank<T>( i_chip, rank );
    if ( SUCCESS != o_rc )
    {
        PRDF_ERR( PRDF_FUNC "MemDealloc::rank<T>(0x%08x,m%ds%d) failed",
                  i_chip->getHuid(), rank.getMaster(), rank.getSlave() );
    }
    */

    #endif

    return o_rc;

    #undef PRDF_FUNC
}

template<>
uint32_t handleMemUe<TYPE_MCA>( ExtensibleChip * i_chip, const MemAddr & i_addr,
                                UE_TABLE::Type i_type,
                                STEP_CODE_DATA_STRUCT & io_sc )
{
    #define PRDF_FUNC "[MemEcc::handleMemUe] "

    PRDF_ASSERT( nullptr != i_chip );
    PRDF_ASSERT( TYPE_MCA == i_chip->getType() );

    uint32_t o_rc = SUCCESS;

    do
    {
        // First check to see if this is a side-effect UE.
        SCAN_COMM_REGISTER_CLASS * fir  = i_chip->getRegister("DDRPHYFIR");
        o_rc = fir->Read();
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "Read() failed on DDRPHYFIR: i_chip=0x%08x",
                      i_chip->getHuid() );
            break;
        }

        // Check DDRPHYFIR[54:55,57:59] to determine if this is a side-effect.
        if ( 0 != (fir->GetBitFieldJustified(54,6) & 0x37) )
        {
            // This is a side-effect. Callout the MCA.
            PRDF_TRAC( PRDF_FUNC "Memory UE is side-effect of DDRPHY error" );
            io_sc.service_data->SetCallout( i_chip->getTrgt() );
            io_sc.service_data->setServiceCall();
        }
        else
        {
            // Handle the memory UE.
            o_rc = __handleMemUe<TYPE_MCA,McaDataBundle *>( i_chip, i_addr,
                                                            i_type, io_sc );
            if ( SUCCESS != o_rc )
            {
                PRDF_ERR( PRDF_FUNC "__handleMemUe(0x%08x,%d) failed",
                          i_chip->getHuid(), i_type );
                break;
            }
        }

    } while (0);

    return o_rc;

    #undef PRDF_FUNC
}

/* TODO RTC 157888
template<>
uint32_t handleMemUe<TYPE_MBA>( ExtensibleChip * i_chip, const MemAddr & i_addr,
                                UE_TABLE::Type i_type,
                                STEP_CODE_DATA_STRUCT & io_sc )
{
    PRDF_ASSERT( nullptr != i_chip );
    PRDF_ASSERT( TYPE_MBA == i_chip->getType() );

    return __handleMemUe<TYPE_MBA,CenMbaDataBundle *>( i_chip, i_addr,
                                                       i_type, io_sc );
}
*/

//------------------------------------------------------------------------------

#ifdef __HOSTBOOT_MODULE

template<>
uint32_t maskMemPort<TYPE_MCA>( ExtensibleChip * i_chip )
{
    #define PRDF_FUNC "[MemEcc::maskMemPort<TYPE_MCA>] "

    PRDF_ASSERT( nullptr != i_chip );
    PRDF_ASSERT( TYPE_MCA == i_chip->getType() );

    uint32_t o_rc = SUCCESS;

    do
    {
        // Mask all FIRs on the port.
        SCAN_COMM_REGISTER_CLASS * c = i_chip->getRegister("MCACALFIR_MASK_OR");
        SCAN_COMM_REGISTER_CLASS * d = i_chip->getRegister("DDRPHYFIR_MASK_OR");
        SCAN_COMM_REGISTER_CLASS * e = i_chip->getRegister("MCAECCFIR_MASK_OR");

        c->setAllBits(); d->setAllBits(); e->setAllBits();

        o_rc = c->Write() | d->Write() | e->Write();
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "Write() failed on 0x%08x", i_chip->getHuid() );
            break;
        }

        #ifdef __HOSTBOOT_RUNTIME

        /* TODO RTC 136129
        // Dynamically deallocate the port.
        o_rc = MemDealloc::port<TYPE_MCA>( i_chip );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "MemDealloc::port<TYPE_MCA>(0x%08x) failed",
                      i_chip->getHuid() );
        }
        */

        #endif

    } while (0);

    return o_rc;

    #undef PRDF_FUNC
}

#endif // __HOSTBOOT_MODULE

//------------------------------------------------------------------------------

#ifdef __HOSTBOOT_RUNTIME

template<>
uint32_t iuePortFail<TYPE_MCA>( ExtensibleChip * i_chip,
                                STEP_CODE_DATA_STRUCT & io_sc )
{
    #define PRDF_FUNC "[MemEcc::iuePortFail<TYPE_MCA>] "

    PRDF_ASSERT( nullptr != i_chip );
    PRDF_ASSERT( TYPE_MCA == i_chip->getType() );

    uint32_t o_rc = SUCCESS;

    McaDataBundle * db = getMcaDataBundle( i_chip );

    // Loop through all our thresholds
    for ( auto & th : db->iv_iueTh )
    {
        // If threshold reached
        if ( th.second.thReached(io_sc) )
        {
            // trigger a port fail
            // set FARB0[59] - MBA_FARB0Q_CFG_INJECT_PARITY_ERR_CONSTANT and
            //     FARB0[40] - MBA_FARB0Q_CFG_INJECT_PARITY_ERR_ADDR5
            SCAN_COMM_REGISTER_CLASS * farb0 = i_chip->getRegister("FARB0");

            o_rc = farb0->Read();
            if ( SUCCESS != o_rc )
            {
                PRDF_ERR( PRDF_FUNC "Read() FARB0 failed: i_chip=0x%08x",
                        i_chip->getHuid() );
                continue;
            }

            farb0->SetBit(59);
            farb0->SetBit(40);

            o_rc = farb0->Write();
            if ( SUCCESS != o_rc )
            {
                PRDF_ERR( PRDF_FUNC "Write() FARB0 failed: i_chip=0x%08x",
                        i_chip->getHuid() );
                continue;
            }

            // reset thresholds to prevent issuing multiple port failures on
            // the same port
            for ( auto & resetTh : db->iv_iueTh )
            {
                resetTh.second.reset();
            }
            break;
        }
    }

    return o_rc;

    #undef PRDF_FUNC
}

#endif // __HOSTBOOT_RUNTIME

//------------------------------------------------------------------------------

#ifdef __HOSTBOOT_MODULE

template<TARGETING::TYPE T, typename D>
uint32_t addVcmEvent( ExtensibleChip * i_chip, const MemRank & i_rank,
                      const MemMark & i_mark, STEP_CODE_DATA_STRUCT & io_sc )
{
    PRDF_ASSERT( T == i_chip->getType() );

    D db = static_cast<D>(i_chip->getDataBundle());

    TdEntry * entry = new VcmEvent<T>( i_chip, i_rank, i_mark );

    return db->getTdCtlr()->handleTdEvent( io_sc, entry );
}

template
uint32_t addVcmEvent<TYPE_MCA, McaDataBundle *>( ExtensibleChip * i_chip,
                                                 const MemRank & i_rank,
                                                 const MemMark & i_mark,
                                                 STEP_CODE_DATA_STRUCT & io_sc);

#endif

//------------------------------------------------------------------------------

#ifdef __HOSTBOOT_MODULE

template<TARGETING::TYPE T, typename D>
uint32_t addTpsEvent( ExtensibleChip * i_chip, const MemRank & i_rank,
                      STEP_CODE_DATA_STRUCT & io_sc, bool i_banTps )
{
    PRDF_ASSERT( T == i_chip->getType() );

    D db = static_cast<D>(i_chip->getDataBundle());

    TdEntry * entry = new TpsEvent<T>( i_chip, i_rank, i_banTps );

    return db->getTdCtlr()->handleTdEvent( io_sc, entry );
}

template
uint32_t addTpsEvent<TYPE_MCA, McaDataBundle *>( ExtensibleChip * i_chip,
                                                 const MemRank & i_rank,
                                                 STEP_CODE_DATA_STRUCT & io_sc,
                                                 bool i_banTps );

#endif

//------------------------------------------------------------------------------

template<TARGETING::TYPE T, typename D>
uint32_t analyzeFetchMpe( ExtensibleChip * i_chip, const MemRank & i_rank,
                          STEP_CODE_DATA_STRUCT & io_sc )
{
    #define PRDF_FUNC "[MemEcc::analyzeFetchMpe] "

    PRDF_ASSERT( T == i_chip->getType() );

    uint32_t o_rc = SUCCESS;

    #ifndef __HOSTBOOT_RUNTIME // IPL

    PRDF_ERR( PRDF_FUNC "Mainline MPE attns should be masked during IPL" );
    PRDF_ASSERT(false); // HWP bug.

    #else // runtime

    do
    {
        // Get the address of the failure.
        MemAddr addr;
        o_rc = getMemReadAddr<T>( i_chip, MemAddr::READ_MPE_ADDR, addr );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "getMemReadAddr(0x%08x, READ_MPE_ADDR) failed",
                      i_chip->getHuid() );
            break;
        }

        // There is only one address register and it will contain the latest
        // chip mark placed. So it is possible this address will be out of sync
        // with the rank that reported the attention. In this case, we will
        // simply fake an address with the correct rank and move on.
        if ( i_rank != addr.getRank() )
        {
            addr = MemAddr ( i_rank, 0, 0, 0 );
        }

        // Add address to UE table.
        D db = static_cast<D>(i_chip->getDataBundle());
        db->iv_ueTable.addEntry( UE_TABLE::FETCH_MPE, addr );

        // Read the chip mark from markstore.
        MemMark chipMark;
        o_rc = MarkStore::readChipMark<T>( i_chip, i_rank, chipMark );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "readChipMark<T>(0x%08x,%d) failed",
                      i_chip->getHuid(), i_rank.getMaster() );
            break;
        }

        // If the chip mark is not valid, then somehow the chip mark was placed
        // on a rank other than the rank with the attention. This would most
        // likely be a code bug.
        PRDF_ASSERT( chipMark.isValid() );

        // Add the mark to the callout list.
        MemoryMru mm { i_chip->getTrgt(), i_rank, chipMark.getSymbol() };
        io_sc.service_data->SetCallout( mm );

        // Add a VCM request to the TD queue.
        o_rc = addVcmEvent<T,D>( i_chip, i_rank, chipMark, io_sc );
        if ( SUCCESS != o_rc )
        {
            PRDF_ERR( PRDF_FUNC "addVcmEvent() failed: i_chip=0x%08x "
                      "i_rank=%d,%d", i_chip->getHuid(), i_rank.getMaster(),
                      i_rank.getSlave() );
            break;
        }

    } while (0);

    // Add ECC capture data for FFDC.
    MemCaptureData::addEccData<T>( i_chip, io_sc );

    #endif // __HOSTBOOT_RUNTIME

    return o_rc;

    #undef PRDF_FUNC
}

// To resolve template linker errors.
template
uint32_t analyzeFetchMpe<TYPE_MCA, McaDataBundle *>( ExtensibleChip * i_chip,
                                                const MemRank & i_rank,
                                                STEP_CODE_DATA_STRUCT & io_sc );

//------------------------------------------------------------------------------

template<TARGETING::TYPE T, typename D>
uint32_t handleMemCe( ExtensibleChip * i_chip, const MemAddr & i_addr,
                      const MemSymbol & i_symbol, bool & o_doTps,
                      STEP_CODE_DATA_STRUCT & io_sc, bool i_isHard )
{
    #define PRDF_FUNC "[MemEcc::handleMemCe] "

    uint32_t o_rc = SUCCESS;

    o_doTps = false;

    TargetHandle_t trgt = i_chip->getTrgt();
    MemRank        rank = i_addr.getRank();

    // Add the DIMM to the callout list
    MemoryMru memmru ( trgt, rank, i_symbol );
    io_sc.service_data->SetCallout( memmru, MRU_MEDA );

{'fraction_non_alphanumeric': 0.136362014203633, 'fraction_numerical': 0.009992505620784412, 'mean_word_length': 1.4509752470917519, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 195, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 102, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5896742', 'n_tokens_mistral': 8610, 'n_tokens_neox': 8215, 'n_words': 1902}