[Skiboot] [PATCH V8 1/9] errorlog: Generalize the error log write path to host

Mukesh Ojha mukesh02 at linux.vnet.ibm.com
Tue Nov 15 21:10:37 AEDT 2016


Movement of OPAL error log generic functions from fsp-elog-write.c to
core/errorlog.c. Function declarations are kept in errorlog.h, which
was there in fsp-elog.h earlier and fsp specific header files are kept
in fsp-elog.h.

It implements a generic init routine 'opal_elog_init()' for error log
write to PowerNV host, which is initialised while booting and it is
independent of the platform on which it is going to run. This routine
also involves 'elog_write_to_host_buffer' a common memory buffer
which will be used to copy the logs from OPAL to PowerNV host buffer.

Signed-off-by: Mukesh Ojha <mukesh02 at linux.vnet.ibm.com>
Reviewed-by: Vasant Hegde <hegdevasant at linux.vnet.ibm.com>
---
Changes in V8:
 - Previous version V7 1/12 to 3/12 is already in the master. 
 - Rebased on master.

Changes in V7:
 - Subject tag changed from opal/errorlog to errorlog.
 - Patch V6 3/12 becomes V7's 4/12.

Changes in V6:
 - Rebased on master.

Changes in V5:
 - Removed the changes related to read path and moved them into
   a separate patch.
 - Patch description.

Changes in V4:
 - V3 1/6 becomes V4 2/6.
 - Took Stewart's comment and moved generic write to host routine
   to core/errorlog.c .
 - Changes are rebased on master.

Changes in V3:
 - Change of letter case in the description.

Changes in V2:
 - No Changes.

 core/errorlog.c            | 183 +++++++++++++++++++++++++++++++++++++++++++++
 hw/fsp/fsp-elog-write.c    | 180 --------------------------------------------
 include/errorlog.h         |  27 ++++++-
 include/fsp-elog.h         |  26 +------
 platforms/ibm-fsp/common.c |   4 +
 5 files changed, 214 insertions(+), 206 deletions(-)

diff --git a/core/errorlog.c b/core/errorlog.c
index 179e09f..4b0784f 100644
--- a/core/errorlog.c
+++ b/core/errorlog.c
@@ -22,6 +22,7 @@
 #include <skiboot.h>
 #include <lock.h>
 #include <errorlog.h>
+#include <pel.h>
 #include <pool.h>
 
 /*
@@ -42,6 +43,17 @@ static struct lock elog_lock = LOCK_UNLOCKED;
 
 static bool elog_available = false;
 
+static LIST_HEAD(elog_write_to_host_pending);
+static LIST_HEAD(elog_write_to_host_processed);
+
+/* Log buffer size to write into PowerNV */
+#define ELOG_WRITE_TO_HOST_BUFFER_SIZE  0x00004000
+void *elog_write_to_host_buffer;
+
+static struct lock elog_write_to_host_lock = LOCK_UNLOCKED;
+/* Manipulate this only with write_lock held */
+static enum elog_head_state elog_write_to_host_head_state = ELOG_STATE_NONE;
+
 static struct errorlog *get_write_buffer(int opal_event_severity)
 {
 	struct errorlog *buf;
@@ -218,6 +230,169 @@ void log_simple_error(struct opal_err_info *e_info, const char *fmt, ...)
 	}
 }
 
