diff options
author | Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> | 2014-07-25 00:11:50 +0530 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-07-25 14:10:52 +1000 |
commit | 91f1712faaa1b8774bb2198e580d1d210ae473cb (patch) | |
tree | 9e3f70291f12828d16d76e6de2451f8885c8e438 | |
parent | e02dd7f7d86f54273a512a4546c716ce659a38c8 (diff) | |
download | skiboot-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>
-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 */ |