Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41a65d16 authored by Hari Bathini's avatar Hari Bathini Committed by Michael Ellerman
Browse files

pseries/fadump: define RTAS register/un-register callback functions



Move platform specific register/un-register code, the RTAS calls, to
register/un-register callback functions. This would also mean moving
code that initializes and prints the platform specific FADump data.

Signed-off-by: default avatarHari Bathini <hbathini@linux.ibm.com>
Reviewed-by: default avatarMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/156821332856.5656.16380417702046411631.stgit@hbathini.in.ibm.com
parent d3833a70
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -89,7 +89,9 @@ struct fw_dump {

	unsigned long	cpu_state_data_size;
	unsigned long	hpte_region_size;

	unsigned long	boot_memory_size;
	u64		boot_mem_dest_addr;

	unsigned long	fadumphdr_addr;
	unsigned long	cpu_notes_buf_vaddr;
+15 −150
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@
#include "../platforms/pseries/rtas-fadump.h"

static struct fw_dump fw_dump;
static struct rtas_fadump_mem_struct fdm;
static const struct rtas_fadump_mem_struct *fdm_active;

static DEFINE_MUTEX(fadump_mutex);
@@ -229,61 +228,6 @@ static void fadump_show_config(void)
	pr_debug("Boot memory size  : %lx\n", fw_dump.boot_memory_size);
}

static unsigned long init_fadump_mem_struct(struct rtas_fadump_mem_struct *fdm,
				unsigned long addr)
{
	if (!fdm)
		return 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));

	/*
	 * Fields for disk dump option.
	 * We are not using disk dump option, hence set these fields to 0.
	 */
	fdm->header.dd_block_size = 0;
	fdm->header.dd_block_offset = 0;
	fdm->header.dd_num_blocks = 0;
	fdm->header.dd_offset_disk_path = 0;

	/* set 0 to disable an automatic dump-reboot. */
	fdm->header.max_time_auto = 0;

	/* 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(fw_dump.cpu_state_data_size);
	fdm->cpu_state_data.destination_address = cpu_to_be64(addr);
	addr += fw_dump.cpu_state_data_size;

	/* 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(fw_dump.hpte_region_size);
	fdm->hpte_region.destination_address = cpu_to_be64(addr);
	addr += fw_dump.hpte_region_size;

	/* 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(RMA_START);
	fdm->rmr_region.source_len = cpu_to_be64(fw_dump.boot_memory_size);
	fdm->rmr_region.destination_address = cpu_to_be64(addr);
	addr += fw_dump.boot_memory_size;

	return addr;
}

/**
 * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM
 *
@@ -546,61 +490,6 @@ static int __init early_fadump_reserve_mem(char *p)
}
early_param("fadump_reserve_mem", early_fadump_reserve_mem);

static int register_fw_dump(struct rtas_fadump_mem_struct *fdm)
{
	int rc, err;
	unsigned int wait_time;

	pr_debug("Registering for firmware-assisted kernel dump...\n");

	/* TODO: Add upper time limit for the delay */
	do {
		rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
			FADUMP_REGISTER, fdm,
			sizeof(struct rtas_fadump_mem_struct));

		wait_time = rtas_busy_delay_time(rc);
		if (wait_time)
			mdelay(wait_time);

	} while (wait_time);

	err = -EIO;
	switch (rc) {
	default:
		pr_err("Failed to register. Unknown Error(%d).\n", rc);
		break;
	case -1:
		printk(KERN_ERR "Failed to register firmware-assisted kernel"
			" dump. Hardware Error(%d).\n", rc);
		break;
	case -3:
		if (!is_fadump_boot_mem_contiguous())
			pr_err("Can't have holes in boot memory area while registering fadump\n");
		else if (!is_fadump_reserved_mem_contiguous())
			pr_err("Can't have holes in reserved memory area while"
			       " registering fadump\n");

		printk(KERN_ERR "Failed to register firmware-assisted kernel"
			" dump. Parameter Error(%d).\n", rc);
		err = -EINVAL;
		break;
	case -9:
		printk(KERN_ERR "firmware-assisted kernel dump is already "
			" registered.");
		fw_dump.dump_registered = 1;
		err = -EEXIST;
		break;
	case 0:
		printk(KERN_INFO "firmware-assisted kernel dump registration"
			" is successful\n");
		fw_dump.dump_registered = 1;
		err = 0;
		break;
	}
	return err;
}

