From 566cb50023f37ad6f5dff778807ca891fc4409eb Mon Sep 17 00:00:00 2001 From: Deepthi Dharwar Date: Thu, 24 Jul 2014 12:02:08 +0530 Subject: elog: Elog read side framework changes to read Sapphire logs. This patch consists of elog-read framework changes to support pulling of Sapphire logs directly on to the host. Signed-off-by: Deepthi Dharwar Signed-off-by: Benjamin Herrenschmidt --- hw/fsp/fsp-elog-read.c | 11 +++++ hw/fsp/fsp-elog-write.c | 117 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 122 insertions(+), 6 deletions(-) (limited to 'hw') 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); -- cgit v1.1