+/* This should be called with elog_write_to_host_lock lock */
+static inline void fsp_elog_write_set_head_state(enum elog_head_state state)
+{
+	elog_set_head_state(true, state);
+	elog_write_to_host_head_state = state;
+}
+
+bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size)
+{
+	struct errorlog *head;
+	bool rc = false;
+
+	lock(&elog_write_to_host_lock);
+	if (elog_write_to_host_head_state == ELOG_STATE_FETCHED_DATA) {
+		head = list_top(&elog_write_to_host_pending,
+				struct errorlog, link);
+		if (!head) {
+			/**
+			 * @fwts-label ElogListInconsistent
+			 * @fwts-advice Bug in interaction between FSP and
+			 * OPAL. The state maintained by OPAL didn't match
+			 * what the FSP sent.
+			 */
+			prlog(PR_ERR, "%s:Inconsistent internal list state !\n",
+					__func__);
+			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
+		} else {
+			*opal_elog_id = head->plid;
+			*opal_elog_size = head->log_size;
+			fsp_elog_write_set_head_state(ELOG_STATE_FETCHED_INFO);
+			rc = true;
+		}
+	}
+
+	unlock(&elog_write_to_host_lock);
+	return rc;
+}
+
+static void opal_commit_elog_in_host(void)
+{
+	struct errorlog *buf;
+
+	lock(&elog_write_to_host_lock);
+	if (!list_empty(&elog_write_to_host_pending) &&
+			(elog_write_to_host_head_state == ELOG_STATE_NONE)) {
+		buf = list_top(&elog_write_to_host_pending,
+				struct errorlog, link);
+		buf->log_size = create_pel_log(buf,
+				(char *)elog_write_to_host_buffer,
+				ELOG_WRITE_TO_HOST_BUFFER_SIZE);
+		fsp_elog_write_set_head_state(ELOG_STATE_FETCHED_DATA);
+	}
+
+	unlock(&elog_write_to_host_lock);
+}
+
+bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
+		uint64_t opal_elog_id)
+{
+	struct errorlog *log_data;
+	bool rc = false;
+
+	lock(&elog_write_to_host_lock);
+	if (elog_write_to_host_head_state == ELOG_STATE_FETCHED_INFO) {
+		log_data = list_top(&elog_write_to_host_pending,
+				struct errorlog, link);
+		if (!log_data) {
+			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
+			unlock(&elog_write_to_host_lock);
+			return rc;
+		}
+
+		if ((opal_elog_id != log_data->plid) &&
+				(opal_elog_size != log_data->log_size)) {
+			unlock(&elog_write_to_host_lock);
+			return rc;
+		}
+
+		memcpy((void *)buffer, elog_write_to_host_buffer,
+				opal_elog_size);
+		list_del(&log_data->link);
+		list_add(&elog_write_to_host_processed, &log_data->link);
+		fsp_elog_write_set_head_state(ELOG_STATE_NONE);
+		rc = true;
+	}
+
+	unlock(&elog_write_to_host_lock);
+	opal_commit_elog_in_host();
+	return rc;
+}
+
+bool opal_elog_ack(uint64_t ack_id)
+{
+	bool rc = false;
+	struct errorlog *log_data;
+	struct errorlog *record, *next_record;
+
+	lock(&elog_write_to_host_lock);
+	if (!list_empty(&elog_write_to_host_processed)) {
+		list_for_each_safe(&elog_write_to_host_processed, record,
+				next_record, link) {
+			if (record->plid != ack_id)
+				continue;
+
+			list_del(&record->link);
+			opal_elog_complete(record, true);
+			rc = true;
+		}
+	}
+
+	if ((!rc) && (!list_empty(&elog_write_to_host_pending))) {
+		log_data = list_top(&elog_write_to_host_pending,
+				struct errorlog, link);
+		if (ack_id == log_data->plid)
+			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
+
+		list_for_each_safe(&elog_write_to_host_pending, record,
+				next_record, link) {
+			if (record->plid != ack_id)
+				continue;
+
+			list_del(&record->link);
+			opal_elog_complete(record, true);
+			rc = true;
+			unlock(&elog_write_to_host_lock);
+			opal_commit_elog_in_host();
+			return rc;
+		}
+	}
+
+	unlock(&elog_write_to_host_lock);
+	return rc;
+}
+
+void opal_resend_pending_logs(void)
+{
+	struct errorlog *record;
+
+	lock(&elog_write_to_host_lock);
+	while (!list_empty(&elog_write_to_host_processed)) {
+		record = list_pop(&elog_write_to_host_processed,
+				struct errorlog, link);
+		list_add_tail(&elog_write_to_host_pending, &record->link);
+	}
+
+	fsp_elog_write_set_head_state(ELOG_STATE_NONE);
+	unlock(&elog_write_to_host_lock);
+	opal_commit_elog_in_host();
+}
+
+void elog_append_write_to_host(struct errorlog *buf)
+{
+	lock(&elog_write_to_host_lock);
+	if (list_empty(&elog_write_to_host_pending)) {
+		list_add(&elog_write_to_host_pending, &buf->link);
+		unlock(&elog_write_to_host_lock);
+		opal_commit_elog_in_host();
+	} else {
+		list_add_tail(&elog_write_to_host_pending, &buf->link);
+		unlock(&elog_write_to_host_lock);
+	}
+}
+
 int elog_init(void)
 {
 	/* Pre-allocate memory for records */
@@ -228,3 +403,11 @@ int elog_init(void)
 	elog_available = true;
 	return 0;
 }
