diff options
Diffstat (limited to 'src/sbefw/core/sbecmdcntrldmt.C')
-rw-r--r-- | src/sbefw/core/sbecmdcntrldmt.C | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/src/sbefw/core/sbecmdcntrldmt.C b/src/sbefw/core/sbecmdcntrldmt.C new file mode 100644 index 00000000..4fac1d59 --- /dev/null +++ b/src/sbefw/core/sbecmdcntrldmt.C @@ -0,0 +1,367 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/sbefw/core/sbecmdcntrldmt.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* */ +/* */ +/* 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: sbe/sbefw/sbecmdcntrldmt.C + * + * @brief This file contains the Core State Control Messages + * + */ + +#include "sbecmdcntrldmt.H" +#include "sbetrace.H" +#include "sbe_build_info.H" +#include "sbeHostMsg.H" +#include "sbeHostUtils.H" +#include "sberegaccess.H" +#include "sbestates.H" +#include "sbe_sp_intf.H" +#include "fapi2.H" +#include "plat_hw_access.H" +#include "p9_sbe_check_master_stop15.H" +#ifdef DD2 +#include "p9_collect_deadman_ffdc.H" +#endif +#include "p9_perv_scom_addresses.H" +#include "p9_block_wakeup_intr.H" +#include "sbeTimerSvc.H" +#include "sbeglobals.H" + +using namespace fapi2; + +#ifdef SEEPROM_IMAGE +// Using Function pointer to force long call +p9_sbe_check_master_stop15_FP_t p9_sbe_check_master_stop15_hwp = + &p9_sbe_check_master_stop15; +p9_block_wakeup_intr_FP_t p9_block_wakeup_intr_hwp = + &p9_block_wakeup_intr; +#endif + +//////////////////////////////////////////////////////////////////// +//Static initialization of the Dmt Pk timer +static timerService g_sbe_pk_dmt_timer; + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +void sbeDmtPkExpiryCallback(void *) +{ + #define SBE_FUNC "sbeDmtPkExpiryCallback" + SBE_INFO (SBE_FUNC "DMT Callback Timer has expired..Checkstop the system"); + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_DUMP_FAILURE_EVENT); + + // check stop the system + plat_target_handle_t l_hndl; + fapiRc = putscom_abs_wrap(&l_hndl, PERV_N3_LOCAL_FIR_OR, + ((uint64_t)1 << N3_FIR_CORE_CHECKSTOP_BIT)); + if(fapiRc != FAPI2_RC_SUCCESS) + { + // Scom failed + SBE_ERROR (SBE_FUNC "PutScom failed: REG PERV_N3_LOCAL_FIR"); + pk_halt(); + } + + (void)SbeRegAccess::theSbeRegAccess().updateAsyncFFDCBit(true); + #undef SBE_FUNC +} + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +uint32_t sbeCollectDeadmanFfdc (void) +{ + #define SBE_FUNC "sbeCollectDeadmanFfdc" + uint32_t rc = SBE_SEC_OPERATION_SUCCESSFUL; + + // trace the saved aync ffdc reason and SBE state as info for debug + SBE_INFO (SBE_FUNC "FFDC Reason: 0x%08X States - Curr: %d Prev: %d", + SBE_GLOBAL->asyncFfdcRC, + SbeRegAccess::theSbeRegAccess().getSbeState(), + SbeRegAccess::theSbeRegAccess().getSbePrevState()); + + fapi2::Target<fapi2::TARGET_TYPE_CORE> coreTarget ( + plat_getTargetHandleByChipletNumber <fapi2::TARGET_TYPE_CORE> ( + (SBE_GLOBAL->deadmanCore + CORE_CHIPLET_OFFSET) )); + +#ifdef DD2 + ReturnCode fapiRc = FAPI2_RC_SUCCESS; + // p9_collect_deadman_ffdc collects the required ffdc into the fapi rc + // which will be available in the SBE Global HWP FFDC region + SBE_EXEC_HWP ( fapiRc, + p9_collect_deadman_ffdc, + coreTarget, + SBE_GLOBAL->asyncFfdcRC ); +#endif + + return rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +uint32_t sbeStartCntlDmt() +{ + #define SBE_FUNC "sbeStartCntlDmt" + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + + do + { + // Fetch the Timer Value and Start a Pk Timer + uint64_t l_timerVal = 0; + l_rc = sbeReadPsu2SbeMbxReg(SBE_HOST_PSU_MBOX_REG1, + (sizeof(l_timerVal)/sizeof(uint64_t)), + &l_timerVal, true ); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC" Failed to extract SBE_HOST_PSU_MBOX_REG1"); + break; + } + + l_rc = g_sbe_pk_dmt_timer.startTimer( (uint32_t )l_timerVal, + (PkTimerCallback)&sbeDmtPkExpiryCallback); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus(SBE_PRI_INTERNAL_ERROR, l_rc); + SBE_ERROR(SBE_FUNC" g_sbe_pk_dmt_timer.startTimer failed"); + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + } + + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, l_fapiRc, l_rc); + + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC" Failed to send response to Hostboot "); + break; + } + + // Set DMT State + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_DMT_ENTER_EVENT); + // To start, assume no errors will hit when starting DMT and hence + // default to potential timeout in stopping DMT for FFDC + SBE_GLOBAL->asyncFfdcRC = RC_CHECK_MASTER_STOP15_DEADMAN_TIMEOUT; + + Target<TARGET_TYPE_PROC_CHIP > l_procTgt = plat_getChipTarget(); + // Fetch the Master EX + uint8_t exId = 0; + uint8_t fuseMode = 0; + FAPI_ATTR_GET(fapi2::ATTR_MASTER_EX,l_procTgt,exId); + FAPI_ATTR_GET(ATTR_FUSED_CORE_MODE, Target<TARGET_TYPE_SYSTEM>(), fuseMode); + fapi2::Target<fapi2::TARGET_TYPE_EX > + exTgt(plat_getTargetHandleByInstance<fapi2::TARGET_TYPE_EX>(exId)); + + bool hwpFailed = false; + // Initialise both cores with fapi2::RC_CHECK_MASTER_STOP15_PENDING + uint32_t rcFapi[2] = {RC_CHECK_MASTER_STOP15_PENDING}; + + // Call HWP p9_sbe_check_master_stop15 in a loop as long as the timer is + // active and HWP returns RC_CHECK_MASTER_STOP15_PENDING + do + { + uint8_t coreCnt = 0; + + for (auto &coreTgt : exTgt.getChildren<fapi2::TARGET_TYPE_CORE>()) + { + // Skip calling on core that already entered stop15 + if (rcFapi[coreCnt] == RC_CHECK_MASTER_STOP15_PENDING) + { + SBE_GLOBAL->deadmanCore = coreTgt.get().getTargetInstance(); + // Core0 is assumed to be the master core + SBE_INFO ( SBE_FUNC + "Executing p9_sbe_check_master_stop15_hwp for" + " Core[%d]", SBE_GLOBAL->deadmanCore ); + SBE_EXEC_HWP ( l_fapiRc, + p9_sbe_check_master_stop15_hwp, + coreTgt); + rcFapi[coreCnt++] = l_fapiRc; + + if (! ((FAPI2_RC_SUCCESS == l_fapiRc) || + (RC_CHECK_MASTER_STOP15_PENDING == l_fapiRc)) ) + { + hwpFailed = true; + // Mark the failure point .. + SBE_GLOBAL->asyncFfdcRC = + RC_CHECK_MASTER_STOP15_INVALID_STATE; + SBE_ERROR ( SBE_FUNC" p9_sbe_check_master_stop15 failed" + "on core[%d]", SBE_GLOBAL->deadmanCore ); + break; + } + + if (!fuseMode) + { // mark odd core as succeeded & exit the core loop + rcFapi[coreCnt] = FAPI2_RC_SUCCESS; + break; + } + } + } // Core loop for check master stop 15 + + // Either Core failed or Both Cores succeeded + if ( hwpFailed || ((FAPI2_RC_SUCCESS == rcFapi[0]) && + (FAPI2_RC_SUCCESS == rcFapi[1]))) + { // Exit timer loop + break; + } + + // Wait if either or both cores are pending to enter stop 15 + // and no error on either cores + pk_sleep(PK_MILLISECONDS(SBE_DMT_SLEEP_INTERVAL)); + + // loop back only if timer is still active + } while (g_sbe_pk_dmt_timer.isActive()); + + if (hwpFailed) + { // exit the do .. while (0) outermost loop + break; + } + + // Both cores entered stop 15 successfully, now unblock interrupts + for (auto coreTgt : exTgt.getChildren<fapi2::TARGET_TYPE_CORE>()) + { + SBE_GLOBAL->deadmanCore = coreTgt.get().getTargetInstance(); + SBE_INFO(SBE_FUNC "Executing p9_block_wakeup_intr_hwp for Core[%d]", + SBE_GLOBAL->deadmanCore); + SBE_EXEC_HWP(l_fapiRc, p9_block_wakeup_intr_hwp, coreTgt, + p9pmblockwkup::CLEAR); + if (l_fapiRc) + { + // Mark the failure point .. SBE waits for DMT timer to expire + SBE_GLOBAL->asyncFfdcRC = RC_BLOCK_WAKEUP_INTR_CHECK_FAIL; + SBE_ERROR(SBE_FUNC" p9_block_wakeup_intr failed for " + "Core[%d]", SBE_GLOBAL->deadmanCore); + + break; + } + // If Success for the First core & it's a Fuse core then + // continue here for the Second core then go on to press the + // Door Bell + if(!fuseMode) + { + break; + } + } + + // Break out for the p9_block_wakeup_intr failure above + // Dont press the Door bell + if(l_fapiRc) + { + break; + } + + // Entered stop15 and unblocked interrupts .. + // Indicate the Host via Bit SBE_SBE2PSU_DOORBELL_SET_BIT2 + // that Stop15 exit + l_rc = sbeSetSbe2PsuDbBitX(SBE_SBE2PSU_DOORBELL_SET_BIT2); + if(l_rc) + { + SBE_ERROR(SBE_FUNC " Failed to Write " + "SBE_SBE2PSU_DOORBELL_SET_BIT2"); + } + } while(0); // Outer loop + + return l_rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +uint32_t sbeStopCntlDmt() +{ + #define SBE_FUNC "sbeStopCntlDmt " + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + uint32_t l_fapiRc = FAPI2_RC_SUCCESS; + + do + { + SBE_INFO(SBE_FUNC "Stop Timer."); + l_rc = g_sbe_pk_dmt_timer.stopTimer( ); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_GLOBAL->sbeSbe2PsuRespHdr.setStatus ( SBE_PRI_INTERNAL_ERROR, + l_rc ); + SBE_ERROR(SBE_FUNC"g_sbe_pk_dmt_timer.stopTimer failed"); + l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + break; + } + + // Reset Async FFDC RC to default success + SBE_GLOBAL->asyncFfdcRC = FAPI2_RC_SUCCESS; + // Set Runtime State + (void)SbeRegAccess::theSbeRegAccess().stateTransition( + SBE_DMT_COMP_EVENT); + }while(0); + // Send the response + sbePSUSendResponse(SBE_GLOBAL->sbeSbe2PsuRespHdr, l_fapiRc, l_rc); + + return l_rc; + #undef SBE_FUNC +} + +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// +uint32_t sbeControlDeadmanTimer (uint8_t *i_pArg) +{ + #define SBE_FUNC "sbeControlDeadmanTimer" + SBE_ENTER(SBE_FUNC); + uint32_t l_rc = SBE_SEC_OPERATION_SUCCESSFUL; + + do + { + if(SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_START_DMT) + { + l_rc = sbeStartCntlDmt(); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC " Failed sbeStartCntlDmt"); + } + break; + } + // Send Ack to Host via SBE_SBE2PSU_DOORBELL_SET_BIT1 + // This util method will check internally on the mbox0 register if ACK + // is requested. + l_rc = sbeAcknowledgeHost(); + if(l_rc) + { + SBE_ERROR(SBE_FUNC " Failed to Sent Ack to Host over " + "SBE_SBE2PSU_DOORBELL_SET_BIT1"); + break; + } + + if(SBE_GLOBAL->sbePsu2SbeCmdReqHdr.flags & SBE_PSU_FLAGS_STOP_DMT) + { + l_rc = sbeStopCntlDmt(); + if(SBE_SEC_OPERATION_SUCCESSFUL != l_rc) + { + SBE_ERROR(SBE_FUNC " Failed sbeStopCntlDmt"); + } + break; + } + SBE_ERROR(SBE_FUNC" Not a valid command "); + l_rc = SBE_SEC_COMMAND_NOT_SUPPORTED; + }while(0); // End of do-while + + SBE_EXIT(SBE_FUNC); + return l_rc; + #undef SBE_FUNC +} |