aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasant Hegde <hegdevasant@linux.vnet.ibm.com>2015-09-04 16:55:09 +0530
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-09-09 15:17:56 +1000
commit425a89ba2f4264a9215b176fe7b2ebf38a29cf09 (patch)
treedcf9ac180596c3bcd217302576e36dfd0ad00c0d
parent87edc3d8c87f113ec2a6d92c71fa25473cb8cec6 (diff)
downloadskiboot-425a89ba2f4264a9215b176fe7b2ebf38a29cf09.zip
skiboot-425a89ba2f4264a9215b176fe7b2ebf38a29cf09.tar.gz
skiboot-425a89ba2f4264a9215b176fe7b2ebf38a29cf09.tar.bz2
IPMI: Pre-allocate memory for PANIC event
Currently we allocate ipmi_msg for every eSEL event.. But in PANIC its not advised to allocate memory. Hence pre-allocate ipmi_msg for PANIC event. Note that we continue to allocate memory for normal event. Also with current implementation we can log only one eSEL event in PANIC path. Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--hw/ipmi/ipmi-sel.c75
-rw-r--r--include/ipmi.h3
-rw-r--r--platforms/astbmc/common.c1
3 files changed, 73 insertions, 6 deletions
diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c
index 42de2a5..5556b65 100644
--- a/hw/ipmi/ipmi-sel.c
+++ b/hw/ipmi/ipmi-sel.c
@@ -134,6 +134,62 @@ struct oem_sel {
#define ESEL_HDR_SIZE 7
+/* Used for sending PANIC events like abort() path */
+struct ipmi_sel_panic_msg {
+ bool busy;
+ struct ipmi_msg *msg;
+ struct lock lock;
+};
+static struct ipmi_sel_panic_msg ipmi_sel_panic_msg;
+
+/* Forward declaration */
+static void ipmi_elog_poll(struct ipmi_msg *msg);
+
+/*
+ * Allocate IPMI message
+ * For normal event, allocate memory using ipmi_mkmsg and for PANIC
+ * event, use pre-allocated buffer.
+ */
+static struct ipmi_msg *ipmi_sel_alloc_msg(struct errorlog *elog_buf)
+{
+ struct ipmi_msg *msg = NULL;
+
+ if (elog_buf->event_severity == OPAL_ERROR_PANIC) {
+ /* Called before initialization completes */
+ if (ipmi_sel_panic_msg.msg == NULL)
+ return NULL;
+
+ if (ipmi_sel_panic_msg.busy == true)
+ return NULL;
+
+ lock(&ipmi_sel_panic_msg.lock);
+ msg = ipmi_sel_panic_msg.msg;
+ ipmi_sel_panic_msg.busy = true;
+ unlock(&ipmi_sel_panic_msg.lock);
+
+ ipmi_init_msg(msg, IPMI_DEFAULT_INTERFACE,
+ IPMI_RESERVE_SEL, ipmi_elog_poll,
+ elog_buf, IPMI_MAX_REQ_SIZE, 2);
+ } else {
+ msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_RESERVE_SEL,
+ ipmi_elog_poll, elog_buf,
+ NULL, IPMI_MAX_REQ_SIZE, 2);
+ }
+
+ return msg;
+}
+
+static void ipmi_sel_free_msg(struct ipmi_msg *msg)
+{
+ if (msg == ipmi_sel_panic_msg.msg) {
+ lock(&ipmi_sel_panic_msg.lock);
+ ipmi_sel_panic_msg.busy = false;
+ unlock(&ipmi_sel_panic_msg.lock);
+ } else {
+ ipmi_free_msg(msg);
+ }
+ msg = NULL;
+}
/* Initialize eSEL record */
static void ipmi_init_esel_record(void)
@@ -199,7 +255,7 @@ static void ipmi_elog_error(struct ipmi_msg *msg)
ipmi_queue_msg(msg);
else {
opal_elog_complete(msg->user_data, false);
- ipmi_free_msg(msg);
+ ipmi_sel_free_msg(msg);
}
}
@@ -208,7 +264,7 @@ static void ipmi_log_sel_event_error(struct ipmi_msg *msg)
if (msg->cc != IPMI_CC_NO_ERROR)
prlog(PR_INFO, "SEL: Failed to log SEL event\n");
- ipmi_free_msg(msg);
+ ipmi_sel_free_msg(msg);
}
static void ipmi_log_sel_event_complete(struct ipmi_msg *msg)
@@ -216,7 +272,7 @@ static void ipmi_log_sel_event_complete(struct ipmi_msg *msg)
prlog(PR_INFO, "SEL: New event logged [ID : %x%x]\n",
msg->data[1], msg->data[0]);
- ipmi_free_msg(msg);
+ ipmi_sel_free_msg(msg);
}
/* Log SEL event with eSEL record ID */
@@ -282,7 +338,7 @@ static void ipmi_elog_poll(struct ipmi_msg *msg)
* sending the message. */
prerror("Invalid reservation id");
opal_elog_complete(elog_buf, false);
- ipmi_free_msg(msg);
+ ipmi_sel_free_msg(msg);
return;
}
@@ -360,8 +416,7 @@ int ipmi_elog_commit(struct errorlog *elog_buf)
/* We pass a large request size in to mkmsg so that we have a
* large enough allocation to reuse the message to pass the
* PEL data via a series of partial add commands. */
- msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_RESERVE_SEL, ipmi_elog_poll,
- elog_buf, NULL, IPMI_MAX_REQ_SIZE, 2);
+ msg = ipmi_sel_alloc_msg(elog_buf);
if (!msg) {
opal_elog_complete(elog_buf, false);
return OPAL_RESOURCE;
@@ -486,3 +541,11 @@ void ipmi_parse_sel(struct ipmi_msg *msg)
sel.cmd);
}
}
+
+void ipmi_sel_init(void)
+{
+ memset(&ipmi_sel_panic_msg, 0, sizeof(struct ipmi_sel_panic_msg));
+ ipmi_sel_panic_msg.msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
+ IPMI_RESERVE_SEL, ipmi_elog_poll,
+ NULL, NULL, IPMI_MAX_REQ_SIZE, 2);
+}
diff --git a/include/ipmi.h b/include/ipmi.h
index 54c415b..a1a236d 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -230,6 +230,9 @@ int ipmi_set_fw_progress_sensor(uint8_t state);
/* Register a backend with the ipmi core. Currently we only support one. */
void ipmi_register_backend(struct ipmi_backend *backend);
+/* Allocate IPMI SEL panic message */
+void ipmi_sel_init(void);
+
/* Register rtc ipmi commands with as opal callbacks. */
void ipmi_rtc_init(void);
diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
index 2af0309..8d37785 100644
--- a/platforms/astbmc/common.c
+++ b/platforms/astbmc/common.c
@@ -115,6 +115,7 @@ void astbmc_init(void)
/* Register the BT interface with the IPMI layer */
bt_init();
+ ipmi_sel_init();
ipmi_wdt_init();
ipmi_rtc_init();
ipmi_opal_init();