diff options
author | Michael Holzheu <holzheu@de.ibm.com> | 2007-04-27 10:01:49 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:44 -0400 |
commit | 411ed3225733dbd83b4cbaaa992ef80d6ec1534e (patch) | |
tree | 388aeac39e9fad5f7cadcc8fcbf0838811f5829d /arch/s390/kernel/smp.c | |
parent | 7039d3a11c4b4b59f9ef933b4b0a28304bdd07d1 (diff) |
[S390] zfcpdump support.
s390 machines provide hardware support for creating Linux dumps on SCSI
disks. For creating a dump a special purpose dump Linux is used. The first
32 MB of memory are saved by the hardware before the dump Linux is
booted. Via an SCLP interface, the saved memory can be accessed from
Linux. This patch exports memory and registers of the crashed Linux to
userspace via a debugfs file. For more information refer to
Documentation/s390/zfcpdump.txt, which is included in this patch.
Signed-off-by: Michael Holzheu <holzheu@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/smp.c')
-rw-r--r-- | arch/s390/kernel/smp.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 97764f710bb7..7c0143fdf710 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/cpu.h> | 32 | #include <linux/cpu.h> |
33 | #include <linux/timex.h> | 33 | #include <linux/timex.h> |
34 | #include <linux/bootmem.h> | ||
34 | #include <asm/ipl.h> | 35 | #include <asm/ipl.h> |
35 | #include <asm/setup.h> | 36 | #include <asm/setup.h> |
36 | #include <asm/sigp.h> | 37 | #include <asm/sigp.h> |
@@ -40,6 +41,7 @@ | |||
40 | #include <asm/cpcmd.h> | 41 | #include <asm/cpcmd.h> |
41 | #include <asm/tlbflush.h> | 42 | #include <asm/tlbflush.h> |
42 | #include <asm/timer.h> | 43 | #include <asm/timer.h> |
44 | #include <asm/lowcore.h> | ||
43 | 45 | ||
44 | extern volatile int __cpu_logical_map[]; | 46 | extern volatile int __cpu_logical_map[]; |
45 | 47 | ||
@@ -395,6 +397,65 @@ void smp_ctl_clear_bit(int cr, int bit) | |||
395 | on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1); | 397 | on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1); |
396 | } | 398 | } |
397 | 399 | ||
400 | #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) | ||
401 | |||
402 | /* | ||
403 | * zfcpdump_prefix_array holds prefix registers for the following scenario: | ||
404 | * 64 bit zfcpdump kernel and 31 bit kernel which is to be dumped. We have to | ||
405 | * save its prefix registers, since they get lost, when switching from 31 bit | ||
406 | * to 64 bit. | ||
407 | */ | ||
408 | unsigned int zfcpdump_prefix_array[NR_CPUS + 1] \ | ||
409 | __attribute__((__section__(".data"))); | ||
410 | |||
411 | static void __init smp_get_save_areas(void) | ||
412 | { | ||
413 | unsigned int cpu, cpu_num, rc; | ||
414 | __u16 boot_cpu_addr; | ||
415 | |||
416 | if (ipl_info.type != IPL_TYPE_FCP_DUMP) | ||
417 | return; | ||
418 | boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; | ||
419 | cpu_num = 1; | ||
420 | for (cpu = 0; cpu <= 65535; cpu++) { | ||
421 | if ((u16) cpu == boot_cpu_addr) | ||
422 | continue; | ||
423 | __cpu_logical_map[1] = (__u16) cpu; | ||
424 | if (signal_processor(1, sigp_sense) == sigp_not_operational) | ||
425 | continue; | ||
426 | if (cpu_num >= NR_CPUS) { | ||
427 | printk("WARNING: Registers for cpu %i are not " | ||
428 | "saved, since dump kernel was compiled with" | ||
429 | "NR_CPUS=%i!\n", cpu_num, NR_CPUS); | ||
430 | continue; | ||
431 | } | ||
432 | zfcpdump_save_areas[cpu_num] = | ||
433 | alloc_bootmem(sizeof(union save_area)); | ||
434 | while (1) { | ||
435 | rc = signal_processor(1, sigp_stop_and_store_status); | ||
436 | if (rc != sigp_busy) | ||
437 | break; | ||
438 | cpu_relax(); | ||
439 | } | ||
440 | memcpy(zfcpdump_save_areas[cpu_num], | ||
441 | (void *)(unsigned long) store_prefix() + | ||
442 | SAVE_AREA_BASE, SAVE_AREA_SIZE); | ||
443 | #ifdef __s390x__ | ||
444 | /* copy original prefix register */ | ||
445 | zfcpdump_save_areas[cpu_num]->s390x.pref_reg = | ||
446 | zfcpdump_prefix_array[cpu_num]; | ||
447 | #endif | ||
448 | cpu_num++; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | union save_area *zfcpdump_save_areas[NR_CPUS + 1]; | ||
453 | EXPORT_SYMBOL_GPL(zfcpdump_save_areas); | ||
454 | |||
455 | #else | ||
456 | #define smp_get_save_areas() do { } while (0) | ||
457 | #endif | ||
458 | |||
398 | /* | 459 | /* |
399 | * Lets check how many CPUs we have. | 460 | * Lets check how many CPUs we have. |
400 | */ | 461 | */ |
@@ -589,6 +650,7 @@ void __init smp_setup_cpu_possible_map(void) | |||
589 | { | 650 | { |
590 | unsigned int phy_cpus, pos_cpus, cpu; | 651 | unsigned int phy_cpus, pos_cpus, cpu; |
591 | 652 | ||
653 | smp_get_save_areas(); | ||
592 | phy_cpus = smp_count_cpus(); | 654 | phy_cpus = smp_count_cpus(); |
593 | pos_cpus = min(phy_cpus + additional_cpus, (unsigned int) NR_CPUS); | 655 | pos_cpus = min(phy_cpus + additional_cpus, (unsigned int) NR_CPUS); |
594 | 656 | ||