Commit 683eab94 authored by Hari Bathini's avatar Hari Bathini Committed by Michael Ellerman

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: default avatarHari Bathini <hbathini@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240509115755.519982-3-hbathini@linux.ibm.com
parent 78d5cc15
......@@ -124,6 +124,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.
......@@ -138,6 +140,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;
};
......
......@@ -1431,6 +1431,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)
......@@ -1490,6 +1527,7 @@ 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 hotplug_ready_attr = __ATTR_RO(hotplug_ready);
static struct kobj_attribute bootargs_append_attr = __ATTR_RW(bootargs_append);
static struct attribute *fadump_attrs[] = {
&enable_attr.attr,
......@@ -1663,6 +1701,54 @@ static void __init fadump_process(void)
fadump_invalidate_release_mem();
}
/*
* 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 PFW/bootloader. So, try reserving
* memory for passing additional parameters in this range to avoid
* being stomped on by PFW/bootloader.
*/
range_start = 0x2A000000;
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");
return;
}
memset(phys_to_virt(fw_dump.param_area), 0, COMMAND_LINE_SIZE);
}
/*
* Prepare for firmware-assisted dump.
*/
......@@ -1686,6 +1772,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();
}
......
......@@ -665,8 +665,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
......
......@@ -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>
......@@ -81,6 +82,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;
......@@ -154,7 +158,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;
......@@ -453,6 +467,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
......@@ -509,6 +530,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),
......@@ -571,9 +599,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);
......
......@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment