Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/fadump: setup additional parameters for dump capture kernel

For fadump case, passing additional parameters to dump capture kernel
helps in minimizing the memory footprint for it and also provides the
flexibility to disable components/modules, like hugepages, that are
hindering the boot process of the special dump capture environment.

Set up a dedicated parameter area to be passed to the capture kernel.
This area type is defined as RTAS_FADUMP_PARAM_AREA. Sysfs attribute
'/sys/kernel/fadump/bootargs_append' is exported to the userspace to
specify the additional parameters to be passed to the capture kernel

Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240509115755.519982-3-hbathini@linux.ibm.com

authored by

Hari Bathini and committed by
Michael Ellerman
683eab94 78d5cc15

+133 -9
+3
arch/powerpc/include/asm/fadump-internal.h
··· 124 124 unsigned long cpu_notes_buf_vaddr; 125 125 unsigned long cpu_notes_buf_size; 126 126 127 + unsigned long param_area; 128 + 127 129 /* 128 130 * Maximum size supported by firmware to copy from source to 129 131 * destination address per entry. ··· 140 138 unsigned long dump_active:1; 141 139 unsigned long dump_registered:1; 142 140 unsigned long nocma:1; 141 + unsigned long param_area_supported:1; 143 142 144 143 struct fadump_ops *ops; 145 144 };
+87
arch/powerpc/kernel/fadump.c
··· 1431 1431 return sprintf(buf, "%d\n", fw_dump.dump_registered); 1432 1432 } 1433 1433 1434 + static ssize_t bootargs_append_show(struct kobject *kobj, 1435 + struct kobj_attribute *attr, 1436 + char *buf) 1437 + { 1438 + return sprintf(buf, "%s\n", (char *)__va(fw_dump.param_area)); 1439 + } 1440 + 1441 + static ssize_t bootargs_append_store(struct kobject *kobj, 1442 + struct kobj_attribute *attr, 1443 + const char *buf, size_t count) 1444 + { 1445 + char *params; 1446 + 1447 + if (!fw_dump.fadump_enabled || fw_dump.dump_active) 1448 + return -EPERM; 1449 + 1450 + if (count >= COMMAND_LINE_SIZE) 1451 + return -EINVAL; 1452 + 1453 + /* 1454 + * Fail here instead of handling this scenario with 1455 + * some silly workaround in capture kernel. 1456 + */ 1457 + if (saved_command_line_len + count >= COMMAND_LINE_SIZE) { 1458 + pr_err("Appending parameters exceeds cmdline size!\n"); 1459 + return -ENOSPC; 1460 + } 1461 + 1462 + params = __va(fw_dump.param_area); 1463 + strscpy_pad(params, buf, COMMAND_LINE_SIZE); 1464 + /* Remove newline character at the end. */ 1465 + if (params[count-1] == '\n') 1466 + params[count-1] = '\0'; 1467 + 1468 + return count; 1469 + } 1470 + 1434 1471 static ssize_t registered_store(struct kobject *kobj, 1435 1472 struct kobj_attribute *attr, 1436 1473 const char *buf, size_t count) ··· 1527 1490 static struct kobj_attribute register_attr = __ATTR_RW(registered); 1528 1491 static struct kobj_attribute mem_reserved_attr = __ATTR_RO(mem_reserved); 1529 1492 static struct kobj_attribute hotplug_ready_attr = __ATTR_RO(hotplug_ready); 1493 + static struct kobj_attribute bootargs_append_attr = __ATTR_RW(bootargs_append); 1530 1494 1531 1495 static struct attribute *fadump_attrs[] = { 1532 1496 &enable_attr.attr, ··· 1702 1664 } 1703 1665 1704 1666 /* 1667 + * Reserve memory to store additional parameters to be passed 1668 + * for fadump/capture kernel. 1669 + */ 1670 + static void fadump_setup_param_area(void) 1671 + { 1672 + phys_addr_t range_start, range_end; 1673 + 1674 + if (!fw_dump.param_area_supported || fw_dump.dump_active) 1675 + return; 1676 + 1677 + /* This memory can't be used by PFW or bootloader as it is shared across kernels */ 1678 + if (radix_enabled()) { 1679 + /* 1680 + * Anywhere in the upper half should be good enough as all memory 1681 + * is accessible in real mode. 1682 + */ 1683 + range_start = memblock_end_of_DRAM() / 2; 1684 + range_end = memblock_end_of_DRAM(); 1685 + } else { 1686 + /* 1687 + * Passing additional parameters is supported for hash MMU only 1688 + * if the first memory block size is 768MB or higher. 1689 + */ 1690 + if (ppc64_rma_size < 0x30000000) 1691 + return; 1692 + 1693 + /* 1694 + * 640 MB to 768 MB is not used by PFW/bootloader. So, try reserving 1695 + * memory for passing additional parameters in this range to avoid 1696 + * being stomped on by PFW/bootloader. 1697 + */ 1698 + range_start = 0x2A000000; 1699 + range_end = range_start + 0x4000000; 1700 + } 1701 + 1702 + fw_dump.param_area = memblock_phys_alloc_range(COMMAND_LINE_SIZE, 1703 + COMMAND_LINE_SIZE, 1704 + range_start, 1705 + range_end); 1706 + if (!fw_dump.param_area || sysfs_create_file(fadump_kobj, &bootargs_append_attr.attr)) { 1707 + pr_warn("WARNING: Could not setup area to pass additional parameters!\n"); 1708 + return; 1709 + } 1710 + 1711 + memset(phys_to_virt(fw_dump.param_area), 0, COMMAND_LINE_SIZE); 1712 + } 1713 + 1714 + /* 1705 1715 * Prepare for firmware-assisted dump. 1706 1716 */ 1707 1717 int __init setup_fadump(void) ··· 1772 1686 } 1773 1687 /* Initialize the kernel dump memory structure and register with f/w */ 1774 1688 else if (fw_dump.reserve_dump_area_size) { 1689 + fadump_setup_param_area(); 1775 1690 fw_dump.ops->fadump_init_mem_struct(&fw_dump); 1776 1691 register_fadump(); 1777 1692 }
+4 -2
arch/powerpc/platforms/powernv/opal-fadump.c
··· 665 665 } 666 666 } 667 667 668 - fadump_conf->ops = &opal_fadump_ops; 669 - fadump_conf->fadump_supported = 1; 668 + fadump_conf->ops = &opal_fadump_ops; 669 + fadump_conf->fadump_supported = 1; 670 + /* TODO: Add support to pass additional parameters */ 671 + fadump_conf->param_area_supported = 0; 670 672 671 673 /* 672 674 * Firmware supports 32-bit field for size. Align it to PAGE_SIZE
+32 -3
arch/powerpc/platforms/pseries/rtas-fadump.c
··· 18 18 19 19 #include <asm/page.h> 20 20 #include <asm/rtas.h> 21 + #include <asm/setup.h> 21 22 #include <asm/fadump.h> 22 23 #include <asm/fadump-internal.h> 23 24 ··· 81 80 hole_size += (base - last_end); 82 81 last_end = base + size; 83 82 fadump_conf->boot_mem_regs_cnt++; 83 + break; 84 + case RTAS_FADUMP_PARAM_AREA: 85 + fadump_conf->param_area = be64_to_cpu(fdm->rgn[i].destination_address); 84 86 break; 85 87 default: 86 88 pr_warn("Section type %d unsupported on this kernel. Ignoring!\n", type); ··· 158 154 sec_cnt++; 159 155 } 160 156 157 + /* Parameters area */ 158 + if (fadump_conf->param_area) { 159 + fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG); 160 + fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_PARAM_AREA); 161 + fdm.rgn[sec_cnt].source_address = cpu_to_be64(fadump_conf->param_area); 162 + fdm.rgn[sec_cnt].source_len = cpu_to_be64(COMMAND_LINE_SIZE); 163 + fdm.rgn[sec_cnt].destination_address = cpu_to_be64(fadump_conf->param_area); 164 + sec_cnt++; 165 + } 161 166 fdm.header.dump_num_sections = cpu_to_be16(sec_cnt); 167 + 162 168 rtas_fadump_update_config(fadump_conf, &fdm); 163 169 164 170 return addr; ··· 467 453 return rc; 468 454 } 469 455 break; 456 + case RTAS_FADUMP_PARAM_AREA: 457 + if (fdm_active->rgn[i].bytes_dumped != fdm_active->rgn[i].source_len || 458 + fdm_active->rgn[i].error_flags != 0) { 459 + pr_warn("Failed to process additional parameters! Proceeding anyway..\n"); 460 + fadump_conf->param_area = 0; 461 + } 462 + break; 470 463 default: 471 464 /* 472 465 * If the first/crashed kernel added a new region type that the ··· 529 508 seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n", 530 509 be64_to_cpu(fdm_ptr->rgn[i].source_len), 531 510 be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped)); 511 + break; 512 + case RTAS_FADUMP_PARAM_AREA: 513 + seq_printf(m, "\n[%#016llx-%#016llx]: cmdline append: '%s'\n", 514 + be64_to_cpu(fdm_ptr->rgn[i].destination_address), 515 + be64_to_cpu(fdm_ptr->rgn[i].destination_address) + 516 + be64_to_cpu(fdm_ptr->rgn[i].source_len) - 1, 517 + (char *)__va(be64_to_cpu(fdm_ptr->rgn[i].destination_address))); 532 518 break; 533 519 default: 534 520 seq_printf(m, "Unknown region type %d : Src: %#016llx, Dest: %#016llx, ", ··· 599 571 if (!token) 600 572 return; 601 573 602 - fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token); 603 - fadump_conf->ops = &rtas_fadump_ops; 604 - fadump_conf->fadump_supported = 1; 574 + fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token); 575 + fadump_conf->ops = &rtas_fadump_ops; 576 + fadump_conf->fadump_supported = 1; 577 + fadump_conf->param_area_supported = 1; 605 578 606 579 /* Firmware supports 64-bit value for size, align it to pagesize. */ 607 580 fadump_conf->max_copy_size = ALIGN_DOWN(U64_MAX, PAGE_SIZE);
+7 -4
arch/powerpc/platforms/pseries/rtas-fadump.h
··· 23 23 #define RTAS_FADUMP_HPTE_REGION 0x0002 24 24 #define RTAS_FADUMP_REAL_MODE_REGION 0x0011 25 25 26 + /* OS defined sections */ 27 + #define RTAS_FADUMP_PARAM_AREA 0x0100 28 + 26 29 /* Dump request flag */ 27 30 #define RTAS_FADUMP_REQUEST_FLAG 0x00000001 28 31 ··· 34 31 35 32 /* 36 33 * The Firmware Assisted Dump Memory structure supports a maximum of 10 sections 37 - * in the dump memory structure. Presently, first two sections are used for 38 - * CPU and HPTE data, while the remaining eight sections can be used for 39 - * boot memory regions. 34 + * in the dump memory structure. Presently, three sections are used for 35 + * CPU state data, HPTE & Parameters area, while the remaining seven sections 36 + * can be used for boot memory regions. 40 37 */ 41 38 #define MAX_SECTIONS 10 42 - #define RTAS_FADUMP_MAX_BOOT_MEM_REGS 8 39 + #define RTAS_FADUMP_MAX_BOOT_MEM_REGS 7 43 40 44 41 /* Kernel Dump section info */ 45 42 struct rtas_fadump_section {