diff options
author | Vasant Hegde <hegdevasant@linux.vnet.ibm.com> | 2016-07-02 21:03:42 +0530 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2016-07-21 16:36:20 +1000 |
commit | e7c8cba4ad773055f390632c2996d3242b633bf4 (patch) | |
tree | d799b64dd96f62b4dc089385f92d7173c96541ae | |
parent | 1fb10de164d3ca034193df81c1f5d007aec37781 (diff) | |
download | skiboot-e7c8cba4ad773055f390632c2996d3242b633bf4.zip skiboot-e7c8cba4ad773055f390632c2996d3242b633bf4.tar.gz skiboot-e7c8cba4ad773055f390632c2996d3242b633bf4.tar.bz2 |
FSP/ELOG: Fix possible event notifier hangs
In some corner cases host may send acknowledgement without
reading actual data (fsp_opal_elog_info -> fsp_opal_elog_ack).
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
ELOG's to host. Hence reset ELOG state and start sending remaining
ELOG's.
Also in normal case we will ACK the logs which are already processed
(elog_read_processed). Hence rearrange the code such that we go
through elog_read_processed first.
Finally return OPAL_PARAMETER if we are not able to find ELOG ID.
Signed-off-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
[stewart@linux.vnet.ibm.com: spelling fix]
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r-- | hw/fsp/fsp-elog-read.c | 18 | ||||
-rw-r--r-- | hw/fsp/fsp-elog-write.c | 3 |
2 files changed, 18 insertions, 3 deletions
diff --git a/hw/fsp/fsp-elog-read.c b/hw/fsp/fsp-elog-read.c index b606236..4f0bf16 100644 --- a/hw/fsp/fsp-elog-read.c +++ b/hw/fsp/fsp-elog-read.c @@ -416,21 +416,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; } /* diff --git a/hw/fsp/fsp-elog-write.c b/hw/fsp/fsp-elog-write.c index 80a0a39..b78bc20 100644 --- a/hw/fsp/fsp-elog-write.c +++ b/hw/fsp/fsp-elog-write.c @@ -248,6 +248,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); |