aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/exceptions.c2
-rw-r--r--core/hmi.c92
-rw-r--r--include/opal.h50
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;
diff --git a/core/hmi.c b/core/hmi.c
index 5f6ddd6..207d3dd 100644
--- a/core/hmi.c
+++ b/core/hmi.c
@@ -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 */