[Skiboot] [PATCH V7 06/12] errorlog: Generalize the error log read path

Mukesh Ojha mukesh02 at linux.vnet.ibm.com
Wed Sep 7 20:21:20 AEST 2016


Introduces platform hooks for error log info, read, ack, and resend pending
logs by adding four new function pointers in the platform structure.

Add opal generic function for read, info, ack and resend pending logs as
callback, which will be called from PowerNV host.

Moving the opal call registration from fsp-elog-read.c to core/errorlog.c
and the calling the fsp specific function via platform hooks, which will
be initialised once the platform is known, otherwise it will be NULL.
Declarations of fsp specific routine are kept in fsp-elog.h .

Signed-off-by: Mukesh Ojha <mukesh02 at linux.vnet.ibm.com>
Reviewed-by: Vasant Hegde <hegdevasant at linux.vnet.ibm.com>
---
Changes in V7:
 - Subject tag changed from opal/errorlog to errorlog.

Changes in V6:
 - Rebased on master.

Changes in V5:
 - Removed redundant return and lock/unlock statement.

Changes in V4:
 - Changes are rebased on master.
 - Changes done for core/elog-host moved to core/errorlog.c .

Changes in V3:
 - No changes.

Changes in V2:
 - Separates the Bug solve part to patch 3/6.

 core/errorlog.c             | 102 ++++++++++++++++++++++++++++++++++++--------
 hw/fsp/fsp-elog-read.c      |  70 ++----------------------------
 include/errorlog.h          |   7 ---
 include/fsp-elog.h          |  11 +++--
 include/platform.h          |  25 ++++++++++-
 platforms/ibm-fsp/apollo.c  |   7 ++-
 platforms/ibm-fsp/firenze.c |   7 ++-
 7 files changed, 132 insertions(+), 97 deletions(-)

diff --git a/core/errorlog.c b/core/errorlog.c
index 5666f7a..337e21d 100644
--- a/core/errorlog.c
+++ b/core/errorlog.c
@@ -42,6 +42,7 @@ static struct pool elog_pool;
 static struct lock elog_lock = LOCK_UNLOCKED;
 
 static bool elog_available = false;
+static bool elog_enabled = false;
 
 static LIST_HEAD(elog_write_to_host_pending);
 static LIST_HEAD(elog_write_to_host_processed);
@@ -230,6 +231,28 @@ void log_simple_error(struct opal_err_info *e_info, const char *fmt, ...)
 	}
 }
 
+void elog_set_head_state(bool opal_logs, enum elog_head_state state)
+{
+	static enum elog_head_state opal_logs_state = ELOG_STATE_NONE;
+	static enum elog_head_state fsp_logs_state = ELOG_STATE_NONE;
+
+	/* ELOG disabled */
+	if (!elog_enabled)
+		return;
+
+	if (opal_logs)
+		opal_logs_state = state;
+	else
+		fsp_logs_state = state;
+
+	if (fsp_logs_state == ELOG_STATE_FETCHED_DATA ||
+				opal_logs_state == ELOG_STATE_FETCHED_DATA)
+		opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL,
+				OPAL_EVENT_ERROR_LOG_AVAIL);
+	else
+		opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL, 0);
+}
+
 /* This should be called with elog_write_to_host_lock lock */
 static inline void opal_elog_write_set_head_state(enum elog_head_state state)
 {
@@ -237,10 +260,11 @@ static inline void opal_elog_write_set_head_state(enum elog_head_state state)
 	elog_write_to_host_head_state = state;
 }
 
-bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size)
+static int opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size,
+				uint64_t *elog_type)
 {
 	struct errorlog *head;
-	bool rc = false;
+	int rc = OPAL_SUCCESS;
 
 	lock(&elog_write_to_host_lock);
 	if (elog_write_to_host_head_state == ELOG_STATE_FETCHED_DATA) {
@@ -256,16 +280,24 @@ bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size)
 			prlog(PR_ERR, "%s:Inconsistent internal list state !\n",
 					__func__);
 			opal_elog_write_set_head_state(ELOG_STATE_NONE);
+			unlock(&elog_write_to_host_lock);
+			return OPAL_INTERNAL_ERROR;
 		} else {
 			*opal_elog_id = head->plid;
 			*opal_elog_size = head->log_size;
 			opal_elog_write_set_head_state(ELOG_STATE_FETCHED_INFO);
-			rc = true;
+			unlock(&elog_write_to_host_lock);
+			return rc;
 		}
 	}
 
 	unlock(&elog_write_to_host_lock);