+
+void opal_elog_init(void)
+{
+	elog_write_to_host_buffer = memalign(TCE_PSIZE,
+					ELOG_WRITE_TO_HOST_BUFFER_SIZE);
+	assert(elog_write_to_host_buffer);
+	elog_init();
+}
diff --git a/hw/fsp/fsp-elog-write.c b/hw/fsp/fsp-elog-write.c
index 9243931..df27bbc 100644
--- a/hw/fsp/fsp-elog-write.c
+++ b/hw/fsp/fsp-elog-write.c
@@ -35,12 +35,9 @@
 #include <timebase.h>
 
 static LIST_HEAD(elog_write_to_fsp_pending);
-static LIST_HEAD(elog_write_to_host_pending);
-static LIST_HEAD(elog_write_to_host_processed);
 
 static struct lock elog_write_lock = LOCK_UNLOCKED;
 static struct lock elog_panic_write_lock = LOCK_UNLOCKED;
-static struct lock elog_write_to_host_lock = LOCK_UNLOCKED;
 
 #define ELOG_WRITE_TO_FSP_BUFFER_SIZE	0x00004000
 /* Log buffer to copy OPAL log for write to FSP. */
@@ -49,14 +46,10 @@ static void *elog_write_to_fsp_buffer;
 #define ELOG_PANIC_WRITE_BUFFER_SIZE	0x00004000
 static void *elog_panic_write_buffer;
 
-#define ELOG_WRITE_TO_HOST_BUFFER_SIZE	0x00004000
-static void *elog_write_to_host_buffer;
-
 static uint32_t elog_write_retries;
 
 /* Manipulate this only with write_lock held */
 static uint32_t elog_plid_fsp_commit = -1;
-static enum elog_head_state elog_write_to_host_head_state = ELOG_STATE_NONE;
 
 /* Need forward declaration because of circular dependency */
 static int opal_send_elog_to_fsp(void);
@@ -129,157 +122,6 @@ static int64_t fsp_opal_elog_write(size_t opal_elog_size)
 	return OPAL_SUCCESS;
 }
 
-/* This should be called with elog_write_to_host_lock lock */
-static inline void fsp_elog_write_set_head_state(enum elog_head_state state)
-{
-	elog_set_head_state(true, state);
-	elog_write_to_host_head_state = state;
-}
-
-bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size)
-{
-	struct errorlog *head;
-	bool rc = false;
-
-	lock(&elog_write_to_host_lock);
-	if (elog_write_to_host_head_state == ELOG_STATE_FETCHED_DATA) {
-		head = list_top(&elog_write_to_host_pending,
-					struct errorlog, link);
-		if (!head) {
-			/**
-			 * @fwts-label ElogListInconsistent
-			 * @fwts-advice Bug in interaction between FSP and
-			 * OPAL. The state maintained by OPAL didn't match
-			 * what the FSP sent.
-			 */
-			prlog(PR_ERR,
-			      "%s: Inconsistent internal list state !\n",
-			      __func__);
-			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
-		} else {
-			*opal_elog_id = head->plid;
-			*opal_elog_size = head->log_size;
-			fsp_elog_write_set_head_state(ELOG_STATE_HOST_INFO);
-			rc = true;
-		}
-	}
-
-	unlock(&elog_write_to_host_lock);
-	return rc;
-}
-
-static void opal_commit_elog_in_host(void)
-{
-	struct errorlog *buf;
-
-	lock(&elog_write_to_host_lock);
-	if (!list_empty(&elog_write_to_host_pending) &&
-			(elog_write_to_host_head_state == ELOG_STATE_NONE)) {
-		buf = list_top(&elog_write_to_host_pending,
-				struct errorlog, link);
-		buf->log_size = create_pel_log(buf,
-					(char *)elog_write_to_host_buffer,
-					ELOG_WRITE_TO_HOST_BUFFER_SIZE);
-		fsp_elog_write_set_head_state(ELOG_STATE_FETCHED_DATA);
-	}
-
-	unlock(&elog_write_to_host_lock);
-}
-
-bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
-		    uint64_t opal_elog_id)
-{
-	struct errorlog *log_data;
-	bool rc = false;
-
-	lock(&elog_write_to_host_lock);
-	if (elog_write_to_host_head_state == ELOG_STATE_HOST_INFO) {
-		log_data = list_top(&elog_write_to_host_pending,
-					struct errorlog, link);
-		if (!log_data) {
-			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
-			unlock(&elog_write_to_host_lock);
-			return rc;
-		}
-
-		if ((opal_elog_id != log_data->plid) &&
-		    (opal_elog_size != log_data->log_size)) {
-			unlock(&elog_write_to_host_lock);
-			return rc;
-		}
-
-		memcpy((void *)buffer, elog_write_to_host_buffer,
-							opal_elog_size);
-		list_del(&log_data->link);
-		list_add(&elog_write_to_host_processed, &log_data->link);
-		fsp_elog_write_set_head_state(ELOG_STATE_NONE);
-		rc = true;
-	}
-
-	unlock(&elog_write_to_host_lock);
-	opal_commit_elog_in_host();
-	return rc;
-}
-
-bool opal_elog_ack(uint64_t ack_id)
-{
-	bool rc = false;
-	struct errorlog *log_data;
-	struct errorlog *record, *next_record;
-
-	lock(&elog_write_to_host_lock);
-	if (!list_empty(&elog_write_to_host_processed)) {
-		list_for_each_safe(&elog_write_to_host_processed, record,
-						next_record, link) {
-			if (record->plid != ack_id)
-				continue;
-
-			list_del(&record->link);
-			opal_elog_complete(record, true);
-			rc = true;
-		}
-	}
-
-	if ((!rc) && (!list_empty(&elog_write_to_host_pending))) {
-		log_data = list_top(&elog_write_to_host_pending,
-						struct errorlog, link);
-		if (ack_id == log_data->plid)
-			fsp_elog_write_set_head_state(ELOG_STATE_NONE);
-
-		list_for_each_safe(&elog_write_to_host_pending, record,
-						next_record, link) {
-			if (record->plid != ack_id)
-				continue;
-
-			list_del(&record->link);
-			opal_elog_complete(record, true);
-			rc = true;
-			unlock(&elog_write_to_host_lock);
-			opal_commit_elog_in_host();
-			return rc;
-		}
-	}
-
-	unlock(&elog_write_to_host_lock);
-	return rc;
-}
-
-void opal_resend_pending_logs(void)
-{
-	struct errorlog *record;
-
-	lock(&elog_write_to_host_lock);
-	while (!list_empty(&elog_write_to_host_processed)) {
-		record = list_pop(&elog_write_to_host_processed,
-					struct errorlog, link);
-		list_add_tail(&elog_write_to_host_pending, &record->link);
-	}
-
-	fsp_elog_write_set_head_state(ELOG_STATE_NONE);
-	unlock(&elog_write_to_host_lock);
-	opal_commit_elog_in_host();
-}
-
 static inline u64 get_elog_timeout(void)
 {
 	return (mftb() + secs_to_tb(ERRORLOG_TIMEOUT_INTERVAL));
@@ -378,19 +220,6 @@ int elog_fsp_commit(struct errorlog *buf)
 	return rc;
 }
 