void crash_fadump(struct pt_regs *regs, const char *str)
{
	struct fadump_crash_info_header *fdh = NULL;
@@ -643,8 +532,7 @@ void crash_fadump(struct pt_regs *regs, const char *str)

	fdh->online_mask = *cpu_online_mask;

	/* Call ibm,os-term rtas call to trigger firmware assisted dump */
	rtas_os_term((char *)str);
	fw_dump.ops->fadump_trigger(fdh, str);
}

#define GPR_MASK	0xffffff0000000000
@@ -1129,7 +1017,7 @@ static int fadump_setup_crash_memory_ranges(void)
static inline unsigned long fadump_relocate(unsigned long paddr)
{
	if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
		return be64_to_cpu(fdm.rmr_region.destination_address) + paddr;
		return fw_dump.boot_mem_dest_addr + paddr;
	else
		return paddr;
}
@@ -1202,7 +1090,7 @@ static int fadump_create_elfcore_headers(char *bufp)
			 * to the specified destination_address. Hence set
			 * the correct offset.
			 */
			phdr->p_offset = be64_to_cpu(fdm.rmr_region.destination_address);
			phdr->p_offset = fw_dump.boot_mem_dest_addr;
		}

		phdr->p_paddr = mbase;
@@ -1254,7 +1142,8 @@ static int register_fadump(void)
	if (ret)
		return ret;

	addr = be64_to_cpu(fdm.rmr_region.destination_address) + be64_to_cpu(fdm.rmr_region.source_len);
	addr = fw_dump.fadumphdr_addr;

	/* Initialize fadump crash info header. */
	addr = init_fadump_header(addr);
	vaddr = __va(addr);
@@ -1263,34 +1152,8 @@ static int register_fadump(void)
	fadump_create_elfcore_headers(vaddr);

	/* register the future kernel dump with firmware. */
	return register_fw_dump(&fdm);
}

static int fadump_unregister_dump(struct rtas_fadump_mem_struct *fdm)
{
	int rc = 0;
	unsigned int wait_time;

	pr_debug("Un-register firmware-assisted dump\n");

	/* TODO: Add upper time limit for the delay */
	do {
		rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
			FADUMP_UNREGISTER, fdm,
			sizeof(struct rtas_fadump_mem_struct));

		wait_time = rtas_busy_delay_time(rc);
		if (wait_time)
			mdelay(wait_time);
	} while (wait_time);

	if (rc) {
		printk(KERN_ERR "Failed to un-register firmware-assisted dump."
			" unexpected error(%d).\n", rc);
		return rc;
	}
	fw_dump.dump_registered = 0;
	return 0;
	pr_debug("Registering for firmware-assisted kernel dump...\n");
	return fw_dump.ops->fadump_register(&fw_dump);
}

static int fadump_invalidate_dump(const struct rtas_fadump_mem_struct *fdm)
@@ -1328,7 +1191,7 @@ void fadump_cleanup(void)
		fadump_invalidate_dump(fdm_active);
	} else if (fw_dump.dump_registered) {
		/* Un-register Firmware-assisted dump if it was registered. */
		fadump_unregister_dump(&fdm);
		fw_dump.ops->fadump_unregister(&fw_dump);
		free_crash_memory_ranges();
	}
}
@@ -1433,7 +1296,7 @@ static void fadump_invalidate_release_mem(void)
	fadump_free_cpu_notes_buf();

	/* Initialize the kernel dump memory structure for FAD registration. */
	init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
	fw_dump.ops->fadump_init_mem_struct(&fw_dump);
}

static ssize_t fadump_release_memory_store(struct kobject *kobj,
@@ -1498,12 +1361,13 @@ static ssize_t fadump_register_store(struct kobject *kobj,
			goto unlock_out;
		}
		/* Un-register Firmware-assisted dump */
		fadump_unregister_dump(&fdm);
		pr_debug("Un-register firmware-assisted dump\n");
		fw_dump.ops->fadump_unregister(&fw_dump);
		break;
	case 1:
		if (fw_dump.dump_registered == 1) {
			/* Un-register Firmware-assisted dump */
			fadump_unregister_dump(&fdm);
			fw_dump.ops->fadump_unregister(&fw_dump);
		}
		/* Register Firmware-assisted dump */
		ret = register_fadump();
@@ -1530,7 +1394,8 @@ static int fadump_region_show(struct seq_file *m, void *private)
		fdm_ptr = fdm_active;
	else {
		mutex_unlock(&fadump_mutex);
		fdm_ptr = &fdm;
		fw_dump.ops->fadump_region_show(&fw_dump, m);
		return 0;
	}

	seq_printf(m,
@@ -1651,7 +1516,7 @@ int __init setup_fadump(void)
	}
	/* Initialize the kernel dump memory structure for FAD registration. */
	else if (fw_dump.reserve_dump_area_size)
		init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
		fw_dump.ops->fadump_init_mem_struct(&fw_dump);
	fadump_init_files();

	return 1;
+159 −3
Original line number Diff line number Diff line
@@ -22,21 +22,153 @@

#include "rtas-fadump.h"

static struct rtas_fadump_mem_struct fdm;

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);
}

static u64 rtas_fadump_init_mem_struct(struct fw_dump *fadump_conf)
{
	return fadump_conf->reserve_dump_area_start;
	u64 addr = fadump_conf->reserve_dump_area_start;

	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));

	/*
	 * Fields for disk dump option.
	 * We are not using disk dump option, hence set these fields to 0.
	 */
	fdm.header.dd_block_size = 0;
	fdm.header.dd_block_offset = 0;
	fdm.header.dd_num_blocks = 0;
	fdm.header.dd_offset_disk_path = 0;

	/* set 0 to disable an automatic dump-reboot. */
	fdm.header.max_time_auto = 0;

	/* 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);
	addr += fadump_conf->cpu_state_data_size;

	/* 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);
	addr += fadump_conf->hpte_region_size;

	/* 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(RMA_START);
	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;

	rtas_fadump_update_config(fadump_conf, &fdm);

	return addr;
}

static int rtas_fadump_register(struct fw_dump *fadump_conf)
{
	return -EIO;
	unsigned int wait_time;
	int rc, err = -EIO;

	/* 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));

		wait_time = rtas_busy_delay_time(rc);
		if (wait_time)
			mdelay(wait_time);

	} while (wait_time);

	switch (rc) {
	case 0:
		pr_info("Registration is successful!\n");
		fadump_conf->dump_registered = 1;
		err = 0;
		break;
	case -1:
		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())
			pr_err("Can't have holes in reserved memory area.\n");

		pr_err("Failed to register. Parameter Error(%d).\n", rc);
		err = -EINVAL;
		break;
	case -9:
		pr_err("Already registered!\n");
		fadump_conf->dump_registered = 1;
		err = -EEXIST;
		break;
	default:
		pr_err("Failed to register. Unknown Error(%d).\n", rc);
		break;
	}

	return err;
}

static int rtas_fadump_unregister(struct fw_dump *fadump_conf)
{
	unsigned int wait_time;
	int rc;

	/* TODO: Add upper time limit for the delay */
	do {
		rc =  rtas_call(fadump_conf->ibm_configure_kernel_dump, 3, 1,
				NULL, FADUMP_UNREGISTER, &fdm,
				sizeof(struct rtas_fadump_mem_struct));

		wait_time = rtas_busy_delay_time(rc);
		if (wait_time)
			mdelay(wait_time);
	} while (wait_time);

	if (rc) {
		pr_err("Failed to un-register - unexpected error(%d).\n", rc);
		return -EIO;
	}

	fadump_conf->dump_registered = 0;
	return 0;
}

static int rtas_fadump_invalidate(struct fw_dump *fadump_conf)
{
	return -EIO;
@@ -54,6 +186,30 @@ 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_mem_struct *fdm_ptr = &fdm;
	const struct rtas_fadump_section *cpu_data_section;

	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: [%#016llx-%#016llx] %#llx bytes, Dumped: %#llx\n",
		   be64_to_cpu(fdm_ptr->rmr_region.destination_address),
		   be64_to_cpu(fdm_ptr->rmr_region.destination_address) +
		   be64_to_cpu(fdm_ptr->rmr_region.source_len) - 1,
		   be64_to_cpu(fdm_ptr->rmr_region.source_len),
		   be64_to_cpu(fdm_ptr->rmr_region.bytes_dumped));
}

static void rtas_fadump_trigger(struct fadump_crash_info_header *fdh,