diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 554a031..ede6a2d 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -174,6 +174,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_GET_PARAM 89
#define OPAL_SET_PARAM 90
#define OPAL_DUMP_RESEND 91
+#define OPAL_ELOG_SEND 92
#ifndef __ASSEMBLY__
@@ -268,6 +269,40 @@ enum OpalMessageType {
OPAL_MSG_TYPE_MAX,
};
+/* Max user dump size is 14K */
+#define OPAL_LOG_MAX_DUMP 14336
+
+/* Multiple user data sections */
+struct __attribute__((__packed__)) opal_user_data_section {
+ uint32_t tag;
+ uint16_t size;
+ uint16_t component_id;
+ char data_dump[1];
+};
+
+/*
+ * All the information regarding an error/event to be reported
+ * needs to populate this structure using pre-defined interfaces
+ * only
+ */
+struct __attribute__((__packed__)) opal_errorlog {
+
+ uint16_t component_id;
+ uint8_t error_event_type;
+ uint8_t subsystem_id;
+
+ uint8_t event_severity;
+ uint8_t event_subtype;
+ uint8_t user_section_count;
+ uint8_t elog_origin;
+
+ uint32_t user_section_size;
+ uint32_t reason_code;
+ uint32_t additional_info[4];
+
+ char user_data_dump[OPAL_LOG_MAX_DUMP];
+};
+
/* Machine check related definitions */
enum OpalMCE_Version {
OpalMCE_V1 = 1,@@ -862,6 +897,7 @@ int64_t opal_get_elog_size(uint64_t *log_id, size_t *size, uint64_t *elog_type);
int64_t opal_write_elog(uint64_t buffer, uint64_t size, uint64_t offset);
int64_t opal_send_ack_elog(uint64_t log_id);
void opal_resend_pending_logs(void);
+int64_t opal_elog_send(void *buffer);
int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
int64_t opal_manage_flash(uint8_t op);
int64_t opal_update_flash(uint64_t blk_list);
diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c
index fc891ae..c9ce835 100644
--- a/arch/powerpc/platforms/powernv/opal-elog.c
+++ b/arch/powerpc/platforms/powernv/opal-elog.c
@@ -8,6 +8,9 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#undef DEBUG
+#define pr_fmt(fmt) "ELOG: " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>
@@ -16,8 +19,9 @@
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/fcntl.h>
+#include <linux/mm.h>
#include <asm/uaccess.h>
-#include <asm/opal.h>
+#include "powernv.h"
/* Maximum size of a single log on FSP is 16KB */
#define OPAL_MAX_ERRLOG_SIZE 16384
@@ -272,6 +276,76 @@ static int init_err_log_buffer(void)
return 0;
}
+/* Interface to be used by POWERNV to push the logs to FSP via Sapphire */
+struct opal_errorlog *pnv_elog_create(uint8_t pnv_error_event_type,
+ uint16_t pnv_component_id, uint8_t pnv_subsystem_id,
+ uint8_t pnv_event_severity, uint8_t pnv_event_subtype,
+ uint32_t reason_code, uint32_t info0, uint32_t info1,
+ uint32_t info2, uint32_t info3)
+{
+ struct opal_errorlog *buf;
+
+ buf = kzalloc(sizeof(struct opal_errorlog), GFP_ATOMIC);
+ if (!buf) {
+ pr_err("Failed to allocate buffer for generating error log\n");
+ return NULL;
+ }
+
+ buf->error_event_type = pnv_error_event_type;
+ buf->component_id = pnv_component_id;
+ buf->subsystem_id = pnv_subsystem_id;
+ buf->event_severity = pnv_event_severity;
+ buf->event_subtype = pnv_event_subtype;
+ buf->reason_code = reason_code;
+ buf->additional_info[0] = info0;
+ buf->additional_info[1] = info1;
+ buf->additional_info[2] = info2;
+ buf->additional_info[3] = info3;
+ return buf;
+}
+
+int pnv_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) {
+ pr_err("Cannot update user data. Error log buffer is invalid");
+ return -1;
+ }
+
+ buffer = (char *)buf->user_data_dump + buf->user_section_size;
+ if ((buf->user_section_size + size) > OPAL_LOG_MAX_DUMP) {
+ pr_err("Size of user data overruns the buffer");
+ 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;
+}
+
+int pnv_commit_errorlog(struct opal_errorlog *buf)
+{
+ int rc;
+
+ rc = opal_elog_send((void *)(__pa(buf)));
+ if (rc == OPAL_SUCCESS) {
+ /* If the log has been committed, free the buffer */
+ kfree(buf);
+ buf = NULL;
+ } else
+ pr_err("Error log could not be committed to FSP");
+
+ return rc;
+}
+
/* Initialize error logging */
int __init opal_elog_init(void)
{diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 81e445f..250f7db 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -137,3 +137,4 @@ OPAL_CALL(opal_sensor_read, OPAL_SENSOR_READ);
OPAL_CALL(opal_get_param, OPAL_GET_PARAM);
OPAL_CALL(opal_set_param, OPAL_SET_PARAM);
OPAL_CALL(opal_dump_resend_notification, OPAL_DUMP_RESEND);
+OPAL_CALL(opal_elog_send, OPAL_ELOG_SEND);
diff --git a/arch/powerpc/platforms/powernv/powernv.h b/arch/powerpc/platforms/powernv/powernv.h
index c9cfb0b..42a8b8c 100644
--- a/arch/powerpc/platforms/powernv/powernv.h
+++ b/arch/powerpc/platforms/powernv/powernv.h
@@ -1,6 +1,8 @@
#ifndef _POWERNV_H
#define _POWERNV_H
+#include <asm/opal.h>
+
#ifdef CONFIG_SMP
extern void pnv_smp_init(void);
#else
@@ -23,4 +25,86 @@ bool cpu_core_split_required(void);
extern void pnv_lpc_init(void);
+/* Classification of error/event type to be reported on POWERNV */
+/* Platform Events/Errors: Report Machine Check Interrupt */
+#define PNV_PLATFORM_ERR_EVT 0x01
+/* INPUT_OUTPUT: Report all I/O related events/errors */
+#define PNV_INPUT_OUTPUT_ERR_EVT 0x02
+/* RESOURCE_DEALLOC: Hotplug events and errors */
+#define PNV_RESOURCE_DEALLOC_ERR_EVT 0x03
+/* MISC: Miscellanous error */
+#define PNV_MISC_ERR_EVT 0x04
+
+/* POWERNV Subsystem IDs listed for reporting events/errors */
+#define PNV_PROCESSOR_SUBSYSTEM 0x10
+#define PNV_MEMORY_SUBSYSTEM 0x20
+#define PNV_IO_SUBSYSTEM 0x30
+#define PNV_IO_DEVICES 0x40
+#define PNV_CEC_HARDWARE 0x50
+#define PNV_POWER_COOLING 0x60
+#define PNV_MISC_SUBSYSTEM 0x70
+#define PNV_SURVEILLANCE_ERR 0x7A
+#define PNV_PLATFORM_FIRMWARE 0x80
+#define PNV_SOFTWARE 0x90
+#define PNV_EXTERNAL_ENV 0xA0
+/*
+ * During reporting an event/error the following represents
+ * how serious the logged event/error is. (Severity)
+ */
+#define PNV_INFO 0x00
+#define PNV_RECOVERED_ERR_GENERAL 0x10
+
+/* 0x2X series is to denote set of Predictive Error */
+/* 0x20 Generic predictive error */
+#define PNV_PREDICTIVE_ERR_GENERAL 0x20
+/* 0x21 Predictive error, degraded performance */
+#define PNV_PREDICTIVE_ERR_DEGRADED_PERF 0x21
+/* 0x22 Predictive error, fault may be corrected after reboot */
+#define PNV_PREDICTIVE_ERR_FAULT_RECTIFY_REBOOT 0x22
+/*
+ * 0x23 Predictive error, fault may be corrected after reboot,
+ * degraded performance
+ */
+#define PNV_PREDICTIVE_ERR_FAULT_RECTIFY_BOOT_DEGRADE_PERF 0x23
+/* 0x24 Predictive error, loss of redundancy */
+#define PNV_PREDICTIVE_ERR_LOSS_OF_REDUNDANCY 0x24
+
+/* 0x4X series for Unrecoverable Error */
+/* 0x40 Generic Unrecoverable error */
+#define PNV_UNRECOVERABLE_ERR_GENERAL 0x40
+/* 0x41 Unrecoverable error bypassed with degraded performance */
+#define PNV_UNRECOVERABLE_ERR_DEGRADE_PERF 0x41
+/* 0x44 Unrecoverable error bypassed with loss of redundancy */
+#define PNV_UNRECOVERABLE_ERR_LOSS_REDUNDANCY 0x44
+/* 0x45 Unrecoverable error bypassed with loss of redundancy and performance */
+#define PNV_UNRECOVERABLE_ERR_LOSS_REDUNDANCY_PERF 0x45
+/* 0x48 Unrecoverable error bypassed with loss of function */
+#define PNV_UNRECOVERABLE_ERR_LOSS_OF_FUNCTION 0x48
+/*
+ * POWERNV Event Sub-type
+ * This field provides additional information on the non-error
+ * event type
+ */
+#define PNV_NA 0x00
+#define PNV_MISCELLANEOUS_INFO_ONLY 0x01
+#define PNV_PREV_REPORTED_ERR_RECTIFIED 0x10
+#define PNV_SYS_RESOURCES_DECONFIG_BY_USER 0x20
+#define PNV_SYS_RESOURCE_DECONFIG_PRIOR_ERR 0x21
+#define PNV_RESOURCE_DEALLOC_EVENT_NOTIFY 0x22
+#define PNV_CONCURRENT_MAINTENANCE_EVENT 0x40
+#define PNV_CAPACITY_UPGRADE_EVENT 0x60
+#define PNV_RESOURCE_SPARING_EVENT 0x70
+#define PNV_DYNAMIC_RECONFIG_EVENT 0x80
+#define PNV_NORMAL_SYS_PLATFORM_SHUTDOWN 0xD0
+#define PNV_ABNORMAL_POWER_OFF 0xE0
+
+struct opal_errorlog *pnv_elog_create(uint8_t pnv_error_event_type,
+ uint16_t pnv_component_id, uint8_t pnv_subsystem_id,
+ uint8_t pnv_event_severity, uint8_t pnv_event_subtype,
+ uint32_t reason_code, uint32_t info0, uint32_t info1,
+ uint32_t info2, uint32_t info3);
+int pnv_elog_update_user_dump(struct opal_errorlog *buf, unsigned char *data,
+ uint32_t tag, uint16_t size);
+int pnv_commit_errorlog(struct opal_errorlog *buf);
+
#endif /* _POWERNV_H */