From 6ac26c8a7eb149dbd669cc6cd9b77ffc9cd0d2fb Mon Sep 17 00:00:00 2001 From: Manish Ahuja Date: Sat, 22 Mar 2008 10:37:08 +1100 Subject: [POWERPC] pseries: phyp dump: Reserve and release memory Initial patch for reserving memory in early boot, and freeing it later. If the previous boot had ended with a crash, the reserved memory would contain a copy of the crashed kernel data. Signed-off-by: Manish Ahuja Signed-off-by: Linas Vepstas Signed-off-by: Paul Mackerras --- include/asm-powerpc/phyp_dump.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 include/asm-powerpc/phyp_dump.h (limited to 'include/asm-powerpc/phyp_dump.h') diff --git a/include/asm-powerpc/phyp_dump.h b/include/asm-powerpc/phyp_dump.h new file mode 100644 index 000000000000..e2d988dcdc99 --- /dev/null +++ b/include/asm-powerpc/phyp_dump.h @@ -0,0 +1,41 @@ +/* + * Hypervisor-assisted dump + * + * Linas Vepstas, Manish Ahuja 2008 + * Copyright 2008 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _PPC64_PHYP_DUMP_H +#define _PPC64_PHYP_DUMP_H + +#ifdef CONFIG_PHYP_DUMP + +/* The RMR region will be saved for later dumping + * whenever the kernel crashes. Set this to 256MB. */ +#define PHYP_DUMP_RMR_START 0x0 +#define PHYP_DUMP_RMR_END (1UL<<28) + +struct phyp_dump { + /* Memory that is reserved during very early boot. */ + unsigned long init_reserve_start; + unsigned long init_reserve_size; + /* Check status during boot if dump supported, active & present*/ + unsigned long phyp_dump_configured; + unsigned long phyp_dump_is_active; + /* store cpu & hpte size */ + unsigned long cpu_state_size; + unsigned long hpte_region_size; +}; + +extern struct phyp_dump *phyp_dump_info; + +int early_init_dt_scan_phyp_dump(unsigned long node, + const char *uname, int depth, void *data); + +#endif /* CONFIG_PHYP_DUMP */ +#endif /* _PPC64_PHYP_DUMP_H */ -- cgit v1.2.3 From a9c508dae10a821dc95653178eec018abc90482e Mon Sep 17 00:00:00 2001 From: Manish Ahuja Date: Sat, 22 Mar 2008 10:45:22 +1100 Subject: [POWERPC] pseries: phyp dump: Invalidate and print dump areas This adds routines to a. invalidate dump b. calculate region that is reserved and needs to be freed. This is exported through sysfs interface. Unregister has been removed for now as it wasn't being used. Signed-off-by: Manish Ahuja Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pseries/phyp_dump.c | 83 +++++++++++++++++++++++++++--- include/asm-powerpc/phyp_dump.h | 3 ++ 2 files changed, 80 insertions(+), 6 deletions(-) (limited to 'include/asm-powerpc/phyp_dump.h') diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c index 5cdba6a6f70c..df4870ec90d8 100644 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ b/arch/powerpc/platforms/pseries/phyp_dump.c @@ -70,6 +70,10 @@ static struct phyp_dump_header phdr; #define DUMP_SOURCE_CPU 0x0001 #define DUMP_SOURCE_HPTE 0x0002 #define DUMP_SOURCE_RMO 0x0011 +#define DUMP_ERROR_FLAG 0x2000 +#define DUMP_TRIGGERED 0x4000 +#define DUMP_PERFORMED 0x8000 + /** * init_dump_header() - initialize the header declaring a dump @@ -181,9 +185,15 @@ static void print_dump_header(const struct phyp_dump_header *ph) 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; + + /* Add addr value if not initialized before */ + if (ph->cpu_data.destination_address == 0) { + ph->cpu_data.destination_address += addr; + ph->hpte_data.destination_address += addr; + ph->kernel_data.destination_address += addr; + } + + /* ToDo Invalidate kdump and free memory range. */ do { rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, @@ -197,6 +207,30 @@ static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) } } +static +void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr) +{ + int rc; + + /* Add addr value if not initialized before */ + if (ph->cpu_data.destination_address == 0) { + 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, + 2, ph, sizeof(struct phyp_dump_header)); + } while (rtas_busy_delay(rc)); + + if (rc) { + printk(KERN_ERR "phyp-dump: unexpected error (%d) " + "on invalidate\n", rc); + print_dump_header(ph); + } +} + /* ------------------------------------------------- */ /** * release_memory_range -- release memory previously lmb_reserved @@ -207,8 +241,8 @@ static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) * lmb_reserved in early boot. The released memory becomes * available for genreal use. */ -static void -release_memory_range(unsigned long start_pfn, unsigned long nr_pages) +static void release_memory_range(unsigned long start_pfn, + unsigned long nr_pages) { struct page *rpage; unsigned long end_pfn; @@ -269,8 +303,29 @@ static ssize_t store_release_region(struct kobject *kobj, return count; } +static ssize_t show_release_region(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + u64 second_addr_range; + + /* total reserved size - start of scratch area */ + second_addr_range = phyp_dump_info->init_reserve_size - + phyp_dump_info->reserved_scratch_size; + return sprintf(buf, "CPU:0x%lx-0x%lx: HPTE:0x%lx-0x%lx:" + " DUMP:0x%lx-0x%lx, 0x%lx-0x%lx:\n", + phdr.cpu_data.destination_address, + phdr.cpu_data.length_copied, + phdr.hpte_data.destination_address, + phdr.hpte_data.length_copied, + phdr.kernel_data.destination_address, + phdr.kernel_data.length_copied, + phyp_dump_info->init_reserve_start, + second_addr_range); +} + static struct kobj_attribute rr = __ATTR(release_region, 0600, - NULL, store_release_region); + show_release_region, + store_release_region); static int __init phyp_dump_setup(void) { @@ -313,6 +368,22 @@ static int __init phyp_dump_setup(void) return 0; } + /* re-register the dump area, if old dump was invalid */ + if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) { + invalidate_last_dump(&phdr, dump_area_start); + register_dump_area(&phdr, dump_area_start); + return 0; + } + + if (dump_header) { + phyp_dump_info->reserved_scratch_addr = + dump_header->cpu_data.destination_address; + phyp_dump_info->reserved_scratch_size = + dump_header->cpu_data.source_length + + dump_header->hpte_data.source_length + + dump_header->kernel_data.source_length; + } + /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ rc = sysfs_create_file(kernel_kobj, &rr.attr); if (rc) diff --git a/include/asm-powerpc/phyp_dump.h b/include/asm-powerpc/phyp_dump.h index e2d988dcdc99..b454de45b2ca 100644 --- a/include/asm-powerpc/phyp_dump.h +++ b/include/asm-powerpc/phyp_dump.h @@ -30,6 +30,9 @@ struct phyp_dump { /* store cpu & hpte size */ unsigned long cpu_state_size; unsigned long hpte_region_size; + /* previous scratch area values */ + unsigned long reserved_scratch_addr; + unsigned long reserved_scratch_size; }; extern struct phyp_dump *phyp_dump_info; -- cgit v1.2.3 From 654f596da4a83a8d2734fba26c2a1257533e6d75 Mon Sep 17 00:00:00 2001 From: Manish Ahuja Date: Sat, 22 Mar 2008 11:38:59 +1100 Subject: [POWERPC] pseries: phyp dump: Disable phyp-dump through boot-var This adds a kernel command line option "phyp_dump", which takes a 0/1 value for disabling/ enabling phyp_dump at boot time. Kdump can use this on cmdline (phyp_dump=0) to disable phyp-dump during boot when enabling itself. This will ensure only one dumping mechanism is active at any given time. Signed-off-by: Manish Ahuja Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 5 +++++ arch/powerpc/platforms/pseries/phyp_dump.c | 18 ++++++++++++++++++ include/asm-powerpc/phyp_dump.h | 1 + 3 files changed, 24 insertions(+) (limited to 'include/asm-powerpc/phyp_dump.h') diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index e6c022ef12ee..9330920265f3 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1060,6 +1060,11 @@ static void __init phyp_dump_reserve_mem(void) return; } + if (!phyp_dump_info->phyp_dump_at_boot) { + printk(KERN_INFO "Phyp-dump disabled at boot time\n"); + return; + } + if (phyp_dump_info->phyp_dump_is_active) { /* Reserve *everything* above RMR.Area freed by userland tools*/ base = PHYP_DUMP_RMR_END; diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c index 034fe1b54dd9..f80f8606c6b8 100644 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ b/arch/powerpc/platforms/pseries/phyp_dump.c @@ -460,3 +460,21 @@ int __init early_init_dt_scan_phyp_dump(unsigned long node, *((unsigned long *)&sizes[4]); return 1; } + +/* Look for phyp_dump= cmdline option */ +static int __init early_phyp_dump_enabled(char *p) +{ + phyp_dump_info->phyp_dump_at_boot = 1; + + if (!p) + return 0; + + if (strncmp(p, "1", 1) == 0) + phyp_dump_info->phyp_dump_at_boot = 1; + else if (strncmp(p, "0", 1) == 0) + phyp_dump_info->phyp_dump_at_boot = 0; + + return 0; +} +early_param("phyp_dump", early_phyp_dump_enabled); + diff --git a/include/asm-powerpc/phyp_dump.h b/include/asm-powerpc/phyp_dump.h index b454de45b2ca..209a98913d9d 100644 --- a/include/asm-powerpc/phyp_dump.h +++ b/include/asm-powerpc/phyp_dump.h @@ -25,6 +25,7 @@ struct phyp_dump { unsigned long init_reserve_start; unsigned long init_reserve_size; /* Check status during boot if dump supported, active & present*/ + unsigned long phyp_dump_at_boot; unsigned long phyp_dump_configured; unsigned long phyp_dump_is_active; /* store cpu & hpte size */ -- cgit v1.2.3 From 37ddd5d053c57fee798d72fa9c18660f59a9299b Mon Sep 17 00:00:00 2001 From: Manish Ahuja Date: Sat, 12 Apr 2008 09:31:52 +1000 Subject: [POWERPC] pseries/phyp dump: Reserve a variable amount of space at boot This changes the way we calculate how much space to reserve for the pHyp dump. Currently we reserve 256MB only. With this change, the code first checks to see if an amount has been specified on the boot command line with the "phyp_dump_reserve_size" option, and if so, uses that much. Otherwise it computes 5% of total ram and rounds it down to a multiple of 256MB, and uses the larger of that or 256MB. This is for large systems with a lot of memory (10GB or more). The aim is to have more space available for the kernel on reboot on machines with more resources. Although the dump will be collected pretty fast and the memory released really early on allowing the machine to have the full memory available, this alleviates any issues that can be caused by having way too little memory on very very large systems during those few minutes. Signed-off-by: Manish Ahuja Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/prom.c | 35 ++++++++++++++++++++++++++++-- arch/powerpc/platforms/pseries/phyp_dump.c | 9 ++++++++ include/asm-powerpc/phyp_dump.h | 4 +++- 3 files changed, 45 insertions(+), 3 deletions(-) (limited to 'include/asm-powerpc/phyp_dump.h') diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 31d5b22c59a2..8a9359ae4718 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1042,6 +1042,33 @@ static void __init early_reserve_mem(void) } #ifdef CONFIG_PHYP_DUMP +/** + * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg + * + * Function to find the largest size we need to reserve + * during early boot process. + * + * It either looks for boot param and returns that OR + * returns larger of 256 or 5% rounded down to multiples of 256MB. + * + */ +static inline unsigned long phyp_dump_calculate_reserve_size(void) +{ + unsigned long tmp; + + if (phyp_dump_info->reserve_bootvar) + return phyp_dump_info->reserve_bootvar; + + /* divide by 20 to get 5% of value */ + tmp = lmb_end_of_DRAM(); + do_div(tmp, 20); + + /* round it down in multiples of 256 */ + tmp = tmp & ~0x0FFFFFFFUL; + + return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END); +} + /** * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory * @@ -1055,6 +1082,8 @@ static void __init early_reserve_mem(void) static void __init phyp_dump_reserve_mem(void) { unsigned long base, size; + unsigned long variable_reserve_size; + if (!phyp_dump_info->phyp_dump_configured) { printk(KERN_ERR "Phyp-dump not supported on this hardware\n"); return; @@ -1065,9 +1094,11 @@ static void __init phyp_dump_reserve_mem(void) return; } + variable_reserve_size = phyp_dump_calculate_reserve_size(); + if (phyp_dump_info->phyp_dump_is_active) { /* Reserve *everything* above RMR.Area freed by userland tools*/ - base = PHYP_DUMP_RMR_END; + base = variable_reserve_size; size = lmb_end_of_DRAM() - base; /* XXX crashed_ram_end is wrong, since it may be beyond @@ -1079,7 +1110,7 @@ static void __init phyp_dump_reserve_mem(void) } else { size = phyp_dump_info->cpu_state_size + phyp_dump_info->hpte_region_size + - PHYP_DUMP_RMR_END; + variable_reserve_size; base = lmb_end_of_DRAM() - size; lmb_reserve(base, size); phyp_dump_info->init_reserve_start = base; diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c index 7ddd10526cea..edbc012c2ebc 100644 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ b/arch/powerpc/platforms/pseries/phyp_dump.c @@ -496,3 +496,12 @@ static int __init early_phyp_dump_enabled(char *p) } early_param("phyp_dump", early_phyp_dump_enabled); +/* Look for phyp_dump_reserve_size= cmdline option */ +static int __init early_phyp_dump_reserve_size(char *p) +{ + if (p) + phyp_dump_info->reserve_bootvar = memparse(p, &p); + + return 0; +} +early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size); diff --git a/include/asm-powerpc/phyp_dump.h b/include/asm-powerpc/phyp_dump.h index 209a98913d9d..fa74c6c3e106 100644 --- a/include/asm-powerpc/phyp_dump.h +++ b/include/asm-powerpc/phyp_dump.h @@ -24,8 +24,10 @@ struct phyp_dump { /* Memory that is reserved during very early boot. */ unsigned long init_reserve_start; unsigned long init_reserve_size; - /* Check status during boot if dump supported, active & present*/ + /* cmd line options during boot */ + unsigned long reserve_bootvar; unsigned long phyp_dump_at_boot; + /* Check status during boot if dump supported, active & present*/ unsigned long phyp_dump_configured; unsigned long phyp_dump_is_active; /* store cpu & hpte size */ -- cgit v1.2.3