/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* $Source: src/import/chips/p9/procedures/hwp/nest/p9_l2_flush.C $ */ /* */ /* OpenPOWER HostBoot Project */ /* */ /* Contributors Listed Below - COPYRIGHT 2015,2019 */ /* [+] 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 */ /// /// @file p9_l2_flush.C /// @brief Flush the P9 L2 cache (FAPI) /// /// *HWP HWP Owner : Benjamin Gass /// *HWP FW Owner : Thi Tran /// *HWP Team : Quad /// *HWP Consumed by : FSP and SBE /// *HWP Level : 3 /// //------------------------------------------------------------------------------ // Includes //------------------------------------------------------------------------------ #include #include #include //------------------------------------------------------------------------------ // Constant definitions //------------------------------------------------------------------------------ // polling constants enum { P9_L2_FLUSH_HW_NS_DELAY = 10000, // unit is nano seconds P9_L2_FLUSH_SIM_CYCLE_DELAY = 12000, // unit is cycles P9_L2_FLUSH_MAX_POLLS = 200 // unit is cycles }; //------------------------------------------------------------------------------ // Function definitions //------------------------------------------------------------------------------ /// See doxygen in header file fapi2::ReturnCode purgeReadyCheck( const fapi2::Target& i_target, const uint64_t i_busyCount, fapi2::buffer& o_prdPurgeCmdReg) { FAPI_DBG("Entering purgeReadyCheck"); uint64_t l_loopCount = 0; do { FAPI_TRY(fapi2::getScom(i_target, EX_PRD_PURGE_CMD_REG, o_prdPurgeCmdReg), "Error from getScom EX_PRD_PURGE_CMD_REG"); // Check the EX_PRD_PURGE_CMD_REG_BUSY bit from scom register if ( !o_prdPurgeCmdReg.getBit(EX_PRD_PURGE_CMD_REG_PRGSM_BUSY)) { // PURGE is done, get out break; } else { l_loopCount++; if (l_loopCount > i_busyCount) { // Time out, exit loop break; } // Delay 10ns for each loop FAPI_TRY(fapi2::delay(P9_L2_FLUSH_HW_NS_DELAY, P9_L2_FLUSH_SIM_CYCLE_DELAY), "Fapi Delay call failed."); } } while (1); // Error out if still busy if (l_loopCount > i_busyCount) { // engine busy, dump status FAPI_DBG("Purge engine busy (reg_busy = %d, busy_on_this = %d," " sm_busy = %d)", o_prdPurgeCmdReg.getBit(), o_prdPurgeCmdReg.getBit(), o_prdPurgeCmdReg.getBit()); FAPI_ASSERT(false, fapi2::P9_PURGE_READY_COMPLETE_TIMEOUT() .set_TARGET(i_target) .set_COUNT_THRESHOLD(i_busyCount) .set_CMD_REG(o_prdPurgeCmdReg), "Previous purge request has not completed prior to issuing L2 flush."); } if (o_prdPurgeCmdReg.getBit()) { FAPI_INF("WARNING: EX_PRD_PURGE_CMD_REG_ERR set prior to L2 flush"); } fapi_try_exit: FAPI_DBG("Exiting purgeReadyCheck - Counter: %d; prdPurgeCmdReg: 0x%.16llX", l_loopCount, o_prdPurgeCmdReg); return fapi2::current_err; } /// See doxygen in header file fapi2::ReturnCode purgeCompleteCheck( const fapi2::Target& i_target, const uint64_t i_busyCount, fapi2::buffer& o_prdPurgeCmdReg) { FAPI_DBG("Entering purgeCompleteCheck"); uint64_t l_loopCount = 0; do { FAPI_TRY(fapi2::getScom(i_target, EX_PRD_PURGE_CMD_REG, o_prdPurgeCmdReg), "Error from getScom EX_PRD_PURGE_CMD_REG"); // Check state of PURGE_CMD_ERR FAPI_ASSERT(!o_prdPurgeCmdReg.getBit(), fapi2::P9_PURGE_CMD_REG_ERR() .set_TARGET(i_target) .set_CMD_REG(o_prdPurgeCmdReg), "Purge failed. EX_PRD_PURGE_CMD_REG_ERR set"); // Check the EX_PRD_PURGE_CMD_REG_BUSY bit from scom register if ( !o_prdPurgeCmdReg.getBit(EX_PRD_PURGE_CMD_REG_BUSY)) { // PURGE is done, get out break; } else { l_loopCount++; if (l_loopCount > i_busyCount) { // Time out, exit loop break; } // Delay 10ns for each loop FAPI_TRY(fapi2::delay(P9_L2_FLUSH_HW_NS_DELAY, P9_L2_FLUSH_SIM_CYCLE_DELAY), "Fapi Delay call failed."); } } while (1); // Error out if still busy if (l_loopCount > i_busyCount) { // engine busy, dump status FAPI_DBG("Purge engine busy (reg_busy = %d, busy_on_this = %d," " sm_busy = %d)", o_prdPurgeCmdReg.getBit(), o_prdPurgeCmdReg.getBit(), o_prdPurgeCmdReg.getBit()); FAPI_ASSERT(false, fapi2::P9_PURGE_COMPLETE_TIMEOUT() .set_TARGET(i_target) .set_COUNT_THRESHOLD(i_busyCount) .set_CMD_REG(o_prdPurgeCmdReg), "Previous purge request has not completed for target"); } fapi_try_exit: FAPI_DBG("Exiting purgeCompleteCheck - Counter: %d; prdPurgeCmdReg: 0x%.16llX", l_loopCount, o_prdPurgeCmdReg); return fapi2::current_err; } /// See doxygen in header file fapi2::ReturnCode setupAndTriggerPrdPurge( const fapi2::Target& i_target, const p9core::purgeData_t& i_purgeData, fapi2::buffer& i_prdPurgeCmdReg) { FAPI_DBG("setupAndTriggerPrdPurge: Enter"); // Start with current CMD reg value fapi2::buffer l_cmdReg = i_prdPurgeCmdReg; // Write PURGE_CMD_TRIGGER bit in Purge Engine Command Register // ensure PURGE_CMD_TYPE/MEM/CGC/BANK are clear to specify flush // of entire cache FAPI_DBG("Write L2 Purge Engine Command Register to initiate cache flush"); l_cmdReg.clearBit(); l_cmdReg.insert(i_purgeData.iv_cmdType); l_cmdReg.insert(i_purgeData.iv_cmdMem); l_cmdReg.insert(i_purgeData.iv_cmdBank); l_cmdReg.insert(i_purgeData.iv_cmdCGC); l_cmdReg.setBit(); FAPI_TRY(fapi2::putScom(i_target, EX_PRD_PURGE_CMD_REG, l_cmdReg), "Error from putScom EX_PRD_PURGE_CMD_REG"); fapi_try_exit: FAPI_DBG("setupAndTriggerPrdPurge: Exit"); return fapi2::current_err; } ///----------------------------------------------------------------------------- /// @brief Utility subroutine to initiate L2 cache flush via purge engine. /// /// @param[in] i_target EX target /// @param[in] i_purgeData Structure having values for MEM, CGC, BANK /// passed by the user /// /// @return FAPI2_RC_SUCCESS if purge operation was started, /// else error code. ///----------------------------------------------------------------------------- fapi2::ReturnCode l2_flush_start( const fapi2::Target& i_target, const p9core::purgeData_t& i_purgeData) { FAPI_DBG("l2_flush_start: Enter"); fapi2::buffer l_cmdReg; // Ensure that purge engine is idle before starting flush // poll Purge Engine status FAPI_TRY(purgeReadyCheck(i_target, P9_L2_FLUSH_MAX_POLLS, l_cmdReg), // 0 = no wait "Error returned from purgeReadyCheck call"); FAPI_TRY(setupAndTriggerPrdPurge(i_target, i_purgeData, l_cmdReg), "Error returned from setupAndTriggerPrdPurge"); fapi_try_exit: FAPI_DBG("l2_flush_start: Exit"); return fapi2::current_err; } //------------------------------------------------------------------------------ // Hardware Procedure // See doxygen in header file. //------------------------------------------------------------------------------ fapi2::ReturnCode p9_l2_flush( const fapi2::Target & i_target, const p9core::purgeData_t& i_purgeData) { fapi2::buffer l_cmdReg; FAPI_DBG("Entering p9_l2_flush: i_purgeData [iv_cmdType: 0x%x] " "[iv_cmdMem : 0x%x] [iv_cmdBank: 0x%x] [iv_cmdCGC : 0x%x]", i_purgeData.iv_cmdType, i_purgeData.iv_cmdMem, i_purgeData.iv_cmdBank, i_purgeData.iv_cmdCGC); // Initiate flush FAPI_TRY(l2_flush_start(i_target, i_purgeData), "Error returned from l2_flush_start()"); // Check for purge complete FAPI_TRY(purgeCompleteCheck(i_target, P9_L2_FLUSH_MAX_POLLS, l_cmdReg), "Error returned from purgeCompleteCheck call"); fapi_try_exit: FAPI_DBG("p9_l2_flush: Exit"); return fapi2::current_err; }