@@ -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();
+}
@@ -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);
}
@@ -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 */
@@ -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 */
@@ -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();