Set up the actual dump header, register it with the hypervisor.
Signed-off-by: Manish Ahuja <[EMAIL PROTECTED]> Signed-off-by: Linas Vepstas <[EMAIL PROTECTED]> ------ arch/powerpc/platforms/pseries/phyp_dump.c | 169 +++++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 6 deletions(-) Index: linux-2.6.24-rc3-git1/arch/powerpc/platforms/pseries/phyp_dump.c =================================================================== --- linux-2.6.24-rc3-git1.orig/arch/powerpc/platforms/pseries/phyp_dump.c 2007-11-21 15:55:37.000000000 -0600 +++ linux-2.6.24-rc3-git1/arch/powerpc/platforms/pseries/phyp_dump.c 2007-11-21 16:06:52.000000000 -0600 @@ -30,6 +30,134 @@ struct phyp_dump *phyp_dump_info = &phyp static int ibm_configure_kernel_dump; /* ------------------------------------------------- */ +/* RTAS interfaces to declare the dump regions */ + +struct dump_section { + u32 dump_flags; + u16 source_type; + u16 error_flags; + u64 source_address; + u64 source_length; + u64 length_copied; + u64 destination_address; +}; + +struct phyp_dump_header { + u32 version; + u16 num_of_sections; + u16 status; + + u32 first_offset_section; + u32 dump_disk_section; + u64 block_num_dd; + u64 num_of_blocks_dd; + u32 offset_dd; + u32 maxtime_to_auto; + /* No dump disk path string used */ + + struct dump_section cpu_data; + struct dump_section hpte_data; + struct dump_section kernel_data; +}; + +/* The dump header *must be* in low memory, so .bss it */ +static struct phyp_dump_header phdr; + +#define NUM_DUMP_SECTIONS 3 +#define DUMP_HEADER_VERSION 0x1 +#define DUMP_REQUEST_FLAG 0x1 +#define DUMP_SOURCE_CPU 0x0001 +#define DUMP_SOURCE_HPTE 0x0002 +#define DUMP_SOURCE_RMO 0x0011 + +/** + * init_dump_header() - initialize the header declaring a dump + * Returns: length of dump save area. + * + * When the hypervisor saves crashed state, it needs to put + * it somewhere. The dump header tells the hypervisor where + * the data can be saved. + */ +static unsigned long init_dump_header(struct phyp_dump_header *ph) +{ + struct device_node *rtas; + const unsigned int *sizes; + int len; + unsigned long cpu_state_size = 0; + unsigned long hpte_region_size = 0; + unsigned long addr_offset = 0; + + /* Get the required dump region sizes */ + rtas = of_find_node_by_path("/rtas"); + sizes = of_get_property(rtas, "ibm,configure-kernel-dump-sizes", &len); + if (!sizes || len < 20) + return 0; + + if (sizes[0] == 1) + cpu_state_size = *((unsigned long *) &sizes[1]); + + if (sizes[3] == 2) + hpte_region_size = *((unsigned long *) &sizes[4]); + + /* Set up the dump header */ + ph->version = DUMP_HEADER_VERSION; + ph->num_of_sections = NUM_DUMP_SECTIONS; + ph->status = 0; + + ph->first_offset_section = + (u32) &(((struct phyp_dump_header *) 0)->cpu_data); + ph->dump_disk_section = 0; + ph->block_num_dd = 0; + ph->num_of_blocks_dd = 0; + ph->offset_dd = 0; + + ph->maxtime_to_auto = 0; /* disabled */ + + /* The first two sections are mandatory */ + ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG; + ph->cpu_data.source_type = DUMP_SOURCE_CPU; + ph->cpu_data.source_address = 0; + ph->cpu_data.source_length = cpu_state_size; + ph->cpu_data.destination_address = addr_offset; + addr_offset += cpu_state_size; + + ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG; + ph->hpte_data.source_type = DUMP_SOURCE_HPTE; + ph->hpte_data.source_address = 0; + ph->hpte_data.source_length = hpte_region_size; + ph->hpte_data.destination_address = addr_offset; + addr_offset += hpte_region_size; + + /* This section describes the low kernel region */ + ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG; + ph->kernel_data.source_type = DUMP_SOURCE_RMO; + ph->kernel_data.source_address = PHYP_DUMP_RMR_START; + ph->kernel_data.source_length = PHYP_DUMP_RMR_END; + ph->kernel_data.destination_address = addr_offset; + addr_offset += ph->kernel_data.source_length; + + return addr_offset; +} + +static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) +{ + int rc; + ph->cpu_data.destination_address += addr; + ph->hpte_data.destination_address += addr; + ph->kernel_data.destination_address += addr; + + do { + rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, + 1, ph, sizeof(struct phyp_dump_header)); + } while (rtas_busy_delay(rc)); + + if (rc) + { + printk (KERN_ERR "phyp-dump: unexpected error (%d) on register\n", rc); + } +} + +/* ------------------------------------------------- */ /** * release_memory_range -- release memory previously lmb_reserved * @start_pfn: starting physical frame number @@ -125,7 +253,11 @@ static void release_all (void) static int __init phyp_dump_setup(void) { struct device_node *rtas; - const int *dump_header; + const struct phyp_dump_header *dump_header; + unsigned long dump_area_start; + unsigned long dump_area_length; + unsigned long free_area_length; + unsigned long start_pfn, nr_pages; int header_len = 0; int rc; @@ -140,22 +272,47 @@ static int __init phyp_dump_setup(void) return -ENOSYS; } - /* Is there dump data waiting for us? */ + /* Is there dump data waiting for us? If there isn't, + * then register a new dump area, and release all of + * the rest of the reserved ram. + * + * The /rtas/ibm,kernel-dump rtas node is present only + * if there is dump data waiting for us. + */ rtas = of_find_node_by_path("/rtas"); dump_header = of_get_property(rtas, "ibm,kernel-dump", &header_len); + + dump_area_length = init_dump_header (&phdr); + free_area_length = phyp_dump_info->init_reserve_size - dump_area_length; + dump_area_start = phyp_dump_info->init_reserve_start + free_area_length; + dump_area_start = dump_area_start & PAGE_MASK; /* align down */ + free_area_length = dump_area_start - phyp_dump_info->init_reserve_start; + if (dump_header == NULL) { - release_all(); - return 0; + register_dump_area (&phdr, dump_area_start); + goto release_mem; } + /* Don't allow user to release the 256MB scratch area */ + phyp_dump_info->init_reserve_size = free_area_length; + /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ rc = subsys_create_file(&kernel_subsys, &rr); if (rc) { printk (KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n", rc); - release_all(); - return 0; + goto release_mem; } + /* ToDo: re-register the dump area, for next time. */ + + return 0; + +release_mem: + /* release everything except the top 256 MB scratch area */ + start_pfn = PFN_DOWN(phyp_dump_info->init_reserve_start); + nr_pages = PFN_DOWN(free_area_length); + release_memory_range(start_pfn, nr_pages); + return 0; } > documentation explaining what this is :-) . Yes, its supposed > to be an improvement over kdump. > > The patches mostly work; a list of open issues / todo list > is included in the documentation. It also appears that > the not-yet-released firmware versions this was tested > on are still, ahem, incomplete; this work is also pending. > > -- Linas & Manish > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@ozlabs.org > https://ozlabs.org/mailman/listinfo/linuxppc-dev _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev