[Skiboot] [PATCH 3/3] opal/errorlog : Enables errorlog write to host on BMC systems

Mukesh Ojha mukesh02 at linux.vnet.ibm.com
Wed Apr 6 21:47:46 AEST 2016


Adds the support of errorlog write to host by using the generic interface
of errorlog read/write framework. OPAL sents the errorlog messages to both
BMC and host kernel by passing the errorlog buffers.

Properly returning of buffers to the pool by introducing ref_count variable
in the errorlog structure, which is manipulated in 'get_elog' and
'put_elog' function. Makes put_elog a wrapper of opal_elog_complete
(static) and exported function. Call to 'opal_elog_complete' made on
ref_count of zero.

'opal_elog_init' initialises the memory and the callbacks require for
errorlog write to host framework.

Signed-off-by: Mukesh Ojha <mukesh02 at linux.vnet.ibm.com>

---
 core/elog-host.c          |  4 ++--
 core/errorlog.c           | 46 +++++++++++++++++++++++++++++++++++-----------
 hw/fsp/fsp-elog-write.c   |  9 +++++----
 hw/ipmi/ipmi-sel.c        | 25 ++++++++++++++++++-------
 include/errorlog.h        |  7 +++----
 platforms/astbmc/common.c |  4 ++--
 6 files changed, 65 insertions(+), 30 deletions(-)

diff --git a/core/elog-host.c b/core/elog-host.c
index c6ec51a..b104447 100644
--- a/core/elog-host.c
+++ b/core/elog-host.c
@@ -180,7 +180,7 @@ static int opal_elog_ack(uint64_t ack_id)
 			if (record->plid != ack_id)
 				continue;
 			list_del(&record->link);
-			opal_elog_complete(record, true);
+			put_elog(record);
 			unlock(&elog_write_to_host_lock);
 			return rc;
 		}
@@ -197,7 +197,7 @@ static int opal_elog_ack(uint64_t ack_id)
 			if (record->plid != ack_id)
 				continue;
 			list_del(&record->link);
-			opal_elog_complete(record, true);
+			put_elog(record);
 			unlock(&elog_write_to_host_lock);
 			return rc;
 		}
diff --git a/core/errorlog.c b/core/errorlog.c
index 7afd16c..af2853b 100644
--- a/core/errorlog.c
+++ b/core/errorlog.c
@@ -42,6 +42,40 @@ static struct pool elog_pool;
 static struct lock elog_lock = LOCK_UNLOCKED;
 
 static bool elog_available = false;
+static struct lock elog_buf_ref_lock = LOCK_UNLOCKED;
+
+static void opal_elog_complete(struct errorlog *buf)
+{
+	lock(&elog_lock);
+	pool_free_object(&elog_pool, buf);
+	unlock(&elog_lock);
+}
+
+void get_elog(struct errorlog *elog_buf)
+{
+	lock(&elog_buf_ref_lock);
+	elog_buf->ref_count++;
+	unlock(&elog_buf_ref_lock);
+}
+
+void put_elog(struct errorlog *elog_buf)
+{
+	lock(&elog_buf_ref_lock);
+	if (!elog_buf->ref_count) {
+		prerror(
+		"put_elog has been called multiple times on reference"
+		" count zero\n"
+		);
+		unlock(&elog_buf_ref_lock);
+		return;
+	}
+
+	elog_buf->ref_count--;
+	if (!elog_buf->ref_count)
+		opal_elog_complete(elog_buf);
+
+	unlock(&elog_buf_ref_lock);
+}
 
 static struct errorlog *get_write_buffer(int opal_event_severity)
 {
@@ -112,16 +146,6 @@ void log_add_section(struct errorlog *buf, uint32_t tag)
 	buf->user_section_count++;
 }
 
-void opal_elog_complete(struct errorlog *buf, bool success)
-{
-	if (!success)
-		printf("Unable to log error\n");
-
-	lock(&elog_lock);
-	pool_free_object(&elog_pool, buf);
-	unlock(&elog_lock);
-}
-
 void log_commit(struct errorlog *elog)
 {
 	int rc;
@@ -135,7 +159,7 @@ void log_commit(struct errorlog *elog)
 			prerror("ELOG: Platform commit error %d\n", rc);
 		return;
 	}
-	opal_elog_complete(elog, false);
+	opal_elog_complete(elog);
 }
 
 void log_append_data(struct errorlog *buf, unsigned char *data, uint16_t size)
diff --git a/hw/fsp/fsp-elog-write.c b/hw/fsp/fsp-elog-write.c
index ee293f1..dced70d 100644
--- a/hw/fsp/fsp-elog-write.c
+++ b/hw/fsp/fsp-elog-write.c
@@ -66,7 +66,7 @@ static void remove_elog_head_entry(void)
 		if (head->plid == elog_plid_fsp_commit) {
 			entry = list_pop(&elog_write_to_fsp_pending,
 					struct errorlog, link);
-			opal_elog_complete(entry, elog_write_retries < MAX_RETRIES);
+			put_elog(entry);
 			/* Reset the counter */
 			elog_plid_fsp_commit = -1;
 		}
@@ -161,7 +161,7 @@ static int opal_push_logs_sync_to_fsp(struct errorlog *buf)
 		prerror("ELOG: PLID: 0x%x Failed to create message for WRITE "
 							"to FSP\n", buf->plid);
 		unlock(&elog_panic_write_lock);
