[RFC PATCH 1/3] powerpc/pseries/fadump: add support for multiple boot memory regions

Sourabh Jain sourabhjain at linux.ibm.com
Fri Dec 15 19:28:57 AEDT 2023


Hello Hari,

On 06/12/23 01:48, Hari Bathini wrote:
> From: Sourabh Jain <sourabhjain at linux.ibm.com>
>
> Currently, fadump on pseries assumes a single boot memory region even
> though f/w supports more than one boot memory region. Add support for
> more boot memory regions to make the implementation flexible for any
> enhancements that introduce other region types. For this, rtas memory
> structure for fadump is updated to have multiple boot memory regions
> instead of just one. Additionally, methods responsible for creating
> the fadump memory structure during both the first and second kernel
> boot have been modified to take these multiple boot memory regions
> into account. Also, a new callback has been added to the fadump_ops
> structure to get the maximum boot memory regions supported by the
> platform.
>
> Signed-off-by: Sourabh Jain <sourabhjain at linux.ibm.com>
> Signed-off-by: Hari Bathini <hbathini at linux.ibm.com>
> ---
>   arch/powerpc/include/asm/fadump-internal.h   |   2 +-
>   arch/powerpc/kernel/fadump.c                 |  27 +-
>   arch/powerpc/platforms/powernv/opal-fadump.c |   8 +
>   arch/powerpc/platforms/pseries/rtas-fadump.c | 258 ++++++++++++-------
>   arch/powerpc/platforms/pseries/rtas-fadump.h |  26 +-
>   5 files changed, 199 insertions(+), 122 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/fadump-internal.h b/arch/powerpc/include/asm/fadump-internal.h
> index 27f9e11eda28..b3956c400519 100644
> --- a/arch/powerpc/include/asm/fadump-internal.h
> +++ b/arch/powerpc/include/asm/fadump-internal.h
> @@ -129,6 +129,7 @@ struct fadump_ops {
>   				      struct seq_file *m);
>   	void	(*fadump_trigger)(struct fadump_crash_info_header *fdh,
>   				  const char *msg);
> +	int	(*fadump_max_boot_mem_rgns)(void);
>   };
>   
>   /* Helper functions */
> @@ -136,7 +137,6 @@ s32 __init fadump_setup_cpu_notes_buf(u32 num_cpus);
>   void fadump_free_cpu_notes_buf(void);
>   u32 *__init fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs);
>   void __init fadump_update_elfcore_header(char *bufp);
> -bool is_fadump_boot_mem_contiguous(void);
>   bool is_fadump_reserved_mem_contiguous(void);
>   
>   #else /* !CONFIG_PRESERVE_FA_DUMP */
> diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
> index d14eda1e8589..757681658dda 100644
> --- a/arch/powerpc/kernel/fadump.c
> +++ b/arch/powerpc/kernel/fadump.c
> @@ -222,28 +222,6 @@ static bool is_fadump_mem_area_contiguous(u64 d_start, u64 d_end)
>   	return ret;
>   }
>   
> -/*
> - * Returns true, if there are no holes in boot memory area,
> - * false otherwise.
> - */
> -bool is_fadump_boot_mem_contiguous(void)
> -{
> -	unsigned long d_start, d_end;
> -	bool ret = false;
> -	int i;
> -
> -	for (i = 0; i < fw_dump.boot_mem_regs_cnt; i++) {
> -		d_start = fw_dump.boot_mem_addr[i];
> -		d_end   = d_start + fw_dump.boot_mem_sz[i];
> -
> -		ret = is_fadump_mem_area_contiguous(d_start, d_end);
> -		if (!ret)
> -			break;
> -	}
> -
> -	return ret;
> -}
> -
>   /*
>    * Returns true, if there are no holes in reserved memory area,
>    * false otherwise.
> @@ -389,10 +367,11 @@ static unsigned long __init get_fadump_area_size(void)
>   static int __init add_boot_mem_region(unsigned long rstart,
>   				      unsigned long rsize)
>   {
> +	int max_boot_mem_rgns = fw_dump.ops->fadump_max_boot_mem_rgns();
>   	int i = fw_dump.boot_mem_regs_cnt++;
>   
> -	if (fw_dump.boot_mem_regs_cnt > FADUMP_MAX_MEM_REGS) {
> -		fw_dump.boot_mem_regs_cnt = FADUMP_MAX_MEM_REGS;
> +	if (fw_dump.boot_mem_regs_cnt > max_boot_mem_rgns) {
> +		fw_dump.boot_mem_regs_cnt = max_boot_mem_rgns;
>   		return 0;
>   	}
>   
> diff --git a/arch/powerpc/platforms/powernv/opal-fadump.c b/arch/powerpc/platforms/powernv/opal-fadump.c
> index 964f464b1b0e..fa26c21a08d9 100644
> --- a/arch/powerpc/platforms/powernv/opal-fadump.c
> +++ b/arch/powerpc/platforms/powernv/opal-fadump.c
> @@ -615,6 +615,13 @@ static void opal_fadump_trigger(struct fadump_crash_info_header *fdh,
>   		pr_emerg("No backend support for MPIPL!\n");
>   }
>   
> +/* FADUMP_MAX_MEM_REGS or lower */
> +static int opal_fadump_max_boot_mem_rgns(void)
> +{
> +	return FADUMP_MAX_MEM_REGS;
> +

Nitpick: we can get rid of the above blank line.

- Sourabh

> +}
> +
>   static struct fadump_ops opal_fadump_ops = {
>   	.fadump_init_mem_struct		= opal_fadump_init_mem_struct,
>   	.fadump_get_metadata_size	= opal_fadump_get_metadata_size,
> @@ -627,6 +634,7 @@ static struct fadump_ops opal_fadump_ops = {
>   	.fadump_process			= opal_fadump_process,
>   	.fadump_region_show		= opal_fadump_region_show,
>   	.fadump_trigger			= opal_fadump_trigger,
> +	.fadump_max_boot_mem_rgns	= opal_fadump_max_boot_mem_rgns,
>   };
>   
>   void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
> diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.c b/arch/powerpc/platforms/pseries/rtas-fadump.c
> index b5853e9fcc3c..1b05b4cefdfd 100644
> --- a/arch/powerpc/platforms/pseries/rtas-fadump.c
> +++ b/arch/powerpc/platforms/pseries/rtas-fadump.c
> @@ -29,9 +29,6 @@ static const struct rtas_fadump_mem_struct *fdm_active;
>   static void rtas_fadump_update_config(struct fw_dump *fadump_conf,
>   				      const struct rtas_fadump_mem_struct *fdm)
>   {
> -	fadump_conf->boot_mem_dest_addr =
> -		be64_to_cpu(fdm->rmr_region.destination_address);
> -
>   	fadump_conf->fadumphdr_addr = (fadump_conf->boot_mem_dest_addr +
>   				       fadump_conf->boot_memory_size);
>   }
> @@ -43,20 +40,52 @@ static void rtas_fadump_update_config(struct fw_dump *fadump_conf,
>   static void __init rtas_fadump_get_config(struct fw_dump *fadump_conf,
>   				   const struct rtas_fadump_mem_struct *fdm)
>   {
> -	fadump_conf->boot_mem_addr[0] =
> -		be64_to_cpu(fdm->rmr_region.source_address);
> -	fadump_conf->boot_mem_sz[0] = be64_to_cpu(fdm->rmr_region.source_len);
> -	fadump_conf->boot_memory_size = fadump_conf->boot_mem_sz[0];
> +	unsigned long base, size, last_end, hole_size;
>   
> -	fadump_conf->boot_mem_top = fadump_conf->boot_memory_size;
> -	fadump_conf->boot_mem_regs_cnt = 1;
> +	last_end = 0;
> +	hole_size = 0;
> +	fadump_conf->boot_memory_size = 0;
> +	fadump_conf->boot_mem_regs_cnt = 0;
> +	pr_debug("Boot memory regions:\n");
> +	for (int i = 0; i < be16_to_cpu(fdm->header.dump_num_sections); i++) {
> +		int type = be16_to_cpu(fdm->rgn[i].source_data_type);
>   
> -	/*
> -	 * Start address of reserve dump area (permanent reservation) for
> -	 * re-registering FADump after dump capture.
> -	 */
> -	fadump_conf->reserve_dump_area_start =
> -		be64_to_cpu(fdm->cpu_state_data.destination_address);
> +		switch (type) {
> +		case RTAS_FADUMP_CPU_STATE_DATA:
> +			u64 addr = be64_to_cpu(fdm->rgn[i].destination_address);
> +
> +			fadump_conf->cpu_state_dest_vaddr = (u64)__va(addr);
> +			/*
> +			 * Start address of reserve dump area (permanent reservation) for
> +			 * re-registering FADump after dump capture.
> +			 */
> +			fadump_conf->reserve_dump_area_start = addr;
> +			break;
> +		case RTAS_FADUMP_HPTE_REGION:
> +			/* Not processed currently. */
> +			break;
> +		case RTAS_FADUMP_REAL_MODE_REGION:
> +			base = be64_to_cpu(fdm->rgn[i].source_address);
> +			size = be64_to_cpu(fdm->rgn[i].source_len);
> +			pr_debug("\t[%03d] base: 0x%lx, size: 0x%lx\n", i, base, size);
> +			if (!base) {
> +				fadump_conf->boot_mem_dest_addr =
> +					be64_to_cpu(fdm->rgn[i].destination_address);
> +			}
> +
> +			fadump_conf->boot_mem_addr[fadump_conf->boot_mem_regs_cnt] = base;
> +			fadump_conf->boot_mem_sz[fadump_conf->boot_mem_regs_cnt] = size;
> +			fadump_conf->boot_memory_size += size;
> +			hole_size += (base - last_end);
> +			last_end = base + size;
> +			fadump_conf->boot_mem_regs_cnt++;
> +			break;
> +		default:
> +			pr_warn("Section type %d unsupported on this kernel. Ignoring!\n", type);
> +			break;
> +		}
> +	}
> +	fadump_conf->boot_mem_top = fadump_conf->boot_memory_size + hole_size;
>   
>   	rtas_fadump_update_config(fadump_conf, fdm);
>   }
> @@ -64,16 +93,15 @@ static void __init rtas_fadump_get_config(struct fw_dump *fadump_conf,
>   static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
>   {
>   	u64 addr = fadump_conf->reserve_dump_area_start;
> +	u16 sec_cnt = 0;
>   
>   	memset(&fdm, 0, sizeof(struct rtas_fadump_mem_struct));
>   	addr = addr & PAGE_MASK;
>   
>   	fdm.header.dump_format_version = cpu_to_be32(0x00000001);
> -	fdm.header.dump_num_sections = cpu_to_be16(3);
>   	fdm.header.dump_status_flag = 0;
>   	fdm.header.offset_first_dump_section =
> -		cpu_to_be32((u32)offsetof(struct rtas_fadump_mem_struct,
> -					  cpu_state_data));
> +		cpu_to_be32((u32)offsetof(struct rtas_fadump_mem_struct, rgn));
>   
>   	/*
>   	 * Fields for disk dump option.
> @@ -89,25 +117,22 @@ static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
>   
>   	/* Kernel dump sections */
>   	/* cpu state data section. */
> -	fdm.cpu_state_data.request_flag =
> -		cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
> -	fdm.cpu_state_data.source_data_type =
> -		cpu_to_be16(RTAS_FADUMP_CPU_STATE_DATA);
> -	fdm.cpu_state_data.source_address = 0;
> -	fdm.cpu_state_data.source_len =
> -		cpu_to_be64(fadump_conf->cpu_state_data_size);
> -	fdm.cpu_state_data.destination_address = cpu_to_be64(addr);
> +	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_CPU_STATE_DATA);
> +	fdm.rgn[sec_cnt].source_address = 0;
> +	fdm.rgn[sec_cnt].source_len = cpu_to_be64(fadump_conf->cpu_state_data_size);
> +	fdm.rgn[sec_cnt].destination_address = cpu_to_be64(addr);
>   	addr += fadump_conf->cpu_state_data_size;
> +	sec_cnt++;
>   
>   	/* hpte region section */
> -	fdm.hpte_region.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
> -	fdm.hpte_region.source_data_type =
> -		cpu_to_be16(RTAS_FADUMP_HPTE_REGION);
> -	fdm.hpte_region.source_address = 0;
> -	fdm.hpte_region.source_len =
> -		cpu_to_be64(fadump_conf->hpte_region_size);
> -	fdm.hpte_region.destination_address = cpu_to_be64(addr);
> +	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_HPTE_REGION);
> +	fdm.rgn[sec_cnt].source_address = 0;
> +	fdm.rgn[sec_cnt].source_len = cpu_to_be64(fadump_conf->hpte_region_size);
> +	fdm.rgn[sec_cnt].destination_address = cpu_to_be64(addr);
>   	addr += fadump_conf->hpte_region_size;
> +	sec_cnt++;
>   
>   	/*
>   	 * Align boot memory area destination address to page boundary to
> @@ -115,15 +140,20 @@ static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
>   	 */
>   	addr = PAGE_ALIGN(addr);
>   
> -	/* RMA region section */
> -	fdm.rmr_region.request_flag = cpu_to_be32(RTAS_FADUMP_REQUEST_FLAG);
> -	fdm.rmr_region.source_data_type =
> -		cpu_to_be16(RTAS_FADUMP_REAL_MODE_REGION);
> -	fdm.rmr_region.source_address = cpu_to_be64(0);
> -	fdm.rmr_region.source_len = cpu_to_be64(fadump_conf->boot_memory_size);
> -	fdm.rmr_region.destination_address = cpu_to_be64(addr);
> -	addr += fadump_conf->boot_memory_size;
> +	/* First boot memory region destination address */
> +	fadump_conf->boot_mem_dest_addr = addr;
> +	for (int i = 0; i < fadump_conf->boot_mem_regs_cnt; i++) {
> +		/* Boot memory regions */
> +		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_REAL_MODE_REGION);
> +		fdm.rgn[sec_cnt].source_address = cpu_to_be64(fadump_conf->boot_mem_addr[i]);
> +		fdm.rgn[sec_cnt].source_len = cpu_to_be64(fadump_conf->boot_mem_sz[i]);
> +		fdm.rgn[sec_cnt].destination_address = cpu_to_be64(addr);
> +		addr += fadump_conf->boot_mem_sz[i];
> +		sec_cnt++;
> +	}
>   
> +	fdm.header.dump_num_sections = cpu_to_be16(sec_cnt);
>   	rtas_fadump_update_config(fadump_conf, &fdm);
>   
>   	return addr;
> @@ -136,14 +166,21 @@ static u64 rtas_fadump_get_bootmem_min(void)
>   
>   static int rtas_fadump_register(struct fw_dump *fadump_conf)
>   {
> -	unsigned int wait_time;
> +	unsigned int wait_time, fdm_size;
>   	int rc, err = -EIO;
>   
> +	/*
> +	 * Platform requires the exact size of the Dump Memory Structure.
> +	 * Avoid including any unused rgns in the calculation, as this
> +	 * could result in a parameter error (-3) from the platform.
> +	 */
> +	fdm_size = sizeof(struct rtas_fadump_section_header);
> +	fdm_size += be16_to_cpu(fdm.header.dump_num_sections) * sizeof(struct rtas_fadump_section);
> +
>   	/* TODO: Add upper time limit for the delay */
>   	do {
>   		rc =  rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1,
> -				NULL, FADUMP_REGISTER, &fdm,
> -				sizeof(struct rtas_fadump_mem_struct));
> +				NULL, FADUMP_REGISTER, &fdm, fdm_size);
>   
>   		wait_time = rtas_busy_delay_time(rc);
>   		if (wait_time)
> @@ -161,9 +198,7 @@ static int rtas_fadump_register(struct fw_dump *fadump_conf)
>   		pr_err("Failed to register. Hardware Error(%d).\n", rc);
>   		break;
>   	case -3:
> -		if (!is_fadump_boot_mem_contiguous())
> -			pr_err("Can't have holes in boot memory area.\n");
> -		else if (!is_fadump_reserved_mem_contiguous())
> +		if (!is_fadump_reserved_mem_contiguous())
>   			pr_err("Can't have holes in reserved memory area.\n");
>   
>   		pr_err("Failed to register. Parameter Error(%d).\n", rc);
> @@ -316,11 +351,9 @@ static int __init rtas_fadump_build_cpu_notes(struct fw_dump *fadump_conf)
>   	u32 num_cpus, *note_buf;
>   	int i, rc = 0, cpu = 0;
>   	struct pt_regs regs;
> -	unsigned long addr;
>   	void *vaddr;
>   
> -	addr = be64_to_cpu(fdm_active->cpu_state_data.destination_address);
> -	vaddr = __va(addr);
> +	vaddr = (void *)fadump_conf->cpu_state_dest_vaddr;
>   
>   	reg_header = vaddr;
>   	if (be64_to_cpu(reg_header->magic_number) !=
> @@ -395,24 +428,48 @@ static int __init rtas_fadump_build_cpu_notes(struct fw_dump *fadump_conf)
>   static int __init rtas_fadump_process(struct fw_dump *fadump_conf)
>   {
>   	struct fadump_crash_info_header *fdh;
> -	int rc = 0;
> +	int i, rc = 0;
>   
>   	if (!fdm_active || !fadump_conf->fadumphdr_addr)
>   		return -EINVAL;
>   
> -	/* Check if the dump data is valid. */
> -	if ((be16_to_cpu(fdm_active->header.dump_status_flag) ==
> -			RTAS_FADUMP_ERROR_FLAG) ||
> -			(fdm_active->cpu_state_data.error_flags != 0) ||
> -			(fdm_active->rmr_region.error_flags != 0)) {
> -		pr_err("Dump taken by platform is not valid\n");
> -		return -EINVAL;
> -	}
> -	if ((fdm_active->rmr_region.bytes_dumped !=
> -			fdm_active->rmr_region.source_len) ||
> -			!fdm_active->cpu_state_data.bytes_dumped) {
> -		pr_err("Dump taken by platform is incomplete\n");
> -		return -EINVAL;
> +	/* Check all regions. */
> +	for (i = 0; i < be16_to_cpu(fdm_active->header.dump_num_sections); i++) {
> +		int type = be16_to_cpu(fdm_active->rgn[i].source_data_type);
> +
> +		switch (type) {
> +		case RTAS_FADUMP_CPU_STATE_DATA:
> +		case RTAS_FADUMP_HPTE_REGION:
> +		case RTAS_FADUMP_REAL_MODE_REGION:
> +			if (fdm_active->rgn[i].error_flags != 0) {
> +				pr_err("Dump taken by platform is not valid (%d)\n", i);
> +				rc = -EINVAL;
> +			}
> +			if (fdm_active->rgn[i].bytes_dumped != fdm_active->rgn[i].source_len) {
> +				pr_err("Dump taken by platform is incomplete (%d)\n", i);
> +				rc = -EINVAL;
> +			}
> +			if (rc) {
> +				pr_warn("Region type: %u src addr: 0x%llx dest addr: 0x%llx\n",
> +					be16_to_cpu(fdm_active->rgn[i].source_data_type),
> +					be64_to_cpu(fdm_active->rgn[i].source_address),
> +					be64_to_cpu(fdm_active->rgn[i].destination_address));
> +				return rc;
> +			}
> +			break;
> +		default:
> +			/*
> +			 * If the first/crashed kernel added a new region type that the
> +			 * second/fadump kernel doesn't recognize, skip it and process
> +			 * assuming backward compatibility.
> +			 */
> +			pr_warn("Unknown region found: type: %u src addr: 0x%llx dest addr: 0x%llx\n",
> +				be16_to_cpu(fdm_active->rgn[i].source_data_type),
> +				be64_to_cpu(fdm_active->rgn[i].source_address),
> +				be64_to_cpu(fdm_active->rgn[i].destination_address));
> +			break;
> +		}
> +
>   	}
>   
>   	/* Validate the fadump crash info header */
> @@ -439,7 +496,6 @@ static int __init rtas_fadump_process(struct fw_dump *fadump_conf)
>   static void rtas_fadump_region_show(struct fw_dump *fadump_conf,
>   				    struct seq_file *m)
>   {
> -	const struct rtas_fadump_section *cpu_data_section;
>   	const struct rtas_fadump_mem_struct *fdm_ptr;
>   
>   	if (fdm_active)
> @@ -447,27 +503,42 @@ static void rtas_fadump_region_show(struct fw_dump *fadump_conf,
>   	else
>   		fdm_ptr = &fdm;
>   
> -	cpu_data_section = &(fdm_ptr->cpu_state_data);
> -	seq_printf(m, "CPU :[%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\n",
> -		   be64_to_cpu(cpu_data_section->destination_address),
> -		   be64_to_cpu(cpu_data_section->destination_address) +
> -		   be64_to_cpu(cpu_data_section->source_len) - 1,
> -		   be64_to_cpu(cpu_data_section->source_len),
> -		   be64_to_cpu(cpu_data_section->bytes_dumped));
> -
> -	seq_printf(m, "HPTE:[%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\n",
> -		   be64_to_cpu(fdm_ptr->hpte_region.destination_address),
> -		   be64_to_cpu(fdm_ptr->hpte_region.destination_address) +
> -		   be64_to_cpu(fdm_ptr->hpte_region.source_len) - 1,
> -		   be64_to_cpu(fdm_ptr->hpte_region.source_len),
> -		   be64_to_cpu(fdm_ptr->hpte_region.bytes_dumped));
> -
> -	seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
> -		   be64_to_cpu(fdm_ptr->rmr_region.source_address),
> -		   be64_to_cpu(fdm_ptr->rmr_region.destination_address));
> -	seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
> -		   be64_to_cpu(fdm_ptr->rmr_region.source_len),
> -		   be64_to_cpu(fdm_ptr->rmr_region.bytes_dumped));
> +
> +	for (int i = 0; i < be16_to_cpu(fdm_ptr->header.dump_num_sections); i++) {
> +		int type = be16_to_cpu(fdm_ptr->rgn[i].source_data_type);
> +
> +		switch (type) {
> +		case RTAS_FADUMP_CPU_STATE_DATA:
> +			seq_printf(m, "CPU :[%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\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,
> +				   be64_to_cpu(fdm_ptr->rgn[i].source_len),
> +				   be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped));
> +			break;
> +		case RTAS_FADUMP_HPTE_REGION:
> +			seq_printf(m, "HPTE:[%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\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,
> +				   be64_to_cpu(fdm_ptr->rgn[i].source_len),
> +				   be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped));
> +			break;
> +		case RTAS_FADUMP_REAL_MODE_REGION:
> +			seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
> +				   be64_to_cpu(fdm_ptr->rgn[i].source_address),
> +				   be64_to_cpu(fdm_ptr->rgn[i].destination_address));
> +			seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
> +				   be64_to_cpu(fdm_ptr->rgn[i].source_len),
> +				   be64_to_cpu(fdm_ptr->rgn[i].bytes_dumped));
> +			break;
> +		default:
> +			seq_printf(m, "Unknown region type %d : Src: %#016llx, Dest: %#016llx, ",
> +				   type, be64_to_cpu(fdm_ptr->rgn[i].source_address),
> +				   be64_to_cpu(fdm_ptr->rgn[i].destination_address));
> +			break;
> +		}
> +	}
>   
>   	/* Dump is active. Show preserved area start address. */
>   	if (fdm_active) {
> @@ -483,6 +554,20 @@ static void rtas_fadump_trigger(struct fadump_crash_info_header *fdh,
>   	rtas_os_term((char *)msg);
>   }
>   
> +/* FADUMP_MAX_MEM_REGS or lower */
> +static int rtas_fadump_max_boot_mem_rgns(void)
> +{
> +	/*
> +	 * Version 1 of Kernel Assisted Dump Memory Structure (PAPR) supports 10 sections.
> +	 * With one each section taken for CPU state data & HPTE respectively, 8 sections
> +	 * can be used for boot memory regions.
> +	 *
> +	 * If new region(s) is(are) defined, maximum boot memory regions will decrease
> +	 * proportionally.
> +	 */
> +	return RTAS_FADUMP_MAX_BOOT_MEM_REGS;
> +}
> +
>   static struct fadump_ops rtas_fadump_ops = {
>   	.fadump_init_mem_struct		= rtas_fadump_init_mem_struct,
>   	.fadump_get_bootmem_min		= rtas_fadump_get_bootmem_min,
> @@ -492,6 +577,7 @@ static struct fadump_ops rtas_fadump_ops = {
>   	.fadump_process			= rtas_fadump_process,
>   	.fadump_region_show		= rtas_fadump_region_show,
>   	.fadump_trigger			= rtas_fadump_trigger,
> +	.fadump_max_boot_mem_rgns	= rtas_fadump_max_boot_mem_rgns,
>   };
>   
>   void __init rtas_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
> diff --git a/arch/powerpc/platforms/pseries/rtas-fadump.h b/arch/powerpc/platforms/pseries/rtas-fadump.h
> index fd59bd7ca9c3..6740f4981bb8 100644
> --- a/arch/powerpc/platforms/pseries/rtas-fadump.h
> +++ b/arch/powerpc/platforms/pseries/rtas-fadump.h
> @@ -29,6 +29,15 @@
>   /* Dump status flag */
>   #define RTAS_FADUMP_ERROR_FLAG		0x2000
>   
> +/*
> + * 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.
> + */
> +#define MAX_SECTIONS				10
> +#define RTAS_FADUMP_MAX_BOOT_MEM_REGS		8
> +
>   /* Kernel Dump section info */
>   struct rtas_fadump_section {
>   	__be32	request_flag;
> @@ -61,20 +70,15 @@ struct rtas_fadump_section_header {
>    * Firmware Assisted dump memory structure. This structure is required for
>    * registering future kernel dump with power firmware through rtas call.
>    *
> - * No disk dump option. Hence disk dump path string section is not included.
> + * In version 1, the platform permits one section header, dump-disk path
> + * and ten sections.
> + *
> + * Note: No disk dump option. Hence disk dump path string section is not
> + * included.
>    */
>   struct rtas_fadump_mem_struct {
>   	struct rtas_fadump_section_header	header;
> -
> -	/* Kernel dump sections */
> -	struct rtas_fadump_section		cpu_state_data;
> -	struct rtas_fadump_section		hpte_region;
> -
> -	/*
> -	 * TODO: Extend multiple boot memory regions support in the kernel
> -	 *       for this platform.
> -	 */
> -	struct rtas_fadump_section		rmr_region;
> +	struct rtas_fadump_section		rgn[MAX_SECTIONS];
>   };
>   
>   /*



More information about the Linuxppc-dev mailing list