// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later /* * We don't want to go on the cart! * * Copyright 2013-2018 IBM Corp. */ #include #include #include #include #include #include #include #include static bool fsp_surv_state = false; static bool fsp_surv_ack_pending = false; static u64 surv_timer; static u64 surv_ack_timer; static u32 surv_state_param; static struct lock surv_lock = LOCK_UNLOCKED; #define FSP_SURV_ACK_TIMEOUT 120 /* surv ack timeout in seconds */ DEFINE_LOG_ENTRY(OPAL_RC_SURVE_INIT, OPAL_MISC_ERR_EVT, OPAL_SURVEILLANCE, OPAL_SURVEILLANCE_ERR, OPAL_PREDICTIVE_ERR_GENERAL, OPAL_MISCELLANEOUS_INFO_ONLY); DEFINE_LOG_ENTRY(OPAL_RC_SURVE_STATUS, OPAL_MISC_ERR_EVT, OPAL_SURVEILLANCE, OPAL_SURVEILLANCE_ERR, OPAL_PREDICTIVE_ERR_GENERAL, OPAL_MISCELLANEOUS_INFO_ONLY); DEFINE_LOG_ENTRY(OPAL_RC_SURVE_ACK, OPAL_MISC_ERR_EVT, OPAL_SURVEILLANCE, OPAL_SURVEILLANCE_ERR, OPAL_PREDICTIVE_ERR_GENERAL, OPAL_MISCELLANEOUS_INFO_ONLY); static void fsp_surv_ack(struct fsp_msg *msg) { uint8_t val; if (!msg->resp) return; val = (msg->resp->word1 >> 8) & 0xff; if (val == 0) { /* reset the pending flag */ prlog(PR_TRACE, "SURV: Received heartbeat acknowledge from FSP\n"); lock(&surv_lock); fsp_surv_ack_pending = false; unlock(&surv_lock); } else { /** * @fwts-label FSPHeartbeatAckError * @fwts-advice Error in acknowledging heartbeat to FSP. * This could mean the FSP has gone away or it may mean * the FSP may kill us for missing too many heartbeats. */ prlog(PR_ERR, "SURV: Heartbeat Acknowledgment error from FSP\n"); } fsp_freemsg(msg); } static void fsp_surv_check_timeout(void) { u64 now = mftb(); /* * We just checked fsp_surv_ack_pending to be true in fsp_surv_hbeat * and we haven't dropped the surv_lock between then and now. So, we * just go ahead and check timeouts. */ if (tb_compare(now, surv_ack_timer) == TB_AAFTERB) { uint32_t plid = log_simple_error(&e_info(OPAL_RC_SURVE_ACK), "SURV: Surv ACK timed out; initiating R/R\n"); /* Reset the pending trigger too */ fsp_surv_ack_pending = false; fsp_trigger_reset(plid); } return; } /* Send surveillance heartbeat based on a timebase trigger */ static void fsp_surv_hbeat(void) { u64 now = mftb(); struct fsp_msg *msg; /* Check if an ack is pending... if so, don't send the ping just yet */ if (fsp_surv_ack_pending) { fsp_surv_check_timeout(); return; } /* add timebase callbacks */ /* * XXX This packet needs to be pushed to FSP in an interval * less than 120s that's advertised to FSP. * * Verify if the command building format and call is fine. */ if (surv_timer == 0 || (tb_compare(now, surv_timer) == TB_AAFTERB) || (tb_compare(now, surv_timer) == TB_AEQUALB)) { prlog(PR_TRACE, "SURV: Sending the heartbeat command to FSP\n"); msg = fsp_mkmsg(FSP_CMD_SURV_HBEAT, 1, 120); if (!msg) { prerror("SURV: Failed to allocate heartbeat msg\n"); return; } if (fsp_queue_msg(msg, fsp_surv_ack)) { fsp_freemsg(msg); prerror("SURV: Failed to queue heartbeat msg\n"); } else { fsp_surv_ack_pending = true; surv_timer = now + secs_to_tb(60); surv_ack_timer = now + secs_to_tb(FSP_SURV_ACK_TIMEOUT); } } } static void fsp_surv_poll(void *data __unused) { if (!fsp_surv_state) return; lock(&surv_lock); fsp_surv_hbeat(); unlock(&surv_lock); } static void fsp_surv_got_param(uint32_t param_id __unused, int err_len, void *data __unused) { if (err_len != 4) { uint32_t plid = log_simple_error(&e_info(OPAL_RC_SURVE_STATUS), "SURV: Error (%d) retrieving surv status; initiating R/R\n", err_len); fsp_trigger_reset(plid); return; } surv_state_param = be32_to_cpu((__be32)surv_state_param); if (!(surv_state_param & 0x01)) { prlog(PR_NOTICE, "SURV: Status from FSP: disabled\n"); return; } prlog(PR_NOTICE, "SURV: Status from FSP: enabled\n"); lock(&surv_lock); fsp_surv_state = true; /* Also send one heartbeat now. The next one will not happen * until we hit the OS. */ fsp_surv_hbeat(); unlock(&surv_lock); } void fsp_surv_query(void) { int rc; printf("SURV: Querying FSP's surveillance status\n"); /* Reset surveillance settings */ lock(&surv_lock); fsp_surv_state = false; surv_timer = 0; surv_ack_timer = 0; unlock(&surv_lock); /* Query FPS for surveillance state */ rc = fsp_get_sys_param(SYS_PARAM_SURV, &surv_state_param, 4, fsp_surv_got_param, NULL); if (rc) { log_simple_error(&e_info(OPAL_RC_SURVE_INIT), "SURV: Error %d queueing param request\n", rc); } } static bool fsp_surv_msg_rr(u32 cmd_sub_mod, struct fsp_msg *msg) { assert(msg == NULL); switch (cmd_sub_mod) { case FSP_RESET_START: printf("SURV: Disabling surveillance\n"); lock(&surv_lock); fsp_surv_state = false; fsp_surv_ack_pending = false; unlock(&surv_lock); return true; case FSP_RELOAD_COMPLETE: fsp_surv_query(); return true; } return false; } static struct fsp_client fsp_surv_client_rr = { .message = fsp_surv_msg_rr, }; /* This is called at boot time */ void fsp_init_surveillance(void) { /* Always register the poller, so we don't have to add/remove * it on reset-reload or change of surveillance state. Also the * poller list has no locking so we don't want to play with it * at runtime. */ opal_add_poller(fsp_surv_poll, NULL); /* Register for the reset/reload event */ fsp_register_client(&fsp_surv_client_rr, FSP_MCLASS_RR_EVENT); /* Send query to FSP */ fsp_surv_query(); }