~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/pseries/rtas-fadump.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Firmware-Assisted Dump support on POWERVM platform.
  4  *
  5  * Copyright 2011, Mahesh Salgaonkar, IBM Corporation.
  6  * Copyright 2019, Hari Bathini, IBM Corporation.
  7  */
  8 
  9 #define pr_fmt(fmt) "rtas fadump: " fmt
 10 
 11 #include <linux/string.h>
 12 #include <linux/memblock.h>
 13 #include <linux/delay.h>
 14 #include <linux/seq_file.h>
 15 #include <linux/crash_dump.h>
 16 #include <linux/of.h>
 17 #include <linux/of_fdt.h>
 18 
 19 #include <asm/page.h>
 20 #include <asm/rtas.h>
 21 #include <asm/setup.h>
 22 #include <asm/fadump.h>
 23 #include <asm/fadump-internal.h>
 24 
 25 #include "rtas-fadump.h"
 26 
 27 static struct rtas_fadump_mem_struct fdm;
 28 static const struct rtas_fadump_mem_struct *fdm_active;
 29 
 30 static void rtas_fadump_update_config(struct fw_dump *fadump_conf,
 31                                       const struct rtas_fadump_mem_struct *fdm)
 32 {
 33         fadump_conf->fadumphdr_addr = (fadump_conf->boot_mem_dest_addr +
 34                                        fadump_conf->boot_memory_size);
 35 }
 36 
 37 /*
 38  * This function is called in the capture kernel to get configuration details
 39  * setup in the first kernel and passed to the f/w.
 40  */
 41 static void __init rtas_fadump_get_config(struct fw_dump *fadump_conf,
 42                                    const struct rtas_fadump_mem_struct *fdm)
 43 {
 44         unsigned long base, size, last_end, hole_size;
 45 
 46         last_end = 0;
 47         hole_size = 0;
 48         fadump_conf->boot_memory_size = 0;
 49         fadump_conf->boot_mem_regs_cnt = 0;
 50         pr_debug("Boot memory regions:\n");
 51         for (int i = 0; i < be16_to_cpu(fdm->header.dump_num_sections); i++) {
 52                 int type = be16_to_cpu(fdm->rgn[i].source_data_type);
 53                 u64 addr;
 54 
 55                 switch (type) {
 56                 case RTAS_FADUMP_CPU_STATE_DATA:
 57                         addr = be64_to_cpu(fdm->rgn[i].destination_address);
 58 
 59                         fadump_conf->cpu_state_dest_vaddr = (u64)__va(addr);
 60                         /*
 61                          * Start address of reserve dump area (permanent reservation) for
 62                          * re-registering FADump after dump capture.
 63                          */
 64                         fadump_conf->reserve_dump_area_start = addr;
 65                         break;
 66                 case RTAS_FADUMP_HPTE_REGION:
 67                         /* Not processed currently. */
 68                         break;
 69                 case RTAS_FADUMP_REAL_MODE_REGION:
 70                         base = be64_to_cpu(fdm->rgn[i].source_address);
 71                         size = be64_to_cpu(fdm->rgn[i].source_len);
 72                         pr_debug("\t[%03d] base: 0x%lx, size: 0x%lx\n", i, base, size);
 73                         if (!base) {
 74                                 fadump_conf->boot_mem_dest_addr =
 75                                         be64_to_cpu(fdm->rgn[i].destination_address);
 76                         }
 77 
 78                         fadump_conf->boot_mem_addr[fadump_conf->boot_mem_regs_cnt] = base;
 79                         fadump_conf->boot_mem_sz[fadump_conf->boot_mem_regs_cnt] = size;
 80                         fadump_conf->boot_memory_size += size;
 81                         hole_size += (base - last_end);
 82                         last_end = base + size;
 83                         fadump_conf->boot_mem_regs_cnt++;
 84                         break;
 85                 case RTAS_FADUMP_PARAM_AREA:
 86                         fadump_conf->param_area = be64_to_cpu(fdm->rgn[i].destination_address);
 87                         break;
 88                 default:
 89                         pr_warn("Section type %d unsupported on this kernel. Ignoring!\n", type);
 90                         break;
 91                 }
 92         }
 93         fadump_conf->boot_mem_top = fadump_conf->boot_memory_size + hole_size;
 94 
 95         rtas_fadump_update_config(fadump_conf, fdm);
 96 }
 97 
 98 static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
 99 {
100         u64 addr = fadump_conf->reserve_dump_area_start;
101         u16 sec_cnt = 0;
102 
103         memset(&fdm, 0, sizeof(struct rtas_fadump_mem_struct));
104         addr = addr & PAGE_MASK;
105 
106         fdm.header.dump_format_version = cpu_to_be32(0x00000001);
107         fdm.header.dump_status_flag = 0;
108         fdm.header.offset_first_dump_section =
109                 cpu_to_be32((u32)offsetof(struct rtas_fadump_mem_struct, rgn));
110 
111         /*
112          * Fields for disk dump option.
113          * We are not using disk dump option, hence set these fields to 0.
114          */
115         fdm.header.dd_block_size = 0;
116         fdm.header.dd_block_offset = 0;
117         fdm.header.dd_num_blocks = 0;
118         fdm.header.dd_offset_disk_path = 0;
119 
120         /* set 0 to disable an automatic dump-reboot. */
121         fdm.header.max_time_auto = 0;
122 
123         /* Kernel dump sections */
124         /* cpu state data section. */
125         fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
126         fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_CPU_STATE_DATA);
127         fdm.rgn[sec_cnt].source_address = 0;
128         fdm.rgn[sec_cnt].source_len = cpu_to_be64(fadump_conf->cpu_state_data_size);
129         fdm.rgn[sec_cnt].destination_address = cpu_to_be64(addr);
130         addr += fadump_conf->cpu_state_data_size;
131         sec_cnt++;
132 
133         /* hpte region section */
134         fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
135         fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_HPTE_REGION);
136         fdm.rgn[sec_cnt].source_address = 0;
137         fdm.rgn[sec_cnt].source_len = cpu_to_be64(fadump_conf->hpte_region_size);
138         fdm.rgn[sec_cnt].destination_address = cpu_to_be64(addr);
139         addr += fadump_conf->hpte_region_size;
140         sec_cnt++;
141 
142         /*
143          * Align boot memory area destination address to page boundary to
144          * be able to mmap read this area in the vmcore.
145          */
146         addr = PAGE_ALIGN(addr);
147 
148         /* First boot memory region destination address */
149         fadump_conf->boot_mem_dest_addr = addr;
150         for (int i = 0; i < fadump_conf->boot_mem_regs_cnt; i++) {
151                 /* Boot memory regions */
152                 fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
153                 fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_REAL_MODE_REGION);
154                 fdm.rgn[sec_cnt].source_address = cpu_to_be64(fadump_conf->boot_mem_addr[i]);
155                 fdm.rgn[sec_cnt].source_len = cpu_to_be64(fadump_conf->boot_mem_sz[i]);
156                 fdm.rgn[sec_cnt].destination_address = cpu_to_be64(addr);
157                 addr += fadump_conf->boot_mem_sz[i];
158                 sec_cnt++;
159         }
160 
161         /* Parameters area */
162         if (fadump_conf->param_area) {
163                 fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
164                 fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_PARAM_AREA);
165                 fdm.rgn[sec_cnt].source_address = cpu_to_be64(fadump_conf->param_area);
166                 fdm.rgn[sec_cnt].source_len = cpu_to_be64(COMMAND_LINE_SIZE);
167                 fdm.rgn[sec_cnt].destination_address = cpu_to_be64(fadump_conf->param_area);
168                 sec_cnt++;
169         }
170         fdm.header.dump_num_sections = cpu_to_be16(sec_cnt);
171 
172         rtas_fadump_update_config(fadump_conf, &fdm);
173 
174         return addr;
175 }
176 
177 static u64 rtas_fadump_get_bootmem_min(void)
178 {
179         return RTAS_FADUMP_MIN_BOOT_MEM;
180 }
181 
182 static int rtas_fadump_register(struct fw_dump *fadump_conf)
183 {
184         unsigned int wait_time, fdm_size;
185         int rc, err = -EIO;
186 
187         /*
188          * Platform requires the exact size of the Dump Memory Structure.
189          * Avoid including any unused rgns in the calculation, as this
190          * could result in a parameter error (-3) from the platform.
191          */
192         fdm_size = sizeof(struct rtas_fadump_section_header);
193         fdm_size += be16_to_cpu(fdm.header.dump_num_sections) * sizeof(struct rtas_fadump_section);
194 
195         /* TODO: Add upper time limit for the delay */
196         do {
197                 rc =  rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1,
198                                 NULL, FADUMP_REGISTER, &fdm, fdm_size);
199 
200                 wait_time = rtas_busy_delay_time(rc);
201                 if (wait_time)
202                         mdelay(wait_time);
203 
204         } while (wait_time);
205 
206         switch (rc) {
207         case 0:
208                 pr_info("Registration is successful!\n");
209                 fadump_conf->dump_registered = 1;
210                 err = 0;
211                 break;
212         case -1:
213                 pr_err("Failed to register. Hardware Error(%d).\n", rc);
214                 break;
215         case -3:
216                 if (!is_fadump_reserved_mem_contiguous())
217                         pr_err("Can't have holes in reserved memory area.\n");
218 
219                 pr_err("Failed to register. Parameter Error(%d).\n", rc);
220                 err = -EINVAL;
221                 break;
222         case -9:
223                 pr_err("Already registered!\n");
224                 fadump_conf->dump_registered = 1;
225                 err = -EEXIST;
226                 break;
227         default:
228                 pr_err("Failed to register. Unknown Error(%d).\n", rc);
229                 break;
230         }
231 
232         return err;
233 }
234 
235 static int rtas_fadump_unregister(struct fw_dump *fadump_conf)
236 {
237         unsigned int wait_time;
238         int rc;
239 
240         /* TODO: Add upper time limit for the delay */
241         do {
242                 rc =  rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1,
243                                 NULL, FADUMP_UNREGISTER, &fdm,
244                                 sizeof(struct rtas_fadump_mem_struct));
245 
246                 wait_time = rtas_busy_delay_time(rc);
247                 if (wait_time)
248                         mdelay(wait_time);
249         } while (wait_time);
250 
251         if (rc) {
252                 pr_err("Failed to un-register - unexpected error(%d).\n", rc);
253                 return -EIO;
254         }
255 
256         fadump_conf->dump_registered = 0;
257         return 0;
258 }
259 
260 static int rtas_fadump_invalidate(struct fw_dump *fadump_conf)
261 {
262         unsigned int wait_time;
263         int rc;
264 
265         /* TODO: Add upper time limit for the delay */
266         do {
267                 rc =  rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1,
268                                 NULL, FADUMP_INVALIDATE, fdm_active,
269                                 sizeof(struct rtas_fadump_mem_struct));
270 
271                 wait_time = rtas_busy_delay_time(rc);
272                 if (wait_time)
273                         mdelay(wait_time);
274         } while (wait_time);
275 
276         if (rc) {
277                 pr_err("Failed to invalidate - unexpected error (%d).\n", rc);
278                 return -EIO;
279         }
280 
281         fadump_conf->dump_active = 0;
282         fdm_active = NULL;
283         return 0;
284 }
285 
286 #define RTAS_FADUMP_GPR_MASK            0xffffff0000000000
287 static inline int rtas_fadump_gpr_index(u64 id)
288 {
289         char str[3];
290         int i = -1;
291 
292         if ((id & RTAS_FADUMP_GPR_MASK) == fadump_str_to_u64("GPR")) {
293                 /* get the digits at the end */
294                 id &= ~RTAS_FADUMP_GPR_MASK;
295                 id >>= 24;
296                 str[2] = '\0';
297                 str[1] = id & 0xff;
298                 str[0] = (id >> 8) & 0xff;
299                 if (kstrtoint(str, 10, &i))
300                         i = -EINVAL;
301                 if (i > 31)
302                         i = -1;
303         }
304         return i;
305 }
306 
307 static void __init rtas_fadump_set_regval(struct pt_regs *regs, u64 reg_id, u64 reg_val)
308 {
309         int i;
310 
311         i = rtas_fadump_gpr_index(reg_id);
312         if (i >= 0)
313                 regs->gpr[i] = (unsigned long)reg_val;
314         else if (reg_id == fadump_str_to_u64("NIA"))
315                 regs->nip = (unsigned long)reg_val;
316         else if (reg_id == fadump_str_to_u64("MSR"))
317                 regs->msr = (unsigned long)reg_val;
318         else if (reg_id == fadump_str_to_u64("CTR"))
319                 regs->ctr = (unsigned long)reg_val;
320         else if (reg_id == fadump_str_to_u64("LR"))
321                 regs->link = (unsigned long)reg_val;
322         else if (reg_id == fadump_str_to_u64("XER"))
323                 regs->xer = (unsigned long)reg_val;
324         else if (reg_id == fadump_str_to_u64("CR"))
325                 regs->ccr = (unsigned long)reg_val;
326         else if (reg_id == fadump_str_to_u64("DAR"))
327                 regs->dar = (unsigned long)reg_val;
328         else if (reg_id == fadump_str_to_u64("DSISR"))
329                 regs->dsisr = (unsigned long)reg_val;
330 }
331 
332 static struct rtas_fadump_reg_entry* __init
333 rtas_fadump_read_regs(struct rtas_fadump_reg_entry *reg_entry,
334                       struct pt_regs *regs)
335 {
336         memset(regs, 0, sizeof(struct pt_regs));
337 
338         while (be64_to_cpu(reg_entry->reg_id) != fadump_str_to_u64("CPUEND")) {
339                 rtas_fadump_set_regval(regs, be64_to_cpu(reg_entry->reg_id),
340                                        be64_to_cpu(reg_entry->reg_value));
341                 reg_entry++;
342         }
343         reg_entry++;
344         return reg_entry;
345 }
346 
347 /*
348  * Read CPU state dump data and convert it into ELF notes.
349  * The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be
350  * used to access the data to allow for additional fields to be added without
351  * affecting compatibility. Each list of registers for a CPU starts with
352  * "CPUSTRT" and ends with "CPUEND". Each register entry is of 16 bytes,
353  * 8 Byte ASCII identifier and 8 Byte register value. The register entry
354  * with identifier "CPUSTRT" and "CPUEND" contains 4 byte cpu id as part
355  * of register value. For more details refer to PAPR document.
356  *
357  * Only for the crashing cpu we ignore the CPU dump data and get exact
358  * state from fadump crash info structure populated by first kernel at the
359  * time of crash.
360  */
361 static int __init rtas_fadump_build_cpu_notes(struct fw_dump *fadump_conf)
362 {
363         struct rtas_fadump_reg_save_area_header *reg_header;
364         struct fadump_crash_info_header *fdh = NULL;
365         struct rtas_fadump_reg_entry *reg_entry;
366         u32 num_cpus, *note_buf;
367         int i, rc = 0, cpu = 0;
368         struct pt_regs regs;
369         void *vaddr;
370 
371         vaddr = (void *)fadump_conf->cpu_state_dest_vaddr;
372 
373         reg_header = vaddr;
374         if (be64_to_cpu(reg_header->magic_number) !=
375             fadump_str_to_u64("REGSAVE")) {
376                 pr_err("Unable to read register save area.\n");
377                 return -ENOENT;
378         }
379 
380         pr_debug("--------CPU State Data------------\n");
381         pr_debug("Magic Number: %llx\n", be64_to_cpu(reg_header->magic_number));
382         pr_debug("NumCpuOffset: %x\n", be32_to_cpu(reg_header->num_cpu_offset));
383 
384         vaddr += be32_to_cpu(reg_header->num_cpu_offset);
385         num_cpus = be32_to_cpu(*((__be32 *)(vaddr)));
386         pr_debug("NumCpus     : %u\n", num_cpus);
387         vaddr += sizeof(u32);
388         reg_entry = (struct rtas_fadump_reg_entry *)vaddr;
389 
390         rc = fadump_setup_cpu_notes_buf(num_cpus);
391         if (rc != 0)
392                 return rc;
393 
394         note_buf = (u32 *)fadump_conf->cpu_notes_buf_vaddr;
395 
396         if (fadump_conf->fadumphdr_addr)
397                 fdh = __va(fadump_conf->fadumphdr_addr);
398 
399         for (i = 0; i < num_cpus; i++) {
400                 if (be64_to_cpu(reg_entry->reg_id) !=
401                     fadump_str_to_u64("CPUSTRT")) {
402                         pr_err("Unable to read CPU state data\n");
403                         rc = -ENOENT;
404                         goto error_out;
405                 }
406                 /* Lower 4 bytes of reg_value contains logical cpu id */
407                 cpu = (be64_to_cpu(reg_entry->reg_value) &
408                        RTAS_FADUMP_CPU_ID_MASK);
409                 if (fdh && !cpumask_test_cpu(cpu, &fdh->cpu_mask)) {
410                         RTAS_FADUMP_SKIP_TO_NEXT_CPU(reg_entry);
411                         continue;
412                 }
413                 pr_debug("Reading register data for cpu %d...\n", cpu);
414                 if (fdh && fdh->crashing_cpu == cpu) {
415                         regs = fdh->regs;
416                         note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
417                         RTAS_FADUMP_SKIP_TO_NEXT_CPU(reg_entry);
418                 } else {
419                         reg_entry++;
420                         reg_entry = rtas_fadump_read_regs(reg_entry, &regs);
421                         note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
422                 }
423         }
424         final_note(note_buf);
425 
426         pr_debug("Updating elfcore header (%llx) with cpu notes\n", fadump_conf->elfcorehdr_addr);
427         fadump_update_elfcore_header((char *)fadump_conf->elfcorehdr_addr);
428         return 0;
429 
430 error_out:
431         fadump_free_cpu_notes_buf();
432         return rc;
433 
434 }
435 
436 /*
437  * Validate and process the dump data stored by the firmware, and update
438  * the CPU notes of elfcorehdr.
439  */
440 static int __init rtas_fadump_process(struct fw_dump *fadump_conf)
441 {
442         if (!fdm_active || !fadump_conf->fadumphdr_addr)
443                 return -EINVAL;
444 
445         /* Check if the dump data is valid. */
446         for (int i = 0; i < be16_to_cpu(fdm_active->header.dump_num_sections); i++) {
447                 int type = be16_to_cpu(fdm_active->rgn[i].source_data_type);
448                 int rc = 0;
449 
450                 switch (type) {
451                 case RTAS_FADUMP_CPU_STATE_DATA:
452                 case RTAS_FADUMP_HPTE_REGION:
453                 case RTAS_FADUMP_REAL_MODE_REGION:
454                         if (fdm_active->rgn[i].error_flags != 0) {
455                                 pr_err("Dump taken by platform is not valid (%d)\n", i);
456                                 rc = -EINVAL;
457                         }
458                         if (fdm_active->rgn[i].bytes_dumped != fdm_active->rgn[i].source_len) {
459                                 pr_err("Dump taken by platform is incomplete (%d)\n", i);
460                                 rc = -EINVAL;
461                         }
462                         if (rc) {
463                                 pr_warn("Region type: %u src addr: 0x%llx dest addr: 0x%llx\n",
464                                         be16_to_cpu(fdm_active->rgn[i].source_data_type),
465                                         be64_to_cpu(fdm_active->rgn[i].source_address),
466                                         be64_to_cpu(fdm_active->rgn[i].destination_address));
467                                 return rc;
468                         }
469                         break;
470                 case RTAS_FADUMP_PARAM_AREA:
471                         if (fdm_active->rgn[i].bytes_dumped != fdm_active->rgn[i].source_len ||
472                             fdm_active->rgn[i].error_flags != 0) {
473                                 pr_warn("Failed to process additional parameters! Proceeding anyway..\n");
474                                 fadump_conf->param_area = 0;
475                         }
476                         break;
477                 default:
478                         /*
479                          * If the first/crashed kernel added a new region type that the
480                          * second/fadump kernel doesn't recognize, skip it and process
481                          * assuming backward compatibility.
482                          */
483                         pr_warn("Unknown region found: type: %u src addr: 0x%llx dest addr: 0x%llx\n",
484                                 be16_to_cpu(fdm_active->rgn[i].source_data_type),
485                                 be64_to_cpu(fdm_active->rgn[i].source_address),
486                                 be64_to_cpu(fdm_active->rgn[i].destination_address));
487                         break;
488                 }
489         }
490 
491         return rtas_fadump_build_cpu_notes(fadump_conf);
492 }
493 
494 static void rtas_fadump_region_show(struct fw_dump *fadump_conf,
495                                     struct seq_file *m)
496 {
497         const struct rtas_fadump_mem_struct *fdm_ptr;
498 
499         if (fdm_active)
500                 fdm_ptr = fdm_active;
501         else
502                 fdm_ptr = &fdm;
503 
504 
505         for (int i = 0; i < be16_to_cpu(fdm_ptr->header.dump_num_sections); i++) {
506                 int type = be16_to_cpu(fdm_ptr->rgn[i].source_data_type);
507 
508                 switch (type) {
509                 case RTAS_FADUMP_CPU_STATE_DATA:
510                         seq_printf(m, "CPU :[%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\n",
511                                    be64_to_cpu(fdm_ptr->rgn[i].destination_address),
512                                    be64_to_cpu(fdm_ptr->rgn[i].destination_address) +
513                                    be64_to_cpu(fdm_ptr->rgn[i].source_len) - 1,
514                                    be64_to_cpu(fdm_ptr->rgn[i].source_len),
515                                    be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped));
516                         break;
517                 case RTAS_FADUMP_HPTE_REGION:
518                         seq_printf(m, "HPTE:[%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\n",
519                                    be64_to_cpu(fdm_ptr->rgn[i].destination_address),
520                                    be64_to_cpu(fdm_ptr->rgn[i].destination_address) +
521                                    be64_to_cpu(fdm_ptr->rgn[i].source_len) - 1,
522                                    be64_to_cpu(fdm_ptr->rgn[i].source_len),
523                                    be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped));
524                         break;
525                 case RTAS_FADUMP_REAL_MODE_REGION:
526                         seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
527                                    be64_to_cpu(fdm_ptr->rgn[i].source_address),
528                                    be64_to_cpu(fdm_ptr->rgn[i].destination_address));
529                         seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
530                                    be64_to_cpu(fdm_ptr->rgn[i].source_len),
531                                    be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped));
532                         break;
533                 case RTAS_FADUMP_PARAM_AREA:
534                         seq_printf(m, "\n[%#016llx-%#016llx]: cmdline append: '%s'\n",
535                                    be64_to_cpu(fdm_ptr->rgn[i].destination_address),
536                                    be64_to_cpu(fdm_ptr->rgn[i].destination_address) +
537                                    be64_to_cpu(fdm_ptr->rgn[i].source_len) - 1,
538                                    (char *)__va(be64_to_cpu(fdm_ptr->rgn[i].destination_address)));
539                         break;
540                 default:
541                         seq_printf(m, "Unknown region type %d : Src: %#016llx, Dest: %#016llx, ",
542                                    type, be64_to_cpu(fdm_ptr->rgn[i].source_address),
543                                    be64_to_cpu(fdm_ptr->rgn[i].destination_address));
544                         break;
545                 }
546         }
547 
548         /* Dump is active. Show preserved area start address. */
549         if (fdm_active) {
550                 seq_printf(m, "\nMemory above %#016llx is reserved for saving crash dump\n",
551                            fadump_conf->boot_mem_top);
552         }
553 }
554 
555 static void rtas_fadump_trigger(struct fadump_crash_info_header *fdh,
556                                 const char *msg)
557 {
558         /* Call ibm,os-term rtas call to trigger firmware assisted dump */
559         rtas_os_term((char *)msg);
560 }
561 
562 /* FADUMP_MAX_MEM_REGS or lower */
563 static int rtas_fadump_max_boot_mem_rgns(void)
564 {
565         /*
566          * Version 1 of Kernel Assisted Dump Memory Structure (PAPR) supports 10 sections.
567          * With one each section taken for CPU state data & HPTE respectively, 8 sections
568          * can be used for boot memory regions.
569          *
570          * If new region(s) is(are) defined, maximum boot memory regions will decrease
571          * proportionally.
572          */
573         return RTAS_FADUMP_MAX_BOOT_MEM_REGS;
574 }
575 
576 static struct fadump_ops rtas_fadump_ops = {
577         .fadump_init_mem_struct         = rtas_fadump_init_mem_struct,
578         .fadump_get_bootmem_min         = rtas_fadump_get_bootmem_min,
579         .fadump_register                = rtas_fadump_register,
580         .fadump_unregister              = rtas_fadump_unregister,
581         .fadump_invalidate              = rtas_fadump_invalidate,
582         .fadump_process                 = rtas_fadump_process,
583         .fadump_region_show             = rtas_fadump_region_show,
584         .fadump_trigger                 = rtas_fadump_trigger,
585         .fadump_max_boot_mem_rgns       = rtas_fadump_max_boot_mem_rgns,
586 };
587 
588 void __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
589 {
590         int i, size, num_sections;
591         const __be32 *sections;
592         const __be32 *token;
593 
594         /*
595          * Check if Firmware Assisted dump is supported. if yes, check
596          * if dump has been initiated on last reboot.
597          */
598         token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL);
599         if (!token)
600                 return;
601 
602         fadump_conf->ibm_configure_kernel_dump  = be32_to_cpu(*token);
603         fadump_conf->ops                        = &rtas_fadump_ops;
604         fadump_conf->fadump_supported           = 1;
605         fadump_conf->param_area_supported       = 1;
606 
607         /* Firmware supports 64-bit value for size, align it to pagesize. */
608         fadump_conf->max_copy_size = ALIGN_DOWN(U64_MAX, PAGE_SIZE);
609 
610         /*
611          * The 'ibm,kernel-dump' rtas node is present only if there is
612          * dump data waiting for us.
613          */
614         fdm_active = of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL);
615         if (fdm_active) {
616                 pr_info("Firmware-assisted dump is active.\n");
617                 fadump_conf->dump_active = 1;
618                 rtas_fadump_get_config(fadump_conf, (void *)__pa(fdm_active));
619         }
620 
621         /* Get the sizes required to store dump data for the firmware provided
622          * dump sections.
623          * For each dump section type supported, a 32bit cell which defines
624          * the ID of a supported section followed by two 32 bit cells which
625          * gives the size of the section in bytes.
626          */
627         sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
628                                         &size);
629 
630         if (!sections)
631                 return;
632 
633         num_sections = size / (3 * sizeof(u32));
634 
635         for (i = 0; i < num_sections; i++, sections += 3) {
636                 u32 type = (u32)of_read_number(sections, 1);
637 
638                 switch (type) {
639                 case RTAS_FADUMP_CPU_STATE_DATA:
640                         fadump_conf->cpu_state_data_size =
641                                         of_read_ulong(&sections[1], 2);
642                         break;
643                 case RTAS_FADUMP_HPTE_REGION:
644                         fadump_conf->hpte_region_size =
645                                         of_read_ulong(&sections[1], 2);
646                         break;
647                 }
648         }
649 }
650 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php