aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStewart Smith <stewart@linux.vnet.ibm.com>2014-03-02 18:25:42 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-03-07 00:19:10 -0500
commitc7e64b9ce04aa2e3fad7396d92b5cb92056d16ac (patch)
treef7d827aa6f19d9573f699e170ada0c0a578be699
parent774fea1a38c6a5a8ccc10969db84da24565f276f (diff)
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>
-rw-r--r--Documentation/ABI/stable/sysfs-firmware-opal-dump41
-rw-r--r--arch/powerpc/include/asm/opal.h14
-rw-r--r--arch/powerpc/platforms/powernv/Makefile2
-rw-r--r--arch/powerpc/platforms/powernv/opal-dump.c525
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S6
-rw-r--r--arch/powerpc/platforms/powernv/opal.c2
6 files changed, 589 insertions, 1 deletions
diff --git a/Documentation/ABI/stable/sysfs-firmware-opal-dump b/Documentation/ABI/stable/sysfs-firmware-opal-dump
new file mode 100644
index 000000000000..32fe7f5c4880
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-firmware-opal-dump
@@ -0,0 +1,41 @@
1What: /sys/firmware/opal/dump
2Date: Feb 2014
3Contact: Stewart Smith <stewart@linux.vnet.ibm.com>
4Description:
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.
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 933adde1bdea..2636acfcd340 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -159,9 +159,15 @@ extern int opal_enter_rtas(struct rtas_args *args,
159#define OPAL_FLASH_VALIDATE 76 159#define OPAL_FLASH_VALIDATE 76
160#define OPAL_FLASH_MANAGE 77 160#define OPAL_FLASH_MANAGE 77
161#define OPAL_FLASH_UPDATE 78 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#define OPAL_GET_MSG 85 166#define OPAL_GET_MSG 85
163#define OPAL_CHECK_ASYNC_COMPLETION 86 167#define OPAL_CHECK_ASYNC_COMPLETION 86
168#define OPAL_DUMP_RESEND 91
164#define OPAL_SYNC_HOST_REBOOT 87 169#define OPAL_SYNC_HOST_REBOOT 87
170#define OPAL_DUMP_INFO2 94
165 171
166#ifndef __ASSEMBLY__ 172#ifndef __ASSEMBLY__
167 173
@@ -242,6 +248,7 @@ enum OpalPendingState {
242 OPAL_EVENT_EPOW = 0x80, 248 OPAL_EVENT_EPOW = 0x80,
243 OPAL_EVENT_LED_STATUS = 0x100, 249 OPAL_EVENT_LED_STATUS = 0x100,
244 OPAL_EVENT_PCI_ERROR = 0x200, 250 OPAL_EVENT_PCI_ERROR = 0x200,
251 OPAL_EVENT_DUMP_AVAIL = 0x400,
245 OPAL_EVENT_MSG_PENDING = 0x800, 252 OPAL_EVENT_MSG_PENDING = 0x800,
246}; 253};
247 254
@@ -838,6 +845,12 @@ void opal_resend_pending_logs(void);
838int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result); 845int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
839int64_t opal_manage_flash(uint8_t op); 846int64_t opal_manage_flash(uint8_t op);
840int64_t opal_update_flash(uint64_t blk_list); 847int64_t opal_update_flash(uint64_t blk_list);
848int64_t opal_dump_init(uint8_t dump_type);
849int64_t opal_dump_info(uint32_t *dump_id, uint32_t *dump_size);
850int64_t opal_dump_info2(uint32_t *dump_id, uint32_t *dump_size, uint32_t *dump_type);
851int64_t opal_dump_read(uint32_t dump_id, uint64_t buffer);
852int64_t opal_dump_ack(uint32_t dump_id);
853int64_t opal_dump_resend_notification(void);
841 854
842int64_t opal_get_msg(uint64_t buffer, size_t size); 855int64_t opal_get_msg(uint64_t buffer, size_t size);
843int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token); 856int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
@@ -876,6 +889,7 @@ extern unsigned long opal_get_boot_time(void);
876extern void opal_nvram_init(void); 889extern void opal_nvram_init(void);
877extern void opal_flash_init(void); 890extern void opal_flash_init(void);
878extern int opal_elog_init(void); 891extern int opal_elog_init(void);
892extern void opal_platform_dump_init(void);
879 893
880extern int opal_machine_check(struct pt_regs *regs); 894extern int opal_machine_check(struct pt_regs *regs);
881extern bool opal_mce_check_early_recovery(struct pt_regs *regs); 895extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 189fd4595161..5125caeb40f4 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -1,6 +1,6 @@
1obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o 1obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o
2obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o 2obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
3obj-y += rng.o opal-elog.o 3obj-y += rng.o opal-elog.o opal-dump.o
4 4
5obj-$(CONFIG_SMP) += smp.o 5obj-$(CONFIG_SMP) += smp.o
6obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o 6obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
diff --git a/arch/powerpc/platforms/powernv/opal-dump.c b/arch/powerpc/platforms/powernv/opal-dump.c
new file mode 100644
index 000000000000..0c767c561dc9
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-dump.c
@@ -0,0 +1,525 @@
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
23struct 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
33struct 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
42static 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
49static 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
59static 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
68static 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 */
78static 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
89static void delay_release_kobj(void *kobj)
90{
91 kobject_put((struct kobject *)kobj);
92}
93
94static 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 */
109static struct dump_attribute id_attribute =
110 __ATTR(id, 0666, dump_id_show, NULL);
111static struct dump_attribute type_attribute =
112 __ATTR(type, 0666, dump_type_show, NULL);
113static struct dump_attribute ack_attribute =
114 __ATTR(acknowledge, 0660, dump_ack_show, dump_ack_store);
115
116static 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
123static 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
134static 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
144static struct dump_attribute initiate_attribute =
145 __ATTR(initiate_dump, 0600, init_dump_show, init_dump_store);
146
147static struct attribute *initiate_attrs[] = {
148 &initiate_attribute.attr,
149 NULL,
150};
151
152static struct attribute_group initiate_attr_group = {
153 .attrs = initiate_attrs,
154};
155
156static struct kset *dump_kset;
157
158static 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
174static 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
190static const struct sysfs_ops dump_sysfs_ops = {
191 .show = dump_attr_show,
192 .store = dump_attr_store,
193};
194
195static 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
204static struct attribute *dump_default_attrs[] = {
205 &id_attribute.attr,
206 &type_attribute.attr,
207 &ack_attribute.attr,
208 NULL,
209};
210
211static struct kobj_type dump_ktype = {
212 .sysfs_ops = &dump_sysfs_ops,
213 .release = &dump_release,
214 .default_attrs = dump_default_attrs,
215};
216
217static 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
228static 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
267nomem:
268 pr_err("%s : Failed to allocate memory\n", __func__);
269 free_dump_sg_list(list);
270 return NULL;
271}
272
273static 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
291static 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
307static 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
351out:
352 return rc;
353}
354
355static 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
394static 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
439static 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
466static void dump_work_fn(struct work_struct *work)
467{
468 process_dump();
469}
470
471static DECLARE_WORK(dump_work, dump_work_fn);
472
473static 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 */
484static 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
493static struct notifier_block dump_nb = {
494 .notifier_call = dump_event,
495 .next = NULL,
496 .priority = 0
497};
498
499void __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}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 5fcbf253a870..47ec3f738062 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -131,6 +131,12 @@ OPAL_CALL(opal_write_elog, OPAL_ELOG_WRITE);
131OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE); 131OPAL_CALL(opal_validate_flash, OPAL_FLASH_VALIDATE);
132OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE); 132OPAL_CALL(opal_manage_flash, OPAL_FLASH_MANAGE);
133OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE); 133OPAL_CALL(opal_update_flash, OPAL_FLASH_UPDATE);
134OPAL_CALL(opal_dump_init, OPAL_DUMP_INIT);
135OPAL_CALL(opal_dump_info, OPAL_DUMP_INFO);
136OPAL_CALL(opal_dump_info2, OPAL_DUMP_INFO2);
137OPAL_CALL(opal_dump_read, OPAL_DUMP_READ);
138OPAL_CALL(opal_dump_ack, OPAL_DUMP_ACK);
134OPAL_CALL(opal_get_msg, OPAL_GET_MSG); 139OPAL_CALL(opal_get_msg, OPAL_GET_MSG);
135OPAL_CALL(opal_check_completion, OPAL_CHECK_ASYNC_COMPLETION); 140OPAL_CALL(opal_check_completion, OPAL_CHECK_ASYNC_COMPLETION);
141OPAL_CALL(opal_dump_resend_notification, OPAL_DUMP_RESEND);
136OPAL_CALL(opal_sync_host_reboot, OPAL_SYNC_HOST_REBOOT); 142OPAL_CALL(opal_sync_host_reboot, OPAL_SYNC_HOST_REBOOT);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 0a4493895d16..2e269c27dd23 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -570,6 +570,8 @@ static int __init opal_init(void)
570 rc = opal_elog_init(); 570 rc = opal_elog_init();
571 /* Setup code update interface */ 571 /* Setup code update interface */
572 opal_flash_init(); 572 opal_flash_init();
573 /* Setup platform dump extract interface */
574 opal_platform_dump_init();
573 } 575 }
574 576
575 return 0; 577 return 0;