-	return rc;
+
+	if (platform.elog_info)
+		return platform.elog_info(opal_elog_id, opal_elog_size,
+				elog_type);
+
+	return OPAL_PARAMETER;
 }
 
 static void opal_commit_elog_in_host(void)
@@ -286,11 +318,11 @@ static void opal_commit_elog_in_host(void)
 	unlock(&elog_write_to_host_lock);
 }
 
-bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
-		uint64_t opal_elog_id)
+static int opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
+				uint64_t opal_elog_id)
 {
 	struct errorlog *log_data;
-	bool rc = false;
+	int rc = OPAL_SUCCESS;
 
 	lock(&elog_write_to_host_lock);
 	if (elog_write_to_host_head_state == ELOG_STATE_FETCHED_INFO) {
@@ -299,13 +331,13 @@ bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
 		if (!log_data) {
 			opal_elog_write_set_head_state(ELOG_STATE_NONE);
 			unlock(&elog_write_to_host_lock);
-			return rc;
+			return OPAL_INTERNAL_ERROR;
 		}
 
 		if ((opal_elog_id != log_data->plid) &&
 				(opal_elog_size != log_data->log_size)) {
 			unlock(&elog_write_to_host_lock);
-			return rc;
+			return OPAL_PARAMETER;
 		}
 
 		memcpy((void *)buffer, elog_write_to_host_buffer,
@@ -313,17 +345,22 @@ bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
 		list_del(&log_data->link);
 		list_add(&elog_write_to_host_processed, &log_data->link);
 		opal_elog_write_set_head_state(ELOG_STATE_NONE);
-		rc = true;
+		unlock(&elog_write_to_host_lock);
+		opal_commit_elog_in_host();
+		return rc;
 	}
 
 	unlock(&elog_write_to_host_lock);
-	opal_commit_elog_in_host();
-	return rc;
+
+	if (platform.elog_read)
+		return platform.elog_read(buffer, opal_elog_size, opal_elog_id);
+
+	return OPAL_PARAMETER;
 }
 
-bool opal_elog_ack(uint64_t ack_id)
+static int opal_elog_ack(uint64_t ack_id)
 {
-	bool rc = false;
+	int rc = OPAL_SUCCESS;
 	struct errorlog *log_data;
 	struct errorlog *record, *next_record;
 
@@ -336,7 +373,8 @@ bool opal_elog_ack(uint64_t ack_id)
 
 			list_del(&record->link);
 			opal_elog_complete(record, true);
-			rc = true;
+			unlock(&elog_write_to_host_lock);
+			return rc;
 		}
 	}
 
@@ -353,7 +391,6 @@ bool opal_elog_ack(uint64_t ack_id)
 
 			list_del(&record->link);
 			opal_elog_complete(record, true);
-			rc = true;
 			unlock(&elog_write_to_host_lock);
 			opal_commit_elog_in_host();
 			return rc;
@@ -361,14 +398,19 @@ bool opal_elog_ack(uint64_t ack_id)
 	}
 
 	unlock(&elog_write_to_host_lock);
-	return rc;
+
+	if (platform.elog_ack)
+		return platform.elog_ack(ack_id);
+
+	return OPAL_PARAMETER;
 }
 
-void opal_resend_pending_logs(void)
+static void opal_resend_pending_logs(void)
 {
 	struct errorlog *record;
 
 	lock(&elog_write_to_host_lock);
+        elog_enabled = true;
 	while (!list_empty(&elog_write_to_host_processed)) {
 		record = list_pop(&elog_write_to_host_processed,
 				struct errorlog, link);
@@ -378,6 +420,9 @@ void opal_resend_pending_logs(void)
 	opal_elog_write_set_head_state(ELOG_STATE_NONE);
 	unlock(&elog_write_to_host_lock);
 	opal_commit_elog_in_host();
+
+	if (platform.resend_pending_elogs)
+		platform.resend_pending_elogs();
 }
 
 void elog_append_write_to_host(struct errorlog *buf)
@@ -393,6 +438,17 @@ void elog_append_write_to_host(struct errorlog *buf)
 	}
 }
 