-		opal_elog_complete(buf, false);
+		put_elog(buf);
 		return OPAL_INTERNAL_ERROR;
 	}
 
@@ -175,9 +175,9 @@ static int opal_push_logs_sync_to_fsp(struct errorlog *buf)
 	unlock(&elog_panic_write_lock);
 
 	if (rc != OPAL_SUCCESS)
-		opal_elog_complete(buf, false);
+		put_elog(buf);
 	else
-		opal_elog_complete(buf, true);
+		put_elog(buf);
 	return rc;
 }
 
@@ -193,6 +193,7 @@ int elog_fsp_commit(struct errorlog *buf)
 	/* Error needs to be committed, update the time out value */
 	buf->elog_timeout = get_elog_timeout();
 
+	get_elog(buf);
 	if (buf->event_severity == OPAL_ERROR_PANIC) {
 		rc = opal_push_logs_sync_to_fsp(buf);
 		return rc;
diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c
index 6bc386a..0950218 100644
--- a/hw/ipmi/ipmi-sel.c
+++ b/hw/ipmi/ipmi-sel.c
@@ -262,7 +262,7 @@ static void ipmi_elog_error(struct ipmi_msg *msg)
 		/* Retry due to SEL erase */
 		ipmi_queue_msg(msg);
 	else {
-		opal_elog_complete(msg->user_data, false);
+		put_elog(msg->user_data);
 		ipmi_sel_free_msg(msg);
 	}
 }
@@ -345,7 +345,7 @@ static void ipmi_elog_poll(struct ipmi_msg *msg)
 			 * get here, but just in case we do we cancel
 			 * sending the message. */
 			prerror("Invalid reservation id");
-			opal_elog_complete(elog_buf, false);
+			put_elog(elog_buf);
 			ipmi_sel_free_msg(msg);
 			return;
 		}
@@ -371,7 +371,7 @@ static void ipmi_elog_poll(struct ipmi_msg *msg)
 		/* Log SEL event and free ipmi message */
 		ipmi_log_sel_event(msg, elog_buf->event_severity, record_id);
 
-		opal_elog_complete(elog_buf, true);
+		put_elog(elog_buf);
 		return;
 	}
 
@@ -415,24 +415,34 @@ int ipmi_elog_commit(struct errorlog *elog_buf)
 {
 	struct ipmi_msg *msg;
 
+	get_elog(elog_buf);
 	/* Only log events that needs attention */
 	if (elog_buf->event_severity < OPAL_PREDICTIVE_ERR_FAULT_RECTIFY_REBOOT ||
 	    elog_buf->elog_origin != ORG_SAPPHIRE) {
 		prlog(PR_INFO, "dropping non severe PEL event\n");
-		opal_elog_complete(elog_buf, true);
+		put_elog(elog_buf);
 		return 0;
 	}
 
+	/* We take get_elog two times to make sure errorlog will be sent to
+	 * both BMC and the host irrespective of either of them is complete
+	 * or not, buffer will be return to the pool during the call of
+	 * put_elog().
+	 */
+	get_elog(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.  */
+	 * PEL data via a series of partial add commands.
+	 */
 	msg = ipmi_sel_alloc_msg(elog_buf);
 	if (!msg) {
-		opal_elog_complete(elog_buf, false);
+		put_elog(elog_buf);
+		elog_append_write_to_host(elog_buf);
 		return OPAL_RESOURCE;
 	}
-	msg->error = ipmi_elog_error;
 
+	msg->error = ipmi_elog_error;
 	msg->req_size = 0;
 
 	if (elog_buf->event_severity == OPAL_ERROR_PANIC)
@@ -440,6 +450,7 @@ int ipmi_elog_commit(struct errorlog *elog_buf)
 	else
 		ipmi_queue_msg(msg);
 
+	elog_append_write_to_host(elog_buf);
 	return 0;
 }
 
diff --git a/include/errorlog.h b/include/errorlog.h
index d58eb5e..d7c25c2 100644
--- a/include/errorlog.h
+++ b/include/errorlog.h
@@ -137,6 +137,7 @@ struct __attribute__((__packed__)) errorlog {
 	uint32_t plid;
 	uint32_t log_size;
 	uint64_t elog_timeout;
+	uint32_t ref_count;
 
 	char user_data_dump[OPAL_LOG_MAX_DUMP];
 	struct list_node link;
@@ -349,10 +350,8 @@ void log_append_msg(struct errorlog *buf,
 		const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
 void log_commit(struct errorlog *elog);
 
-/* Called by the backend after an error has been logged by the
- * backend. If the error could not be logged successfully success is
- * set to false. */
-void opal_elog_complete(struct errorlog *elog, bool success);
+void get_elog(struct errorlog *elog_buf);
+void put_elog(struct errorlog *elog_buf);
 
 void opal_elog_init(void);
 void opal_commit_elog_in_host(void);
diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
index 1ed7d42..4dd5401 100644
--- a/platforms/astbmc/common.c
+++ b/platforms/astbmc/common.c
@@ -115,8 +115,8 @@ void astbmc_init(void)
 
 	/* Register the BT interface with the IPMI layer */
 	bt_init();
-	/* Initialize elog */
-	elog_init();
+	/*Initialize the errorlog framework*/
+	opal_elog_init();
 	ipmi_sel_init();
 	ipmi_wdt_init();
 	ipmi_rtc_init();
-- 
2.1.4



More information about the Skiboot mailing list