Message ID | 20231205201835.388030-3-hbathini@linux.ibm.com (mailing list archive) |
---|---|
State | RFC |
Headers | show |
Series | powerpc/fadump: pass additional args to dump capture kernel | expand |
Hello Hari, On 06/12/23 01:48, Hari Bathini wrote: > 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> > --- > arch/powerpc/include/asm/fadump-internal.h | 3 + > arch/powerpc/kernel/fadump.c | 80 ++++++++++++++++++++ > arch/powerpc/platforms/powernv/opal-fadump.c | 6 +- > arch/powerpc/platforms/pseries/rtas-fadump.c | 35 ++++++++- > arch/powerpc/platforms/pseries/rtas-fadump.h | 11 ++- > 5 files changed, 126 insertions(+), 9 deletions(-) > > diff --git a/arch/powerpc/include/asm/fadump-internal.h b/arch/powerpc/include/asm/fadump-internal.h > index b3956c400519..81629226b15f 100644 > --- a/arch/powerpc/include/asm/fadump-internal.h > +++ b/arch/powerpc/include/asm/fadump-internal.h > @@ -97,6 +97,8 @@ struct fw_dump { > unsigned long cpu_notes_buf_vaddr; > unsigned long cpu_notes_buf_size; > > + unsigned long param_area; > + > /* > * Maximum size supported by firmware to copy from source to > * destination address per entry. > @@ -111,6 +113,7 @@ struct fw_dump { > unsigned long dump_active:1; > unsigned long dump_registered:1; > unsigned long nocma:1; > + unsigned long param_area_supported:1; > > struct fadump_ops *ops; > }; > diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c > index 757681658dda..98f089747ac9 100644 > --- a/arch/powerpc/kernel/fadump.c > +++ b/arch/powerpc/kernel/fadump.c > @@ -1470,6 +1470,7 @@ static ssize_t mem_reserved_show(struct kobject *kobj, > return sprintf(buf, "%ld\n", fw_dump.reserve_dump_area_size); > } > > + > static ssize_t registered_show(struct kobject *kobj, > struct kobj_attribute *attr, > char *buf) > @@ -1477,6 +1478,43 @@ static ssize_t registered_show(struct kobject *kobj, > return sprintf(buf, "%d\n", fw_dump.dump_registered); > } > > +static ssize_t bootargs_append_show(struct kobject *kobj, > + struct kobj_attribute *attr, > + char *buf) > +{ > + return sprintf(buf, "%s\n", (char *)__va(fw_dump.param_area)); > +} > + > +static ssize_t bootargs_append_store(struct kobject *kobj, > + struct kobj_attribute *attr, > + const char *buf, size_t count) > +{ > + char *params; > + > + if (!fw_dump.fadump_enabled || fw_dump.dump_active) > + return -EPERM; > + > + if (count >= COMMAND_LINE_SIZE) > + return -EINVAL; > + > + /* > + * Fail here instead of handling this scenario with > + * some silly workaround in capture kernel. > + */ > + if (saved_command_line_len + count >= COMMAND_LINE_SIZE) { > + pr_err("Appending parameters exceeds cmdline size!\n"); > + return -ENOSPC; > + } > + > + params = __va(fw_dump.param_area); > + strscpy_pad(params, buf, COMMAND_LINE_SIZE); > + /* Remove newline character at the end. */ > + if (params[count-1] == '\n') > + params[count-1] = '\0'; > + > + return count; > +} > + > static ssize_t registered_store(struct kobject *kobj, > struct kobj_attribute *attr, > const char *buf, size_t count) > @@ -1535,6 +1573,7 @@ static struct kobj_attribute release_attr = __ATTR_WO(release_mem); > static struct kobj_attribute enable_attr = __ATTR_RO(enabled); > static struct kobj_attribute register_attr = __ATTR_RW(registered); > static struct kobj_attribute mem_reserved_attr = __ATTR_RO(mem_reserved); > +static struct kobj_attribute bootargs_append_attr = __ATTR_RW(bootargs_append); > > static struct attribute *fadump_attrs[] = { > &enable_attr.attr, > @@ -1611,6 +1650,46 @@ static void __init fadump_init_files(void) > return; > } > > +/* > + * Reserve memory to store additional parameters to be passed > + * for fadump/capture kernel. > + */ > +static void fadump_setup_param_area(void) > +{ > + phys_addr_t range_start, range_end; > + > + if (!fw_dump.param_area_supported || fw_dump.dump_active) > + return; > + > + /* This memory can't be used by PFW or bootloader as it is shared across kernels */ > + if (radix_enabled()) { > + /* > + * Anywhere in the upper half should be good enough as all memory > + * is accessible in real mode. > + */ > + range_start = memblock_end_of_DRAM() / 2; > + range_end = memblock_end_of_DRAM(); > + } else { > + /* > + * Passing additional parameters is supported for hash MMU only > + * if the first memory block size is 768MB or higher. > + */ > + if (ppc64_rma_size < 0x30000000) > + return; > + > + /* 640 MB to 768 MB is not used by bootloader */ > + range_start = 0x28000000; > + range_end = range_start + 0x4000000; > + } > + > + fw_dump.param_area = memblock_phys_alloc_range(COMMAND_LINE_SIZE, > + COMMAND_LINE_SIZE, > + range_start, > + range_end); Should we initialize the `param_area` to avoid garbage values, or retrieve command-line arguments from the previous boot? I observed that cat /sys/kernel/fadump/bootargs_append prints the same value which I set before reboot. Is this expected? Thanks, Sourabh > + if (!fw_dump.param_area || sysfs_create_file(fadump_kobj, &bootargs_append_attr.attr)) > + pr_warn("WARNING: Could not setup area to pass additional parameters!\n"); > +} > + > /* > * Prepare for firmware-assisted dump. > */ > @@ -1639,6 +1718,7 @@ int __init setup_fadump(void) > } > /* Initialize the kernel dump memory structure and register with f/w */ > else if (fw_dump.reserve_dump_area_size) { > + fadump_setup_param_area(); > fw_dump.ops->fadump_init_mem_struct(&fw_dump); > register_fadump(); > } > diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c > index fa26c21a08d9..13370f5cd5ac 100644 > --- a/arch/powerpc/platforms/powernv/opal-fadump.c > +++ b/arch/powerpc/platforms/powernv/opal-fadump.c > @@ -682,8 +682,10 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node) > } > } > > - fadump_conf->ops = &opal_fadump_ops; > - fadump_conf->fadump_supported = 1; > + fadump_conf->ops = &opal_fadump_ops; > + fadump_conf->fadump_supported = 1; > + /* TODO: Add support to pass additional parameters */ > + fadump_conf->param_area_supported = 0; > > /* > * Firmware supports 32-bit field for size. Align it to PAGE_SIZE > diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c > index 1b05b4cefdfd..18838ae90688 100644 > --- a/arch/powerpc/platforms/pseries/rtas-fadump.c > +++ b/arch/powerpc/platforms/pseries/rtas-fadump.c > @@ -18,6 +18,7 @@ > > #include <asm/page.h> > #include <asm/rtas.h> > +#include <asm/setup.h> > #include <asm/fadump.h> > #include <asm/fadump-internal.h> > > @@ -80,6 +81,9 @@ static void __init rtas_fadump_get_config(struct fw_dump *fadump_conf, > last_end = base + size; > fadump_conf->boot_mem_regs_cnt++; > break; > + case RTAS_FADUMP_PARAM_AREA: > + fadump_conf->param_area = be64_to_cpu(fdm->rgn[i].destination_address); > + break; > default: > pr_warn("Section type %d unsupported on this kernel. Ignoring!\n", type); > break; > @@ -153,7 +157,17 @@ static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf) > sec_cnt++; > } > > + /* Parameters area */ > + if (fadump_conf->param_area) { > + fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG); > + fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_PARAM_AREA); > + fdm.rgn[sec_cnt].source_address = cpu_to_be64(fadump_conf->param_area); > + fdm.rgn[sec_cnt].source_len = cpu_to_be64(COMMAND_LINE_SIZE); > + fdm.rgn[sec_cnt].destination_address = cpu_to_be64(fadump_conf->param_area); > + sec_cnt++; > + } > fdm.header.dump_num_sections = cpu_to_be16(sec_cnt); > + > rtas_fadump_update_config(fadump_conf, &fdm); > > return addr; > @@ -457,6 +471,13 @@ static int __init rtas_fadump_process(struct fw_dump *fadump_conf) > return rc; > } > break; > + case RTAS_FADUMP_PARAM_AREA: > + if (fdm_active->rgn[i].bytes_dumped != fdm_active->rgn[i].source_len || > + fdm_active->rgn[i].error_flags != 0) { > + pr_warn("Failed to process additional parameters! Proceeding anyway..\n"); > + fadump_conf->param_area = 0; > + } > + break; > default: > /* > * If the first/crashed kernel added a new region type that the > @@ -532,6 +553,13 @@ static void rtas_fadump_region_show(struct fw_dump *fadump_conf, > be64_to_cpu(fdm_ptr->rgn[i].source_len), > be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped)); > break; > + case RTAS_FADUMP_PARAM_AREA: > + seq_printf(m, "\n[%#016llx-%#016llx]: cmdline append: '%s'\n", > + be64_to_cpu(fdm_ptr->rgn[i].destination_address), > + be64_to_cpu(fdm_ptr->rgn[i].destination_address) + > + be64_to_cpu(fdm_ptr->rgn[i].source_len) - 1, > + (char *)__va(be64_to_cpu(fdm_ptr->rgn[i].destination_address))); > + break; > default: > seq_printf(m, "Unknown region type %d : Src: %#016llx, Dest: %#016llx, ", > type, be64_to_cpu(fdm_ptr->rgn[i].source_address), > @@ -594,9 +622,10 @@ void __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node) > if (!token) > return; > > - fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token); > - fadump_conf->ops = &rtas_fadump_ops; > - fadump_conf->fadump_supported = 1; > + fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token); > + fadump_conf->ops = &rtas_fadump_ops; > + fadump_conf->fadump_supported = 1; > + fadump_conf->param_area_supported = 1; > > /* Firmware supports 64-bit value for size, align it to pagesize. */ > fadump_conf->max_copy_size = ALIGN_DOWN(U64_MAX, PAGE_SIZE); > diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.h b/arch/powerpc/platforms/pseries/rtas-fadump.h > index 6740f4981bb8..c109abf6befd 100644 > --- a/arch/powerpc/platforms/pseries/rtas-fadump.h > +++ b/arch/powerpc/platforms/pseries/rtas-fadump.h > @@ -23,6 +23,9 @@ > #define RTAS_FADUMP_HPTE_REGION 0x0002 > #define RTAS_FADUMP_REAL_MODE_REGION 0x0011 > > +/* OS defined sections */ > +#define RTAS_FADUMP_PARAM_AREA 0x0100 > + > /* Dump request flag */ > #define RTAS_FADUMP_REQUEST_FLAG 0x00000001 > > @@ -31,12 +34,12 @@ > > /* > * The Firmware Assisted Dump Memory structure supports a maximum of 10 sections > - * in the dump memory structure. Presently, first two sections are used for > - * CPU and HPTE data, while the remaining eight sections can be used for > - * boot memory regions. > + * in the dump memory structure. Presently, three sections are used for > + * CPU state data, HPTE & Parameters area, while the remaining seven sections > + * can be used for boot memory regions. > */ > #define MAX_SECTIONS 10 > -#define RTAS_FADUMP_MAX_BOOT_MEM_REGS 8 > +#define RTAS_FADUMP_MAX_BOOT_MEM_REGS 7 > > /* Kernel Dump section info */ > struct rtas_fadump_section {
Hi Sourabh, On 15/12/23 2:12 pm, Sourabh Jain wrote: > Hello Hari, > > On 06/12/23 01:48, Hari Bathini wrote: >> 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> >> --- >> arch/powerpc/include/asm/fadump-internal.h | 3 + >> arch/powerpc/kernel/fadump.c | 80 ++++++++++++++++++++ >> arch/powerpc/platforms/powernv/opal-fadump.c | 6 +- >> arch/powerpc/platforms/pseries/rtas-fadump.c | 35 ++++++++- >> arch/powerpc/platforms/pseries/rtas-fadump.h | 11 ++- >> 5 files changed, 126 insertions(+), 9 deletions(-) >> >> diff --git a/arch/powerpc/include/asm/fadump-internal.h >> b/arch/powerpc/include/asm/fadump-internal.h >> index b3956c400519..81629226b15f 100644 >> --- a/arch/powerpc/include/asm/fadump-internal.h >> +++ b/arch/powerpc/include/asm/fadump-internal.h >> @@ -97,6 +97,8 @@ struct fw_dump { >> unsigned long cpu_notes_buf_vaddr; >> unsigned long cpu_notes_buf_size; >> + unsigned long param_area; >> + >> /* >> * Maximum size supported by firmware to copy from source to >> * destination address per entry. >> @@ -111,6 +113,7 @@ struct fw_dump { >> unsigned long dump_active:1; >> unsigned long dump_registered:1; >> unsigned long nocma:1; >> + unsigned long param_area_supported:1; >> struct fadump_ops *ops; >> }; >> diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c >> index 757681658dda..98f089747ac9 100644 >> --- a/arch/powerpc/kernel/fadump.c >> +++ b/arch/powerpc/kernel/fadump.c >> @@ -1470,6 +1470,7 @@ static ssize_t mem_reserved_show(struct kobject >> *kobj, >> return sprintf(buf, "%ld\n", fw_dump.reserve_dump_area_size); >> } >> + >> static ssize_t registered_show(struct kobject *kobj, >> struct kobj_attribute *attr, >> char *buf) >> @@ -1477,6 +1478,43 @@ static ssize_t registered_show(struct kobject >> *kobj, >> return sprintf(buf, "%d\n", fw_dump.dump_registered); >> } >> +static ssize_t bootargs_append_show(struct kobject *kobj, >> + struct kobj_attribute *attr, >> + char *buf) >> +{ >> + return sprintf(buf, "%s\n", (char *)__va(fw_dump.param_area)); >> +} >> + >> +static ssize_t bootargs_append_store(struct kobject *kobj, >> + struct kobj_attribute *attr, >> + const char *buf, size_t count) >> +{ >> + char *params; >> + >> + if (!fw_dump.fadump_enabled || fw_dump.dump_active) >> + return -EPERM; >> + >> + if (count >= COMMAND_LINE_SIZE) >> + return -EINVAL; >> + >> + /* >> + * Fail here instead of handling this scenario with >> + * some silly workaround in capture kernel. >> + */ >> + if (saved_command_line_len + count >= COMMAND_LINE_SIZE) { >> + pr_err("Appending parameters exceeds cmdline size!\n"); >> + return -ENOSPC; >> + } >> + >> + params = __va(fw_dump.param_area); >> + strscpy_pad(params, buf, COMMAND_LINE_SIZE); >> + /* Remove newline character at the end. */ >> + if (params[count-1] == '\n') >> + params[count-1] = '\0'; >> + >> + return count; >> +} >> + >> static ssize_t registered_store(struct kobject *kobj, >> struct kobj_attribute *attr, >> const char *buf, size_t count) >> @@ -1535,6 +1573,7 @@ static struct kobj_attribute release_attr = >> __ATTR_WO(release_mem); >> static struct kobj_attribute enable_attr = __ATTR_RO(enabled); >> static struct kobj_attribute register_attr = __ATTR_RW(registered); >> static struct kobj_attribute mem_reserved_attr = >> __ATTR_RO(mem_reserved); >> +static struct kobj_attribute bootargs_append_attr = >> __ATTR_RW(bootargs_append); >> static struct attribute *fadump_attrs[] = { >> &enable_attr.attr, >> @@ -1611,6 +1650,46 @@ static void __init fadump_init_files(void) >> return; >> } >> +/* >> + * Reserve memory to store additional parameters to be passed >> + * for fadump/capture kernel. >> + */ >> +static void fadump_setup_param_area(void) >> +{ >> + phys_addr_t range_start, range_end; >> + >> + if (!fw_dump.param_area_supported || fw_dump.dump_active) >> + return; >> + >> + /* This memory can't be used by PFW or bootloader as it is shared >> across kernels */ >> + if (radix_enabled()) { >> + /* >> + * Anywhere in the upper half should be good enough as all >> memory >> + * is accessible in real mode. >> + */ >> + range_start = memblock_end_of_DRAM() / 2; >> + range_end = memblock_end_of_DRAM(); >> + } else { >> + /* >> + * Passing additional parameters is supported for hash MMU only >> + * if the first memory block size is 768MB or higher. >> + */ >> + if (ppc64_rma_size < 0x30000000) >> + return; >> + >> + /* 640 MB to 768 MB is not used by bootloader */ >> + range_start = 0x28000000; >> + range_end = range_start + 0x4000000; >> + } >> + >> + fw_dump.param_area = memblock_phys_alloc_range(COMMAND_LINE_SIZE, >> + COMMAND_LINE_SIZE, >> + range_start, >> + range_end); > > Should we initialize the `param_area` to avoid garbage values, or retrieve > command-line arguments from the previous boot? > > I observed that cat /sys/kernel/fadump/bootargs_append prints the same > value which I set before reboot. Is this expected? I implemented it as such to reuse the arguments set in the previous boot. Not likely to see garbage there. Even if we do, unlikely that garbage is going to have a negative impact on capture kernel boot (even if we don't reset the bootargs in the userspace before crash).. Thanks Hari
diff --git a/arch/powerpc/include/asm/fadump-internal.h b/arch/powerpc/include/asm/fadump-internal.h index b3956c400519..81629226b15f 100644 --- a/arch/powerpc/include/asm/fadump-internal.h +++ b/arch/powerpc/include/asm/fadump-internal.h @@ -97,6 +97,8 @@ struct fw_dump { unsigned long cpu_notes_buf_vaddr; unsigned long cpu_notes_buf_size; + unsigned long param_area; + /* * Maximum size supported by firmware to copy from source to * destination address per entry. @@ -111,6 +113,7 @@ struct fw_dump { unsigned long dump_active:1; unsigned long dump_registered:1; unsigned long nocma:1; + unsigned long param_area_supported:1; struct fadump_ops *ops; }; diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 757681658dda..98f089747ac9 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1470,6 +1470,7 @@ static ssize_t mem_reserved_show(struct kobject *kobj, return sprintf(buf, "%ld\n", fw_dump.reserve_dump_area_size); } + static ssize_t registered_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -1477,6 +1478,43 @@ static ssize_t registered_show(struct kobject *kobj, return sprintf(buf, "%d\n", fw_dump.dump_registered); } +static ssize_t bootargs_append_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%s\n", (char *)__va(fw_dump.param_area)); +} + +static ssize_t bootargs_append_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + char *params; + + if (!fw_dump.fadump_enabled || fw_dump.dump_active) + return -EPERM; + + if (count >= COMMAND_LINE_SIZE) + return -EINVAL; + + /* + * Fail here instead of handling this scenario with + * some silly workaround in capture kernel. + */ + if (saved_command_line_len + count >= COMMAND_LINE_SIZE) { + pr_err("Appending parameters exceeds cmdline size!\n"); + return -ENOSPC; + } + + params = __va(fw_dump.param_area); + strscpy_pad(params, buf, COMMAND_LINE_SIZE); + /* Remove newline character at the end. */ + if (params[count-1] == '\n') + params[count-1] = '\0'; + + return count; +} + static ssize_t registered_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) @@ -1535,6 +1573,7 @@ static struct kobj_attribute release_attr = __ATTR_WO(release_mem); static struct kobj_attribute enable_attr = __ATTR_RO(enabled); static struct kobj_attribute register_attr = __ATTR_RW(registered); static struct kobj_attribute mem_reserved_attr = __ATTR_RO(mem_reserved); +static struct kobj_attribute bootargs_append_attr = __ATTR_RW(bootargs_append); static struct attribute *fadump_attrs[] = { &enable_attr.attr, @@ -1611,6 +1650,46 @@ static void __init fadump_init_files(void) return; } +/* + * Reserve memory to store additional parameters to be passed + * for fadump/capture kernel. + */ +static void fadump_setup_param_area(void) +{ + phys_addr_t range_start, range_end; + + if (!fw_dump.param_area_supported || fw_dump.dump_active) + return; + + /* This memory can't be used by PFW or bootloader as it is shared across kernels */ + if (radix_enabled()) { + /* + * Anywhere in the upper half should be good enough as all memory + * is accessible in real mode. + */ + range_start = memblock_end_of_DRAM() / 2; + range_end = memblock_end_of_DRAM(); + } else { + /* + * Passing additional parameters is supported for hash MMU only + * if the first memory block size is 768MB or higher. + */ + if (ppc64_rma_size < 0x30000000) + return; + + /* 640 MB to 768 MB is not used by bootloader */ + range_start = 0x28000000; + range_end = range_start + 0x4000000; + } + + fw_dump.param_area = memblock_phys_alloc_range(COMMAND_LINE_SIZE, + COMMAND_LINE_SIZE, + range_start, + range_end); + if (!fw_dump.param_area || sysfs_create_file(fadump_kobj, &bootargs_append_attr.attr)) + pr_warn("WARNING: Could not setup area to pass additional parameters!\n"); +} + /* * Prepare for firmware-assisted dump. */ @@ -1639,6 +1718,7 @@ int __init setup_fadump(void) } /* Initialize the kernel dump memory structure and register with f/w */ else if (fw_dump.reserve_dump_area_size) { + fadump_setup_param_area(); fw_dump.ops->fadump_init_mem_struct(&fw_dump); register_fadump(); } diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c index fa26c21a08d9..13370f5cd5ac 100644 --- a/arch/powerpc/platforms/powernv/opal-fadump.c +++ b/arch/powerpc/platforms/powernv/opal-fadump.c @@ -682,8 +682,10 @@ void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node) } } - fadump_conf->ops = &opal_fadump_ops; - fadump_conf->fadump_supported = 1; + fadump_conf->ops = &opal_fadump_ops; + fadump_conf->fadump_supported = 1; + /* TODO: Add support to pass additional parameters */ + fadump_conf->param_area_supported = 0; /* * Firmware supports 32-bit field for size. Align it to PAGE_SIZE diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c index 1b05b4cefdfd..18838ae90688 100644 --- a/arch/powerpc/platforms/pseries/rtas-fadump.c +++ b/arch/powerpc/platforms/pseries/rtas-fadump.c @@ -18,6 +18,7 @@ #include <asm/page.h> #include <asm/rtas.h> +#include <asm/setup.h> #include <asm/fadump.h> #include <asm/fadump-internal.h> @@ -80,6 +81,9 @@ static void __init rtas_fadump_get_config(struct fw_dump *fadump_conf, last_end = base + size; fadump_conf->boot_mem_regs_cnt++; break; + case RTAS_FADUMP_PARAM_AREA: + fadump_conf->param_area = be64_to_cpu(fdm->rgn[i].destination_address); + break; default: pr_warn("Section type %d unsupported on this kernel. Ignoring!\n", type); break; @@ -153,7 +157,17 @@ static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf) sec_cnt++; } + /* Parameters area */ + if (fadump_conf->param_area) { + fdm.rgn[sec_cnt].request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG); + fdm.rgn[sec_cnt].source_data_type = cpu_to_be16(RTAS_FADUMP_PARAM_AREA); + fdm.rgn[sec_cnt].source_address = cpu_to_be64(fadump_conf->param_area); + fdm.rgn[sec_cnt].source_len = cpu_to_be64(COMMAND_LINE_SIZE); + fdm.rgn[sec_cnt].destination_address = cpu_to_be64(fadump_conf->param_area); + sec_cnt++; + } fdm.header.dump_num_sections = cpu_to_be16(sec_cnt); + rtas_fadump_update_config(fadump_conf, &fdm); return addr; @@ -457,6 +471,13 @@ static int __init rtas_fadump_process(struct fw_dump *fadump_conf) return rc; } break; + case RTAS_FADUMP_PARAM_AREA: + if (fdm_active->rgn[i].bytes_dumped != fdm_active->rgn[i].source_len || + fdm_active->rgn[i].error_flags != 0) { + pr_warn("Failed to process additional parameters! Proceeding anyway..\n"); + fadump_conf->param_area = 0; + } + break; default: /* * If the first/crashed kernel added a new region type that the @@ -532,6 +553,13 @@ static void rtas_fadump_region_show(struct fw_dump *fadump_conf, be64_to_cpu(fdm_ptr->rgn[i].source_len), be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped)); break; + case RTAS_FADUMP_PARAM_AREA: + seq_printf(m, "\n[%#016llx-%#016llx]: cmdline append: '%s'\n", + be64_to_cpu(fdm_ptr->rgn[i].destination_address), + be64_to_cpu(fdm_ptr->rgn[i].destination_address) + + be64_to_cpu(fdm_ptr->rgn[i].source_len) - 1, + (char *)__va(be64_to_cpu(fdm_ptr->rgn[i].destination_address))); + break; default: seq_printf(m, "Unknown region type %d : Src: %#016llx, Dest: %#016llx, ", type, be64_to_cpu(fdm_ptr->rgn[i].source_address), @@ -594,9 +622,10 @@ void __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node) if (!token) return; - fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token); - fadump_conf->ops = &rtas_fadump_ops; - fadump_conf->fadump_supported = 1; + fadump_conf->ibm_configure_kernel_dump = be32_to_cpu(*token); + fadump_conf->ops = &rtas_fadump_ops; + fadump_conf->fadump_supported = 1; + fadump_conf->param_area_supported = 1; /* Firmware supports 64-bit value for size, align it to pagesize. */ fadump_conf->max_copy_size = ALIGN_DOWN(U64_MAX, PAGE_SIZE); diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.h b/arch/powerpc/platforms/pseries/rtas-fadump.h index 6740f4981bb8..c109abf6befd 100644 --- a/arch/powerpc/platforms/pseries/rtas-fadump.h +++ b/arch/powerpc/platforms/pseries/rtas-fadump.h @@ -23,6 +23,9 @@ #define RTAS_FADUMP_HPTE_REGION 0x0002 #define RTAS_FADUMP_REAL_MODE_REGION 0x0011 +/* OS defined sections */ +#define RTAS_FADUMP_PARAM_AREA 0x0100 + /* Dump request flag */ #define RTAS_FADUMP_REQUEST_FLAG 0x00000001 @@ -31,12 +34,12 @@ /* * The Firmware Assisted Dump Memory structure supports a maximum of 10 sections - * in the dump memory structure. Presently, first two sections are used for - * CPU and HPTE data, while the remaining eight sections can be used for - * boot memory regions. + * in the dump memory structure. Presently, three sections are used for + * CPU state data, HPTE & Parameters area, while the remaining seven sections + * can be used for boot memory regions. */ #define MAX_SECTIONS 10 -#define RTAS_FADUMP_MAX_BOOT_MEM_REGS 8 +#define RTAS_FADUMP_MAX_BOOT_MEM_REGS 7 /* Kernel Dump section info */ struct rtas_fadump_section {
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> --- arch/powerpc/include/asm/fadump-internal.h | 3 + arch/powerpc/kernel/fadump.c | 80 ++++++++++++++++++++ arch/powerpc/platforms/powernv/opal-fadump.c | 6 +- arch/powerpc/platforms/pseries/rtas-fadump.c | 35 ++++++++- arch/powerpc/platforms/pseries/rtas-fadump.h | 11 ++- 5 files changed, 126 insertions(+), 9 deletions(-)