+/* Disable ELOG event flag until PowerNV is ready to receive event */
+static bool opal_kexec_elog_notify(void *data __unused)
+{
+	lock(&elog_write_to_host_lock);
+	elog_enabled = false;
+	opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL, 0);
+	unlock(&elog_write_to_host_lock);
+
+	return true;
+}
+
 int elog_init(void)
 {
 	/* Pre-allocate memory for records */
@@ -409,5 +465,15 @@ 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);
+
+	/* Register for sync on PowerNV reboot call */
+	opal_add_host_sync_notifier(opal_kexec_elog_notify, NULL);
+
+	/* Register OPAL interface */
+	opal_register(OPAL_ELOG_READ, opal_elog_read, 3);
+	opal_register(OPAL_ELOG_ACK, opal_elog_ack, 1);
+	opal_register(OPAL_ELOG_RESEND, opal_resend_pending_logs, 0);
+	opal_register(OPAL_ELOG_SIZE, opal_elog_info, 3);
+
 	elog_init();
 }
diff --git a/hw/fsp/fsp-elog-read.c b/hw/fsp/fsp-elog-read.c
index fb8c753..f207d07 100644
--- a/hw/fsp/fsp-elog-read.c
+++ b/hw/fsp/fsp-elog-read.c
@@ -83,8 +83,6 @@ static uint32_t elog_read_retries;	/* Bad response status count */
 /* Initialize the state of the log */
 static enum elog_head_state elog_read_from_fsp_head_state = ELOG_STATE_NONE;
 
-static bool elog_enabled = false;
-
 /* Need forward declaration because of circular dependency. */
 static void fsp_elog_queue_fetch(void);
 
@@ -140,28 +138,6 @@ static void fsp_elog_check_and_fetch_head(void)
 	unlock(&elog_read_lock);
 }
 
-void elog_set_head_state(bool opal_logs, enum elog_head_state state)
-{
-	static enum elog_head_state opal_logs_state = ELOG_STATE_NONE;
-	static enum elog_head_state fsp_logs_state = ELOG_STATE_NONE;
-
-	/* ELOG disabled */
-	if (!elog_enabled)
-		return;
-
-	if (opal_logs)
-		opal_logs_state = state;
-	else
-		fsp_logs_state = state;
-
-	if (fsp_logs_state == ELOG_STATE_FETCHED_DATA ||
-		opal_logs_state == ELOG_STATE_FETCHED_DATA)
-		opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL,
-					OPAL_EVENT_ERROR_LOG_AVAIL);
-	else
-		opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL, 0);
-}
-
 /* This function should be called with the lock held. */
 static inline void fsp_elog_set_head_state(enum elog_head_state state)
 {
@@ -279,7 +255,7 @@ static void fsp_elog_queue_fetch(void)
 }
 
 /* OPAL interface for PowerNV to read log size and log ID from Sapphire. */
