Commit c7e64b9ce04aa2e3fad7396d92b5cb92056d16ac

Authored by Stewart Smith
Committed by Benjamin Herrenschmidt
1 parent 774fea1a38

powerpc/powernv Platform dump interface

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.

Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Showing 6 changed files with 589 additions and 1 deletions Side-by-side Diff

Documentation/ABI/stable/sysfs-firmware-opal-dump
  1 +What: /sys/firmware/opal/dump
  2 +Date: Feb 2014
  3 +Contact: Stewart Smith <stewart@linux.vnet.ibm.com>
  4 +Description:
  5 + This directory exposes interfaces for interacting with
  6 + the FSP and platform dumps through OPAL firmware interface.
  7 +
  8 + This is only for the powerpc/powernv platform.
  9 +
  10 + initiate_dump: When '1' is written to it,
  11 + we will initiate a dump.
  12 + Read this file for supported commands.
  13 +
  14 + 0xXX-0xYYYY: A directory for dump of type 0xXX and
  15 + id 0xYYYY (in hex). The name of this
  16 + directory should not be relied upon to
  17 + be in this format, only that it's unique
  18 + among all dumps. For determining the type
  19 + and ID of the dump, use the id and type files.
  20 + Do not rely on any particular size of dump
  21 + type or dump id.
  22 +
  23 + Each dump has the following files:
  24 + id: An ASCII representation of the dump ID
  25 + in hex (e.g. '0x01')
  26 + type: An ASCII representation of the type of
  27 + dump in the format "0x%x %s" with the ID
  28 + in hex and a description of the dump type
  29 + (or 'unknown').
  30 + Type '0xffffffff unknown' is used when
  31 + we could not get the type from firmware.
  32 + e.g. '0x02 System/Platform Dump'
  33 + dump: A binary file containing the dump.
  34 + The size of the dump is the size of this file.
  35 + acknowledge: When 'ack' is written to this, we will
  36 + acknowledge that we've retrieved the
  37 + dump to the service processor. It will
  38 + then remove it, making the dump
  39 + inaccessible.
  40 + Reading this file will get a list of
  41 + supported actions.
arch/powerpc/include/asm/opal.h
... ... @@ -159,9 +159,15 @@
159 159 #define OPAL_FLASH_VALIDATE 76
160 160 #define OPAL_FLASH_MANAGE 77
161 161 #define OPAL_FLASH_UPDATE 78
  162 +#define OPAL_DUMP_INIT 81
  163 +#define OPAL_DUMP_INFO 82
  164 +#define OPAL_DUMP_READ 83
  165 +#define OPAL_DUMP_ACK 84
162 166 #define OPAL_GET_MSG 85
163 167 #define OPAL_CHECK_ASYNC_COMPLETION 86
  168 +#define OPAL_DUMP_RESEND 91
164 169 #define OPAL_SYNC_HOST_REBOOT 87
  170 +#define OPAL_DUMP_INFO2 94
165 171  
166 172 #ifndef __ASSEMBLY__
167 173  
... ... @@ -242,6 +248,7 @@
242 248 OPAL_EVENT_EPOW = 0x80,
243 249 OPAL_EVENT_LED_STATUS = 0x100,
244 250 OPAL_EVENT_PCI_ERROR = 0x200,
  251 + OPAL_EVENT_DUMP_AVAIL = 0x400,
245 252 OPAL_EVENT_MSG_PENDING = 0x800,
246 253 };
247 254  
... ... @@ -838,6 +845,12 @@
838 845 int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
839 846 int64_t opal_manage_flash(uint8_t op);
840 847 int64_t opal_update_flash(uint64_t blk_list);
  848 +int64_t opal_dump_init(uint8_t dump_type);
  849 +int64_t opal_dump_info(uint32_t *dump_id, uint32_t *dump_size);
  850 +int64_t opal_dump_info2(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type);
  851 +int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
  852 +int64_t opal_dump_ack(uint32_t dump_id);
  853 +int64_t opal_dump_resend_notification(void);
