diff options
author | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-07-21 16:53:56 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-07-21 16:53:56 +1000 |
commit | 4ee8c5e30d181f3e414e0d8cf8b4f88069f02827 (patch) | |
tree | 5c6cb682a170749ab34582e8495bda903f9a7b2b | |
parent | c672a77a43c659b355230ac7dbdc66c476b8dd13 (diff) | |
parent | 1e89e2d6f8ee1927bab453de49b1aa68e70aee66 (diff) | |
download | skiboot-4ee8c5e30d181f3e414e0d8cf8b4f88069f02827.zip skiboot-4ee8c5e30d181f3e414e0d8cf8b4f88069f02827.tar.gz skiboot-4ee8c5e30d181f3e414e0d8cf8b4f88069f02827.tar.bz2 |
Merge branch 'skiboot-5.1.x' into skiboot-5.2.x
-rw-r--r-- | hw/fsp/fsp-elog-read.c | 94 | ||||
-rw-r--r-- | hw/fsp/fsp-elog-write.c | 31 | ||||
-rw-r--r-- | include/fsp-elog.h | 3 |
3 files changed, 89 insertions, 39 deletions
diff --git a/hw/fsp/fsp-elog-read.c b/hw/fsp/fsp-elog-read.c index 16667ae..7fc6709 100644 --- a/hw/fsp/fsp-elog-read.c +++ b/hw/fsp/fsp-elog-read.c @@ -88,6 +88,8 @@ 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; + /* Need forward declaration because of Circular dependency */ static void fsp_elog_queue_fetch(void); @@ -130,6 +132,9 @@ static int64_t fsp_send_elog_ack(uint32_t log_id) /* retrive error log from FSP with TCE for the data transfer */ static void fsp_elog_check_and_fetch_head(void) { + if (!elog_enabled) + return; + lock(&elog_read_lock); if (elog_read_from_fsp_head_state != ELOG_STATE_NONE || @@ -145,22 +150,35 @@ static void fsp_elog_check_and_fetch_head(void) unlock(&elog_read_lock); } -/* this function should be called with the lock held */ -static void fsp_elog_set_head_state(enum elog_head_state state) +void elog_set_head_state(bool opal_logs, enum elog_head_state state) { - enum elog_head_state old_state = elog_read_from_fsp_head_state; + static enum elog_head_state opal_logs_state = ELOG_STATE_NONE; + static enum elog_head_state fsp_logs_state = ELOG_STATE_NONE; - elog_read_from_fsp_head_state = state; + /* ELOG disabled */ + if (!elog_enabled) + return; - if (state == ELOG_STATE_FETCHED_DATA && - old_state != ELOG_STATE_FETCHED_DATA) + 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); - if (state != ELOG_STATE_FETCHED_DATA && - old_state == ELOG_STATE_FETCHED_DATA) + 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) +{ + elog_set_head_state(false, state); + elog_read_from_fsp_head_state = state; +} + /* * when we try maximum time of fetching log from fsp * we call following function to delete log from the @@ -281,11 +299,13 @@ static int64_t fsp_opal_elog_info(uint64_t *opal_elog_id, if (!log_data) { prlog(PR_ERR, "%s: Inconsistent internal list state !\n", __func__); + fsp_elog_set_head_state(ELOG_STATE_NONE); unlock(&elog_read_lock); return OPAL_WRONG_STATE; } *opal_elog_id = log_data->log_id; *opal_elog_size = log_data->log_size; + fsp_elog_set_head_state(ELOG_STATE_HOST_INFO); unlock(&elog_read_lock); return OPAL_SUCCESS; } @@ -306,7 +326,7 @@ static int64_t fsp_opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size, * as we know always top record of the list is fetched from FSP */ lock(&elog_read_lock); - if (elog_read_from_fsp_head_state != ELOG_STATE_FETCHED_DATA) { + if (elog_read_from_fsp_head_state != ELOG_STATE_HOST_INFO) { unlock(&elog_read_lock); return OPAL_WRONG_STATE; } @@ -315,6 +335,7 @@ static int64_t fsp_opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size, if (!log_data) { prlog(PR_ERR, "%s: Inconsistent internal list state !\n", __func__); + fsp_elog_set_head_state(ELOG_STATE_NONE); unlock(&elog_read_lock); return OPAL_WRONG_STATE; } @@ -354,7 +375,7 @@ static void elog_reject_head(void) { if (elog_read_from_fsp_head_state == ELOG_STATE_FETCHING) fsp_elog_set_head_state(ELOG_STATE_REJECTED); - if (elog_read_from_fsp_head_state == ELOG_STATE_FETCHED_DATA) + else fsp_elog_set_head_state(ELOG_STATE_NONE); } @@ -374,21 +395,33 @@ static int64_t fsp_opal_elog_ack(uint64_t ack_id) return rc; } lock(&elog_read_lock); - list_for_each_safe(&elog_read_pending, record, next_record, link) { + list_for_each_safe(&elog_read_processed, record, next_record, link) { if (record->log_id != ack_id) continue; list_del(&record->link); list_add(&elog_read_free, &record->link); + unlock(&elog_read_lock); + return rc; } - list_for_each_safe(&elog_read_processed, record, next_record, link) { + list_for_each_safe(&elog_read_pending, record, next_record, link) { if (record->log_id != ack_id) continue; + /* It means host has sent ACK without reading actual data. + * Because of this elog_read_from_fsp_head_state may be + * stuck in wrong state (ELOG_STATE_HOST_INFO) and not able + * to send remaining ELOGs to host. Hence reset ELOG state + * and start sending remaining ELOGs. + */ list_del(&record->link); list_add(&elog_read_free, &record->link); + elog_reject_head(); + unlock(&elog_read_lock); + fsp_elog_check_and_fetch_head(); + return rc; } unlock(&elog_read_lock); - return rc; + return OPAL_PARAMETER; } /* @@ -399,6 +432,10 @@ static 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(); @@ -414,23 +451,25 @@ static void fsp_opal_resend_pending_logs(void) list_add(&elog_read_pending, &entry->link); } - /* - * If the current fetched or fetching log doesn't match our - * new pending list head, then reject it - */ - if (!list_empty(&elog_read_pending)) { - entry = list_top(&elog_read_pending, - struct fsp_log_entry, link); - if (entry->log_id != elog_head_id) - elog_reject_head(); - } - unlock(&elog_read_lock); - /* Read error log from FSP if needed */ + /* Read error log from FSP */ + elog_reject_head(); fsp_elog_check_and_fetch_head(); } +/* Disable ELOG event flag until host is ready to receive event */ +static bool opal_kexec_elog_notify(void *data __unused) +{ + lock(&elog_read_lock); + elog_reject_head(); + 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) { @@ -552,9 +591,14 @@ void fsp_elog_read_init(void) if (val != 0) return; + elog_enabled = true; + /* register Eror log Class D2 */ fsp_register_client(&fsp_get_elog_notify, FSP_MCLASS_ERR_LOG); + /* Register for sync on host 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); diff --git a/hw/fsp/fsp-elog-write.c b/hw/fsp/fsp-elog-write.c index cf915a2..fd6ded2 100644 --- a/hw/fsp/fsp-elog-write.c +++ b/hw/fsp/fsp-elog-write.c @@ -126,6 +126,13 @@ 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; @@ -139,11 +146,11 @@ bool opal_elog_info(uint64_t *opal_elog_id, uint64_t *opal_elog_size) prlog(PR_ERR, "%s: Inconsistent internal list state !\n", __func__); - elog_write_to_host_head_state = ELOG_STATE_NONE; + fsp_elog_write_set_head_state(ELOG_STATE_NONE); } else { *opal_elog_id = head->plid; *opal_elog_size = head->log_size; - elog_write_to_host_head_state = ELOG_STATE_FETCHED_INFO; + fsp_elog_write_set_head_state(ELOG_STATE_FETCHED_INFO); rc = true; } } @@ -164,9 +171,7 @@ static void opal_commit_elog_in_host(void) buf->log_size = create_pel_log(buf, (char *)elog_write_to_host_buffer, ELOG_WRITE_TO_HOST_BUFFER_SIZE); - elog_write_to_host_head_state = ELOG_STATE_FETCHED_DATA; - opal_update_pending_evt(OPAL_EVENT_ERROR_LOG_AVAIL, - OPAL_EVENT_ERROR_LOG_AVAIL); + fsp_elog_write_set_head_state(ELOG_STATE_FETCHED_DATA); } unlock(&elog_write_to_host_lock); } @@ -183,7 +188,7 @@ bool opal_elog_read(uint64_t *buffer, uint64_t opal_elog_size, log_data = list_top(&elog_write_to_host_pending, struct errorlog, link); if (!log_data) { - elog_write_to_host_head_state = ELOG_STATE_NONE; + fsp_elog_write_set_head_state(ELOG_STATE_NONE); unlock(&elog_write_to_host_lock); return rc; } @@ -198,7 +203,7 @@ 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); - elog_write_to_host_head_state = ELOG_STATE_NONE; + fsp_elog_write_set_head_state(ELOG_STATE_NONE); rc = true; } unlock(&elog_write_to_host_lock); @@ -228,7 +233,7 @@ bool opal_elog_ack(uint64_t ack_id) log_data = list_top(&elog_write_to_host_pending, struct errorlog, link); if (ack_id == log_data->plid) - elog_write_to_host_head_state = ELOG_STATE_NONE; + fsp_elog_write_set_head_state(ELOG_STATE_NONE); list_for_each_safe(&elog_write_to_host_pending, record, next_record, link) { @@ -237,6 +242,9 @@ 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; } } unlock(&elog_write_to_host_lock); @@ -248,17 +256,12 @@ void opal_resend_pending_logs(void) struct errorlog *record; lock(&elog_write_to_host_lock); - if (list_empty(&elog_write_to_host_processed)) { - unlock(&elog_write_to_host_lock); - return; - } - 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); } - elog_write_to_host_head_state = ELOG_STATE_NONE; + fsp_elog_write_set_head_state(ELOG_STATE_NONE); unlock(&elog_write_to_host_lock); opal_commit_elog_in_host(); } diff --git a/include/fsp-elog.h b/include/fsp-elog.h index 1522b18..a796f5e 100644 --- a/include/fsp-elog.h +++ b/include/fsp-elog.h @@ -31,6 +31,7 @@ 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 */ }; @@ -50,4 +51,6 @@ 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 */ |