aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/fsp/fsp-elog-read.c11
-rw-r--r--hw/fsp/fsp-elog-write.c117
-rw-r--r--include/fsp-elog.h7
3 files changed, 129 insertions, 6 deletions
diff --git a/hw/fsp/fsp-elog-read.c b/hw/fsp/fsp-elog-read.c
index c94f962..95a63a7 100644
--- a/hw/fsp/fsp-elog-read.c
+++ b/hw/fsp/fsp-elog-read.c
@@ -250,6 +250,10 @@ 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);
@@ -268,6 +272,10 @@ static int64_t fsp_opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
{
struct fsp_log_entry *log_data;
+
+ /* Check if any OPAL log needs to be reported to the host */
+ 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
@@ -321,6 +329,9 @@ static int64_t 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) {
diff --git a/hw/fsp/fsp-elog-write.c b/hw/fsp/fsp-elog-write.c
index 957d87c..87342a8 100644
--- a/hw/fsp/fsp-elog-write.c
+++ b/hw/fsp/fsp-elog-write.c
@@ -42,6 +42,7 @@
static LIST_HEAD(elog_write_to_fsp_pending);
static LIST_HEAD(elog_write_free);
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;
@@ -64,8 +65,10 @@ static void *elog_write_to_host_buffer;
struct opal_errorlog *panic_write_buffer;
static int panic_write_buffer_valid;
static uint32_t elog_write_retries;
+
/* Manipulate this only with write_lock held */
static uint32_t elog_plid_fsp_commit = -1;
+enum elog_head_state elog_write_to_host_head_state = ELOG_STATE_NONE;
/* Need forward declaration because of Circular dependency */
static int create_opal_event(struct opal_errorlog *elog_data, char *pel_buffer);
@@ -243,6 +246,111 @@ static int64_t fsp_opal_elog_write(size_t opal_elog_size)
return OPAL_SUCCESS;
}
+bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size)
+{
+ struct opal_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 opal_errorlog, link);
+ *opal_elog_id = head->plid;
+ *opal_elog_size = head->log_size;
+ elog_write_to_host_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 opal_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 opal_errorlog, link);
+ buf->log_size = create_opal_event(buf,
+ (char *)elog_write_to_host_buffer);
+ elog_write_to_host_head_state = ELOG_STATE_FETCHED_DATA;
+ opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL,
+ OPAL_EVENT_ERROR_LOG_AVAIL);
+ }
+ unlock(&elog_write_to_host_lock);
+}
+
+
+bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
+ uint64_t opal_elog_id)
+{
+ struct opal_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 opal_errorlog, link);
+
+ 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);
+ elog_write_to_host_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 opal_errorlog *log_data;
+ struct opal_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);
+ list_add(&elog_write_free, &record->link);
+ rc = true;
+ }
+ }
+
+ if ((!rc) && (!list_empty(&elog_write_to_host_pending))) {
+ log_data = list_top(&elog_write_to_host_pending,
+ struct opal_errorlog, link);
+ if (ack_id == log_data->plid)
+ elog_write_to_host_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);
+ list_add(&elog_write_free, &record->link);
+ rc = true;
+ }
+ }
+ unlock(&elog_write_to_host_lock);
+ return rc;
+}
+
static int opal_send_elog_to_fsp(void)
{
struct opal_errorlog *head;
@@ -561,7 +669,7 @@ static void create_private_header_section(struct opal_errorlog *elog_data,
else
privhdr->creator_id = OPAL_CID_POWERNV;
- privhdr->log_entry_id = 0x00; /* entry id is updated by FSP */
+ privhdr->log_entry_id = elog_data->plid; /*entry id is updated by FSP*/
*pel_offset += PRIVATE_HEADER_SECTION_SIZE;
}
@@ -602,7 +710,7 @@ static int create_opal_event(struct opal_errorlog *elog_data, char *pel_buffer)
{
int pel_offset = 0;
- memset(pel_buffer, 0, PSI_DMA_ERRLOG_WRITE_BUF_SZ);
+ memset(pel_buffer, 0, PSI_DMA_ELOG_WR_TO_HOST_BUF_SZ);
create_private_header_section(elog_data, pel_buffer, &pel_offset);
create_user_header_section(elog_data, pel_buffer, &pel_offset);
@@ -647,11 +755,8 @@ static void elog_append_write_to_host(struct opal_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);
- buf->log_size = create_opal_event(buf,
- (char *)elog_write_to_host_buffer);
unlock(&elog_write_to_host_lock);
- opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL,
- OPAL_EVENT_ERROR_LOG_AVAIL);
+ opal_commit_elog_in_host();
} else {
list_add_tail(&elog_write_to_host_pending, &buf->link);
unlock(&elog_write_to_host_lock);
diff --git a/include/fsp-elog.h b/include/fsp-elog.h
index 864a590..a3217b7 100644
--- a/include/fsp-elog.h
+++ b/include/fsp-elog.h
@@ -361,6 +361,13 @@ int opal_elog_update_user_dump(struct opal_errorlog *buf, unsigned char *data,
int elog_fsp_commit(struct opal_errorlog *buf);
+bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size);
+
+bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size,
+ uint64_t opal_elog_id);
+
+bool opal_elog_ack(uint64_t ack_id);
+
/* This is wrapper around the error log function, which creates
* and commits the error to FSP.
* Used for simple error logging