841 854  
842 855 int64_t opal_get_msg(uint64_t buffer, size_t size);
843 856 int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
... ... @@ -876,6 +889,7 @@
876 889 extern void opal_nvram_init(void);
877 890 extern void opal_flash_init(void);
878 891 extern int opal_elog_init(void);
  892 +extern void opal_platform_dump_init(void);
879 893  
880 894 extern int opal_machine_check(struct pt_regs *regs);
881 895 extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
arch/powerpc/platforms/powernv/Makefile
1 1 obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o
2 2 obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
3   -obj-y += rng.o opal-elog.o
  3 +obj-y += rng.o opal-elog.o opal-dump.o
4 4  
5 5 obj-$(CONFIG_SMP) += smp.o
6 6 obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
arch/powerpc/platforms/powernv/opal-dump.c
  1 +/*
  2 + * PowerNV OPAL Dump Interface
  3 + *
  4 + * Copyright 2013,2014 IBM Corp.
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License
  8 + * as published by the Free Software Foundation; either version
  9 + * 2 of the License, or (at your option) any later version.
  10 + */
  11 +
  12 +#include <linux/kobject.h>
  13 +#include <linux/mm.h>
  14 +#include <linux/slab.h>
  15 +#include <linux/vmalloc.h>
  16 +#include <linux/pagemap.h>
  17 +#include <linux/delay.h>
  18 +
  19 +#include <asm/opal.h>
  20 +
  21 +#define DUMP_TYPE_FSP 0x01
  22 +
  23 +struct dump_obj {
  24 + struct kobject kobj;
  25 + struct bin_attribute dump_attr;
  26 + uint32_t id; /* becomes object name */
  27 + uint32_t type;
  28 + uint32_t size;
  29 + char *buffer;
  30 +};
  31 +#define to_dump_obj(x) container_of(x, struct dump_obj, kobj)
  32 +
  33 +struct dump_attribute {
  34 + struct attribute attr;
  35 + ssize_t (*show)(struct dump_obj *dump, struct dump_attribute *attr,
  36 + char *buf);
  37 + ssize_t (*store)(struct dump_obj *dump, struct dump_attribute *attr,
  38 + const char *buf, size_t count);
  39 +};
  40 +#define to_dump_attr(x) container_of(x, struct dump_attribute, attr)
  41 +
  42 +static ssize_t dump_id_show(struct dump_obj *dump_obj,
  43 + struct dump_attribute *attr,
  44 + char *buf)
  45 +{
  46 + return sprintf(buf, "0x%x\n", dump_obj->id);
  47 +}
  48 +
  49 +static const char* dump_type_to_string(uint32_t type)
  50 +{
  51 + switch (type) {
  52 + case 0x01: return "SP Dump";
  53 + case 0x02: return "System/Platform Dump";
  54 + case 0x03: return "SMA Dump";
  55 + default: return "unknown";
  56 + }
  57 +}
  58 +
  59 +static ssize_t dump_type_show(struct dump_obj *dump_obj,
  60 + struct dump_attribute *attr,
  61 + char *buf)
  62 +{
  63 +
  64 + return sprintf(buf, "0x%x %s\n", dump_obj->type,
  65 + dump_type_to_string(dump_obj->type));
  66 +}
  67 +
  68 +static ssize_t dump_ack_show(struct dump_obj *dump_obj,
  69 + struct dump_attribute *attr,
  70 + char *buf)
  71 +{
  72 + return sprintf(buf, "ack - acknowledge dump\n");
  73 +}
  74 +
  75 +/*
  76 + * Send acknowledgement to OPAL
  77 + */
  78 +static int64_t dump_send_ack(uint32_t dump_id)
  79 +{
  80 + int rc;
  81 +
  82 + rc = opal_dump_ack(dump_id);
  83 + if (rc)
  84 + pr_warn("%s: Failed to send ack to Dump ID 0x%x (%d)\n",
  85 + __func__, dump_id, rc);
  86 + return rc;
  87 +}
  88 +
  89 +static void delay_release_kobj(void *kobj)
  90 +{
  91 + kobject_put((struct kobject *)kobj);
  92 +}
  93 +
  94 +static ssize_t dump_ack_store(struct dump_obj *dump_obj,
  95 + struct dump_attribute *attr,
  96 + const char *buf,
  97 + size_t count)
  98 +{
  99 + dump_send_ack(dump_obj->id);
  100 + sysfs_schedule_callback(&dump_obj->kobj, delay_release_kobj,
  101 + &dump_obj->kobj, THIS_MODULE);
  102 + return count;
  103 +}
  104 +
  105 +/* Attributes of a dump
  106 + * The binary attribute of the dump itself is dynamic
  107 + * due to the dynamic size of the dump
  108 + */
  109 +static struct dump_attribute id_attribute =
  110 + __ATTR(id, 0666, dump_id_show, NULL);
  111 +static struct dump_attribute type_attribute =
  112 + __ATTR(type, 0666, dump_type_show, NULL);
  113 +static struct dump_attribute ack_attribute =
  114 + __ATTR(acknowledge, 0660, dump_ack_show, dump_ack_store);
  115 +
  116 +static ssize_t init_dump_show(struct dump_obj *dump_obj,
  117 + struct dump_attribute *attr,
  118 + char *buf)
  119 +{
  120 + return sprintf(buf, "1 - initiate dump\n");
  121 +}
  122 +
  123 +static int64_t dump_fips_init(uint8_t type)
  124 +{
  125 + int rc;
  126 +
  127 + rc = opal_dump_init(type);
  128 + if (rc)
  129 + pr_warn("%s: Failed to initiate FipS dump (%d)\n",
  130 + __func__, rc);
  131 + return rc;
  132 +}
  133 +
  134 +static ssize_t init_dump_store(struct dump_obj *dump_obj,
  135 + struct dump_attribute *attr,
  136 + const char *buf,
  137 + size_t count)
  138 +{
  139 + dump_fips_init(DUMP_TYPE_FSP);
  140 + pr_info("%s: Initiated FSP dump\n", __func__);
  141 + return count;
  142 +}
  143 +
  144 +static struct dump_attribute initiate_attribute =
  145 + __ATTR(initiate_dump, 0600, init_dump_show, init_dump_store);
  146 +
  147 +static struct attribute *initiate_attrs[] = {
  148 + &initiate_attribute.attr,
  149 + NULL,
  150 +};
  151 +
  152 +static struct attribute_group initiate_attr_group = {
  153 + .attrs = initiate_attrs,
  154 +};
  155 +
  156 +static struct kset *dump_kset;
  157 +
  158 +static ssize_t dump_attr_show(struct kobject *kobj,
  159 + struct attribute *attr,
  160 + char *buf)
  161 +{
  162 + struct dump_attribute *attribute;
  163 + struct dump_obj *dump;
  164 +
  165 + attribute = to_dump_attr(attr);
  166 + dump = to_dump_obj(kobj);
  167 +
  168 + if (!attribute->show)
  169 + return -EIO;
  170 +
  171 + return attribute->show(dump, attribute, buf);
  172 +}
  173 +
  174 +static ssize_t dump_attr_store(struct kobject *kobj,
  175 + struct attribute *attr,
  176 + const char *buf, size_t len)
  177 +{
  178 + struct dump_attribute *attribute;
  179 + struct dump_obj *dump;
  180 +
  181 + attribute = to_dump_attr(attr);
  182 + dump = to_dump_obj(kobj);
  183 +
  184 + if (!attribute->store)
  185 + return -EIO;
  186 +
  187 + return attribute->store(dump, attribute, buf, len);
  188 +}
  189 +
  190 +static const struct sysfs_ops dump_sysfs_ops = {
  191 + .show = dump_attr_show,
  192 + .store = dump_attr_store,
  193 +};
  194 +
  195 +static void dump_release(struct kobject *kobj)
  196 +{
  197 + struct dump_obj *dump;
  198 +
  199 + dump = to_dump_obj(kobj);
  200 + vfree(dump->buffer);
  201 + kfree(dump);
  202 +}
  203 +
  204 +static struct attribute *dump_default_attrs[] = {
  205 + &id_attribute.attr,
  206 + &type_attribute.attr,
  207 + &ack_attribute.attr,
  208 + NULL,
  209 +};
  210 +
  211 +static struct kobj_type dump_ktype = {
  212 + .sysfs_ops = &dump_sysfs_ops,
  213 + .release = &dump_release,
  214 + .default_attrs = dump_default_attrs,
  215 +};
  216 +
  217 +static void free_dump_sg_list(struct opal_sg_list *list)
  218 +{
  219 + struct opal_sg_list *sg1;
  220 + while (list) {
  221 + sg1 = list->next;
  222 + kfree(list);
  223 + list = sg1;
  224 + }
  225 + list = NULL;
  226 +}
  227 +
  228 +static struct opal_sg_list *dump_data_to_sglist(struct dump_obj *dump)
  229 +{
  230 + struct opal_sg_list *sg1, *list = NULL;
  231 + void *addr;
  232 + int64_t size;
  233 +
  234 + addr = dump->buffer;
  235 + size = dump->size;
  236 +
  237 + sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
  238 + if (!sg1)
  239 + goto nomem;
  240 +
  241 + list = sg1;
  242 + sg1->num_entries = 0;
  243 + while (size > 0) {
  244 + /* Translate virtual address to physical address */
  245 + sg1->entry[sg1->num_entries].data =
  246 + (void *)(vmalloc_to_pfn(addr) << PAGE_SHIFT);
  247 +
  248 + if (size > PAGE_SIZE)
  249 + sg1->entry[sg1->num_entries].length = PAGE_SIZE;
  250 + else
  251 + sg1->entry[sg1->num_entries].length = size;
  252 +
  253 + sg1->num_entries++;
  254 + if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
  255 + sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
  256 + if (!sg1->next)
  257 + goto nomem;
  258 +
  259 + sg1 = sg1->next;
  260 + sg1->num_entries = 0;
  261 + }
  262 + addr += PAGE_SIZE;
  263 + size -= PAGE_SIZE;
  264 + }
  265 + return list;
  266 +
  267 +nomem:
  268 + pr_err("%s : Failed to allocate memory\n", __func__);
  269 + free_dump_sg_list(list);
  270 + return NULL;
  271 +}
  272 +
  273 +static void sglist_to_phy_addr(struct opal_sg_list *list)
  274 +{
  275 + struct opal_sg_list *sg, *next;
  276 +
  277 + for (sg = list; sg; sg = next) {
  278 + next = sg->next;
  279 + /* Don't translate NULL pointer for last entry */
  280 + if (sg->next)
  281 + sg->next = (struct opal_sg_list *)__pa(sg->next);
  282 + else
  283 + sg->next = NULL;
  284 +
  285 + /* Convert num_entries to length */
  286 + sg->num_entries =
  287 + sg->num_entries * sizeof(struct opal_sg_entry) + 16;
  288 + }
  289 +}
  290 +
  291 +static int64_t dump_read_info(uint32_t *id, uint32_t *size, uint32_t *type)
  292 +{
  293 + int rc;
  294 + *type = 0xffffffff;
  295 +
  296 + rc = opal_dump_info2(id, size, type);
  297 +
  298 + if (rc == OPAL_PARAMETER)
  299 + rc = opal_dump_info(id, size);
  300 +
  301 + if (rc)
  302 + pr_warn("%s: Failed to get dump info (%d)\n",
  303 + __func__, rc);
  304 + return rc;
  305 +}
  306 +
  307 +static int64_t dump_read_data(struct dump_obj *dump)
  308 +{
  309 + struct opal_sg_list *list;
  310 + uint64_t addr;
  311 + int64_t rc;
  312 +
  313 + /* Allocate memory */
  314 + dump->buffer = vzalloc(PAGE_ALIGN(dump->size));
  315 + if (!dump->buffer) {
  316 + pr_err("%s : Failed to allocate memory\n", __func__);
  317 + rc = -ENOMEM;
  318 + goto out;
  319 + }
  320 +
  321 + /* Generate SG list */
  322 + list = dump_data_to_sglist(dump);
  323 + if (!list) {
  324 + rc = -ENOMEM;
  325 + goto out;
  326 + }
  327 +
  328 + /* Translate sg list addr to real address */
  329 + sglist_to_phy_addr(list);
  330 +
  331 + /* First entry address */
  332 + addr = __pa(list);
  333 +
  334 + /* Fetch data */
  335 + rc = OPAL_BUSY_EVENT;
  336 + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
  337 + rc = opal_dump_read(dump->id, addr);
  338 + if (rc == OPAL_BUSY_EVENT) {
  339 + opal_poll_events(NULL);
  340 + msleep(20);
  341 + }
  342 + }
  343 +
  344 + if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL)
  345 + pr_warn("%s: Extract dump failed for ID 0x%x\n",
  346 + __func__, dump->id);
  347 +
  348 + /* Free SG list */
  349 + free_dump_sg_list(list);
  350 +
  351 +out:
  352 + return rc;
  353 +}
  354 +
  355 +static ssize_t dump_attr_read(struct file *filep, struct kobject *kobj,
  356 + struct bin_attribute *bin_attr,
  357 + char *buffer, loff_t pos, size_t count)
  358 +{
  359 + ssize_t rc;
  360 +
  361 + struct dump_obj *dump = to_dump_obj(kobj);
  362 +
  363 + if (!dump->buffer) {
  364 + rc = dump_read_data(dump);
  365 +
  366 + if (rc != OPAL_SUCCESS && rc != OPAL_PARTIAL) {
  367 + vfree(dump->buffer);
  368 + dump->buffer = NULL;
  369 +
  370 + return -EIO;
  371 + }
  372 + if (rc == OPAL_PARTIAL) {
  373 + /* On a partial read, we just return EIO
  374 + * and rely on userspace to ask us to try
  375 + * again.
  376 + */
  377 + pr_info("%s: Platform dump partially read.ID = 0x%x\n",
  378 + __func__, dump->id);
  379 + return -EIO;
  380 + }
  381 + }
  382 +
  383 + memcpy(buffer, dump->buffer + pos, count);
  384 +
  385 + /* You may think we could free the dump buffer now and retrieve
  386 + * it again later if needed, but due to current firmware limitation,
  387 + * that's not the case. So, once read into userspace once,
  388 + * we keep the dump around until it's acknowledged by userspace.
  389 + */
  390 +
  391 + return count;
  392 +}
  393 +
  394 +static struct dump_obj *create_dump_obj(uint32_t id, size_t size,
  395 + uint32_t type)
  396 +{
  397 + struct dump_obj *dump;
  398 + int rc;
  399 +
  400 + dump = kzalloc(sizeof(*dump), GFP_KERNEL);
  401 + if (!dump)
  402 + return NULL;
  403 +
  404 + dump->kobj.kset = dump_kset;
  405 +
  406 + kobject_init(&dump->kobj, &dump_ktype);
  407 +
  408 + sysfs_bin_attr_init(&dump->dump_attr);
  409 +
  410 + dump->dump_attr.attr.name = "dump";
  411 + dump->dump_attr.attr.mode = 0400;
  412 + dump->dump_attr.size = size;
  413 + dump->dump_attr.read = dump_attr_read;
  414 +
  415 + dump->id = id;
  416 + dump->size = size;
  417 + dump->type = type;
  418 +
  419 + rc = kobject_add(&dump->kobj, NULL, "0x%x-0x%x", type, id);
  420 + if (rc) {
  421 + kobject_put(&dump->kobj);
  422 + return NULL;
  423 + }
  424 +
  425 + rc = sysfs_create_bin_file(&dump->kobj, &dump->dump_attr);
  426 + if (rc) {
  427 + kobject_put(&dump->kobj);
  428 + return NULL;
  429 + }
  430 +
  431 + pr_info("%s: New platform dump. ID = 0x%x Size %u\n",
  432 + __func__, dump->id, dump->size);
  433 +
  434 + kobject_uevent(&dump->kobj, KOBJ_ADD);
  435 +
  436 + return dump;
  437 +}
  438 +
  439 +static int process_dump(void)
  440 +{
  441 + int rc;
  442 + uint32_t dump_id, dump_size, dump_type;
  443 + struct dump_obj *dump;
  444 + char name[22];
  445 +
  446 + rc = dump_read_info(&dump_id, &dump_size, &dump_type);
  447 + if (rc != OPAL_SUCCESS)
  448 + return rc;
  449 +
  450 + sprintf(name, "0x%x-0x%x", dump_type, dump_id);
  451 +
  452 + /* we may get notified twice, let's handle
  453 + * that gracefully and not create two conflicting
  454 + * entries.
  455 + */
  456 + if (kset_find_obj(dump_kset, name))
  457 + return 0;
  458 +
  459 + dump = create_dump_obj(dump_id, dump_size, dump_type);
  460 + if (!dump)
  461 + return -1;
  462 +
  463 + return 0;
  464 +}
  465 +
  466 +static void dump_work_fn(struct work_struct *work)
  467 +{
  468 + process_dump();
  469 +}
  470 +
  471 +static DECLARE_WORK(dump_work, dump_work_fn);
  472 +
  473 +static void schedule_process_dump(void)
  474 +{
  475 + schedule_work(&dump_work);
  476 +}
  477 +
  478 +/*
  479 + * New dump available notification
  480 + *
  481 + * Once we get notification, we add sysfs entries for it.
  482 + * We only fetch the dump on demand, and create sysfs asynchronously.
  483 + */
  484 +static int dump_event(struct notifier_block *nb,
  485 + unsigned long events, void *change)
  486 +{
  487 + if (events & OPAL_EVENT_DUMP_AVAIL)
  488 + schedule_process_dump();
  489 +
  490 + return 0;
  491 +}
  492 +
  493 +static struct notifier_block dump_nb = {
  494 + .notifier_call = dump_event,
  495 + .next = NULL,
  496 + .priority = 0
  497 +};
  498 +
  499 +void __init opal_platform_dump_init(void)
  500 +{
  501 + int rc;
  502 +
  503 + dump_kset = kset_create_and_add("dump", NULL, opal_kobj);
  504 + if (!dump_kset) {
  505 + pr_warn("%s: Failed to create dump kset\n", __func__);
  506 + return;
  507 + }
  508 +
  509 + rc = sysfs_create_group(&dump_kset->kobj, &initiate_attr_group);
  510 + if (rc) {
  511 + pr_warn("%s: Failed to create initiate dump attr group\n",
  512 + __func__);
  513 + kobject_put(&dump_kset->kobj);
  514 + return;
  515 + }
  516 +
  517 + rc = opal_notifier_register(&dump_nb);
  518 + if (rc) {
  519 + pr_warn("%s: Can't register OPAL event notifier (%d)\n",
  520 + __func__, rc);
  521 + return;
  522 + }
  523 +
  524 + opal_dump_resend_notification();
  525 +}
arch/powerpc/platforms/powernv/opal-wrappers.S
... ... @@ -131,7 +131,13 @@
131 131 OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE);
132 132 OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE);
133 133 OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE);
  134 +OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT);
  135 +OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO);
  136 +OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2);
  137 +OPAL_CALL(opal_dump_read, OPAL_DUMP_READ);
  138 +OPAL_CALL(opal_dump_ack, OPAL_DUMP_ACK);
134 139 OPAL_CALL(opal_get_msg, OPAL_GET_MSG);
135 140 OPAL_CALL(opal_check_completion, OPAL_CHECK_ASYNC_COMPLETION);
  141 +OPAL_CALL(opal_dump_resend_notification, OPAL_DUMP_RESEND);
136 142 OPAL_CALL(opal_sync_host_reboot, OPAL_SYNC_HOST_REBOOT);
arch/powerpc/platforms/powernv/opal.c
... ... @@ -570,6 +570,8 @@
570 570 rc = opal_elog_init();
571 571 /* Setup code update interface */
572 572 opal_flash_init();
  573 + /* Setup platform dump extract interface */
  574 + opal_platform_dump_init();
573 575 }
574 576  
575 577 return 0;