aboutsummaryrefslogtreecommitdiff
path: root/core/hmi.c
diff options
context:
space:
mode:
authorMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>2014-07-25 00:11:50 +0530
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-07-25 14:10:52 +1000
commit91f1712faaa1b8774bb2198e580d1d210ae473cb (patch)
tree9e3f70291f12828d16d76e6de2451f8885c8e438 /core/hmi.c
parente02dd7f7d86f54273a512a4546c716ce659a38c8 (diff)
downloadskiboot-91f1712faaa1b8774bb2198e580d1d210ae473cb.zip
skiboot-91f1712faaa1b8774bb2198e580d1d210ae473cb.tar.gz
skiboot-91f1712faaa1b8774bb2198e580d1d210ae473cb.tar.bz2
opal: Add opal call to handle HMI.
With new proposed change, Linux will get the HMI interrupt directly. Linux will then invoke opal_handle_hmi to handle HMI recovery in opal. After handling HMI errors, opal will generate an OPAL HMI event and queue it up in opal message infrastructure so that Linux host can pull the event and act upon it accordingly. This patch also adds new message type for HMI event. Changes in v2: - Removed the token argument from opal_handle_hmi() Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'core/hmi.c')
-rw-r--r--core/hmi.c92
1 files changed, 85 insertions, 7 deletions
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);