aboutsummaryrefslogtreecommitdiff
path: root/hw/fsp/fsp-elog-write.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/fsp/fsp-elog-write.c')
-rw-r--r--hw/fsp/fsp-elog-write.c643
1 files changed, 643 insertions, 0 deletions
diff --git a/hw/fsp/fsp-elog-write.c b/hw/fsp/fsp-elog-write.c
new file mode 100644
index 0000000..ee79c4d
--- /dev/null
+++ b/hw/fsp/fsp-elog-write.c
@@ -0,0 +1,643 @@
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/*
+ * This code will enable generation and pushing of error log
+ * from powernv, sapphire to FSP
+ * Critical events from sapphire that needs to be reported
+ * will be pushed on to FSP after converting the
+ * error log to Platform Error Log (PEL) format.
+ * This is termed as WRITE action to FSP.
+ */
+
+#include <skiboot.h>
+#include <fsp.h>
+#include <cpu.h>
+#include <lock.h>
+#include <errno.h>
+#include <fsp-elog.h>
+
+/*
+ * Maximum number buffers that are pre-allocated
+ * to hold elogs that are reported on Sapphire and
+ * powernv.
+ */
+#define ELOG_WRITE_MAX_RECORD 64
+
+static LIST_HEAD(elog_write_pending);
+static LIST_HEAD(elog_write_free);
+
+static struct lock elog_write_lock = LOCK_UNLOCKED;
+static struct lock elog_panic_write_lock = LOCK_UNLOCKED;
+
+/* Platform Log ID as per the spec */
+static uint32_t sapphire_elog_id = 0xB0000000;
+static uint32_t powernv_elog_id = 0xB1000000;
+
+/* log buffer to copy FSP log for READ */
+#define ELOG_WRITE_BUFFER_SIZE 0x00050000
+static void *elog_write_buffer = NULL;
+
+#define ELOG_PANIC_WRITE_BUFFER_SIZE 0x0010000
+static void *elog_panic_write_buffer = NULL;
+
+struct opal_errorlog *panic_write_buffer;
+static int panic_write_buffer_valid;
+static uint32_t elog_write_retries;
+
+/* Need forward declaration because of Circular dependency */
+static int create_opal_event(struct opal_errorlog *elog_data, char *pel_buffer);
+static int opal_send_elog_to_fsp(void);
+
+void log_error(struct opal_err_info *e_info, void *data, uint16_t size,
+ const char *fmt, ...)
+{
+ struct opal_errorlog *buf;
+ int tag = 0x44455343; /* ASCII of DESC */
+ va_list list;
+ char err_msg[250];
+
+ va_start(list, fmt);
+ vsnprintf(err_msg, sizeof(err_msg), fmt, list);
+ va_end(list);
+
+ /* Log the error on to Sapphire console */
+ prerror("%s", err_msg);
+
+ buf = opal_elog_create(e_info);
+ if (buf == NULL)
+ prerror("ELOG: Error getting buffer to log error\n");
+ else {
+ opal_elog_update_user_dump(buf, err_msg, tag, strlen(err_msg));
+ /* Append any number of call out dumps */
+ if (e_info->call_out)
+ e_info->call_out(buf, data, size);
+ if (elog_fsp_commit(buf))
+ prerror("ELOG: Re-try error logging\n");
+ }
+}
+
+
+void log_simple_error(struct opal_err_info *e_info, const char *fmt, ...)
+{
+ struct opal_errorlog *buf;
+ int tag = 0x44455343; /* ASCII of DESC */
+ va_list list;
+ char err_msg[250];
+
+ va_start(list, fmt);
+ vsnprintf(err_msg, sizeof(err_msg), fmt, list);
+ va_end(list);
+
+ /* Log the error on to Sapphire console */
+ prerror("%s", err_msg);
+
+ buf = opal_elog_create(e_info);
+ if (buf == NULL)
+ prerror("ELOG: Error getting buffer to log error\n");
+ else {
+ opal_elog_update_user_dump(buf, err_msg, tag, strlen(err_msg));
+ if (elog_fsp_commit(buf))
+ prerror("ELOG: Re-try error logging\n");
+ }
+}
+
+static struct opal_errorlog *get_write_buffer(int opal_event_severity)
+{
+ struct opal_errorlog *buf;
+
+ lock(&elog_write_lock);
+ if (list_empty(&elog_write_free)) {
+ unlock(&elog_write_lock);
+ if (opal_event_severity == OPAL_ERROR_PANIC) {
+ lock(&elog_panic_write_lock);
+ if (panic_write_buffer_valid == 0) {
+ buf = (struct opal_errorlog *)
+ panic_write_buffer;
+ panic_write_buffer_valid = 1; /* In Use */
+ unlock(&elog_panic_write_lock);
+ } else {
+ unlock(&elog_panic_write_lock);
+ prerror("ELOG: Write buffer full. Retry later\n");
+ return NULL;
+ }
+ } else {
+ prerror("ELOG: Write buffer list is full. Retry later\n");
+ return NULL;
+ }
+ } else {
+ buf = list_pop(&elog_write_free, struct opal_errorlog, link);
+ unlock(&elog_write_lock);
+ }
+
+ memset(buf, 0, sizeof(struct opal_errorlog));
+ return buf;
+}
+
+/* Reporting of error via struct opal_errorlog */
+struct opal_errorlog *opal_elog_create(struct opal_err_info *e_info)
+{
+ struct opal_errorlog *buf;
+
+ buf = get_write_buffer(e_info->sev);
+ if (buf) {
+ buf->error_event_type = e_info->err_type;
+ buf->component_id = e_info->cmp_id;
+ buf->subsystem_id = e_info->subsystem;
+ buf->event_severity = e_info->sev;
+ buf->event_subtype = e_info->event_subtype;
+ buf->reason_code = e_info->reason_code;
+ buf->elog_origin = ORG_SAPPHIRE;
+ }
+
+ return buf;
+}
+
+static void remove_elog_head_entry(void)
+{
+ struct opal_errorlog *entry;
+
+ lock(&elog_write_lock);
+ entry = list_pop(&elog_write_pending, struct opal_errorlog, link);
+ list_add_tail(&elog_write_free, &entry->link);
+ elog_write_retries = 0;
+ unlock(&elog_write_lock);
+}
+
+static void opal_fsp_write_complete(struct fsp_msg *read_msg)
+{
+ uint8_t val;
+
+ val = (read_msg->resp->word1 >> 8) & 0xff;
+ fsp_freemsg(read_msg);
+
+ switch (val) {
+ case FSP_STATUS_SUCCESS:
+ remove_elog_head_entry();
+ break;
+
+ default:
+ if (elog_write_retries++ >= MAX_RETRIES) {
+ remove_elog_head_entry();
+ prerror("ELOG: Error in writing to FSP!\n");
+ }
+ break;
+ }
+
+ if (opal_send_elog_to_fsp() != OPAL_SUCCESS)
+ prerror("ELOG: Error sending elog to FSP !\n");
+}
+
+/* write PEL format hex dump of the log to FSP */
+static int64_t fsp_opal_elog_write(size_t opal_elog_size)
+{
+ struct fsp_msg *elog_msg;
+
+ elog_msg = fsp_mkmsg(FSP_CMD_CREATE_ERRLOG, 3, opal_elog_size,
+ 0, PSI_DMA_ERRLOG_WRITE_BUF);
+ if (!elog_msg) {
+ prerror("ELOG: Failed to create message for WRITE to FSP\n");
+ return OPAL_INTERNAL_ERROR;
+ }
+ if (fsp_queue_msg(elog_msg, opal_fsp_write_complete)) {
+ fsp_freemsg(elog_msg);
+ elog_msg = NULL;
+ prerror("FSP: Error queueing elog update\n");
+ return OPAL_INTERNAL_ERROR;
+ }
+ return OPAL_SUCCESS;
+}
+
+static int opal_send_elog_to_fsp(void)
+{
+ struct opal_errorlog *head;
+ int rc = OPAL_SUCCESS;
+ int pel_offset = 0;
+
+ /* Convert entry to PEL
+ * and push it down to FSP. We wait for the ack from
+ * FSP.
+ */
+ lock(&elog_write_lock);
+ if (!list_empty(&elog_write_pending)) {
+ head = list_top(&elog_write_pending,
+ struct opal_errorlog, link);
+ pel_offset = create_opal_event(head, (char *)elog_write_buffer);
+ rc = fsp_opal_elog_write(pel_offset);
+ unlock(&elog_write_lock);
+ return rc;
+ }
+ unlock(&elog_write_lock);
+ return rc;
+}
+
+static int opal_push_logs_sync_to_fsp(struct opal_errorlog *buf)
+{
+ struct fsp_msg *elog_msg;
+ int opal_elog_size = 0;
+ int rc = OPAL_SUCCESS;
+
+ lock(&elog_panic_write_lock);
+ opal_elog_size = create_opal_event(buf,
+ (char *)elog_panic_write_buffer);
+
+ elog_msg = fsp_mkmsg(FSP_CMD_CREATE_ERRLOG, 3, opal_elog_size,
+ 0, PSI_DMA_ELOG_PANIC_WRITE_BUF);
+ if (!elog_msg) {
+ prerror("ELOG: Failed to create message for WRITE to FSP\n");
+ unlock(&elog_panic_write_lock);
+ return OPAL_INTERNAL_ERROR;
+ }
+
+ if (fsp_sync_msg(elog_msg, false)) {
+ fsp_freemsg(elog_msg);
+ rc = OPAL_INTERNAL_ERROR;
+ } else {
+ rc = (elog_msg->resp->word1 >> 8) & 0xff;
+ fsp_freemsg(elog_msg);
+ }
+
+ if ((buf == panic_write_buffer) && (panic_write_buffer_valid == 1)) {
+ panic_write_buffer_valid = 0;
+ unlock(&elog_panic_write_lock);
+ } else {
+ /* buffer got from the elog_write list , put it back */
+ unlock(&elog_panic_write_lock);
+ lock(&elog_write_lock);
+ list_add_tail(&elog_write_free, &buf->link);
+ unlock(&elog_write_lock);
+ }
+ return rc;
+}
+
+int elog_fsp_commit(struct opal_errorlog *buf)
+{
+ int rc = OPAL_SUCCESS;
+
+ if (buf->event_severity == OPAL_ERROR_PANIC) {
+ rc = opal_push_logs_sync_to_fsp(buf);
+ return rc;
+ }
+
+ lock(&elog_write_lock);
+ if (list_empty(&elog_write_pending)) {
+ list_add_tail(&elog_write_pending, &buf->link);
+ unlock(&elog_write_lock);
+ rc = opal_send_elog_to_fsp();
+ return rc;
+ }
+ list_add_tail(&elog_write_pending, &buf->link);
+ unlock(&elog_write_lock);
+ return rc;
+}
+
+/* This function is called from POWERNV to push logs
+ * on FSP
+ */
+static int opal_commit_log_to_fsp(struct opal_errorlog *buf)
+{
+ struct opal_errorlog *opal_buf;
+ int rc = OPAL_SUCCESS;
+
+ /* Copy the buffer to Sapphire and queue it to push
+ * to FSP and return
+ */
+ lock(&elog_write_lock);
+ if (list_empty(&elog_write_free)) {
+ unlock(&elog_write_lock);
+ prerror("ELOG: Error! Write buffer list is full. Retry later\n");
+ return -1;
+ }
+ opal_buf = list_pop(&elog_write_free, struct opal_errorlog, link);
+ unlock(&elog_write_lock);
+ memcpy(opal_buf, buf, sizeof(struct opal_errorlog));
+ opal_buf->elog_origin = ORG_POWERNV;
+ rc = elog_fsp_commit(opal_buf);
+ return rc;
+}
+
+int opal_elog_update_user_dump(struct opal_errorlog *buf, unsigned char *data,
+ uint32_t tag, uint16_t size)
+{
+ char *buffer;
+ struct opal_user_data_section *tmp;
+
+ if (!buf) {
+ prerror("ELOG: Cannot update user data. Buffer is invalid\n");
+ return -1;
+ }
+
+ buffer = (char *)buf->user_data_dump + buf->user_section_size;
+ if ((buf->user_section_size + size) > OPAL_LOG_MAX_DUMP) {
+ prerror("ELOG: Size of dump data overruns buffer\n");
+ return -1;
+ }
+
+ tmp = (struct opal_user_data_section *)buffer;
+ tmp->tag = tag;
+ tmp->size = size + sizeof(struct opal_user_data_section) - 1;
+ memcpy(tmp->data_dump, data, size);
+
+ buf->user_section_size += tmp->size;
+ buf->user_section_count++;
+ return 0;
+}
+
+/* Create MTMS section for sapphire log */
+static void create_mtms_section(struct opal_errorlog *elog_data,
+ char *pel_buffer, int *pel_offset)
+{
+ struct opal_mtms_section *mtms = (struct opal_mtms_section *)
+ (pel_buffer + *pel_offset);
+
+ mtms->v6header.id = ELOG_SID_MACHINE_TYPE;
+ mtms->v6header.length = MTMS_SECTION_SIZE;
+ mtms->v6header.version = OPAL_EXT_HRD_VER;
+ mtms->v6header.subtype = 0;
+ mtms->v6header.component_id = elog_data->component_id;
+
+ memset(mtms->model, 0x00, sizeof(mtms->model));
+ memcpy(mtms->model, dt_prop_get(dt_root, "model"), OPAL_SYS_MODEL_LEN);
+ memset(mtms->serial_no, 0x00, sizeof(mtms->serial_no));
+
+ memcpy(mtms->serial_no, dt_prop_get(dt_root, "system-id"),
+ OPAL_SYS_SERIAL_LEN);
+ *pel_offset += MTMS_SECTION_SIZE;
+}
+
+/* Create extended header section */
+static void create_extended_header_section(struct opal_errorlog *elog_data,
+ char *pel_buffer, int *pel_offset)
+{
+ const char *opalmodel = NULL;
+ uint64_t extd_time;
+
+ struct opal_extended_header_section *extdhdr =
+ (struct opal_extended_header_section *)
+ (pel_buffer + *pel_offset);
+
+ extdhdr->v6header.id = ELOG_SID_EXTENDED_HEADER;
+ extdhdr->v6header.length = EXTENDED_HEADER_SECTION_SIZE;
+ extdhdr->v6header.version = OPAL_EXT_HRD_VER;
+ extdhdr->v6header.subtype = 0;
+ extdhdr->v6header.component_id = elog_data->component_id;
+
+ memset(extdhdr->model, 0x00, sizeof(extdhdr->model));
+ opalmodel = dt_prop_get(dt_root, "model");
+ memcpy(extdhdr->model, opalmodel, OPAL_SYS_MODEL_LEN);
+
+ memset(extdhdr->serial_no, 0x00, sizeof(extdhdr->serial_no));
+ memcpy(extdhdr->serial_no, dt_prop_get(dt_root, "system-id"),
+ OPAL_SYS_SERIAL_LEN);
+
+ memset(extdhdr->opal_release_version, 0x00,
+ sizeof(extdhdr->opal_release_version));
+ memset(extdhdr->opal_subsys_version, 0x00,
+ sizeof(extdhdr->opal_subsys_version));
+
+ fsp_rtc_get_cached_tod(&extdhdr->extended_header_date, &extd_time);
+ extdhdr->extended_header_time = extd_time >> 32;
+ extdhdr->opal_symid_len = 0;
+ memset(extdhdr->opalsymid, 0x00, sizeof(extdhdr->opalsymid));
+
+ *pel_offset += EXTENDED_HEADER_SECTION_SIZE;
+}
+
+/* set src type */
+static void settype(struct opal_src_section *src, uint8_t src_type)
+{
+ char type[4];
+ sprintf(type, "%02X", src_type);
+ memcpy(src->srcstring, type, 2);
+}
+
+/* set SRC subsystem type */
+static void setsubsys(struct opal_src_section *src, uint8_t src_subsys)
+{
+ char subsys[4];
+ sprintf(subsys, "%02X", src_subsys);
+ memcpy(src->srcstring+2, subsys, 2);
+}
+
+/* Ser reason code of SRC */
+static void setrefcode(struct opal_src_section *src, uint16_t src_refcode)
+{
+ char refcode[8];
+ sprintf(refcode, "%04X", src_refcode);
+ memcpy(src->srcstring+4, refcode, 4);
+}
+
+/* Create SRC section of OPAL log */
+static void create_src_section(struct opal_errorlog *elog_data,
+ char *pel_buffer, int *pel_offset)
+{
+ struct opal_src_section *src = (struct opal_src_section *)
+ (pel_buffer + *pel_offset);
+
+ src->v6header.id = ELOG_SID_PRIMARY_SRC;
+ src->v6header.length = SRC_SECTION_SIZE;
+ src->v6header.version = OPAL_ELOG_VERSION;
+ src->v6header.subtype = OPAL_ELOG_SST;
+ src->v6header.component_id = elog_data->component_id;
+
+ src->version = OPAL_SRC_SEC_VER;
+ src->flags = 0;
+ src->wordcount = OPAL_SRC_MAX_WORD_COUNT;
+ src->srclength = SRC_LENGTH;
+ settype(src, OPAL_SRC_TYPE_ERROR);
+ setsubsys(src, OPAL_FAILING_SUBSYSTEM);
+ setrefcode(src, elog_data->reason_code);
+ memset(src->hexwords, 0 , (8 * 4));
+ src->hexwords[0] = OPAL_SRC_FORMAT;
+ src->hexwords[4] = elog_data->additional_info[0];
+ src->hexwords[5] = elog_data->additional_info[1];
+ src->hexwords[6] = elog_data->additional_info[2];
+ src->hexwords[7] = elog_data->additional_info[3];
+ *pel_offset += SRC_SECTION_SIZE;
+}
+
+/* Create user header section */
+static void create_user_header_section(struct opal_errorlog *elog_data,
+ char *pel_buffer, int *pel_offset)
+{
+ struct opal_user_header_section *usrhdr =
+ (struct opal_user_header_section *)
+ (pel_buffer + *pel_offset);
+
+ usrhdr->v6header.id = ELOG_SID_USER_HEADER;
+ usrhdr->v6header.length = USER_HEADER_SECTION_SIZE;
+ usrhdr->v6header.version = OPAL_ELOG_VERSION;
+ usrhdr->v6header.subtype = OPAL_ELOG_SST;
+ usrhdr->v6header.component_id = elog_data->component_id;
+
+ usrhdr->subsystem_id = elog_data->subsystem_id;
+ usrhdr->event_scope = 0;
+ usrhdr->event_severity = elog_data->event_severity;
+ usrhdr->event_type = elog_data->event_subtype;
+
+ if (elog_data->elog_origin == ORG_SAPPHIRE)
+ usrhdr->action_flags = ERRL_ACTION_REPORT;
+ else
+ usrhdr->action_flags = ERRL_ACTION_NONE;
+
+ *pel_offset += USER_HEADER_SECTION_SIZE;
+}
+
+/* Create private header section */
+static void create_private_header_section(struct opal_errorlog *elog_data,
+ char *pel_buffer, int *pel_offset)
+{
+ uint64_t ctime;
+ struct opal_private_header_section *privhdr =
+ (struct opal_private_header_section *)
+ pel_buffer;
+
+ privhdr->v6header.id = ELOG_SID_PRIVATE_HEADER;
+ privhdr->v6header.length = PRIVATE_HEADER_SECTION_SIZE;
+ privhdr->v6header.version = OPAL_ELOG_VERSION;
+ privhdr->v6header.subtype = OPAL_ELOG_SST;
+ privhdr->v6header.component_id = elog_data->component_id;
+
+ fsp_rtc_get_cached_tod(&privhdr->create_date, &ctime);
+ privhdr->create_time = ctime >> 32;
+ privhdr->section_count = 5;
+
+ privhdr->creator_subid_hi = 0x00;
+ privhdr->creator_subid_lo = 0x00;
+
+ if (elog_data->elog_origin == ORG_SAPPHIRE) {
+ privhdr->plid = ++sapphire_elog_id;
+ privhdr->creator_id = OPAL_CID_SAPPHIRE;
+ } else {
+ privhdr->plid = ++powernv_elog_id;
+ privhdr->creator_id = OPAL_CID_POWERNV;
+ }
+ privhdr->log_entry_id = 0x00; /* entry id is updated by FSP */
+
+ *pel_offset += PRIVATE_HEADER_SECTION_SIZE;
+}
+
+static void create_user_defined_section(struct opal_errorlog *elog_data,
+ char *pel_buffer, int *pel_offset)
+{
+ char *dump = (char *)pel_buffer + *pel_offset;
+ char *opal_buf = (char *)elog_data->user_data_dump;
+ struct opal_user_section *usrhdr;
+ struct opal_user_data_section *opal_usr_data;
+ struct opal_private_header_section *privhdr =
+ (struct opal_private_header_section *)pel_buffer;
+ int i;
+
+ for (i = 0; i < elog_data->user_section_count; i++) {
+
+ usrhdr = (struct opal_user_section *)dump;
+ opal_usr_data = (struct opal_user_data_section *)opal_buf;
+
+ usrhdr->v6header.id = ELOG_SID_USER_DEFINED;
+ usrhdr->v6header.version = OPAL_ELOG_VERSION;
+ usrhdr->v6header.length = sizeof(struct opal_v6_header) +
+ opal_usr_data->size;
+ usrhdr->v6header.subtype = OPAL_ELOG_SST;
+ usrhdr->v6header.component_id = elog_data->component_id;
+
+ memcpy(usrhdr->dump, opal_buf, opal_usr_data->size);
+ *pel_offset += usrhdr->v6header.length;
+ dump += usrhdr->v6header.length;
+ opal_buf += opal_usr_data->size;
+ privhdr->section_count++;
+ }
+}
+
+/* Create all require section of PEL log and write to TCE buffer */
+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);
+
+ create_private_header_section(elog_data, pel_buffer, &pel_offset);
+ create_user_header_section(elog_data, pel_buffer, &pel_offset);
+ create_src_section(elog_data, pel_buffer, &pel_offset);
+ create_extended_header_section(elog_data, pel_buffer, &pel_offset);
+ create_mtms_section(elog_data, pel_buffer, &pel_offset);
+ if (elog_data->user_section_count)
+ create_user_defined_section(elog_data, pel_buffer, &pel_offset);
+
+ return pel_offset;
+}
+
+/* Pre-allocate memory for writing error log to FSP */
+static int init_elog_write_free_list(uint32_t num_entries)
+{
+ struct opal_errorlog *entry;
+ int i;
+
+ entry = zalloc(sizeof(struct opal_errorlog) * num_entries);
+ if (!entry)
+ goto out_err;
+
+ for (i = 0; i < num_entries; ++i) {
+ list_add_tail(&elog_write_free, &entry->link);
+ entry++;
+ }
+
+ /* Pre-allocate one single buffer for PANIC path */
+ panic_write_buffer = zalloc(sizeof(struct opal_errorlog));
+ if (!panic_write_buffer)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ return -ENOMEM;
+}
+
+/* fsp elog init function */
+void fsp_elog_write_init(void)
+{
+ if (!fsp_present())
+ return;
+
+ elog_panic_write_buffer = memalign(TCE_PSIZE,
+ ELOG_PANIC_WRITE_BUFFER_SIZE);
+ if (!elog_panic_write_buffer) {
+ prerror("FSP: could not allocate ELOG_PANIC_WRITE_BUFFER!\n");
+ return;
+ }
+
+ elog_write_buffer = memalign(TCE_PSIZE, ELOG_WRITE_BUFFER_SIZE);
+ if (!elog_write_buffer) {
+ prerror("FSP: could not allocate ELOG_WRITE_BUFFER!\n");
+ return;
+ }
+
+ /* Map TCEs */
+ fsp_tce_map(PSI_DMA_ELOG_PANIC_WRITE_BUF, elog_panic_write_buffer,
+ PSI_DMA_ELOG_PANIC_WRITE_BUF_SZ);
+
+ fsp_tce_map(PSI_DMA_ERRLOG_WRITE_BUF, elog_write_buffer,
+ PSI_DMA_ERRLOG_WRITE_BUF_SZ);
+
+ /* pre-allocate memory for 128 records */
+ if (init_elog_write_free_list(ELOG_WRITE_MAX_RECORD)) {
+ prerror("ELOG: Cannot allocate WRITE buffers to log errors!\n");
+ return;
+ }
+
+ /* register opal Interface */
+ opal_register(OPAL_ELOG_SEND, opal_commit_log_to_fsp, 1);
+}