-static void elog_append_write_to_host(struct errorlog *buf)
-{
-	lock(&elog_write_to_host_lock);
-	if (list_empty(&elog_write_to_host_pending)) {
-		list_add(&elog_write_to_host_pending, &buf->link);
-		unlock(&elog_write_to_host_lock);
-		opal_commit_elog_in_host();
-	} else {
-		list_add_tail(&elog_write_to_host_pending, &buf->link);
-		unlock(&elog_write_to_host_lock);
-	}
-}
-
 static void elog_timeout_poll(void *data __unused)
 {
 	uint64_t now;
@@ -435,13 +264,6 @@ void fsp_elog_write_init(void)
 		return;
 	}
 
-	elog_write_to_host_buffer = memalign(TCE_PSIZE,
-					ELOG_WRITE_TO_HOST_BUFFER_SIZE);
-	if (!elog_write_to_host_buffer) {
-		prerror("FSP: could not allocate ELOG_WRITE_TO_HOST_BUFFER!\n");
-		return;
-	}
-
 	/* Map TCEs */
 	fsp_tce_map(PSI_DMA_ELOG_PANIC_WRITE_BUF, elog_panic_write_buffer,
 					PSI_DMA_ELOG_PANIC_WRITE_BUF_SZ);
@@ -449,8 +271,6 @@ void fsp_elog_write_init(void)
 	fsp_tce_map(PSI_DMA_ERRLOG_WRITE_BUF, elog_write_to_fsp_buffer,
 					PSI_DMA_ERRLOG_WRITE_BUF_SZ);
 
-	elog_init();
-
 	/* Add a poller */
 	opal_add_poller(elog_timeout_poll, NULL);
 }
