Exemplo n.º 1
0
/**
 * @brief  Write 1 page of data to the PNOR device
 */
errlHndl_t PnorRP::writeToDevice( uint64_t i_offset,
                                  uint64_t i_chip,
                                  bool i_ecc,
                                  void* i_src )
{
    TRACUCOMP(g_trac_pnor, "PnorRP::writeToDevice> i_offset=%X, i_chip=%d", i_offset, i_chip );
    errlHndl_t l_errhdl = NULL;
    uint8_t* ecc_buffer = NULL;

    do
    {
#ifdef CONFIG_SFC_IS_AST2400
        //@todo RTC:106881 -- Add full write/erase support
        TRACFCOMP(g_trac_pnor, "PnorRP::writeToDevice> Skipping all writes in BMC for now" );
        break;
#endif


        TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL;

        // assume a single page to write
        void* data_to_write = i_src;
        size_t write_size = PAGESIZE;

        // apply ECC to data if needed
        if( i_ecc )
        {
            ecc_buffer = new uint8_t[PAGESIZE_PLUS_ECC];
            PNOR::ECC::injectECC( reinterpret_cast<uint8_t*>(i_src),
                                  PAGESIZE,
                                  reinterpret_cast<uint8_t*>(ecc_buffer) );
            data_to_write = reinterpret_cast<void*>(ecc_buffer);
            write_size = PAGESIZE_PLUS_ECC;
        }

        //no need for mutex since only ever a singleton object
        iv_stats[i_offset/PAGESIZE].numWrites++;

        // write the data out to the PNOR DD
        errlHndl_t l_errhdl = DeviceFW::deviceWrite( pnor_target,
                                       data_to_write,
                                       write_size,
                                       DEVICE_PNOR_ADDRESS(i_chip,i_offset) );
        if( l_errhdl )
        {
            TRACFCOMP(g_trac_pnor, "PnorRP::writeToDevice> Error from device : RC=%X", l_errhdl->reasonCode() );
            break;
        }
    } while(0);

    if( ecc_buffer )
    {
        delete[] ecc_buffer;
    }

    TRACUCOMP(g_trac_pnor, "< PnorRP::writeToDevice" );
    return l_errhdl;
}
Exemplo n.º 2
0
/**
 * @brief  Retrieve 1 page of data from the PNOR device
 */
errlHndl_t PnorRP::readFromDevice( uint64_t i_offset,
                                   uint64_t i_chip,
                                   bool i_ecc,
                                   void* o_dest,
                                   uint64_t& o_fatalError )
{
    TRACUCOMP(g_trac_pnor, "PnorRP::readFromDevice> i_offset=0x%X, i_chip=%d", i_offset, i_chip );
    errlHndl_t l_errhdl = NULL;
    uint8_t* ecc_buffer = NULL;
    o_fatalError = 0;

    do
    {
        TARGETING::Target* pnor_target = TARGETING::MASTER_PROCESSOR_CHIP_TARGET_SENTINEL;

        // assume a single page
        void* data_to_read = o_dest;
        size_t read_size = PAGESIZE;

        // if we need to handle ECC we need to read more than 1 page
        if( i_ecc )
        {
            ecc_buffer = new uint8_t[PAGESIZE_PLUS_ECC]();
            data_to_read = ecc_buffer;
            read_size = PAGESIZE_PLUS_ECC;
        }

        // get the data from the PNOR DD
        l_errhdl = DeviceFW::deviceRead(pnor_target,
                                        data_to_read,
                                        read_size,
                                        DEVICE_PNOR_ADDRESS(i_chip,i_offset) );
        if( l_errhdl )
        {
            TRACFCOMP(g_trac_pnor, "PnorRP::readFromDevice> Error from device : RC=%X", l_errhdl->reasonCode() );
            break;
        }

        // remove the ECC data
        if( i_ecc )
        {
            // remove the ECC and fix the original data if it is broken
            PNOR::ECC::eccStatus ecc_stat =
              PNOR::ECC::removeECC( reinterpret_cast<uint8_t*>(data_to_read),
                                    reinterpret_cast<uint8_t*>(o_dest),
                                    PAGESIZE );

            // create an error if we couldn't correct things
            if( ecc_stat == PNOR::ECC::UNCORRECTABLE )
            {
                TRACFCOMP( g_trac_pnor, "PnorRP::readFromDevice> Uncorrectable ECC error : chip=%d,offset=0x%.X", i_chip, i_offset );

                // Need to shutdown here instead of creating an error log
                //  because the bad page could be critical to the regular
                //  error handling path and cause an infinite loop.
                // Also need to spawn a separate task to do the shutdown
                //  so that the regular PNOR task can service the writes
                //  that happen during shutdown.
                o_fatalError = PNOR::RC_ECC_UE;
                INITSERVICE::doShutdown( PNOR::RC_ECC_UE, true );
            }
            // found an error so we need to fix something
            else if( ecc_stat != PNOR::ECC::CLEAN )
            {
                TRACFCOMP( g_trac_pnor, "PnorRP::readFromDevice> Correctable ECC error : chip=%d, offset=0x%.X", i_chip, i_offset );

                // need to write good data back to PNOR
                l_errhdl = DeviceFW::deviceWrite(pnor_target,
                                       data_to_read,//corrected data
                                       read_size,
                                       DEVICE_PNOR_ADDRESS(i_chip,i_offset) );
                if( l_errhdl )
                {
                    TRACFCOMP(g_trac_pnor, "PnorRP::readFromDevice> Error writing corrected data back to device : RC=%X", l_errhdl->reasonCode() );
                    // we don't need to fail here since we can correct
                    //  it the next time we read it again, instead just
                    //  commit the log here
                    errlCommit(l_errhdl,PNOR_COMP_ID);
                }

                // keep some stats here in case we want them someday
                //no need for mutex since only ever 1 thread accessing this
                iv_stats[i_offset/PAGESIZE].numCEs++;
            }
        }
    } while(0);

    if( ecc_buffer )
    {
        delete[] ecc_buffer;
    }

    TRACUCOMP(g_trac_pnor, "< PnorRP::readFromDevice" );
    return l_errhdl;
}