-static int64_t fsp_opal_elog_info(uint64_t *opal_elog_id,
+int fsp_opal_elog_info(uint64_t *opal_elog_id,
 				  uint64_t *opal_elog_size, uint64_t *elog_type)
 {
 	struct fsp_log_entry *log_data;
@@ -287,10 +263,6 @@ static int64_t fsp_opal_elog_info(uint64_t *opal_elog_id,
 	/* Copy type of the error log */
 	*elog_type = ELOG_TYPE_PEL;
 
-	/* Check if any OPAL log needs to be reported to the host */
-	if (opal_elog_info(opal_elog_id, opal_elog_size))
-		return OPAL_SUCCESS;
-
 	lock(&elog_read_lock);
 	if (elog_read_from_fsp_head_state != ELOG_STATE_FETCHED_DATA) {
 		unlock(&elog_read_lock);
@@ -320,16 +292,12 @@ static int64_t fsp_opal_elog_info(uint64_t *opal_elog_id,
 }
 
 /* OPAL interface for PowerNV to read log from Sapphire. */
-static int64_t fsp_opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
+int fsp_opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
 				  uint64_t opal_elog_id)
 {
 	int size = opal_elog_size;
 	struct fsp_log_entry *log_data;
 
-	/* Check if any OPAL log needs to be reported to the PowerNV */
-	if (opal_elog_read(buffer, opal_elog_size, opal_elog_id))
-		return OPAL_SUCCESS;
-
 	/*
 	 * Read top entry from list.
 	 * As we know always top record of the list is fetched from FSP
@@ -393,14 +361,11 @@ static void elog_reject_head(void)
 }
 
 /* OPAL interface for PowerNV to send ack to FSP with log ID */
-static int64_t fsp_opal_elog_ack(uint64_t ack_id)
+int fsp_opal_elog_ack(uint64_t ack_id)
 {
 	int rc = 0;
 	struct fsp_log_entry  *record, *next_record;
 
-	if (opal_elog_ack(ack_id))
-		return rc;
-
 	/* Send acknowledgement to FSP */
 	rc = fsp_send_elog_ack(ack_id);
 	if (rc != OPAL_SUCCESS) {
@@ -445,18 +410,11 @@ static int64_t fsp_opal_elog_ack(uint64_t ack_id)
  * Once Linux kexec's it ask to resend all logs which
  * are not acknowledged from Linux.
  */
-static void fsp_opal_resend_pending_logs(void)
+void fsp_opal_resend_pending_logs(void)
 {
 	struct fsp_log_entry  *entry;
 
 	lock(&elog_read_lock);
-	elog_enabled = true;
-	unlock(&elog_read_lock);
-
-	/* Check if any Sapphire logs are pending. */
-	opal_resend_pending_logs();
-
-	lock(&elog_read_lock);
 	/*
 	 * If processed list is not empty add all record from
 	 * processed list to pending list at head of the list
@@ -475,17 +433,6 @@ static void fsp_opal_resend_pending_logs(void)
 	fsp_elog_check_and_fetch_head();
 }
 
-/* Disable ELOG event flag until PowerNV is ready to receive event */
-static bool opal_kexec_elog_notify(void *data __unused)
-{
-	lock(&elog_read_lock);
-	elog_enabled = false;
-	opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL, 0);
-	unlock(&elog_read_lock);
-
-	return true;
-}
-
 /* FSP elog notify function */
 static bool fsp_elog_msg(uint32_t cmd_sub_mod, struct fsp_msg *msg)
 {
@@ -610,13 +557,4 @@ void fsp_elog_read_init(void)
 
 	/* Register error log class D2 */
 	fsp_register_client(&fsp_get_elog_notify, FSP_MCLASS_ERR_LOG);
-
-	/* Register for sync on PowerNV reboot call */
-	opal_add_host_sync_notifier(opal_kexec_elog_notify, NULL);
-
-	/* Register OPAL interface */
-	opal_register(OPAL_ELOG_READ, fsp_opal_elog_read, 3);
-	opal_register(OPAL_ELOG_ACK, fsp_opal_elog_ack, 1);
-	opal_register(OPAL_ELOG_RESEND, fsp_opal_resend_pending_logs, 0);
-	opal_register(OPAL_ELOG_SIZE, fsp_opal_elog_info, 3);
 }
diff --git a/include/errorlog.h b/include/errorlog.h
index 8f58cd0..3225e49 100644
--- a/include/errorlog.h
+++ b/include/errorlog.h
@@ -372,13 +372,6 @@ void log_commit(struct errorlog *elog);
  * backend. If the error could not be logged successfully success is
  * set to false. */
 void opal_elog_complete(struct errorlog *elog, bool success);
-
-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);
diff --git a/include/fsp-elog.h b/include/fsp-elog.h
index f69f5c8..74197e2 100644
--- a/include/fsp-elog.h
+++ b/include/fsp-elog.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.
@@ -15,6 +15,7 @@
  */
 #ifndef __ELOG_H
 #define __ELOG_H
+
 #include <opal.h>
 #include <errorlog.h>
 #include <pel.h>
@@ -27,7 +28,11 @@
 				OPAL_FAILING_SUBSYSTEM << 16 | src_comp)
 
 int elog_fsp_commit(struct errorlog *buf) __warn_unused_result;
-
-void elog_set_head_state(bool opal_logs, enum elog_head_state state);
+int fsp_opal_elog_info(uint64_t *opal_elog_id,
+		uint64_t *opal_elog_size, uint64_t *elog_type);
+int fsp_opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
+		uint64_t opal_elog_id);
+int fsp_opal_elog_ack(uint64_t ack_id);
+void fsp_opal_resend_pending_logs(void);
 
 #endif /* __ELOG_H */
diff --git a/include/platform.h b/include/platform.h
index 334c0a4..3efebcd 100644
--- a/include/platform.h
+++ b/include/platform.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.
@@ -168,6 +168,29 @@ struct platform {
 	 * OPAL terminate
 	 */
 	void __attribute__((noreturn)) (*terminate)(const char *msg);
+
+	/*
+	 * OPAL interface for host OS to read elog size and log ID from OPAL
+	 */
+	int		(*elog_info)(uint64_t *opal_elog_id,
+				uint64_t *opal_elog_size, uint64_t *elog_type);
+
+	/*
+	 * OPAL interface for host OS to read elog from OPAL
+	 */
+	int		(*elog_read)(uint64_t *buffer, uint64_t opal_elog_size,
+				uint64_t opal_elog_id);
+
+	/*
+	 * OPAL interface for host OS to send elog acknowledgement
+	 */
+	int		(*elog_ack)(uint64_t ack_id);
+
+	/*
+	 * Once linux kexec's it ask to resend all logs which
+	 * are not acknowledged from linux
+	 */
+	void		(*resend_pending_elogs)(void);
 };
 
 extern struct platform __platforms_start;
diff --git a/platforms/ibm-fsp/apollo.c b/platforms/ibm-fsp/apollo.c
index d98699d..17595ef 100644
--- a/platforms/ibm-fsp/apollo.c
+++ b/platforms/ibm-fsp/apollo.c
@@ -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.
@@ -18,6 +18,7 @@
 #include <skiboot.h>
 #include <device.h>
 #include <fsp.h>
+#include <fsp-elog.h>
 #include <pci.h>
 #include <pci-slot.h>
 
@@ -47,4 +48,8 @@ DECLARE_PLATFORM(apollo) = {
 	.resource_loaded	= fsp_resource_loaded,
 	.sensor_read		= ibm_fsp_sensor_read,
 	.terminate		= ibm_fsp_terminate,
+	.elog_info		= fsp_opal_elog_info,
+	.elog_read		= fsp_opal_elog_read,
+	.elog_ack		= fsp_opal_elog_ack,
+	.resend_pending_elogs	= fsp_opal_resend_pending_logs,
 };
diff --git a/platforms/ibm-fsp/firenze.c b/platforms/ibm-fsp/firenze.c
index 00aba8d..da93ee5 100644
--- a/platforms/ibm-fsp/firenze.c
+++ b/platforms/ibm-fsp/firenze.c
@@ -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.
@@ -18,6 +18,7 @@
 #include <skiboot.h>
 #include <device.h>
 #include <fsp.h>
+#include <fsp-elog.h>
 #include <pci.h>
 #include <pci-cfg.h>
 #include <chip.h>
@@ -229,4 +230,8 @@ DECLARE_PLATFORM(firenze) = {
 	.resource_loaded	= fsp_resource_loaded,
 	.sensor_read		= ibm_fsp_sensor_read,
 	.terminate		= ibm_fsp_terminate,
+	.elog_info		= fsp_opal_elog_info,
+	.elog_read		= fsp_opal_elog_read,
+	.elog_ack		= fsp_opal_elog_ack,
+	.resend_pending_elogs	= fsp_opal_resend_pending_logs,
 };
-- 
2.7.4



More information about the Skiboot mailing list