aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.vnet.ibm.com>2014-03-03 10:36:39 +1100
committerEli Qiao <taget@linux.vnet.ibm.com>2014-03-04 11:46:22 +0800
commit70466f3b4c793eca47b5a33712f19c16cdb58ee1 (patch)
tree3a40a9d88c68233096bd721b9f0ac315c7e628f3
parent63b4cc86c1a599279eba0cc7f7d19654097edb22 (diff)
downloadpowerkvm-70466f3b4c793eca47b5a33712f19c16cdb58ee1.tar.gz
Backport upstream powerpc/powernv Platform dump sysfs interface
This patch makes the sysfs interface match that of what's pushed upstream. changes in kernel: - fetch dump on-demand - directory per dump - in sysfs rather than debugfs Userspace changes needed - read from sysfs rather than debugfs. This enables support for userspace to fetch and initiate FSP and Platform dumps from the service processor (via firmware) through sysfs. Based on original patch from Vasant Hegde <hegdevasant@linux.vnet.ibm.com> Flow: - We register for OPAL notification events. - OPAL sends new dump available notification. - We make information on dump available via sysfs - Userspace requests dump contents - We retrieve the dump via OPAL interface - User copies the dump data - userspace sends ack for dump - We send ACK to OPAL. sysfs files: - We add the /sys/firmware/opal/dump directory - echoing 1 (well, anything, but in future we may support different dump types) to /sys/firmware/opal/dump/initiate_dump will initiate a dump. - Each dump that we've been notified of gets a directory in /sys/firmware/opal/dump/ with a name of the dump type and ID (in hex, as this is what's used elsewhere to identify the dump). - Each dump has files: id, type, dump and acknowledge dump is binary and is the dump itself. echoing 'ack' to acknowledge (currently any string will do) will acknowledge the dump and it will soon after disappear from sysfs. OPAL APIs: - opal_dump_init() - opal_dump_info() - opal_dump_read() - opal_dump_ack() - opal_dump_resend_notification() Currently we are only ever notified for one dump at a time (until the user explicitly acks the current dump, then we get a notification of the next dump), but this kernel code should "just work" when OPAL starts notifying us of all the dumps present. Changes since v2: - fix bug where we would free the dump buffer after userspace read it, refetching if needed. Refetching doesn't currently work, so we must keep the dump around for subsequent reads. Changes since v1: - Add support for getting dump type from OPAL through new OPAL call (falling back to old OPAL_DUMP_INFO call if OPAL_DUMP_INFO2 isn't supported) - use dump type in directory name for dump Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com> Conflicts: arch/powerpc/include/asm/opal.h arch/powerpc/platforms/powernv/Makefile arch/powerpc/platforms/powernv/opal-dump.c arch/powerpc/platforms/powernv/opal-wrappers.S arch/powerpc/platforms/powernv/opal.c
-rw-r--r--Documentation/ABI/stable/sysfs-firmware-opal-dump41
-rw-r--r--arch/powerpc/include/asm/opal.h2
-rw-r--r--arch/powerpc/platforms/powernv/opal-dump.c559
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S1
4 files changed, 364 insertions, 239 deletions
diff --git a/Documentation/ABI/stable/sysfs-firmware-opal-dump b/Documentation/ABI/stable/sysfs-firmware-opal-dump
new file mode 100644
index 00000000000000..32fe7f5c488069
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-firmware-opal-dump
@@ -0,0 +1,41 @@
+What: /sys/firmware/opal/dump
+Date: Feb 2014
+Contact: Stewart Smith <stewart@linux.vnet.ibm.com>
+Description:
+ This directory exposes interfaces for interacting with
+ the FSP and platform dumps through OPAL firmware interface.
+
+ This is only for the powerpc/powernv platform.
+
+ initiate_dump: When '1' is written to it,
+ we will initiate a dump.
+ Read this file for supported commands.
+
+ 0xXX-0xYYYY: A directory for dump of type 0xXX and
+ id 0xYYYY (in hex). The name of this
+ directory should not be relied upon to
+ be in this format, only that it's unique
+ among all dumps. For determining the type
+ and ID of the dump, use the id and type files.
+ Do not rely on any particular size of dump
+ type or dump id.
+
+ Each dump has the following files:
+ id: An ASCII representation of the dump ID
+ in hex (e.g. '0x01')
+ type: An ASCII representation of the type of
+ dump in the format "0x%x %s" with the ID
+ in hex and a description of the dump type
+ (or 'unknown').
+ Type '0xffffffff unknown' is used when
+ we could not get the type from firmware.
+ e.g. '0x02 System/Platform Dump'
+ dump: A binary file containing the dump.
+ The size of the dump is the size of this file.
+ acknowledge: When 'ack' is written to this, we will
+ acknowledge that we've retrieved the
+ dump to the service processor. It will
+ then remove it, making the dump
+ inaccessible.
+ Reading this file will get a list of
+ supported actions.
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 554a031dcde807..05a23d04606d1e 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_DUMP_INFO2 94
#ifndef __ASSEMBLY__
@@ -870,6 +871,7 @@ int64_t opal_dump_info(uint32_t *dump_id, uint32_t *dump_size);
int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
int64_t opal_dump_ack(uint32_t dump_id);
int64_t opal_dump_resend_notification(void);
+int64_t opal_dump_info2(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type);
int64_t opal_get_msg(uint64_t buffer, size_t size);
int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
int64_t opal_sync_host_reboot(void);
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
index 53c26756559b35..0c767c561dc994 100644
--- a/arch/powerpc/platforms/powernv/opal-dump.c
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -1,7 +1,7 @@
/*
* PowerNV OPAL Dump Interface
*
- * Copyright 2013 IBM Corp.
+ * Copyright 2013,2014 IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -10,7 +10,6 @@
*/
#include <linux/kobject.h>
-#include <linux/debugfs.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -19,31 +18,201 @@
#include <asm/opal.h>
-/* Dump type */
#define DUMP_TYPE_FSP 0x01
-/* Extract failed */
-#define DUMP_NACK_ID 0x00
-
-/* Dump record */
-struct dump_record {
- uint8_t type;
- uint32_t id;
+struct dump_obj {
+ struct kobject kobj;
+ struct bin_attribute dump_attr;
+ uint32_t id; /* becomes object name */
+ uint32_t type;
uint32_t size;
char *buffer;
};
-static struct dump_record dump_record;
+#define to_dump_obj(x) container_of(x, struct dump_obj, kobj)
+
+struct dump_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct dump_obj *dump, struct dump_attribute *attr,
+ char *buf);
+ ssize_t (*store)(struct dump_obj *dump, struct dump_attribute *attr,
+ const char *buf, size_t count);
+};
+#define to_dump_attr(x) container_of(x, struct dump_attribute, attr)
+
+static ssize_t dump_id_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "0x%x\n", dump_obj->id);
+}
+
+static const char* dump_type_to_string(uint32_t type)
+{
+ switch (type) {
+ case 0x01: return "SP Dump";
+ case 0x02: return "System/Platform Dump";
+ case 0x03: return "SMA Dump";
+ default: return "unknown";
+ }
+}
+
+static ssize_t dump_type_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+
+ return sprintf(buf, "0x%x %s\n", dump_obj->type,
+ dump_type_to_string(dump_obj->type));
+}
+
+static ssize_t dump_ack_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "ack - acknowledge dump\n");
+}
+
+/*
+ * Send acknowledgement to OPAL
+ */
+static int64_t dump_send_ack(uint32_t dump_id)
+{
+ int rc;
+
+ rc = opal_dump_ack(dump_id);
+ if (rc)
+ pr_warn("%s: Failed to send ack to Dump ID 0x%x (%d)\n",
+ __func__, dump_id, rc);
+ return rc;
+}
+
+static void delay_release_kobj(void *kobj)
+{
+ kobject_put((struct kobject *)kobj);
+}
+
+static ssize_t dump_ack_store(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ dump_send_ack(dump_obj->id);
+ sysfs_schedule_callback(&dump_obj->kobj, delay_release_kobj,
+ &dump_obj->kobj, THIS_MODULE);
+ return count;
+}
+
+/* Attributes of a dump
+ * The binary attribute of the dump itself is dynamic
+ * due to the dynamic size of the dump
+ */
+static struct dump_attribute id_attribute =
+ __ATTR(id, 0666, dump_id_show, NULL);
+static struct dump_attribute type_attribute =
+ __ATTR(type, 0666, dump_type_show, NULL);
+static struct dump_attribute ack_attribute =
+ __ATTR(acknowledge, 0660, dump_ack_show, dump_ack_store);
+
+static ssize_t init_dump_show(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "1 - initiate dump\n");
+}
+
+static int64_t dump_fips_init(uint8_t type)
+{
+ int rc;
+
+ rc = opal_dump_init(type);
+ if (rc)
+ pr_warn("%s: Failed to initiate FipS dump (%d)\n",
+ __func__, rc);
+ return rc;
+}
+
+static ssize_t init_dump_store(struct dump_obj *dump_obj,
+ struct dump_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ dump_fips_init(DUMP_TYPE_FSP);
+ pr_info("%s: Initiated FSP dump\n", __func__);
+ return count;
+}
+
+static struct dump_attribute initiate_attribute =
+ __ATTR(initiate_dump, 0600, init_dump_show, init_dump_store);
+
+static struct attribute *initiate_attrs[] = {
+ &initiate_attribute.attr,
+ NULL,
+};
+
+static struct attribute_group initiate_attr_group = {
+ .attrs = initiate_attrs,
+};
-/* Dump available status */
-static u32 dump_avail;
+static struct kset *dump_kset;
-/* Binary blobs */
-static struct debugfs_blob_wrapper dump_blob;
-static struct debugfs_blob_wrapper readme_blob;
+static ssize_t dump_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct dump_attribute *attribute;
+ struct dump_obj *dump;
-/* Ignore dump notification, if we fail to create debugfs files */
-static bool dump_disarmed = false;
+ attribute = to_dump_attr(attr);
+ dump = to_dump_obj(kobj);
+ if (!attribute->show)
+ return -EIO;
+
+ return attribute->show(dump, attribute, buf);
+}
+
+static ssize_t dump_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct dump_attribute *attribute;
+ struct dump_obj *dump;
+
+ attribute = to_dump_attr(attr);
+ dump = to_dump_obj(kobj);
+
+ if (!attribute->store)
+ return -EIO;
+
+ return attribute->store(dump, attribute, buf, len);
+}
+
+static const struct sysfs_ops dump_sysfs_ops = {
+ .show = dump_attr_show,
+ .store = dump_attr_store,
+};
+
+static void dump_release(struct kobject *kobj)
+{
+ struct dump_obj *dump;
+
+ dump = to_dump_obj(kobj);
+ vfree(dump->buffer);
+ kfree(dump);
+}
+
+static struct attribute *dump_default_attrs[] = {
+ &id_attribute.attr,
+ &type_attribute.attr,
+ &ack_attribute.attr,
+ NULL,
+};
+
+static struct kobj_type dump_ktype = {
+ .sysfs_ops = &dump_sysfs_ops,
+ .release = &dump_release,
+ .default_attrs = dump_default_attrs,
+};
static void free_dump_sg_list(struct opal_sg_list *list)
{
@@ -56,17 +225,14 @@ static void free_dump_sg_list(struct opal_sg_list *list)
list = NULL;
}
-/*
- * Build dump buffer scatter gather list
- */
-static struct opal_sg_list *dump_data_to_sglist(void)
+static struct opal_sg_list *dump_data_to_sglist(struct dump_obj *dump)
{
struct opal_sg_list *sg1, *list = NULL;
void *addr;
int64_t size;
- addr = dump_record.buffer;
- size = dump_record.size;
+ addr = dump->buffer;
+ size = dump->size;
sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!sg1)
@@ -104,9 +270,6 @@ nomem:
return NULL;
}
-/*
- * Translate sg list address to absolute
- */
static void sglist_to_phy_addr(struct opal_sg_list *list)
{
struct opal_sg_list *sg, *next;
@@ -125,83 +288,38 @@ static void sglist_to_phy_addr(struct opal_sg_list *list)
}
}
-static void free_dump_data_buf(void)
-{
- vfree(dump_record.buffer);
- dump_record.size = 0;
-}
-
-/*
- * Allocate dump data buffer.
- */
-static int alloc_dump_data_buf(void)
-{
- dump_record.buffer = vzalloc(PAGE_ALIGN(dump_record.size));
- if (!dump_record.buffer) {
- pr_err("%s : Failed to allocate memory\n", __func__);
- return -ENOMEM;
- }
- return 0;
-}
-
-/*
- * Initiate FipS dump
- */
-static int64_t dump_fips_init(uint8_t type)
+static int64_t dump_read_info(uint32_t *id, uint32_t *size, uint32_t *type)
{
int rc;
+ *type = 0xffffffff;
- rc = opal_dump_init(type);
- if (rc)
- pr_warn("%s: Failed to initiate FipS dump (%d)\n",
- __func__, rc);
- return rc;
-}
+ rc = opal_dump_info2(id, size, type);
-/*
- * Get dump ID and size.
- */
-static int64_t dump_read_info(void)
-{
- int rc;
+ if (rc == OPAL_PARAMETER)
+ rc = opal_dump_info(id, size);
- rc = opal_dump_info(&dump_record.id, &dump_record.size);
if (rc)
pr_warn("%s: Failed to get dump info (%d)\n",
__func__, rc);
return rc;
}
-/*
- * Send acknowledgement to OPAL
- */
-static int64_t dump_send_ack(uint32_t dump_id)
-{
- int rc;
-
- rc = opal_dump_ack(dump_id);
- if (rc)
- pr_warn("%s: Failed to send ack to Dump ID 0x%x (%d)\n",
- __func__, dump_id, rc);
- return rc;
-}
-
-/*
- * Retrieve dump data
- */
-static int64_t dump_read_data(void)
+static int64_t dump_read_data(struct dump_obj *dump)
{
struct opal_sg_list *list;
uint64_t addr;
int64_t rc;
/* Allocate memory */
- rc = alloc_dump_data_buf();
- if (rc)
+ dump->buffer = vzalloc(PAGE_ALIGN(dump->size));
+ if (!dump->buffer) {
+ pr_err("%s : Failed to allocate memory\n", __func__);
+ rc = -ENOMEM;
goto out;
+ }
/* Generate SG list */
- list = dump_data_to_sglist();
+ list = dump_data_to_sglist(dump);
if (!list) {
rc = -ENOMEM;
goto out;
@@ -216,16 +334,16 @@ static int64_t dump_read_data(void)
/* Fetch data */
rc = OPAL_BUSY_EVENT;
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
- rc = opal_dump_read(dump_record.id, addr);
+ rc = opal_dump_read(dump->id, addr);
if (rc == OPAL_BUSY_EVENT) {
opal_poll_events(NULL);
- msleep(10);
+ msleep(20);
}
}
if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL)
pr_warn("%s: Extract dump failed for ID 0x%x\n",
- __func__, dump_record.id);
+ __func__, dump->id);
/* Free SG list */
free_dump_sg_list(list);
@@ -234,63 +352,125 @@ out:
return rc;
}
-static int extract_dump(void)
+static ssize_t dump_attr_read(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
- int rc;
+ ssize_t rc;
+
+ struct dump_obj *dump = to_dump_obj(kobj);
+
+ if (!dump->buffer) {
+ rc = dump_read_data(dump);
+
+ if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL) {
+ vfree(dump->buffer);
+ dump->buffer = NULL;
+
+ return -EIO;
+ }
+ if (rc == OPAL_PARTIAL) {
+ /* On a partial read, we just return EIO
+ * and rely on userspace to ask us to try
+ * again.
+ */
+ pr_info("%s: Platform dump partially read.ID = 0x%x\n",
+ __func__, dump->id);
+ return -EIO;
+ }
+ }
- /* We can get notified that a dump is available multiple times
- * (dump_read_info clears the bit in the event from OPAL).
- * But we should not re-read the dump from OPAL as we
- * don't get the next dump until we've explicitly acked this one.
+ memcpy(buffer, dump->buffer + pos, count);
+
+ /* You may think we could free the dump buffer now and retrieve
+ * it again later if needed, but due to current firmware limitation,
+ * that's not the case. So, once read into userspace once,
+ * we keep the dump around until it's acknowledged by userspace.
*/
- if (dump_avail)
- return OPAL_SUCCESS;
- /* Get dump ID, size */
- rc = dump_read_info();
- if (rc != OPAL_SUCCESS)
- return rc;
+ return count;
+}
+
+static struct dump_obj *create_dump_obj(uint32_t id, size_t size,
+ uint32_t type)
+{
+ struct dump_obj *dump;
+ int rc;
- /* Read dump data */
- rc = dump_read_data();
- if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL) {
- /*
- * Failed to allocate memory to retrieve dump. Lets send
- * negative ack so that we get notification again.
- */
- dump_send_ack(DUMP_NACK_ID);
+ dump = kzalloc(sizeof(*dump), GFP_KERNEL);
+ if (!dump)
+ return NULL;
- /* Free dump buffer */
- free_dump_data_buf();
+ dump->kobj.kset = dump_kset;
- return rc;
+ kobject_init(&dump->kobj, &dump_ktype);
+
+ sysfs_bin_attr_init(&dump->dump_attr);
+
+ dump->dump_attr.attr.name = "dump";
+ dump->dump_attr.attr.mode = 0400;
+ dump->dump_attr.size = size;
+ dump->dump_attr.read = dump_attr_read;
+
+ dump->id = id;
+ dump->size = size;
+ dump->type = type;
+
+ rc = kobject_add(&dump->kobj, NULL, "0x%x-0x%x", type, id);
+ if (rc) {
+ kobject_put(&dump->kobj);
+ return NULL;
}
- if (rc == OPAL_PARTIAL)
- pr_info("%s: Platform dump partially read. ID = 0x%x\n",
- __func__, dump_record.id);
- else
- pr_info("%s: New platform dump available. ID = 0x%x\n",
- __func__, dump_record.id);
- /* Update dump blob */
- dump_blob.data = (void *)dump_record.buffer;
- dump_blob.size = dump_record.size;
+ rc = sysfs_create_bin_file(&dump->kobj, &dump->dump_attr);
+ if (rc) {
+ kobject_put(&dump->kobj);
+ return NULL;
+ }
- /* Update dump available status */
- dump_avail = 1;
+ pr_info("%s: New platform dump. ID = 0x%x Size %u\n",
+ __func__, dump->id, dump->size);
- return rc;
+ kobject_uevent(&dump->kobj, KOBJ_ADD);
+
+ return dump;
}
-static void dump_extract_fn(struct work_struct *work)
+static int process_dump(void)
{
- extract_dump();
+ int rc;
+ uint32_t dump_id, dump_size, dump_type;
+ struct dump_obj *dump;
+ char name[22];
+
+ rc = dump_read_info(&dump_id, &dump_size, &dump_type);
+ if (rc != OPAL_SUCCESS)
+ return rc;
+
+ sprintf(name, "0x%x-0x%x", dump_type, dump_id);
+
+ /* we may get notified twice, let's handle
+ * that gracefully and not create two conflicting
+ * entries.
+ */
+ if (kset_find_obj(dump_kset, name))
+ return 0;
+
+ dump = create_dump_obj(dump_id, dump_size, dump_type);
+ if (!dump)
+ return -1;
+
+ return 0;
+}
+
+static void dump_work_fn(struct work_struct *work)
+{
+ process_dump();
}
-static DECLARE_WORK(dump_work, dump_extract_fn);
+static DECLARE_WORK(dump_work, dump_work_fn);
-/* Workqueue to extract dump */
-static void schedule_extract_dump(void)
+static void schedule_process_dump(void)
{
schedule_work(&dump_work);
}
@@ -298,22 +478,14 @@ static void schedule_extract_dump(void)
/*
* New dump available notification
*
- * Once we get notification, we extract dump via OPAL call
- * and then pass dump to userspace via debugfs interface.
+ * Once we get notification, we add sysfs entries for it.
+ * We only fetch the dump on demand, and create sysfs asynchronously.
*/
static int dump_event(struct notifier_block *nb,
unsigned long events, void *change)
{
- /*
- * Don't retrieve dump, if we don't have debugfs
- * interface to pass data to userspace.
- */
- if (dump_disarmed)
- return 0;
-
- /* Check for dump available notification */
if (events & OPAL_EVENT_DUMP_AVAIL)
- schedule_extract_dump();
+ schedule_process_dump();
return 0;
}
@@ -324,114 +496,24 @@ static struct notifier_block dump_nb = {
.priority = 0
};
-
-/* debugfs README message */
-static const char readme_msg[] =
- "Platform dump HOWTO:\n\n"
- "files:\n"
- " dump - Binary file, contains actual dump data\n"
- " dump_available (r--) - New dump available notification\n"
- " 0 : No dump available\n"
- " 1 : New dump available\n"
- " dump_control(-w-) - Dump control file\n"
- " 1 : Send acknowledgement (dump copied)\n"
- " 2 : Initiate FipS dump\n";
-
-/* debugfs dump_control file operations */
-static ssize_t dump_control_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- char buf[4];
- size_t buf_size;
-
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
-
- switch (buf[0]) {
- case '1': /* Dump send ack */
- if (dump_avail) {
- dump_avail = 0;
- free_dump_data_buf();
- dump_send_ack(dump_record.id);
- }
- break;
- case '2': /* Initiate FipS dump */
- dump_fips_init(DUMP_TYPE_FSP);
- break;
- default:
- break;
- }
- return count;
-}
-
-static const struct file_operations dump_control_fops = {
- .open = simple_open,
- .write = dump_control_write,
- .llseek = default_llseek,
-};
-
-/*
- * Create dump debugfs file
- */
-static int debugfs_dump_init(void)
-{
- struct dentry *dir, *file;
-
- /* FSP dump directory */
- dir = debugfs_create_dir("fsp", NULL);
- if (!dir)
- goto out;
-
- /* README */
- readme_blob.data = (void *)readme_msg;
- readme_blob.size = strlen(readme_msg);
- file = debugfs_create_blob("README", 0400, dir, &readme_blob);
- if (!file)
- goto remove_dir;
-
- /* Dump available notification */
- file = debugfs_create_u32("dump_avail", 0400, dir, &dump_avail);
- if (!file)
- goto remove_dir;
-
- /* data file */
- dump_blob.data = (void *)dump_record.buffer;
- dump_blob.size = dump_record.size;
- file = debugfs_create_blob("dump", 0400, dir, &dump_blob);
- if (!file)
- goto remove_dir;
-
- /* Control file */
- file = debugfs_create_file("dump_control", 0200, dir,
- NULL, &dump_control_fops);
- if (!file)
- goto remove_dir;
-
- return 0;
-
-remove_dir:
- debugfs_remove_recursive(dir);
-
-out:
- dump_disarmed = true;
- return -1;
-}
-
void __init opal_platform_dump_init(void)
{
int rc;
- /* debugfs interface */
- rc = debugfs_dump_init();
+ dump_kset = kset_create_and_add("dump", NULL, opal_kobj);
+ if (!dump_kset) {
+ pr_warn("%s: Failed to create dump kset\n", __func__);
+ return;
+ }
+
+ rc = sysfs_create_group(&dump_kset->kobj, &initiate_attr_group);
if (rc) {
- pr_warn("%s: Failed to create debugfs interface (%d)\n",
- __func__, rc);
+ pr_warn("%s: Failed to create initiate dump attr group\n",
+ __func__);
+ kobject_put(&dump_kset->kobj);
return;
}
- /* Register for opal notifier */
rc = opal_notifier_register(&dump_nb);
if (rc) {
pr_warn("%s: Can't register OPAL event notifier (%d)\n",
@@ -439,6 +521,5 @@ void __init opal_platform_dump_init(void)
return;
}
- /* Request to resend dump available notification */
opal_dump_resend_notification();
}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 81e445f689232d..ca4697aa440717 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -128,6 +128,7 @@ OPAL_CALL(opal_resync_timebase, OPAL_RESYNC_TIMEBASE);
OPAL_CALL(opal_check_token, OPAL_CHECK_TOKEN);
OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT);
OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO);
+OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2);
OPAL_CALL(opal_dump_read, OPAL_DUMP_READ);
OPAL_CALL(opal_dump_ack, OPAL_DUMP_ACK);
OPAL_CALL(opal_get_msg, OPAL_GET_MSG);