@@ -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();
}
@@ -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);
}
@@ -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);
@@ -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 */
@@ -186,6 +186,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;
@@ -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,
};
@@ -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>
@@ -228,4 +229,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,
};