diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/phyp_dump.c | 83 |
1 files changed, 77 insertions, 6 deletions
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; | |||
70 | #define DUMP_SOURCE_CPU 0x0001 | 70 | #define DUMP_SOURCE_CPU 0x0001 |
71 | #define DUMP_SOURCE_HPTE 0x0002 | 71 | #define DUMP_SOURCE_HPTE 0x0002 |
72 | #define DUMP_SOURCE_RMO 0x0011 | 72 | #define DUMP_SOURCE_RMO 0x0011 |
73 | #define DUMP_ERROR_FLAG 0x2000 | ||
74 | #define DUMP_TRIGGERED 0x4000 | ||
75 | #define DUMP_PERFORMED 0x8000 | ||
76 | |||
73 | 77 | ||
74 | /** | 78 | /** |
75 | * init_dump_header() - initialize the header declaring a dump | 79 | * init_dump_header() - initialize the header declaring a dump |
@@ -181,9 +185,15 @@ static void print_dump_header(const struct phyp_dump_header *ph) | |||
181 | static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) | 185 | static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) |
182 | { | 186 | { |
183 | int rc; | 187 | int rc; |
184 | ph->cpu_data.destination_address += addr; | 188 | |
185 | ph->hpte_data.destination_address += addr; | 189 | /* Add addr value if not initialized before */ |
186 | ph->kernel_data.destination_address += addr; | 190 | if (ph->cpu_data.destination_address == 0) { |
191 | ph->cpu_data.destination_address += addr; | ||
192 | ph->hpte_data.destination_address += addr; | ||
193 | ph->kernel_data.destination_address += addr; | ||
194 | } | ||
195 | |||
196 | /* ToDo Invalidate kdump and free memory range. */ | ||
187 | 197 | ||
188 | do { | 198 | do { |
189 | rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, | 199 | 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) | |||
197 | } | 207 | } |
198 | } | 208 | } |
199 | 209 | ||
210 | static | ||
211 | void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr) | ||
212 | { | ||
213 | int rc; | ||
214 | |||
215 | /* Add addr value if not initialized before */ | ||
216 | if (ph->cpu_data.destination_address == 0) { | ||
217 | ph->cpu_data.destination_address += addr; | ||
218 | ph->hpte_data.destination_address += addr; | ||
219 | ph->kernel_data.destination_address += addr; | ||
220 | } | ||
221 | |||
222 | do { | ||
223 | rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, | ||
224 | 2, ph, sizeof(struct phyp_dump_header)); | ||
225 | } while (rtas_busy_delay(rc)); | ||
226 | |||
227 | if (rc) { | ||
228 | printk(KERN_ERR "phyp-dump: unexpected error (%d) " | ||
229 | "on invalidate\n", rc); | ||
230 | print_dump_header(ph); | ||
231 | } | ||
232 | } | ||
233 | |||
200 | /* ------------------------------------------------- */ | 234 | /* ------------------------------------------------- */ |
201 | /** | 235 | /** |
202 | * release_memory_range -- release memory previously lmb_reserved | 236 | * 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) | |||
207 | * lmb_reserved in early boot. The released memory becomes | 241 | * lmb_reserved in early boot. The released memory becomes |
208 | * available for genreal use. | 242 | * available for genreal use. |
209 | */ | 243 | */ |
210 | static void | 244 | static void release_memory_range(unsigned long start_pfn, |
211 | release_memory_range(unsigned long start_pfn, unsigned long nr_pages) | 245 | unsigned long nr_pages) |
212 | { | 246 | { |
213 | struct page *rpage; | 247 | struct page *rpage; |
214 | unsigned long end_pfn; | 248 | unsigned long end_pfn; |
@@ -269,8 +303,29 @@ static ssize_t store_release_region(struct kobject *kobj, | |||
269 | return count; | 303 | return count; |
270 | } | 304 | } |
271 | 305 | ||
306 | static ssize_t show_release_region(struct kobject *kobj, | ||
307 | struct kobj_attribute *attr, char *buf) | ||
308 | { | ||
309 | u64 second_addr_range; | ||
310 | |||
311 | /* total reserved size - start of scratch area */ | ||
312 | second_addr_range = phyp_dump_info->init_reserve_size - | ||
313 | phyp_dump_info->reserved_scratch_size; | ||
314 | return sprintf(buf, "CPU:0x%lx-0x%lx: HPTE:0x%lx-0x%lx:" | ||
315 | " DUMP:0x%lx-0x%lx, 0x%lx-0x%lx:\n", | ||
316 | phdr.cpu_data.destination_address, | ||
317 | phdr.cpu_data.length_copied, | ||
318 | phdr.hpte_data.destination_address, | ||
319 | phdr.hpte_data.length_copied, | ||
320 | phdr.kernel_data.destination_address, | ||
321 | phdr.kernel_data.length_copied, | ||
322 | phyp_dump_info->init_reserve_start, | ||
323 | second_addr_range); | ||
324 | } | ||
325 | |||
272 | static struct kobj_attribute rr = __ATTR(release_region, 0600, | 326 | static struct kobj_attribute rr = __ATTR(release_region, 0600, |
273 | NULL, store_release_region); | 327 | show_release_region, |
328 | store_release_region); | ||
274 | 329 | ||
275 | static int __init phyp_dump_setup(void) | 330 | static int __init phyp_dump_setup(void) |
276 | { | 331 | { |
@@ -313,6 +368,22 @@ static int __init phyp_dump_setup(void) | |||
313 | return 0; | 368 | return 0; |
314 | } | 369 | } |
315 | 370 | ||
371 | /* re-register the dump area, if old dump was invalid */ | ||
372 | if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) { | ||
373 | invalidate_last_dump(&phdr, dump_area_start); | ||
374 | register_dump_area(&phdr, dump_area_start); | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | if (dump_header) { | ||
379 | phyp_dump_info->reserved_scratch_addr = | ||
380 | dump_header->cpu_data.destination_address; | ||
381 | phyp_dump_info->reserved_scratch_size = | ||
382 | dump_header->cpu_data.source_length + | ||
383 | dump_header->hpte_data.source_length + | ||
384 | dump_header->kernel_data.source_length; | ||
385 | } | ||
386 | |||
316 | /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ | 387 | /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ |
317 | rc = sysfs_create_file(kernel_kobj, &rr.attr); | 388 | rc = sysfs_create_file(kernel_kobj, &rr.attr); |
318 | if (rc) | 389 | if (rc) |