diff --git a/include/errorlog.h b/include/errorlog.h
index 247198b..8f58cd0 100644
--- a/include/errorlog.h
+++ b/include/errorlog.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2014 IBM Corp.
+/* Copyright 2013-2016 IBM Corp.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -332,6 +332,20 @@ enum opal_reasoncode {
 	OPAL_RC_ABNORMAL_REBOOT	    = OPAL_SRC_COMPONENT_CEC | 0x10,
 };
 
+/* Following variables are used to indicate state of the
+ * head log entry which is being fetched from FSP/OPAL and
+ * these variables are not overwritten until next log is
+ * retrieved from FSP/OPAL.
+ */
+enum elog_head_state {
+	ELOG_STATE_FETCHING,    /*In the process of reading log from FSP. */
+	ELOG_STATE_FETCHED_INFO,/* Indicates reading log info is completed */
+	ELOG_STATE_FETCHED_DATA,/* Indicates reading log is completed */
+	ELOG_STATE_HOST_INFO,   /* Host read log info */
+	ELOG_STATE_NONE,        /* Indicates to fetch next log */
+	ELOG_STATE_REJECTED,    /* resend all pending logs to linux */
+};
+
 #define DEFINE_LOG_ENTRY(reason, type, id, subsys,			\
 severity, subtype) static struct opal_err_info err_##reason =		\
 { .reason_code = reason, .err_type = type, .cmp_id = id,		\
@@ -359,6 +373,15 @@ void log_commit(struct errorlog *elog);
  * set to false. */
 void opal_elog_complete(struct errorlog *elog, bool success);
 
-int elog_init(void);
+bool opal_elog_info(uint64_t *opal_elog_id,
+		uint64_t *opal_elog_size) __warn_unused_result;
+bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
+		uint64_t opal_elog_id) __warn_unused_result;
+bool opal_elog_ack(uint64_t ack_id) __warn_unused_result;
+void opal_resend_pending_logs(void);
+void opal_elog_init(void);
 
+int elog_init(void);
+void elog_append_write_to_host(struct errorlog *buf);
+void elog_set_head_state(bool opal_logs, enum elog_head_state state);
 #endif /* __ERRORLOG_H */
diff --git a/include/fsp-elog.h b/include/fsp-elog.h
index eb9c28f..f69f5c8 100644
--- a/include/fsp-elog.h
+++ b/include/fsp-elog.h
@@ -13,43 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#ifndef __ELOG_H
+#define __ELOG_H
 #include <opal.h>
 #include <errorlog.h>
 #include <pel.h>
-#ifndef __ELOG_H
-#define __ELOG_H
 
 #define ELOG_TYPE_PEL			0
 #define MAX_RETRIES			3
 
-/* Following variables are used to indicate state of the
- * head log entry which is being fetched from FSP/OPAL and
- * these variables are not overwritten until next log is
- * retrieved from FSP/OPAL.
- */
-enum elog_head_state {
-	ELOG_STATE_FETCHING,    /*In the process of reading log from FSP. */
-	ELOG_STATE_FETCHED_DATA,/* Indicates reading log is completed */
-	ELOG_STATE_HOST_INFO,	/* Host read log info */
-	ELOG_STATE_NONE,        /* Indicates to fetch next log */
-	ELOG_STATE_REJECTED,    /* resend all pending logs to linux */
-};
-
 /* Generate src from opal reason code (src_comp) */
 #define generate_src_from_comp(src_comp)  (OPAL_SRC_TYPE_ERROR << 24 | \
 				OPAL_FAILING_SUBSYSTEM << 16 | src_comp)
 
 int elog_fsp_commit(struct errorlog *buf) __warn_unused_result;
 
-bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size) __warn_unused_result;
-
-bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
-						uint64_t opal_elog_id) __warn_unused_result;
-
-bool opal_elog_ack(uint64_t ack_id) __warn_unused_result;
-
-void opal_resend_pending_logs(void);
-
 void elog_set_head_state(bool opal_logs, enum elog_head_state state);
 
 #endif /* __ELOG_H */
diff --git a/platforms/ibm-fsp/common.c b/platforms/ibm-fsp/common.c
index dc3a002..17622a3 100644
--- a/platforms/ibm-fsp/common.c
+++ b/platforms/ibm-fsp/common.c
@@ -22,6 +22,7 @@
 #include <console.h>
 #include <hostservices.h>
 #include <ipmi.h>
+#include <errorlog.h>
 
 #include "ibm-fsp.h"
 
@@ -92,6 +93,9 @@ void ibm_fsp_init(void)
 	/* Get ready to receive OCC related messages */
 	occ_fsp_init();
 
+	/* Initialize the error log framework */
+	opal_elog_init();
+
 	/* Get ready to receive Memory [Un]corretable Error messages. */
 	fsp_memory_err_init();
 
-- 
2.7.4



More information about the Skiboot mailing list