diff options
| author | Manish Ahuja <ahuja@austin.ibm.com> | 2008-03-21 19:37:08 -0400 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2008-03-25 17:44:06 -0400 |
| commit | 6ac26c8a7eb149dbd669cc6cd9b77ffc9cd0d2fb (patch) | |
| tree | 4eb613ed5f8eb7accb042e30c89d9d25097d557f | |
| parent | d28a79326a4028dbb1755b8efe6daa915d8bfeea (diff) | |
[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 <mahuja@us.ibm.com>
Signed-off-by: Linas Vepstas <linasvepstas@gmail.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
| -rw-r--r-- | arch/powerpc/kernel/prom.c | 52 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/Makefile | 1 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/phyp_dump.c | 103 | ||||
| -rw-r--r-- | include/asm-powerpc/phyp_dump.h | 41 |
4 files changed, 197 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index ff600ef0b4d6..e6c022ef12ee 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
| @@ -51,6 +51,7 @@ | |||
| 51 | #include <asm/machdep.h> | 51 | #include <asm/machdep.h> |
| 52 | #include <asm/pSeries_reconfig.h> | 52 | #include <asm/pSeries_reconfig.h> |
| 53 | #include <asm/pci-bridge.h> | 53 | #include <asm/pci-bridge.h> |
| 54 | #include <asm/phyp_dump.h> | ||
| 54 | #include <asm/kexec.h> | 55 | #include <asm/kexec.h> |
| 55 | 56 | ||
| 56 | #ifdef DEBUG | 57 | #ifdef DEBUG |
| @@ -1040,6 +1041,51 @@ static void __init early_reserve_mem(void) | |||
| 1040 | #endif | 1041 | #endif |
| 1041 | } | 1042 | } |
| 1042 | 1043 | ||
| 1044 | #ifdef CONFIG_PHYP_DUMP | ||
| 1045 | /** | ||
| 1046 | * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory | ||
| 1047 | * | ||
| 1048 | * This routine may reserve memory regions in the kernel only | ||
| 1049 | * if the system is supported and a dump was taken in last | ||
| 1050 | * boot instance or if the hardware is supported and the | ||
| 1051 | * scratch area needs to be setup. In other instances it returns | ||
| 1052 | * without reserving anything. The memory in case of dump being | ||
| 1053 | * active is freed when the dump is collected (by userland tools). | ||
| 1054 | */ | ||
| 1055 | static void __init phyp_dump_reserve_mem(void) | ||
| 1056 | { | ||
| 1057 | unsigned long base, size; | ||
| 1058 | if (!phyp_dump_info->phyp_dump_configured) { | ||
| 1059 | printk(KERN_ERR "Phyp-dump not supported on this hardware\n"); | ||
| 1060 | return; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | if (phyp_dump_info->phyp_dump_is_active) { | ||
| 1064 | /* Reserve *everything* above RMR.Area freed by userland tools*/ | ||
| 1065 | base = PHYP_DUMP_RMR_END; | ||
| 1066 | size = lmb_end_of_DRAM() - base; | ||
| 1067 | |||
| 1068 | /* XXX crashed_ram_end is wrong, since it may be beyond | ||
| 1069 | * the memory_limit, it will need to be adjusted. */ | ||
| 1070 | lmb_reserve(base, size); | ||
| 1071 | |||
| 1072 | phyp_dump_info->init_reserve_start = base; | ||
| 1073 | phyp_dump_info->init_reserve_size = size; | ||
| 1074 | } else { | ||
| 1075 | size = phyp_dump_info->cpu_state_size + | ||
| 1076 | phyp_dump_info->hpte_region_size + | ||
| 1077 | PHYP_DUMP_RMR_END; | ||
| 1078 | base = lmb_end_of_DRAM() - size; | ||
| 1079 | lmb_reserve(base, size); | ||
| 1080 | phyp_dump_info->init_reserve_start = base; | ||
| 1081 | phyp_dump_info->init_reserve_size = size; | ||
| 1082 | } | ||
| 1083 | } | ||
| 1084 | #else | ||
| 1085 | static inline void __init phyp_dump_reserve_mem(void) {} | ||
| 1086 | #endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ | ||
| 1087 | |||
| 1088 | |||
| 1043 | void __init early_init_devtree(void *params) | 1089 | void __init early_init_devtree(void *params) |
| 1044 | { | 1090 | { |
| 1045 | DBG(" -> early_init_devtree(%p)\n", params); | 1091 | DBG(" -> early_init_devtree(%p)\n", params); |
| @@ -1052,6 +1098,11 @@ void __init early_init_devtree(void *params) | |||
| 1052 | of_scan_flat_dt(early_init_dt_scan_rtas, NULL); | 1098 | of_scan_flat_dt(early_init_dt_scan_rtas, NULL); |
| 1053 | #endif | 1099 | #endif |
| 1054 | 1100 | ||
| 1101 | #ifdef CONFIG_PHYP_DUMP | ||
| 1102 | /* scan tree to see if dump occured during last boot */ | ||
| 1103 | of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); | ||
| 1104 | #endif | ||
| 1105 | |||
| 1055 | /* Retrieve various informations from the /chosen node of the | 1106 | /* Retrieve various informations from the /chosen node of the |
| 1056 | * device-tree, including the platform type, initrd location and | 1107 | * device-tree, including the platform type, initrd location and |
| 1057 | * size, TCE reserve, and more ... | 1108 | * size, TCE reserve, and more ... |
| @@ -1072,6 +1123,7 @@ void __init early_init_devtree(void *params) | |||
| 1072 | reserve_kdump_trampoline(); | 1123 | reserve_kdump_trampoline(); |
| 1073 | reserve_crashkernel(); | 1124 | reserve_crashkernel(); |
| 1074 | early_reserve_mem(); | 1125 | early_reserve_mem(); |
| 1126 | phyp_dump_reserve_mem(); | ||
| 1075 | 1127 | ||
| 1076 | lmb_enforce_memory_limit(memory_limit); | 1128 | lmb_enforce_memory_limit(memory_limit); |
| 1077 | lmb_analyze(); | 1129 | lmb_analyze(); |
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 992ba6753cf2..bdae04bb7a01 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
| @@ -18,3 +18,4 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o | |||
| 18 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o | 18 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o |
| 19 | obj-$(CONFIG_HVCS) += hvcserver.o | 19 | obj-$(CONFIG_HVCS) += hvcserver.o |
| 20 | obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o | 20 | obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o |
| 21 | obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o | ||
diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c new file mode 100644 index 000000000000..230286cafffe --- /dev/null +++ b/arch/powerpc/platforms/pseries/phyp_dump.c | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | /* | ||
| 2 | * Hypervisor-assisted dump | ||
| 3 | * | ||
| 4 | * Linas Vepstas, Manish Ahuja 2008 | ||
| 5 | * Copyright 2008 IBM Corp. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version | ||
| 10 | * 2 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/mm.h> | ||
| 16 | #include <linux/pfn.h> | ||
| 17 | #include <linux/swap.h> | ||
| 18 | |||
| 19 | #include <asm/page.h> | ||
| 20 | #include <asm/phyp_dump.h> | ||
| 21 | #include <asm/machdep.h> | ||
| 22 | #include <asm/prom.h> | ||
| 23 | |||
| 24 | /* Variables, used to communicate data between early boot and late boot */ | ||
| 25 | static struct phyp_dump phyp_dump_vars; | ||
| 26 | struct phyp_dump *phyp_dump_info = &phyp_dump_vars; | ||
| 27 | |||
| 28 | /** | ||
| 29 | * release_memory_range -- release memory previously lmb_reserved | ||
| 30 | * @start_pfn: starting physical frame number | ||
| 31 | * @nr_pages: number of pages to free. | ||
| 32 | * | ||
| 33 | * This routine will release memory that had been previously | ||
| 34 | * lmb_reserved in early boot. The released memory becomes | ||
| 35 | * available for genreal use. | ||
| 36 | */ | ||
| 37 | static void | ||
| 38 | release_memory_range(unsigned long start_pfn, unsigned long nr_pages) | ||
| 39 | { | ||
| 40 | struct page *rpage; | ||
| 41 | unsigned long end_pfn; | ||
| 42 | long i; | ||
| 43 | |||
| 44 | end_pfn = start_pfn + nr_pages; | ||
| 45 | |||
| 46 | for (i = start_pfn; i <= end_pfn; i++) { | ||
| 47 | rpage = pfn_to_page(i); | ||
| 48 | if (PageReserved(rpage)) { | ||
| 49 | ClearPageReserved(rpage); | ||
| 50 | init_page_count(rpage); | ||
| 51 | __free_page(rpage); | ||
| 52 | totalram_pages++; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | static int __init phyp_dump_setup(void) | ||
| 58 | { | ||
| 59 | unsigned long start_pfn, nr_pages; | ||
| 60 | |||
| 61 | /* If no memory was reserved in early boot, there is nothing to do */ | ||
| 62 | if (phyp_dump_info->init_reserve_size == 0) | ||
| 63 | return 0; | ||
| 64 | |||
| 65 | /* Release memory that was reserved in early boot */ | ||
| 66 | start_pfn = PFN_DOWN(phyp_dump_info->init_reserve_start); | ||
| 67 | nr_pages = PFN_DOWN(phyp_dump_info->init_reserve_size); | ||
| 68 | release_memory_range(start_pfn, nr_pages); | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | machine_subsys_initcall(pseries, phyp_dump_setup); | ||
| 73 | |||
| 74 | int __init early_init_dt_scan_phyp_dump(unsigned long node, | ||
| 75 | const char *uname, int depth, void *data) | ||
| 76 | { | ||
| 77 | const unsigned int *sizes; | ||
| 78 | |||
| 79 | phyp_dump_info->phyp_dump_configured = 0; | ||
| 80 | phyp_dump_info->phyp_dump_is_active = 0; | ||
| 81 | |||
| 82 | if (depth != 1 || strcmp(uname, "rtas") != 0) | ||
| 83 | return 0; | ||
| 84 | |||
| 85 | if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL)) | ||
| 86 | phyp_dump_info->phyp_dump_configured++; | ||
| 87 | |||
| 88 | if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL)) | ||
| 89 | phyp_dump_info->phyp_dump_is_active++; | ||
| 90 | |||
| 91 | sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", | ||
| 92 | NULL); | ||
| 93 | if (!sizes) | ||
| 94 | return 0; | ||
| 95 | |||
| 96 | if (sizes[0] == 1) | ||
| 97 | phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]); | ||
| 98 | |||
| 99 | if (sizes[3] == 2) | ||
| 100 | phyp_dump_info->hpte_region_size = | ||
| 101 | *((unsigned long *)&sizes[4]); | ||
| 102 | return 1; | ||
| 103 | } | ||
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 @@ | |||
| 1 | /* | ||
| 2 | * Hypervisor-assisted dump | ||
| 3 | * | ||
| 4 | * Linas Vepstas, Manish Ahuja 2008 | ||
| 5 | * Copyright 2008 IBM Corp. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version | ||
| 10 | * 2 of the License, or (at your option) any later version. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #ifndef _PPC64_PHYP_DUMP_H | ||
| 14 | #define _PPC64_PHYP_DUMP_H | ||
| 15 | |||
| 16 | #ifdef CONFIG_PHYP_DUMP | ||
| 17 | |||
| 18 | /* The RMR region will be saved for later dumping | ||
| 19 | * whenever the kernel crashes. Set this to 256MB. */ | ||
| 20 | #define PHYP_DUMP_RMR_START 0x0 | ||
| 21 | #define PHYP_DUMP_RMR_END (1UL<<28) | ||
| 22 | |||
| 23 | struct phyp_dump { | ||
| 24 | /* Memory that is reserved during very early boot. */ | ||
| 25 | unsigned long init_reserve_start; | ||
| 26 | unsigned long init_reserve_size; | ||
| 27 | /* Check status during boot if dump supported, active & present*/ | ||
| 28 | unsigned long phyp_dump_configured; | ||
| 29 | unsigned long phyp_dump_is_active; | ||
| 30 | /* store cpu & hpte size */ | ||
| 31 | unsigned long cpu_state_size; | ||
| 32 | unsigned long hpte_region_size; | ||
| 33 | }; | ||
| 34 | |||
| 35 | extern struct phyp_dump *phyp_dump_info; | ||
| 36 | |||
| 37 | int early_init_dt_scan_phyp_dump(unsigned long node, | ||
| 38 | const char *uname, int depth, void *data); | ||
| 39 | |||
| 40 | #endif /* CONFIG_PHYP_DUMP */ | ||
| 41 | #endif /* _PPC64_PHYP_DUMP_H */ | ||
