aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.vnet.ibm.com>2016-07-21 16:53:56 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-07-21 16:53:56 +1000
commit4ee8c5e30d181f3e414e0d8cf8b4f88069f02827 (patch)
tree5c6cb682a170749ab34582e8495bda903f9a7b2b
parentc672a77a43c659b355230ac7dbdc66c476b8dd13 (diff)
parent1e89e2d6f8ee1927bab453de49b1aa68e70aee66 (diff)
downloadskiboot-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.c94
-rw-r--r--hw/fsp/fsp-elog-write.c31
-rw-r--r--include/fsp-elog.h3
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 */