diff options
Diffstat (limited to 'arch/powerpc/kernel/machine_kexec.c')
-rw-r--r-- | arch/powerpc/kernel/machine_kexec.c | 91 |
1 files changed, 79 insertions, 12 deletions
diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index ac2a21f45c75..b3abebb7ee64 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c | |||
@@ -13,13 +13,17 @@ | |||
13 | #include <linux/reboot.h> | 13 | #include <linux/reboot.h> |
14 | #include <linux/threads.h> | 14 | #include <linux/threads.h> |
15 | #include <linux/lmb.h> | 15 | #include <linux/lmb.h> |
16 | #include <linux/of.h> | ||
16 | #include <asm/machdep.h> | 17 | #include <asm/machdep.h> |
17 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
19 | #include <asm/sections.h> | ||
18 | 20 | ||
19 | void machine_crash_shutdown(struct pt_regs *regs) | 21 | void machine_crash_shutdown(struct pt_regs *regs) |
20 | { | 22 | { |
21 | if (ppc_md.machine_crash_shutdown) | 23 | if (ppc_md.machine_crash_shutdown) |
22 | ppc_md.machine_crash_shutdown(regs); | 24 | ppc_md.machine_crash_shutdown(regs); |
25 | else | ||
26 | default_machine_crash_shutdown(regs); | ||
23 | } | 27 | } |
24 | 28 | ||
25 | /* | 29 | /* |
@@ -31,11 +35,8 @@ int machine_kexec_prepare(struct kimage *image) | |||
31 | { | 35 | { |
32 | if (ppc_md.machine_kexec_prepare) | 36 | if (ppc_md.machine_kexec_prepare) |
33 | return ppc_md.machine_kexec_prepare(image); | 37 | return ppc_md.machine_kexec_prepare(image); |
34 | /* | 38 | else |
35 | * Fail if platform doesn't provide its own machine_kexec_prepare | 39 | return default_machine_kexec_prepare(image); |
36 | * implementation. | ||
37 | */ | ||
38 | return -ENOSYS; | ||
39 | } | 40 | } |
40 | 41 | ||
41 | void machine_kexec_cleanup(struct kimage *image) | 42 | void machine_kexec_cleanup(struct kimage *image) |
@@ -52,13 +53,11 @@ void machine_kexec(struct kimage *image) | |||
52 | { | 53 | { |
53 | if (ppc_md.machine_kexec) | 54 | if (ppc_md.machine_kexec) |
54 | ppc_md.machine_kexec(image); | 55 | ppc_md.machine_kexec(image); |
55 | else { | 56 | else |
56 | /* | 57 | default_machine_kexec(image); |
57 | * Fall back to normal restart if platform doesn't provide | 58 | |
58 | * its own kexec function, and user insist to kexec... | 59 | /* Fall back to normal restart if we're still alive. */ |
59 | */ | 60 | machine_restart(NULL); |
60 | machine_restart(NULL); | ||
61 | } | ||
62 | for(;;); | 61 | for(;;); |
63 | } | 62 | } |
64 | 63 | ||
@@ -118,3 +117,71 @@ int overlaps_crashkernel(unsigned long start, unsigned long size) | |||
118 | { | 117 | { |
119 | return (start + size) > crashk_res.start && start <= crashk_res.end; | 118 | return (start + size) > crashk_res.start && start <= crashk_res.end; |
120 | } | 119 | } |
120 | |||
121 | /* Values we need to export to the second kernel via the device tree. */ | ||
122 | static unsigned long kernel_end; | ||
123 | static unsigned long crashk_size; | ||
124 | |||
125 | static struct property kernel_end_prop = { | ||
126 | .name = "linux,kernel-end", | ||
127 | .length = sizeof(unsigned long), | ||
128 | .value = &kernel_end, | ||
129 | }; | ||
130 | |||
131 | static struct property crashk_base_prop = { | ||
132 | .name = "linux,crashkernel-base", | ||
133 | .length = sizeof(unsigned long), | ||
134 | .value = &crashk_res.start, | ||
135 | }; | ||
136 | |||
137 | static struct property crashk_size_prop = { | ||
138 | .name = "linux,crashkernel-size", | ||
139 | .length = sizeof(unsigned long), | ||
140 | .value = &crashk_size, | ||
141 | }; | ||
142 | |||
143 | static void __init export_crashk_values(struct device_node *node) | ||
144 | { | ||
145 | struct property *prop; | ||
146 | |||
147 | /* There might be existing crash kernel properties, but we can't | ||
148 | * be sure what's in them, so remove them. */ | ||
149 | prop = of_find_property(node, "linux,crashkernel-base", NULL); | ||
150 | if (prop) | ||
151 | prom_remove_property(node, prop); | ||
152 | |||
153 | prop = of_find_property(node, "linux,crashkernel-size", NULL); | ||
154 | if (prop) | ||
155 | prom_remove_property(node, prop); | ||
156 | |||
157 | if (crashk_res.start != 0) { | ||
158 | prom_add_property(node, &crashk_base_prop); | ||
159 | crashk_size = crashk_res.end - crashk_res.start + 1; | ||
160 | prom_add_property(node, &crashk_size_prop); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static int __init kexec_setup(void) | ||
165 | { | ||
166 | struct device_node *node; | ||
167 | struct property *prop; | ||
168 | |||
169 | node = of_find_node_by_path("/chosen"); | ||
170 | if (!node) | ||
171 | return -ENOENT; | ||
172 | |||
173 | /* remove any stale properties so ours can be found */ | ||
174 | prop = of_find_property(node, kernel_end_prop.name, NULL); | ||
175 | if (prop) | ||
176 | prom_remove_property(node, prop); | ||
177 | |||
178 | /* information needed by userspace when using default_machine_kexec */ | ||
179 | kernel_end = __pa(_end); | ||
180 | prom_add_property(node, &kernel_end_prop); | ||
181 | |||
182 | export_crashk_values(node); | ||
183 | |||
184 | of_node_put(node); | ||
185 | return 0; | ||
186 | } | ||
187 | late_initcall(kexec_setup); | ||