diff options
-rw-r--r-- | core/exceptions.c | 2 | ||||
-rw-r--r-- | core/hmi.c | 92 | ||||
-rw-r--r-- | include/opal.h | 50 |
3 files changed, 134 insertions, 10 deletions
diff --git a/core/exceptions.c b/core/exceptions.c index 2b2aa6c..6e0d27f 100644 --- a/core/exceptions.c +++ b/core/exceptions.c @@ -366,7 +366,7 @@ void handle_hmi(struct stack_frame *stack) int recover; orig_hmer = mfspr(SPR_HMER); - recover = handle_hmi_exception(orig_hmer); + recover = handle_hmi_exception(orig_hmer, NULL); if (recover) return; @@ -6,6 +6,7 @@ * Supplement V032404DR-3 dated August 16, 2012 (the “NDA”). */ #include <skiboot.h> #include <opal.h> +#include <opal-msg.h> #include <processor.h> /* @@ -129,31 +130,55 @@ * NOTE: Per Dave Larson, never enable 8,9,21-23 */ -int handle_hmi_exception(uint64_t hmer) +int handle_hmi_exception(uint64_t hmer, struct OpalHMIEvent *hmi_evt) { int recover = 1; printf("HMI: Received HMI interrupt: HMER = 0x%016llx\n", hmer); - if (hmer & (SPR_HMER_PROC_RECV_DONE - | SPR_HMER_PROC_RECV_ERROR_MASKED)) { - hmer &= ~(SPR_HMER_PROC_RECV_DONE - | SPR_HMER_PROC_RECV_ERROR_MASKED); + if (hmi_evt) + hmi_evt->hmer = hmer; + if (hmer & SPR_HMER_PROC_RECV_DONE) { + hmer &= ~SPR_HMER_PROC_RECV_DONE; + if (hmi_evt) { + hmi_evt->severity = OpalHMI_SEV_NO_ERROR; + hmi_evt->type = OpalHMI_ERROR_PROC_RECOV_DONE; + } printf("HMI: Processor recovery Done.\n"); } + if (hmer & SPR_HMER_PROC_RECV_ERROR_MASKED) { + hmer &= ~SPR_HMER_PROC_RECV_ERROR_MASKED; + if (hmi_evt) { + hmi_evt->severity = OpalHMI_SEV_NO_ERROR; + hmi_evt->type = OpalHMI_ERROR_PROC_RECOV_MASKED; + } + printf("HMI: Processor recovery Done (masked).\n"); + } if (hmer & SPR_HMER_PROC_RECV_AGAIN) { hmer &= ~SPR_HMER_PROC_RECV_AGAIN; + if (hmi_evt) { + hmi_evt->severity = OpalHMI_SEV_NO_ERROR; + hmi_evt->type = OpalHMI_ERROR_PROC_RECOV_DONE_AGAIN; + } printf("HMI: Processor recovery occurred again before" "bit2 was cleared\n"); } /* Assert if we see malfunction alert, we can not continue. */ if (hmer & SPR_HMER_MALFUNCTION_ALERT) { hmer &= ~SPR_HMER_MALFUNCTION_ALERT; + if (hmi_evt) { + hmi_evt->severity = OpalHMI_SEV_FATAL; + hmi_evt->type = OpalHMI_ERROR_MALFUNC_ALERT; + } recover = 0; } /* Assert if we see Hypervisor resource error, we can not continue. */ if (hmer & SPR_HMER_HYP_RESOURCE_ERR) { hmer &= ~SPR_HMER_HYP_RESOURCE_ERR; + if (hmi_evt) { + hmi_evt->severity = OpalHMI_SEV_FATAL; + hmi_evt->type = OpalHMI_ERROR_HYP_RESOURCE; + } recover = 0; } @@ -161,8 +186,22 @@ int handle_hmi_exception(uint64_t hmer) * Assert for now for all TOD errors. In future we need to decode * TFMR and take corrective action wherever required. */ - if (hmer & (SPR_HMER_TFAC_ERROR | SPR_HMER_TFMR_PARITY_ERROR)) { - hmer &= ~(SPR_HMER_TFAC_ERROR | SPR_HMER_TFMR_PARITY_ERROR); + if (hmer & SPR_HMER_TFAC_ERROR) { + hmer &= ~SPR_HMER_TFAC_ERROR; + if (hmi_evt) { + hmi_evt->severity = OpalHMI_SEV_ERROR_SYNC; + hmi_evt->type = OpalHMI_ERROR_TFAC; + hmi_evt->tfmr = mfspr(SPR_TFMR); + } + recover = 0; + } + if (hmer & SPR_HMER_TFMR_PARITY_ERROR) { + hmer &= ~SPR_HMER_TFMR_PARITY_ERROR; + if (hmi_evt) { + hmi_evt->severity = OpalHMI_SEV_FATAL; + hmi_evt->type = OpalHMI_ERROR_TFMR_PARITY; + hmi_evt->tfmr = mfspr(SPR_TFMR); + } recover = 0; } @@ -174,3 +213,42 @@ int handle_hmi_exception(uint64_t hmer) mtspr(SPR_HMER, hmer); return recover; } + +static int queue_hmi_event(struct OpalHMIEvent *hmi_evt) +{ + uint64_t *hmi_data; + + /* + * struct OpalHMIEvent is of (3 * 64 bits) size and well packed + * structure. Hence use uint64_t pointer to pass entire structure + * using 4 params in generic message format. + */ + hmi_data = (uint64_t *)hmi_evt; + + /* queue up for delivery to host. */ + return opal_queue_msg(OPAL_MSG_HMI_EVT, NULL, NULL, + hmi_data[0], hmi_data[1], hmi_data[2]); +} + +static int64_t opal_handle_hmi(void) +{ + uint64_t hmer; + int rc = OPAL_SUCCESS; + struct OpalHMIEvent hmi_evt; + int recover; + + memset(&hmi_evt, 0, sizeof(struct OpalHMIEvent)); + hmi_evt.version = OpalHMIEvt_V1; + + hmer = mfspr(SPR_HMER); /* Get HMER register value */ + recover = handle_hmi_exception(hmer, &hmi_evt); + + if (recover) + hmi_evt.disposition = OpalHMI_DISPOSITION_RECOVERED; + else + hmi_evt.disposition = OpalHMI_DISPOSITION_NOT_RECOVERED; + + rc = queue_hmi_event(&hmi_evt); + return rc; +} +opal_call(OPAL_HANDLE_HMI, opal_handle_hmi, 0); diff --git a/include/opal.h b/include/opal.h index 22f6a9f..4833726 100644 --- a/include/opal.h +++ b/include/opal.h @@ -133,7 +133,8 @@ #define OPAL_WRITE_OPPANEL_ASYNC 95 #define OPAL_PCI_ERR_INJCT 96 #define OPAL_PCI_EEH_FREEZE_SET 97 -#define OPAL_LAST 97 +#define OPAL_HANDLE_HMI 98 +#define OPAL_LAST 98 #ifndef __ASSEMBLY__ @@ -429,6 +430,7 @@ enum OpalMessageType { OPAL_MSG_MEM_ERR, OPAL_MSG_EPOW, OPAL_MSG_SHUTDOWN, + OPAL_MSG_HMI_EVT, OPAL_MSG_TYPE_MAX, }; @@ -544,6 +546,50 @@ struct OpalMemoryErrorData { } u; }; +/* HMI interrupt event */ +enum OpalHMI_Version { + OpalHMIEvt_V1 = 1, +}; + +enum OpalHMI_Severity { + OpalHMI_SEV_NO_ERROR = 0, + OpalHMI_SEV_WARNING = 1, + OpalHMI_SEV_ERROR_SYNC = 2, + OpalHMI_SEV_FATAL = 3, +}; + +enum OpalHMI_Disposition { + OpalHMI_DISPOSITION_RECOVERED = 0, + OpalHMI_DISPOSITION_NOT_RECOVERED = 1, +}; + +enum OpalHMI_ErrType { + OpalHMI_ERROR_MALFUNC_ALERT = 0, + OpalHMI_ERROR_PROC_RECOV_DONE, + OpalHMI_ERROR_PROC_RECOV_DONE_AGAIN, + OpalHMI_ERROR_PROC_RECOV_MASKED, + OpalHMI_ERROR_TFAC, + OpalHMI_ERROR_TFMR_PARITY, + OpalHMI_ERROR_HA_OVERFLOW_WARN, + OpalHMI_ERROR_XSCOM_FAIL, + OpalHMI_ERROR_XSCOM_DONE, + OpalHMI_ERROR_SCOM_FIR, + OpalHMI_ERROR_DEBUG_TRIG_FIR, + OpalHMI_ERROR_HYP_RESOURCE, +}; + +struct OpalHMIEvent { + uint8_t version; /* 0x00 */ + uint8_t severity; /* 0x01 */ + uint8_t type; /* 0x02 */ + uint8_t disposition; /* 0x03 */ + uint8_t reserved_1[4]; /* 0x04 */ + + uint64_t hmer; + /* TFMR register. Valid only for TFAC and TFMR_PARITY error type. */ + uint64_t tfmr; +}; + enum { OPAL_P7IOC_DIAG_TYPE_NONE = 0, OPAL_P7IOC_DIAG_TYPE_RGC = 1, @@ -831,7 +877,7 @@ extern void opal_del_host_sync_notifier(bool (*notify)(void *data)); /* * Opal internal function prototype */ -extern int handle_hmi_exception(uint64_t hmer); +extern int handle_hmi_exception(uint64_t hmer, struct OpalHMIEvent *hmi_evt); #endif /* __ASSEMBLY__ */ #endif /* __OPAL_H */ |