blob: 502e49ab4b9825da19627d3bbff8142e9b06a81a [file] [log] [blame]
Thomas Gleixner1a59d1b82019-05-27 08:55:05 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +00002/*
3 * Firmware Assisted dump: A robust mechanism to get reliable kernel crash
4 * dump with assistance from firmware. This approach does not use kexec,
5 * instead firmware assists in booting the kdump kernel while preserving
6 * memory contents. The most of the code implementation has been adapted
7 * from phyp assisted dump implementation written by Linas Vepstas and
8 * Manish Ahuja
9 *
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000010 * Copyright 2011 IBM Corporation
11 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
12 */
13
14#undef DEBUG
15#define pr_fmt(fmt) "fadump: " fmt
16
17#include <linux/string.h>
18#include <linux/memblock.h>
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000019#include <linux/delay.h>
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000020#include <linux/seq_file.h>
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +000021#include <linux/crash_dump.h>
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +000022#include <linux/kobject.h>
23#include <linux/sysfs.h>
Hari Bathinia5818312018-08-18 02:10:56 +053024#include <linux/slab.h>
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +053025#include <linux/cma.h>
Christophe Leroy45d0ba52019-04-26 05:59:47 +000026#include <linux/hugetlb.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000027
Michael Ellerman7644d582017-02-10 12:04:56 +110028#include <asm/debugfs.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000029#include <asm/page.h>
30#include <asm/prom.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000031#include <asm/fadump.h>
Hari Bathinica986d72019-09-11 20:16:21 +053032#include <asm/fadump-internal.h>
Stephen Rothwellcad3c832012-03-30 14:01:07 +000033#include <asm/setup.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000034
35static struct fw_dump fw_dump;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000036
37static DEFINE_MUTEX(fadump_mutex);
Hari Bathinie4fc48f2019-09-11 20:25:05 +053038struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0 };
Hari Bathinidda9dbf2019-09-11 20:25:36 +053039struct fadump_mrange_info reserved_mrange_info = { "reserved", NULL, 0, 0, 0 };
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000040
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +053041#ifdef CONFIG_CMA
Hari Bathini0226e552019-09-11 20:18:14 +053042static struct cma *fadump_cma;
43
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +053044/*
45 * fadump_cma_init() - Initialize CMA area from a fadump reserved memory
46 *
47 * This function initializes CMA area from fadump reserved memory.
48 * The total size of fadump reserved memory covers for boot memory size
49 * + cpu data size + hpte size and metadata.
50 * Initialize only the area equivalent to boot memory size for CMA use.
51 * The reamining portion of fadump reserved memory will be not given
52 * to CMA and pages for thoes will stay reserved. boot memory size is
53 * aligned per CMA requirement to satisy cma_init_reserved_mem() call.
54 * But for some reason even if it fails we still have the memory reservation
55 * with us and we can still continue doing fadump.
56 */
57int __init fadump_cma_init(void)
58{
59 unsigned long long base, size;
60 int rc;
61
62 if (!fw_dump.fadump_enabled)
63 return 0;
64
65 /*
66 * Do not use CMA if user has provided fadump=nocma kernel parameter.
67 * Return 1 to continue with fadump old behaviour.
68 */
69 if (fw_dump.nocma)
70 return 1;
71
72 base = fw_dump.reserve_dump_area_start;
73 size = fw_dump.boot_memory_size;
74
75 if (!size)
76 return 0;
77
78 rc = cma_init_reserved_mem(base, size, 0, "fadump_cma", &fadump_cma);
79 if (rc) {
80 pr_err("Failed to init cma area for firmware-assisted dump,%d\n", rc);
81 /*
82 * Though the CMA init has failed we still have memory
83 * reservation with us. The reserved memory will be
84 * blocked from production system usage. Hence return 1,
85 * so that we can continue with fadump.
86 */
87 return 1;
88 }
89
90 /*
91 * So we now have successfully initialized cma area for fadump.
92 */
93 pr_info("Initialized 0x%lx bytes cma area at %ldMB from 0x%lx "
94 "bytes of memory reserved for firmware-assisted dump\n",
95 cma_get_size(fadump_cma),
96 (unsigned long)cma_get_base(fadump_cma) >> 20,
97 fw_dump.reserve_dump_area_size);
98 return 1;
99}
100#else
101static int __init fadump_cma_init(void) { return 1; }
102#endif /* CONFIG_CMA */
103
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000104/* Scan the Firmware Assisted dump configuration details. */
Hari Bathinif3512012019-09-11 20:19:44 +0530105int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
106 int depth, void *data)
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000107{
Hari Bathini41df5922019-09-11 20:20:26 +0530108 if (depth != 1)
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000109 return 0;
110
Hari Bathini41df5922019-09-11 20:20:26 +0530111 if (strcmp(uname, "rtas") == 0) {
112 rtas_fadump_dt_scan(&fw_dump, node);
113 return 1;
114 }
115
116 if (strcmp(uname, "ibm,opal") == 0) {
117 opal_fadump_dt_scan(&fw_dump, node);
118 return 1;
119 }
120
121 return 0;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000122}
123
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530124/*
125 * If fadump is registered, check if the memory provided
Mahesh Salgaonkar0db68962018-08-20 13:47:32 +0530126 * falls within boot memory area and reserved memory area.
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530127 */
Mahesh Salgaonkar0db68962018-08-20 13:47:32 +0530128int is_fadump_memory_area(u64 addr, ulong size)
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530129{
Mahesh Salgaonkar0db68962018-08-20 13:47:32 +0530130 u64 d_start = fw_dump.reserve_dump_area_start;
131 u64 d_end = d_start + fw_dump.reserve_dump_area_size;
132
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530133 if (!fw_dump.dump_registered)
134 return 0;
135
Mahesh Salgaonkar0db68962018-08-20 13:47:32 +0530136 if (((addr + size) > d_start) && (addr <= d_end))
137 return 1;
138
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530139 return (addr + size) > RMA_START && addr <= fw_dump.boot_memory_size;
140}
141
Nicholas Piggin6fcd6ba2017-07-19 16:59:11 +1000142int should_fadump_crash(void)
143{
144 if (!fw_dump.dump_registered || !fw_dump.fadumphdr_addr)
145 return 0;
146 return 1;
147}
148
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000149int is_fadump_active(void)
150{
151 return fw_dump.dump_active;
152}
153
Hari Bathinia5a05b92017-06-01 22:52:10 +0530154/*
Hari Bathini961cf262019-09-11 20:16:36 +0530155 * Returns true, if there are no holes in memory area between d_start to d_end,
156 * false otherwise.
Hari Bathinia5a05b92017-06-01 22:52:10 +0530157 */
Hari Bathini961cf262019-09-11 20:16:36 +0530158static bool is_fadump_mem_area_contiguous(u64 d_start, u64 d_end)
Hari Bathinia5a05b92017-06-01 22:52:10 +0530159{
160 struct memblock_region *reg;
Hari Bathini961cf262019-09-11 20:16:36 +0530161 bool ret = false;
162 u64 start, end;
Hari Bathinia5a05b92017-06-01 22:52:10 +0530163
164 for_each_memblock(memory, reg) {
Hari Bathini961cf262019-09-11 20:16:36 +0530165 start = max_t(u64, d_start, reg->base);
166 end = min_t(u64, d_end, (reg->base + reg->size));
167 if (d_start < end) {
168 /* Memory hole from d_start to start */
169 if (start > d_start)
Hari Bathinia5a05b92017-06-01 22:52:10 +0530170 break;
171
Hari Bathini961cf262019-09-11 20:16:36 +0530172 if (end == d_end) {
173 ret = true;
Hari Bathinia5a05b92017-06-01 22:52:10 +0530174 break;
175 }
176
Hari Bathini961cf262019-09-11 20:16:36 +0530177 d_start = end + 1;
Hari Bathinia5a05b92017-06-01 22:52:10 +0530178 }
179 }
180
181 return ret;
182}
183
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530184/*
Hari Bathini961cf262019-09-11 20:16:36 +0530185 * Returns true, if there are no holes in boot memory area,
186 * false otherwise.
187 */
Hari Bathini7f0ad112019-09-11 20:16:52 +0530188bool is_fadump_boot_mem_contiguous(void)
Hari Bathini961cf262019-09-11 20:16:36 +0530189{
190 return is_fadump_mem_area_contiguous(0, fw_dump.boot_memory_size);
191}
192
193/*
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530194 * Returns true, if there are no holes in reserved memory area,
195 * false otherwise.
196 */
Hari Bathini7f0ad112019-09-11 20:16:52 +0530197bool is_fadump_reserved_mem_contiguous(void)
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530198{
Hari Bathini961cf262019-09-11 20:16:36 +0530199 u64 d_start, d_end;
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530200
Hari Bathini961cf262019-09-11 20:16:36 +0530201 d_start = fw_dump.reserve_dump_area_start;
202 d_end = d_start + fw_dump.reserve_dump_area_size;
203 return is_fadump_mem_area_contiguous(d_start, d_end);
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530204}
205
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000206/* Print firmware assisted dump configurations for debugging purpose. */
207static void fadump_show_config(void)
208{
209 pr_debug("Support for firmware-assisted dump (fadump): %s\n",
210 (fw_dump.fadump_supported ? "present" : "no support"));
211
212 if (!fw_dump.fadump_supported)
213 return;
214
215 pr_debug("Fadump enabled : %s\n",
216 (fw_dump.fadump_enabled ? "yes" : "no"));
217 pr_debug("Dump Active : %s\n",
218 (fw_dump.dump_active ? "yes" : "no"));
219 pr_debug("Dump section sizes:\n");
220 pr_debug(" CPU state data size: %lx\n", fw_dump.cpu_state_data_size);
221 pr_debug(" HPTE region size : %lx\n", fw_dump.hpte_region_size);
222 pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size);
223}
224
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000225/**
226 * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM
227 *
228 * Function to find the largest memory size we need to reserve during early
229 * boot process. This will be the size of the memory that is required for a
230 * kernel to boot successfully.
231 *
232 * This function has been taken from phyp-assisted dump feature implementation.
233 *
234 * returns larger of 256MB or 5% rounded down to multiples of 256MB.
235 *
236 * TODO: Come up with better approach to find out more accurate memory size
237 * that is required for a kernel to boot successfully.
238 *
239 */
240static inline unsigned long fadump_calculate_reserve_size(void)
241{
Hari Bathini11550dc2017-05-08 15:56:28 -0700242 int ret;
243 unsigned long long base, size;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000244
Hari Bathini81d9eca2017-05-22 15:04:23 +0530245 if (fw_dump.reserve_bootvar)
246 pr_warn("'fadump_reserve_mem=' parameter is deprecated in favor of 'crashkernel=' parameter.\n");
247
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000248 /*
Hari Bathini11550dc2017-05-08 15:56:28 -0700249 * Check if the size is specified through crashkernel= cmdline
Hari Bathinie7467dc2017-05-22 15:04:47 +0530250 * option. If yes, then use that but ignore base as fadump reserves
251 * memory at a predefined offset.
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000252 */
Hari Bathini11550dc2017-05-08 15:56:28 -0700253 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
254 &size, &base);
255 if (ret == 0 && size > 0) {
Hari Bathini48a316e2017-06-02 13:00:27 +0530256 unsigned long max_size;
257
Hari Bathini81d9eca2017-05-22 15:04:23 +0530258 if (fw_dump.reserve_bootvar)
259 pr_info("Using 'crashkernel=' parameter for memory reservation.\n");
260
Hari Bathini11550dc2017-05-08 15:56:28 -0700261 fw_dump.reserve_bootvar = (unsigned long)size;
Hari Bathini48a316e2017-06-02 13:00:27 +0530262
263 /*
264 * Adjust if the boot memory size specified is above
265 * the upper limit.
266 */
267 max_size = memblock_phys_mem_size() / MAX_BOOT_MEM_RATIO;
268 if (fw_dump.reserve_bootvar > max_size) {
269 fw_dump.reserve_bootvar = max_size;
270 pr_info("Adjusted boot memory size to %luMB\n",
271 (fw_dump.reserve_bootvar >> 20));
272 }
273
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000274 return fw_dump.reserve_bootvar;
Hari Bathini81d9eca2017-05-22 15:04:23 +0530275 } else if (fw_dump.reserve_bootvar) {
276 /*
277 * 'fadump_reserve_mem=' is being used to reserve memory
278 * for firmware-assisted dump.
279 */
280 return fw_dump.reserve_bootvar;
Hari Bathini11550dc2017-05-08 15:56:28 -0700281 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000282
283 /* divide by 20 to get 5% of value */
Hari Bathini48a316e2017-06-02 13:00:27 +0530284 size = memblock_phys_mem_size() / 20;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000285
286 /* round it down in multiples of 256 */
287 size = size & ~0x0FFFFFFFUL;
288
289 /* Truncate to memory_limit. We don't want to over reserve the memory.*/
290 if (memory_limit && size > memory_limit)
291 size = memory_limit;
292
293 return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM);
294}
295
296/*
297 * Calculate the total memory size required to be reserved for
298 * firmware-assisted dump registration.
299 */
300static unsigned long get_fadump_area_size(void)
301{
302 unsigned long size = 0;
303
304 size += fw_dump.cpu_state_data_size;
305 size += fw_dump.hpte_region_size;
306 size += fw_dump.boot_memory_size;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000307 size += sizeof(struct fadump_crash_info_header);
308 size += sizeof(struct elfhdr); /* ELF core header.*/
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000309 size += sizeof(struct elf_phdr); /* place holder for cpu notes */
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000310 /* Program headers for crash memory regions. */
311 size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000312
313 size = PAGE_ALIGN(size);
Hari Bathini742a2652019-09-11 20:20:57 +0530314
315 /* This is to hold kernel metadata on platforms that support it */
316 size += (fw_dump.ops->fadump_get_metadata_size ?
317 fw_dump.ops->fadump_get_metadata_size() : 0);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000318 return size;
319}
320
Mahesh Salgaonkarb71a6932018-04-10 19:11:16 +0530321static void __init fadump_reserve_crash_area(unsigned long base,
322 unsigned long size)
323{
324 struct memblock_region *reg;
325 unsigned long mstart, mend, msize;
326
327 for_each_memblock(memory, reg) {
328 mstart = max_t(unsigned long, base, reg->base);
329 mend = reg->base + reg->size;
330 mend = min(base + size, mend);
331
332 if (mstart < mend) {
333 msize = mend - mstart;
334 memblock_reserve(mstart, msize);
335 pr_info("Reserved %ldMB of memory at %#016lx for saving crash dump\n",
336 (msize >> 20), mstart);
337 }
338 }
339}
340
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000341int __init fadump_reserve_mem(void)
342{
Hari Bathini579ca1a2019-09-11 20:24:28 +0530343 bool is_memblock_bottom_up = memblock_bottom_up();
344 u64 base, size, mem_boundary, align = PAGE_SIZE;
Hari Bathini6abec122019-09-11 20:20:41 +0530345 int ret = 1;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000346
347 if (!fw_dump.fadump_enabled)
348 return 0;
349
350 if (!fw_dump.fadump_supported) {
Hari Bathini6abec122019-09-11 20:20:41 +0530351 pr_info("Firmware-Assisted Dump is not supported on this hardware\n");
352 goto error_out;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000353 }
Hari Bathini742a2652019-09-11 20:20:57 +0530354
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000355 /*
356 * Initialize boot memory size
357 * If dump is active then we have already calculated the size during
358 * first kernel.
359 */
Hari Bathinif3512012019-09-11 20:19:44 +0530360 if (!fw_dump.dump_active) {
Hari Bathini6abec122019-09-11 20:20:41 +0530361 fw_dump.boot_memory_size =
362 PAGE_ALIGN(fadump_calculate_reserve_size());
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530363#ifdef CONFIG_CMA
Hari Bathini579ca1a2019-09-11 20:24:28 +0530364 if (!fw_dump.nocma) {
365 align = FADUMP_CMA_ALIGNMENT;
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530366 fw_dump.boot_memory_size =
Hari Bathini579ca1a2019-09-11 20:24:28 +0530367 ALIGN(fw_dump.boot_memory_size, align);
368 }
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530369#endif
370 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000371
372 /*
373 * Calculate the memory boundary.
374 * If memory_limit is less than actual memory boundary then reserve
375 * the memory for fadump beyond the memory_limit and adjust the
376 * memory_limit accordingly, so that the running kernel can run with
377 * specified memory_limit.
378 */
379 if (memory_limit && memory_limit < memblock_end_of_DRAM()) {
380 size = get_fadump_area_size();
381 if ((memory_limit + size) < memblock_end_of_DRAM())
382 memory_limit += size;
383 else
384 memory_limit = memblock_end_of_DRAM();
385 printk(KERN_INFO "Adjusted memory_limit for firmware-assisted"
Suzuki Poulosea84fcd42012-08-21 01:42:33 +0000386 " dump, now %#016llx\n", memory_limit);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000387 }
388 if (memory_limit)
Hari Bathini6abec122019-09-11 20:20:41 +0530389 mem_boundary = memory_limit;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000390 else
Hari Bathini6abec122019-09-11 20:20:41 +0530391 mem_boundary = memblock_end_of_DRAM();
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000392
Hari Bathini6abec122019-09-11 20:20:41 +0530393 base = fw_dump.boot_memory_size;
Hari Bathini8255da92019-09-11 20:19:28 +0530394 size = get_fadump_area_size();
395 fw_dump.reserve_dump_area_size = size;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000396 if (fw_dump.dump_active) {
Mahesh Salgaonkarb71a6932018-04-10 19:11:16 +0530397 pr_info("Firmware-assisted dump is active.\n");
398
Hari Bathini85975382018-04-10 19:11:31 +0530399#ifdef CONFIG_HUGETLB_PAGE
400 /*
401 * FADump capture kernel doesn't care much about hugepages.
402 * In fact, handling hugepages in capture kernel is asking for
403 * trouble. So, disable HugeTLB support when fadump is active.
404 */
405 hugetlb_disabled = true;
406#endif
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000407 /*
408 * If last boot has crashed then reserve all the memory
409 * above boot_memory_size so that we don't touch it until
410 * dump is written to disk by userspace tool. This memory
411 * will be released for general use once the dump is saved.
412 */
Hari Bathini6abec122019-09-11 20:20:41 +0530413 size = mem_boundary - base;
Mahesh Salgaonkarb71a6932018-04-10 19:11:16 +0530414 fadump_reserve_crash_area(base, size);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000415
Hari Bathinif3512012019-09-11 20:19:44 +0530416 pr_debug("fadumphdr_addr = %#016lx\n", fw_dump.fadumphdr_addr);
417 pr_debug("Reserve dump area start address: 0x%lx\n",
418 fw_dump.reserve_dump_area_start);
Hari Bathini8255da92019-09-11 20:19:28 +0530419 } else {
420 /*
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530421 * Reserve memory at an offset closer to bottom of the RAM to
Hari Bathini579ca1a2019-09-11 20:24:28 +0530422 * minimize the impact of memory hot-remove operation.
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530423 */
Hari Bathini579ca1a2019-09-11 20:24:28 +0530424 memblock_set_bottom_up(true);
425 base = memblock_find_in_range(base, mem_boundary, size, align);
Hari Bathini6abec122019-09-11 20:20:41 +0530426
Hari Bathini579ca1a2019-09-11 20:24:28 +0530427 /* Restore the previous allocation mode */
428 memblock_set_bottom_up(is_memblock_bottom_up);
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530429
Hari Bathini579ca1a2019-09-11 20:24:28 +0530430 if (!base) {
Hari Bathini742a2652019-09-11 20:20:57 +0530431 pr_err("Failed to find memory chunk for reservation!\n");
432 goto error_out;
433 }
434 fw_dump.reserve_dump_area_start = base;
435
436 /*
437 * Calculate the kernel metadata address and register it with
438 * f/w if the platform supports.
439 */
440 if (fw_dump.ops->fadump_setup_metadata &&
441 (fw_dump.ops->fadump_setup_metadata(&fw_dump) < 0))
442 goto error_out;
443
444 if (memblock_reserve(base, size)) {
Hari Bathini6abec122019-09-11 20:20:41 +0530445 pr_err("Failed to reserve memory!\n");
446 goto error_out;
447 }
448
449 pr_info("Reserved %lldMB of memory at %#016llx (System RAM: %lldMB)\n",
450 (size >> 20), base, (memblock_phys_mem_size() >> 20));
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530451
Hari Bathini6abec122019-09-11 20:20:41 +0530452 ret = fadump_cma_init();
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530453 }
Hari Bathini6abec122019-09-11 20:20:41 +0530454
455 return ret;
456error_out:
457 fw_dump.fadump_enabled = 0;
458 return 0;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000459}
460
Srikar Dronamraju1e76609c2016-10-07 16:59:21 -0700461unsigned long __init arch_reserved_kernel_pages(void)
462{
463 return memblock_reserved_size() / PAGE_SIZE;
464}
465
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000466/* Look for fadump= cmdline option. */
467static int __init early_fadump_param(char *p)
468{
469 if (!p)
470 return 1;
471
472 if (strncmp(p, "on", 2) == 0)
473 fw_dump.fadump_enabled = 1;
474 else if (strncmp(p, "off", 3) == 0)
475 fw_dump.fadump_enabled = 0;
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530476 else if (strncmp(p, "nocma", 5) == 0) {
477 fw_dump.fadump_enabled = 1;
478 fw_dump.nocma = 1;
479 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000480
481 return 0;
482}
483early_param("fadump", early_fadump_param);
484
Hari Bathini81d9eca2017-05-22 15:04:23 +0530485/*
486 * Look for fadump_reserve_mem= cmdline option
487 * TODO: Remove references to 'fadump_reserve_mem=' parameter,
488 * the sooner 'crashkernel=' parameter is accustomed to.
489 */
490static int __init early_fadump_reserve_mem(char *p)
491{
492 if (p)
493 fw_dump.reserve_bootvar = memparse(p, &p);
494 return 0;
495}
496early_param("fadump_reserve_mem", early_fadump_reserve_mem);
497
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000498void crash_fadump(struct pt_regs *regs, const char *str)
499{
500 struct fadump_crash_info_header *fdh = NULL;
Mahesh Salgaonkarf2a5e8f2016-10-24 23:51:51 +0530501 int old_cpu, this_cpu;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000502
Nicholas Piggin6fcd6ba2017-07-19 16:59:11 +1000503 if (!should_fadump_crash())
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000504 return;
505
Mahesh Salgaonkarf2a5e8f2016-10-24 23:51:51 +0530506 /*
507 * old_cpu == -1 means this is the first CPU which has come here,
508 * go ahead and trigger fadump.
509 *
510 * old_cpu != -1 means some other CPU has already on it's way
511 * to trigger fadump, just keep looping here.
512 */
513 this_cpu = smp_processor_id();
514 old_cpu = cmpxchg(&crashing_cpu, -1, this_cpu);
515
516 if (old_cpu != -1) {
517 /*
518 * We can't loop here indefinitely. Wait as long as fadump
519 * is in force. If we race with fadump un-registration this
520 * loop will break and then we go down to normal panic path
521 * and reboot. If fadump is in force the first crashing
522 * cpu will definitely trigger fadump.
523 */
524 while (fw_dump.dump_registered)
525 cpu_relax();
526 return;
527 }
528
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000529 fdh = __va(fw_dump.fadumphdr_addr);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000530 fdh->crashing_cpu = crashing_cpu;
531 crash_save_vmcoreinfo();
532
533 if (regs)
534 fdh->regs = *regs;
535 else
536 ppc_save_regs(&fdh->regs);
537
Rasmus Villemoesa0512162016-01-20 15:00:13 -0800538 fdh->online_mask = *cpu_online_mask;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000539
Hari Bathini41a65d12019-09-11 20:18:57 +0530540 fw_dump.ops->fadump_trigger(fdh, str);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000541}
542
Hari Bathini7f0ad112019-09-11 20:16:52 +0530543u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000544{
545 struct elf_prstatus prstatus;
546
547 memset(&prstatus, 0, sizeof(prstatus));
548 /*
549 * FIXME: How do i get PID? Do I really need it?
550 * prstatus.pr_pid = ????
551 */
552 elf_core_copy_kernel_regs(&prstatus.pr_reg, regs);
Hari Bathini22bd0172017-05-08 15:56:24 -0700553 buf = append_elf_note(buf, CRASH_CORE_NOTE_NAME, NT_PRSTATUS,
554 &prstatus, sizeof(prstatus));
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000555 return buf;
556}
557
Hari Bathini7f0ad112019-09-11 20:16:52 +0530558void fadump_update_elfcore_header(char *bufp)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000559{
560 struct elfhdr *elf;
561 struct elf_phdr *phdr;
562
563 elf = (struct elfhdr *)bufp;
564 bufp += sizeof(struct elfhdr);
565
566 /* First note is a place holder for cpu notes info. */
567 phdr = (struct elf_phdr *)bufp;
568
569 if (phdr->p_type == PT_NOTE) {
Hari Bathini961cf262019-09-11 20:16:36 +0530570 phdr->p_paddr = __pa(fw_dump.cpu_notes_buf_vaddr);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000571 phdr->p_offset = phdr->p_paddr;
572 phdr->p_filesz = fw_dump.cpu_notes_buf_size;
573 phdr->p_memsz = fw_dump.cpu_notes_buf_size;
574 }
575 return;
576}
577
Hari Bathini961cf262019-09-11 20:16:36 +0530578static void *fadump_alloc_buffer(unsigned long size)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000579{
Hari Bathini72aa6512019-09-11 20:17:56 +0530580 unsigned long count, i;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000581 struct page *page;
Hari Bathini72aa6512019-09-11 20:17:56 +0530582 void *vaddr;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000583
Hari Bathini72aa6512019-09-11 20:17:56 +0530584 vaddr = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000585 if (!vaddr)
586 return NULL;
587
Hari Bathini72aa6512019-09-11 20:17:56 +0530588 count = PAGE_ALIGN(size) / PAGE_SIZE;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000589 page = virt_to_page(vaddr);
590 for (i = 0; i < count; i++)
Hari Bathini72aa6512019-09-11 20:17:56 +0530591 mark_page_reserved(page + i);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000592 return vaddr;
593}
594
Hari Bathini961cf262019-09-11 20:16:36 +0530595static void fadump_free_buffer(unsigned long vaddr, unsigned long size)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000596{
Hari Bathini72aa6512019-09-11 20:17:56 +0530597 free_reserved_area((void *)vaddr, (void *)(vaddr + size), -1, NULL);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000598}
599
Hari Bathini7f0ad112019-09-11 20:16:52 +0530600s32 fadump_setup_cpu_notes_buf(u32 num_cpus)
Hari Bathini961cf262019-09-11 20:16:36 +0530601{
602 /* Allocate buffer to hold cpu crash notes. */
603 fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
604 fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size);
605 fw_dump.cpu_notes_buf_vaddr =
606 (unsigned long)fadump_alloc_buffer(fw_dump.cpu_notes_buf_size);
607 if (!fw_dump.cpu_notes_buf_vaddr) {
608 pr_err("Failed to allocate %ld bytes for CPU notes buffer\n",
609 fw_dump.cpu_notes_buf_size);
610 return -ENOMEM;
611 }
612
613 pr_debug("Allocated buffer for cpu notes of size %ld at 0x%lx\n",
614 fw_dump.cpu_notes_buf_size,
615 fw_dump.cpu_notes_buf_vaddr);
616 return 0;
617}
618
Hari Bathini7f0ad112019-09-11 20:16:52 +0530619void fadump_free_cpu_notes_buf(void)
Hari Bathini961cf262019-09-11 20:16:36 +0530620{
621 if (!fw_dump.cpu_notes_buf_vaddr)
622 return;
623
624 fadump_free_buffer(fw_dump.cpu_notes_buf_vaddr,
625 fw_dump.cpu_notes_buf_size);
626 fw_dump.cpu_notes_buf_vaddr = 0;
627 fw_dump.cpu_notes_buf_size = 0;
628}
629
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530630static void fadump_free_mem_ranges(struct fadump_mrange_info *mrange_info)
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530631{
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530632 kfree(mrange_info->mem_ranges);
633 mrange_info->mem_ranges = NULL;
634 mrange_info->mem_ranges_sz = 0;
635 mrange_info->max_mem_ranges = 0;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530636}
637
638/*
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530639 * Allocate or reallocate mem_ranges array in incremental units
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530640 * of PAGE_SIZE.
641 */
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530642static int fadump_alloc_mem_ranges(struct fadump_mrange_info *mrange_info)
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530643{
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530644 struct fadump_memory_range *new_array;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530645 u64 new_size;
646
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530647 new_size = mrange_info->mem_ranges_sz + PAGE_SIZE;
648 pr_debug("Allocating %llu bytes of memory for %s memory ranges\n",
649 new_size, mrange_info->name);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530650
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530651 new_array = krealloc(mrange_info->mem_ranges, new_size, GFP_KERNEL);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530652 if (new_array == NULL) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530653 pr_err("Insufficient memory for setting up %s memory ranges\n",
654 mrange_info->name);
655 fadump_free_mem_ranges(mrange_info);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530656 return -ENOMEM;
657 }
658
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530659 mrange_info->mem_ranges = new_array;
660 mrange_info->mem_ranges_sz = new_size;
661 mrange_info->max_mem_ranges = (new_size /
662 sizeof(struct fadump_memory_range));
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530663 return 0;
664}
665
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530666static inline int fadump_add_mem_range(struct fadump_mrange_info *mrange_info,
667 u64 base, u64 end)
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000668{
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530669 struct fadump_memory_range *mem_ranges = mrange_info->mem_ranges;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530670 bool is_adjacent = false;
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530671 u64 start, size;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530672
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000673 if (base == end)
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530674 return 0;
675
Hari Bathiniced1bf52018-08-07 02:12:54 +0530676 /*
677 * Fold adjacent memory ranges to bring down the memory ranges/
678 * PT_LOAD segments count.
679 */
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530680 if (mrange_info->mem_range_cnt) {
681 start = mem_ranges[mrange_info->mem_range_cnt - 1].base;
682 size = mem_ranges[mrange_info->mem_range_cnt - 1].size;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530683
Hari Bathiniced1bf52018-08-07 02:12:54 +0530684 if ((start + size) == base)
685 is_adjacent = true;
686 }
687 if (!is_adjacent) {
688 /* resize the array on reaching the limit */
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530689 if (mrange_info->mem_range_cnt == mrange_info->max_mem_ranges) {
Hari Bathiniced1bf52018-08-07 02:12:54 +0530690 int ret;
691
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530692 ret = fadump_alloc_mem_ranges(mrange_info);
Hari Bathiniced1bf52018-08-07 02:12:54 +0530693 if (ret)
694 return ret;
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530695
696 /* Update to the new resized array */
697 mem_ranges = mrange_info->mem_ranges;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530698 }
699
700 start = base;
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530701 mem_ranges[mrange_info->mem_range_cnt].base = start;
702 mrange_info->mem_range_cnt++;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530703 }
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000704
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530705 mem_ranges[mrange_info->mem_range_cnt - 1].size = (end - start);
706 pr_debug("%s_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n",
707 mrange_info->name, (mrange_info->mem_range_cnt - 1),
708 start, end - 1, (end - start));
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530709 return 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000710}
711
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530712static int fadump_exclude_reserved_area(u64 start, u64 end)
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000713{
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530714 u64 ra_start, ra_end;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530715 int ret = 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000716
717 ra_start = fw_dump.reserve_dump_area_start;
718 ra_end = ra_start + fw_dump.reserve_dump_area_size;
719
720 if ((ra_start < end) && (ra_end > start)) {
721 if ((start < ra_start) && (end > ra_end)) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530722 ret = fadump_add_mem_range(&crash_mrange_info,
723 start, ra_start);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530724 if (ret)
725 return ret;
726
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530727 ret = fadump_add_mem_range(&crash_mrange_info,
728 ra_end, end);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000729 } else if (start < ra_start) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530730 ret = fadump_add_mem_range(&crash_mrange_info,
731 start, ra_start);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000732 } else if (ra_end < end) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530733 ret = fadump_add_mem_range(&crash_mrange_info,
734 ra_end, end);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000735 }
736 } else
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530737 ret = fadump_add_mem_range(&crash_mrange_info, start, end);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530738
739 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000740}
741
742static int fadump_init_elfcore_header(char *bufp)
743{
744 struct elfhdr *elf;
745
746 elf = (struct elfhdr *) bufp;
747 bufp += sizeof(struct elfhdr);
748 memcpy(elf->e_ident, ELFMAG, SELFMAG);
749 elf->e_ident[EI_CLASS] = ELF_CLASS;
750 elf->e_ident[EI_DATA] = ELF_DATA;
751 elf->e_ident[EI_VERSION] = EV_CURRENT;
752 elf->e_ident[EI_OSABI] = ELF_OSABI;
753 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
754 elf->e_type = ET_CORE;
755 elf->e_machine = ELF_ARCH;
756 elf->e_version = EV_CURRENT;
757 elf->e_entry = 0;
758 elf->e_phoff = sizeof(struct elfhdr);
759 elf->e_shoff = 0;
Daniel Axtensd8bced22016-09-06 15:32:42 +1000760#if defined(_CALL_ELF)
761 elf->e_flags = _CALL_ELF;
762#else
763 elf->e_flags = 0;
764#endif
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000765 elf->e_ehsize = sizeof(struct elfhdr);
766 elf->e_phentsize = sizeof(struct elf_phdr);
767 elf->e_phnum = 0;
768 elf->e_shentsize = 0;
769 elf->e_shnum = 0;
770 elf->e_shstrndx = 0;
771
772 return 0;
773}
774
775/*
776 * Traverse through memblock structure and setup crash memory ranges. These
777 * ranges will be used create PT_LOAD program headers in elfcore header.
778 */
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530779static int fadump_setup_crash_memory_ranges(void)
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000780{
781 struct memblock_region *reg;
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530782 u64 start, end;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530783 int ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000784
785 pr_debug("Setup crash memory ranges.\n");
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530786 crash_mrange_info.mem_range_cnt = 0;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530787
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000788 /*
789 * add the first memory chunk (RMA_START through boot_memory_size) as
790 * a separate memory chunk. The reason is, at the time crash firmware
791 * will move the content of this memory chunk to different location
792 * specified during fadump registration. We need to create a separate
793 * program header for this chunk with the correct offset.
794 */
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530795 ret = fadump_add_mem_range(&crash_mrange_info,
796 RMA_START, fw_dump.boot_memory_size);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530797 if (ret)
798 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000799
800 for_each_memblock(memory, reg) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530801 start = (u64)reg->base;
802 end = start + (u64)reg->size;
Hari Bathinia77af5522017-06-01 22:50:38 +0530803
804 /*
805 * skip the first memory chunk that is already added (RMA_START
806 * through boot_memory_size). This logic needs a relook if and
807 * when RMA_START changes to a non-zero value.
808 */
809 BUILD_BUG_ON(RMA_START != 0);
810 if (start < fw_dump.boot_memory_size) {
811 if (end > fw_dump.boot_memory_size)
812 start = fw_dump.boot_memory_size;
813 else
814 continue;
815 }
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000816
817 /* add this range excluding the reserved dump area. */
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530818 ret = fadump_exclude_reserved_area(start, end);
819 if (ret)
820 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000821 }
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530822
823 return 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000824}
825
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000826/*
827 * If the given physical address falls within the boot memory region then
828 * return the relocated address that points to the dump region reserved
829 * for saving initial boot memory contents.
830 */
831static inline unsigned long fadump_relocate(unsigned long paddr)
832{
833 if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
Hari Bathini41a65d12019-09-11 20:18:57 +0530834 return fw_dump.boot_mem_dest_addr + paddr;
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000835 else
836 return paddr;
837}
838
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000839static int fadump_create_elfcore_headers(char *bufp)
840{
841 struct elfhdr *elf;
842 struct elf_phdr *phdr;
843 int i;
844
845 fadump_init_elfcore_header(bufp);
846 elf = (struct elfhdr *)bufp;
847 bufp += sizeof(struct elfhdr);
848
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000849 /*
850 * setup ELF PT_NOTE, place holder for cpu notes info. The notes info
851 * will be populated during second kernel boot after crash. Hence
852 * this PT_NOTE will always be the first elf note.
853 *
854 * NOTE: Any new ELF note addition should be placed after this note.
855 */
856 phdr = (struct elf_phdr *)bufp;
857 bufp += sizeof(struct elf_phdr);
858 phdr->p_type = PT_NOTE;
859 phdr->p_flags = 0;
860 phdr->p_vaddr = 0;
861 phdr->p_align = 0;
862
863 phdr->p_offset = 0;
864 phdr->p_paddr = 0;
865 phdr->p_filesz = 0;
866 phdr->p_memsz = 0;
867
868 (elf->e_phnum)++;
869
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000870 /* setup ELF PT_NOTE for vmcoreinfo */
871 phdr = (struct elf_phdr *)bufp;
872 bufp += sizeof(struct elf_phdr);
873 phdr->p_type = PT_NOTE;
874 phdr->p_flags = 0;
875 phdr->p_vaddr = 0;
876 phdr->p_align = 0;
877
878 phdr->p_paddr = fadump_relocate(paddr_vmcoreinfo_note());
879 phdr->p_offset = phdr->p_paddr;
Xunlei Pang5203f492017-07-12 14:33:17 -0700880 phdr->p_memsz = phdr->p_filesz = VMCOREINFO_NOTE_SIZE;
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000881
882 /* Increment number of program headers. */
883 (elf->e_phnum)++;
884
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000885 /* setup PT_LOAD sections. */
886
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530887 for (i = 0; i < crash_mrange_info.mem_range_cnt; i++) {
888 u64 mbase, msize;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000889
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530890 mbase = crash_mrange_info.mem_ranges[i].base;
891 msize = crash_mrange_info.mem_ranges[i].size;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000892 if (!msize)
893 continue;
894
895 phdr = (struct elf_phdr *)bufp;
896 bufp += sizeof(struct elf_phdr);
897 phdr->p_type = PT_LOAD;
898 phdr->p_flags = PF_R|PF_W|PF_X;
899 phdr->p_offset = mbase;
900
901 if (mbase == RMA_START) {
902 /*
903 * The entire RMA region will be moved by firmware
904 * to the specified destination_address. Hence set
905 * the correct offset.
906 */
Hari Bathini41a65d12019-09-11 20:18:57 +0530907 phdr->p_offset = fw_dump.boot_mem_dest_addr;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000908 }
909
910 phdr->p_paddr = mbase;
911 phdr->p_vaddr = (unsigned long)__va(mbase);
912 phdr->p_filesz = msize;
913 phdr->p_memsz = msize;
914 phdr->p_align = 0;
915
916 /* Increment number of program headers. */
917 (elf->e_phnum)++;
918 }
919 return 0;
920}
921
922static unsigned long init_fadump_header(unsigned long addr)
923{
924 struct fadump_crash_info_header *fdh;
925
926 if (!addr)
927 return 0;
928
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000929 fdh = __va(addr);
930 addr += sizeof(struct fadump_crash_info_header);
931
932 memset(fdh, 0, sizeof(struct fadump_crash_info_header));
933 fdh->magic_number = FADUMP_CRASH_INFO_MAGIC;
934 fdh->elfcorehdr_addr = addr;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000935 /* We will set the crashing cpu id in crash_fadump() during crash. */
Hari Bathini0226e552019-09-11 20:18:14 +0530936 fdh->crashing_cpu = FADUMP_CPU_UNKNOWN;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000937
938 return addr;
939}
940
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200941static int register_fadump(void)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000942{
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000943 unsigned long addr;
944 void *vaddr;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530945 int ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000946
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000947 /*
948 * If no memory is reserved then we can not register for firmware-
949 * assisted dump.
950 */
951 if (!fw_dump.reserve_dump_area_size)
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200952 return -ENODEV;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000953
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530954 ret = fadump_setup_crash_memory_ranges();
955 if (ret)
956 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000957
Hari Bathini41a65d12019-09-11 20:18:57 +0530958 addr = fw_dump.fadumphdr_addr;
959
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000960 /* Initialize fadump crash info header. */
961 addr = init_fadump_header(addr);
962 vaddr = __va(addr);
963
964 pr_debug("Creating ELF core headers at %#016lx\n", addr);
965 fadump_create_elfcore_headers(vaddr);
966
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000967 /* register the future kernel dump with firmware. */
Hari Bathini41a65d12019-09-11 20:18:57 +0530968 pr_debug("Registering for firmware-assisted kernel dump...\n");
969 return fw_dump.ops->fadump_register(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000970}
971
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000972void fadump_cleanup(void)
973{
Hari Bathini2790d012019-09-11 20:21:16 +0530974 if (!fw_dump.fadump_supported)
975 return;
976
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000977 /* Invalidate the registration only if dump is active. */
978 if (fw_dump.dump_active) {
Hari Bathinif3512012019-09-11 20:19:44 +0530979 pr_debug("Invalidating firmware-assisted dump registration\n");
980 fw_dump.ops->fadump_invalidate(&fw_dump);
Mahesh Salgaonkar722cde72018-04-27 11:53:18 +0530981 } else if (fw_dump.dump_registered) {
982 /* Un-register Firmware-assisted dump if it was registered. */
Hari Bathini41a65d12019-09-11 20:18:57 +0530983 fw_dump.ops->fadump_unregister(&fw_dump);
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530984 fadump_free_mem_ranges(&crash_mrange_info);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000985 }
Hari Bathini2790d012019-09-11 20:21:16 +0530986
987 if (fw_dump.ops->fadump_cleanup)
988 fw_dump.ops->fadump_cleanup(&fw_dump);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000989}
990
Hari Bathini68fa6472017-06-02 01:10:10 +0530991static void fadump_free_reserved_memory(unsigned long start_pfn,
992 unsigned long end_pfn)
993{
994 unsigned long pfn;
995 unsigned long time_limit = jiffies + HZ;
996
997 pr_info("freeing reserved memory (0x%llx - 0x%llx)\n",
998 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
999
1000 for (pfn = start_pfn; pfn < end_pfn; pfn++) {
1001 free_reserved_page(pfn_to_page(pfn));
1002
1003 if (time_after(jiffies, time_limit)) {
1004 cond_resched();
1005 time_limit = jiffies + HZ;
1006 }
1007 }
1008}
1009
1010/*
1011 * Skip memory holes and free memory that was actually reserved.
1012 */
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301013static void fadump_release_reserved_area(u64 start, u64 end)
Hari Bathini68fa6472017-06-02 01:10:10 +05301014{
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301015 u64 tstart, tend, spfn, epfn;
Hari Bathini68fa6472017-06-02 01:10:10 +05301016 struct memblock_region *reg;
Hari Bathini68fa6472017-06-02 01:10:10 +05301017
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301018 spfn = PHYS_PFN(start);
1019 epfn = PHYS_PFN(end);
Hari Bathini68fa6472017-06-02 01:10:10 +05301020 for_each_memblock(memory, reg) {
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301021 tstart = max_t(u64, spfn, memblock_region_memory_base_pfn(reg));
1022 tend = min_t(u64, epfn, memblock_region_memory_end_pfn(reg));
Hari Bathini68fa6472017-06-02 01:10:10 +05301023 if (tstart < tend) {
1024 fadump_free_reserved_memory(tstart, tend);
1025
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301026 if (tend == epfn)
Hari Bathini68fa6472017-06-02 01:10:10 +05301027 break;
1028
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301029 spfn = tend;
Hari Bathini68fa6472017-06-02 01:10:10 +05301030 }
1031 }
1032}
1033
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001034/*
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301035 * Sort the mem ranges in-place and merge adjacent ranges
1036 * to minimize the memory ranges count.
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001037 */
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301038static void sort_and_merge_mem_ranges(struct fadump_mrange_info *mrange_info)
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001039{
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301040 struct fadump_memory_range *mem_ranges;
1041 struct fadump_memory_range tmp_range;
1042 u64 base, size;
1043 int i, j, idx;
1044
1045 if (!reserved_mrange_info.mem_range_cnt)
1046 return;
1047
1048 /* Sort the memory ranges */
1049 mem_ranges = mrange_info->mem_ranges;
1050 for (i = 0; i < mrange_info->mem_range_cnt; i++) {
1051 idx = i;
1052 for (j = (i + 1); j < mrange_info->mem_range_cnt; j++) {
1053 if (mem_ranges[idx].base > mem_ranges[j].base)
1054 idx = j;
1055 }
1056 if (idx != i) {
1057 tmp_range = mem_ranges[idx];
1058 mem_ranges[idx] = mem_ranges[i];
1059 mem_ranges[i] = tmp_range;
1060 }
1061 }
1062
1063 /* Merge adjacent reserved ranges */
1064 idx = 0;
1065 for (i = 1; i < mrange_info->mem_range_cnt; i++) {
1066 base = mem_ranges[i-1].base;
1067 size = mem_ranges[i-1].size;
1068 if (mem_ranges[i].base == (base + size))
1069 mem_ranges[idx].size += mem_ranges[i].size;
1070 else {
1071 idx++;
1072 if (i == idx)
1073 continue;
1074
1075 mem_ranges[idx] = mem_ranges[i];
1076 }
1077 }
1078 mrange_info->mem_range_cnt = idx + 1;
1079}
1080
1081/*
1082 * Scan reserved-ranges to consider them while reserving/releasing
1083 * memory for FADump.
1084 */
1085static inline int fadump_scan_reserved_mem_ranges(void)
1086{
1087 struct device_node *root;
1088 const __be32 *prop;
1089 int len, ret = -1;
1090 unsigned long i;
1091
1092 root = of_find_node_by_path("/");
1093 if (!root)
1094 return ret;
1095
1096 prop = of_get_property(root, "reserved-ranges", &len);
1097 if (!prop)
1098 return ret;
1099
1100 /*
1101 * Each reserved range is an (address,size) pair, 2 cells each,
1102 * totalling 4 cells per range.
1103 */
1104 for (i = 0; i < len / (sizeof(*prop) * 4); i++) {
1105 u64 base, size;
1106
1107 base = of_read_number(prop + (i * 4) + 0, 2);
1108 size = of_read_number(prop + (i * 4) + 2, 2);
1109
1110 if (size) {
1111 ret = fadump_add_mem_range(&reserved_mrange_info,
1112 base, base + size);
1113 if (ret < 0) {
1114 pr_warn("some reserved ranges are ignored!\n");
1115 break;
1116 }
1117 }
1118 }
1119
1120 return ret;
1121}
1122
1123/*
1124 * Release the memory that was reserved during early boot to preserve the
1125 * crash'ed kernel's memory contents except reserved dump area (permanent
1126 * reservation) and reserved ranges used by F/W. The released memory will
1127 * be available for general use.
1128 */
1129static void fadump_release_memory(u64 begin, u64 end)
1130{
1131 u64 ra_start, ra_end, tstart;
1132 int i, ret;
1133
1134 fadump_scan_reserved_mem_ranges();
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001135
1136 ra_start = fw_dump.reserve_dump_area_start;
1137 ra_end = ra_start + fw_dump.reserve_dump_area_size;
1138
Hari Bathini68fa6472017-06-02 01:10:10 +05301139 /*
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301140 * Add reserved dump area to reserved ranges list
1141 * and exclude all these ranges while releasing memory.
Hari Bathini68fa6472017-06-02 01:10:10 +05301142 */
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301143 ret = fadump_add_mem_range(&reserved_mrange_info, ra_start, ra_end);
1144 if (ret != 0) {
1145 /*
1146 * Not enough memory to setup reserved ranges but the system is
1147 * running shortage of memory. So, release all the memory except
1148 * Reserved dump area (reused for next fadump registration).
1149 */
1150 if (begin < ra_end && end > ra_start) {
1151 if (begin < ra_start)
1152 fadump_release_reserved_area(begin, ra_start);
1153 if (end > ra_end)
1154 fadump_release_reserved_area(ra_end, end);
1155 } else
1156 fadump_release_reserved_area(begin, end);
1157
1158 return;
1159 }
1160
1161 /* Get the reserved ranges list in order first. */
1162 sort_and_merge_mem_ranges(&reserved_mrange_info);
1163
1164 /* Exclude reserved ranges and release remaining memory */
1165 tstart = begin;
1166 for (i = 0; i < reserved_mrange_info.mem_range_cnt; i++) {
1167 ra_start = reserved_mrange_info.mem_ranges[i].base;
1168 ra_end = ra_start + reserved_mrange_info.mem_ranges[i].size;
1169
1170 if (tstart >= ra_end)
1171 continue;
1172
1173 if (tstart < ra_start)
1174 fadump_release_reserved_area(tstart, ra_start);
1175 tstart = ra_end;
1176 }
1177
1178 if (tstart < end)
1179 fadump_release_reserved_area(tstart, end);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001180}
1181
1182static void fadump_invalidate_release_mem(void)
1183{
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001184 mutex_lock(&fadump_mutex);
1185 if (!fw_dump.dump_active) {
1186 mutex_unlock(&fadump_mutex);
1187 return;
1188 }
1189
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001190 fadump_cleanup();
1191 mutex_unlock(&fadump_mutex);
1192
Hari Bathini8255da92019-09-11 20:19:28 +05301193 fadump_release_memory(fw_dump.boot_memory_size, memblock_end_of_DRAM());
Hari Bathini961cf262019-09-11 20:16:36 +05301194 fadump_free_cpu_notes_buf();
1195
Hari Bathinia4e2e2c2019-09-11 20:23:28 +05301196 /*
1197 * Setup kernel metadata and initialize the kernel dump
1198 * memory structure for FADump re-registration.
1199 */
1200 if (fw_dump.ops->fadump_setup_metadata &&
1201 (fw_dump.ops->fadump_setup_metadata(&fw_dump) < 0))
1202 pr_warn("Failed to setup kernel metadata!\n");
Hari Bathini41a65d12019-09-11 20:18:57 +05301203 fw_dump.ops->fadump_init_mem_struct(&fw_dump);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001204}
1205
1206static ssize_t fadump_release_memory_store(struct kobject *kobj,
1207 struct kobj_attribute *attr,
1208 const char *buf, size_t count)
1209{
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001210 int input = -1;
1211
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001212 if (!fw_dump.dump_active)
1213 return -EPERM;
1214
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001215 if (kstrtoint(buf, 0, &input))
1216 return -EINVAL;
1217
1218 if (input == 1) {
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001219 /*
1220 * Take away the '/proc/vmcore'. We are releasing the dump
1221 * memory, hence it will not be valid anymore.
1222 */
Michael Ellerman2685f822016-09-30 10:51:46 +10001223#ifdef CONFIG_PROC_VMCORE
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001224 vmcore_cleanup();
Michael Ellerman2685f822016-09-30 10:51:46 +10001225#endif
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001226 fadump_invalidate_release_mem();
1227
1228 } else
1229 return -EINVAL;
1230 return count;
1231}
1232
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001233static ssize_t fadump_enabled_show(struct kobject *kobj,
1234 struct kobj_attribute *attr,
1235 char *buf)
1236{
1237 return sprintf(buf, "%d\n", fw_dump.fadump_enabled);
1238}
1239
1240static ssize_t fadump_register_show(struct kobject *kobj,
1241 struct kobj_attribute *attr,
1242 char *buf)
1243{
1244 return sprintf(buf, "%d\n", fw_dump.dump_registered);
1245}
1246
1247static ssize_t fadump_register_store(struct kobject *kobj,
1248 struct kobj_attribute *attr,
1249 const char *buf, size_t count)
1250{
1251 int ret = 0;
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001252 int input = -1;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001253
Hari Bathinif3512012019-09-11 20:19:44 +05301254 if (!fw_dump.fadump_enabled || fw_dump.dump_active)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001255 return -EPERM;
1256
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001257 if (kstrtoint(buf, 0, &input))
1258 return -EINVAL;
1259
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001260 mutex_lock(&fadump_mutex);
1261
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001262 switch (input) {
1263 case 0:
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001264 if (fw_dump.dump_registered == 0) {
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001265 goto unlock_out;
1266 }
Hari Bathinif3512012019-09-11 20:19:44 +05301267
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001268 /* Un-register Firmware-assisted dump */
Hari Bathini41a65d12019-09-11 20:18:57 +05301269 pr_debug("Un-register firmware-assisted dump\n");
1270 fw_dump.ops->fadump_unregister(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001271 break;
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001272 case 1:
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001273 if (fw_dump.dump_registered == 1) {
Hari Bathini0823c682018-09-14 19:36:02 +05301274 /* Un-register Firmware-assisted dump */
Hari Bathini41a65d12019-09-11 20:18:57 +05301275 fw_dump.ops->fadump_unregister(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001276 }
1277 /* Register Firmware-assisted dump */
Michal Suchanek98b8cd72017-05-27 17:46:15 +02001278 ret = register_fadump();
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001279 break;
1280 default:
1281 ret = -EINVAL;
1282 break;
1283 }
1284
1285unlock_out:
1286 mutex_unlock(&fadump_mutex);
1287 return ret < 0 ? ret : count;
1288}
1289
1290static int fadump_region_show(struct seq_file *m, void *private)
1291{
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001292 if (!fw_dump.fadump_enabled)
1293 return 0;
1294
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001295 mutex_lock(&fadump_mutex);
Hari Bathinif3512012019-09-11 20:19:44 +05301296 fw_dump.ops->fadump_region_show(&fw_dump, m);
1297 mutex_unlock(&fadump_mutex);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001298 return 0;
1299}
1300
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001301static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem,
1302 0200, NULL,
1303 fadump_release_memory_store);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001304static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
1305 0444, fadump_enabled_show,
1306 NULL);
1307static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered,
1308 0644, fadump_register_show,
1309 fadump_register_store);
1310
Yangtao Lif6cee262018-11-05 10:01:19 -05001311DEFINE_SHOW_ATTRIBUTE(fadump_region);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001312
1313static void fadump_init_files(void)
1314{
1315 struct dentry *debugfs_file;
1316 int rc = 0;
1317
1318 rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr);
1319 if (rc)
1320 printk(KERN_ERR "fadump: unable to create sysfs file"
1321 " fadump_enabled (%d)\n", rc);
1322
1323 rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr);
1324 if (rc)
1325 printk(KERN_ERR "fadump: unable to create sysfs file"
1326 " fadump_registered (%d)\n", rc);
1327
1328 debugfs_file = debugfs_create_file("fadump_region", 0444,
1329 powerpc_debugfs_root, NULL,
1330 &fadump_region_fops);
1331 if (!debugfs_file)
1332 printk(KERN_ERR "fadump: unable to create debugfs file"
1333 " fadump_region\n");
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001334
1335 if (fw_dump.dump_active) {
1336 rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr);
1337 if (rc)
1338 printk(KERN_ERR "fadump: unable to create sysfs file"
1339 " fadump_release_mem (%d)\n", rc);
1340 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001341 return;
1342}
1343
1344/*
1345 * Prepare for firmware-assisted dump.
1346 */
1347int __init setup_fadump(void)
1348{
1349 if (!fw_dump.fadump_enabled)
1350 return 0;
1351
1352 if (!fw_dump.fadump_supported) {
1353 printk(KERN_ERR "Firmware-assisted dump is not supported on"
1354 " this hardware\n");
1355 return 0;
1356 }
1357
1358 fadump_show_config();
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001359 /*
1360 * If dump data is available then see if it is valid and prepare for
1361 * saving it to the disk.
1362 */
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001363 if (fw_dump.dump_active) {
1364 /*
1365 * if dump process fails then invalidate the registration
1366 * and release memory before proceeding for re-registration.
1367 */
Hari Bathinif3512012019-09-11 20:19:44 +05301368 if (fw_dump.ops->fadump_process(&fw_dump) < 0)
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001369 fadump_invalidate_release_mem();
1370 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001371 /* Initialize the kernel dump memory structure for FAD registration. */
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001372 else if (fw_dump.reserve_dump_area_size)
Hari Bathini41a65d12019-09-11 20:18:57 +05301373 fw_dump.ops->fadump_init_mem_struct(&fw_dump);
Hari Bathinif3512012019-09-11 20:19:44 +05301374
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001375 fadump_init_files();
1376
1377 return 1;
1378}
1379subsys_initcall(setup_fadump);