diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-10-29 05:28:26 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-11-27 03:24:14 -0500 |
commit | 1a36a39e225d3558fb3776a3d3d7736cf1ec9f60 (patch) | |
tree | 63a1c8892ff95dac939beb6e7a13456fcec20cb7 | |
parent | f08b8414632c9f256e33f0a18104d8d5e103d204 (diff) |
s390/dump: rework CPU register dump code
To collect the CPU registers of the crashed system allocated a single
page with memblock_alloc_base and use it as a copy buffer. Replace the
stop-and-store-status sigp with a store-status-at-address sigp in
smp_save_dump_cpus() and smp_store_status(). In both cases the target
CPU is already stopped and store-status-at-address avoids the detour
via the absolute zero page.
For kexec simplify s390_reset_system and call store_status() before
the prefix register of the boot CPU has been set to zero. Use STPX
to store the prefix register and remove dump_prefix_page.
Acked-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/fpu/internal.h | 10 | ||||
-rw-r--r-- | arch/s390/include/asm/ipl.h | 3 | ||||
-rw-r--r-- | arch/s390/include/asm/reset.h | 3 | ||||
-rw-r--r-- | arch/s390/include/asm/smp.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 9 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 17 | ||||
-rw-r--r-- | arch/s390/kernel/machine_kexec.c | 104 | ||||
-rw-r--r-- | arch/s390/kernel/reipl.S | 37 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 112 | ||||
-rw-r--r-- | drivers/s390/char/zcore.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 2 |
12 files changed, 158 insertions, 145 deletions
diff --git a/arch/s390/include/asm/fpu/internal.h b/arch/s390/include/asm/fpu/internal.h index 2559b16da525..ea91ddfe54eb 100644 --- a/arch/s390/include/asm/fpu/internal.h +++ b/arch/s390/include/asm/fpu/internal.h | |||
@@ -12,21 +12,13 @@ | |||
12 | #include <asm/ctl_reg.h> | 12 | #include <asm/ctl_reg.h> |
13 | #include <asm/fpu/types.h> | 13 | #include <asm/fpu/types.h> |
14 | 14 | ||
15 | static inline void save_vx_regs_safe(__vector128 *vxrs) | 15 | static inline void save_vx_regs(__vector128 *vxrs) |
16 | { | 16 | { |
17 | unsigned long cr0, flags; | ||
18 | |||
19 | flags = arch_local_irq_save(); | ||
20 | __ctl_store(cr0, 0, 0); | ||
21 | __ctl_set_bit(0, 17); | ||
22 | __ctl_set_bit(0, 18); | ||
23 | asm volatile( | 17 | asm volatile( |
24 | " la 1,%0\n" | 18 | " la 1,%0\n" |
25 | " .word 0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */ | 19 | " .word 0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */ |
26 | " .word 0xe70f,0x1100,0x0c3e\n" /* vstm 16,31,256(1) */ | 20 | " .word 0xe70f,0x1100,0x0c3e\n" /* vstm 16,31,256(1) */ |
27 | : "=Q" (*(struct vx_array *) vxrs) : : "1"); | 21 | : "=Q" (*(struct vx_array *) vxrs) : : "1"); |
28 | __ctl_load(cr0, 0, 0); | ||
29 | arch_local_irq_restore(flags); | ||
30 | } | 22 | } |
31 | 23 | ||
32 | static inline void convert_vx_to_fp(freg_t *fprs, __vector128 *vxrs) | 24 | static inline void convert_vx_to_fp(freg_t *fprs, __vector128 *vxrs) |
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index 86634e71b69f..1dc55db8cd81 100644 --- a/arch/s390/include/asm/ipl.h +++ b/arch/s390/include/asm/ipl.h | |||
@@ -87,7 +87,6 @@ struct ipl_parameter_block { | |||
87 | * IPL validity flags | 87 | * IPL validity flags |
88 | */ | 88 | */ |
89 | extern u32 ipl_flags; | 89 | extern u32 ipl_flags; |
90 | extern u32 dump_prefix_page; | ||
91 | 90 | ||
92 | struct dump_save_areas { | 91 | struct dump_save_areas { |
93 | struct save_area_ext **areas; | 92 | struct save_area_ext **areas; |
@@ -176,7 +175,7 @@ enum diag308_rc { | |||
176 | 175 | ||
177 | extern int diag308(unsigned long subcode, void *addr); | 176 | extern int diag308(unsigned long subcode, void *addr); |
178 | extern void diag308_reset(void); | 177 | extern void diag308_reset(void); |
179 | extern void store_status(void); | 178 | extern void store_status(void (*fn)(void *), void *data); |
180 | extern void lgr_info_log(void); | 179 | extern void lgr_info_log(void); |
181 | 180 | ||
182 | #endif /* _ASM_S390_IPL_H */ | 181 | #endif /* _ASM_S390_IPL_H */ |
diff --git a/arch/s390/include/asm/reset.h b/arch/s390/include/asm/reset.h index 72786067b300..fe11fa88a0e0 100644 --- a/arch/s390/include/asm/reset.h +++ b/arch/s390/include/asm/reset.h | |||
@@ -15,6 +15,5 @@ struct reset_call { | |||
15 | 15 | ||
16 | extern void register_reset_call(struct reset_call *reset); | 16 | extern void register_reset_call(struct reset_call *reset); |
17 | extern void unregister_reset_call(struct reset_call *reset); | 17 | extern void unregister_reset_call(struct reset_call *reset); |
18 | extern void s390_reset_system(void (*fn_pre)(void), | 18 | extern void s390_reset_system(void); |
19 | void (*fn_post)(void *), void *data); | ||
20 | #endif /* _ASM_S390_RESET_H */ | 19 | #endif /* _ASM_S390_RESET_H */ |
diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index 5df26b11cf47..0cc383b9be7f 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h | |||
@@ -18,6 +18,7 @@ | |||
18 | extern struct mutex smp_cpu_state_mutex; | 18 | extern struct mutex smp_cpu_state_mutex; |
19 | extern unsigned int smp_cpu_mt_shift; | 19 | extern unsigned int smp_cpu_mt_shift; |
20 | extern unsigned int smp_cpu_mtid; | 20 | extern unsigned int smp_cpu_mtid; |
21 | extern __vector128 __initdata boot_cpu_vector_save_area[__NUM_VXRS]; | ||
21 | 22 | ||
22 | extern int __cpu_up(unsigned int cpu, struct task_struct *tidle); | 23 | extern int __cpu_up(unsigned int cpu, struct task_struct *tidle); |
23 | 24 | ||
@@ -55,7 +56,6 @@ static inline int smp_store_status(int cpu) { return 0; } | |||
55 | static inline int smp_vcpu_scheduled(int cpu) { return 1; } | 56 | static inline int smp_vcpu_scheduled(int cpu) { return 1; } |
56 | static inline void smp_yield_cpu(int cpu) { } | 57 | static inline void smp_yield_cpu(int cpu) { } |
57 | static inline void smp_fill_possible_mask(void) { } | 58 | static inline void smp_fill_possible_mask(void) { } |
58 | static inline void smp_save_dump_cpus(void) { } | ||
59 | 59 | ||
60 | #endif /* CONFIG_SMP */ | 60 | #endif /* CONFIG_SMP */ |
61 | 61 | ||
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 3c31609df959..20a5caf6d981 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -335,6 +335,14 @@ static __init void detect_machine_facilities(void) | |||
335 | } | 335 | } |
336 | } | 336 | } |
337 | 337 | ||
338 | static inline void save_vector_registers(void) | ||
339 | { | ||
340 | #ifdef CONFIG_CRASH_DUMP | ||
341 | if (test_facility(129)) | ||
342 | save_vx_regs(boot_cpu_vector_save_area); | ||
343 | #endif | ||
344 | } | ||
345 | |||
338 | static int __init disable_vector_extension(char *str) | 346 | static int __init disable_vector_extension(char *str) |
339 | { | 347 | { |
340 | S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; | 348 | S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; |
@@ -451,6 +459,7 @@ void __init startup_init(void) | |||
451 | detect_diag9c(); | 459 | detect_diag9c(); |
452 | detect_diag44(); | 460 | detect_diag44(); |
453 | detect_machine_facilities(); | 461 | detect_machine_facilities(); |
462 | save_vector_registers(); | ||
454 | setup_topology(); | 463 | setup_topology(); |
455 | sclp_early_detect(); | 464 | sclp_early_detect(); |
456 | lockdep_on(); | 465 | lockdep_on(); |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index b1f0a90f933b..26d58cf72573 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -2039,10 +2039,7 @@ static void do_reset_calls(void) | |||
2039 | reset->fn(); | 2039 | reset->fn(); |
2040 | } | 2040 | } |
2041 | 2041 | ||
2042 | u32 dump_prefix_page; | 2042 | void s390_reset_system(void) |
2043 | |||
2044 | void s390_reset_system(void (*fn_pre)(void), | ||
2045 | void (*fn_post)(void *), void *data) | ||
2046 | { | 2043 | { |
2047 | struct _lowcore *lc; | 2044 | struct _lowcore *lc; |
2048 | 2045 | ||
@@ -2051,9 +2048,6 @@ void s390_reset_system(void (*fn_pre)(void), | |||
2051 | /* Stack for interrupt/machine check handler */ | 2048 | /* Stack for interrupt/machine check handler */ |
2052 | lc->panic_stack = S390_lowcore.panic_stack; | 2049 | lc->panic_stack = S390_lowcore.panic_stack; |
2053 | 2050 | ||
2054 | /* Save prefix page address for dump case */ | ||
2055 | dump_prefix_page = (u32)(unsigned long) lc; | ||
2056 | |||
2057 | /* Disable prefixing */ | 2051 | /* Disable prefixing */ |
2058 | set_prefix(0); | 2052 | set_prefix(0); |
2059 | 2053 | ||
@@ -2077,14 +2071,5 @@ void s390_reset_system(void (*fn_pre)(void), | |||
2077 | S390_lowcore.subchannel_id = 0; | 2071 | S390_lowcore.subchannel_id = 0; |
2078 | S390_lowcore.subchannel_nr = 0; | 2072 | S390_lowcore.subchannel_nr = 0; |
2079 | 2073 | ||
2080 | /* Store status at absolute zero */ | ||
2081 | store_status(); | ||
2082 | |||
2083 | /* Call function before reset */ | ||
2084 | if (fn_pre) | ||
2085 | fn_pre(); | ||
2086 | do_reset_calls(); | 2074 | do_reset_calls(); |
2087 | /* Call function after reset */ | ||
2088 | if (fn_post) | ||
2089 | fn_post(data); | ||
2090 | } | 2075 | } |
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index bf2cd699556f..2f1b7217c25c 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c | |||
@@ -35,40 +35,6 @@ extern const unsigned long long relocate_kernel_len; | |||
35 | #ifdef CONFIG_CRASH_DUMP | 35 | #ifdef CONFIG_CRASH_DUMP |
36 | 36 | ||
37 | /* | 37 | /* |
38 | * Initialize CPU ELF notes | ||
39 | */ | ||
40 | static void setup_regs(void) | ||
41 | { | ||
42 | struct save_area *sa, *sa_0; | ||
43 | unsigned long prefix; | ||
44 | int cpu, this_cpu; | ||
45 | |||
46 | /* setup_regs is called with the prefix register = 0 */ | ||
47 | sa_0 = (struct save_area *) __LC_FPREGS_SAVE_AREA; | ||
48 | |||
49 | /* Get status of this CPU out of absolute zero */ | ||
50 | prefix = (unsigned long) S390_lowcore.prefixreg_save_area; | ||
51 | sa = (struct save_area *)(prefix + __LC_FPREGS_SAVE_AREA); | ||
52 | memcpy(sa, sa_0, sizeof(struct save_area)); | ||
53 | if (MACHINE_HAS_VX) { | ||
54 | struct _lowcore *lc = (struct _lowcore *) prefix; | ||
55 | save_vx_regs_safe((void *) lc->vector_save_area_addr); | ||
56 | } | ||
57 | |||
58 | /* Get status of the other CPUs */ | ||
59 | this_cpu = smp_find_processor_id(stap()); | ||
60 | for_each_online_cpu(cpu) { | ||
61 | if (cpu == this_cpu) | ||
62 | continue; | ||
63 | if (smp_store_status(cpu)) | ||
64 | continue; | ||
65 | prefix = (unsigned long) S390_lowcore.prefixreg_save_area; | ||
66 | sa = (struct save_area *)(prefix + __LC_FPREGS_SAVE_AREA); | ||
67 | memcpy(sa, sa_0, sizeof(struct save_area)); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * PM notifier callback for kdump | 38 | * PM notifier callback for kdump |
73 | */ | 39 | */ |
74 | static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action, | 40 | static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action, |
@@ -99,14 +65,66 @@ static int __init machine_kdump_pm_init(void) | |||
99 | arch_initcall(machine_kdump_pm_init); | 65 | arch_initcall(machine_kdump_pm_init); |
100 | 66 | ||
101 | /* | 67 | /* |
102 | * Start kdump: We expect here that a store status has been done on our CPU | 68 | * Reset the system, copy boot CPU registers to absolute zero, |
69 | * and jump to the kdump image | ||
103 | */ | 70 | */ |
104 | static void __do_machine_kdump(void *image) | 71 | static void __do_machine_kdump(void *image) |
105 | { | 72 | { |
106 | int (*start_kdump)(int) = (void *)((struct kimage *) image)->start; | 73 | int (*start_kdump)(int); |
74 | unsigned long prefix; | ||
75 | |||
76 | /* store_status() saved the prefix register to lowcore */ | ||
77 | prefix = (unsigned long) S390_lowcore.prefixreg_save_area; | ||
78 | |||
79 | /* Now do the reset */ | ||
80 | s390_reset_system(); | ||
81 | |||
82 | /* | ||
83 | * Copy dump CPU store status info to absolute zero. | ||
84 | * This need to be done *after* s390_reset_system set the | ||
85 | * prefix register of this CPU to zero | ||
86 | */ | ||
87 | memcpy((void *) __LC_FPREGS_SAVE_AREA, | ||
88 | (void *)(prefix + __LC_FPREGS_SAVE_AREA), 512); | ||
107 | 89 | ||
108 | __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); | 90 | __load_psw_mask(PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA); |
91 | start_kdump = (void *)((struct kimage *) image)->start; | ||
109 | start_kdump(1); | 92 | start_kdump(1); |
93 | |||
94 | /* Die if start_kdump returns */ | ||
95 | disabled_wait((unsigned long) __builtin_return_address(0)); | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * Start kdump: create a LGR log entry, store status of all CPUs and | ||
100 | * branch to __do_machine_kdump. | ||
101 | */ | ||
102 | static noinline void __machine_kdump(void *image) | ||
103 | { | ||
104 | int this_cpu, cpu; | ||
105 | |||
106 | lgr_info_log(); | ||
107 | /* Get status of the other CPUs */ | ||
108 | this_cpu = smp_find_processor_id(stap()); | ||
109 | for_each_online_cpu(cpu) { | ||
110 | if (cpu == this_cpu) | ||
111 | continue; | ||
112 | if (smp_store_status(cpu)) | ||
113 | continue; | ||
114 | } | ||
115 | /* Store status of the boot CPU */ | ||
116 | if (MACHINE_HAS_VX) | ||
117 | save_vx_regs((void *) &S390_lowcore.vector_save_area); | ||
118 | /* | ||
119 | * To create a good backchain for this CPU in the dump store_status | ||
120 | * is passed the address of a function. The address is saved into | ||
121 | * the PSW save area of the boot CPU and the function is invoked as | ||
122 | * a tail call of store_status. The backchain in the dump will look | ||
123 | * like this: | ||
124 | * restart_int_handler -> __machine_kexec -> __do_machine_kdump | ||
125 | * The call to store_status() will not return. | ||
126 | */ | ||
127 | store_status(__do_machine_kdump, image); | ||
110 | } | 128 | } |
111 | #endif | 129 | #endif |
112 | 130 | ||
@@ -229,10 +247,14 @@ static void __do_machine_kexec(void *data) | |||
229 | relocate_kernel_t data_mover; | 247 | relocate_kernel_t data_mover; |
230 | struct kimage *image = data; | 248 | struct kimage *image = data; |
231 | 249 | ||
250 | s390_reset_system(); | ||
232 | data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); | 251 | data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); |
233 | 252 | ||
234 | /* Call the moving routine */ | 253 | /* Call the moving routine */ |
235 | (*data_mover)(&image->head, image->start); | 254 | (*data_mover)(&image->head, image->start); |
255 | |||
256 | /* Die if kexec returns */ | ||
257 | disabled_wait((unsigned long) __builtin_return_address(0)); | ||
236 | } | 258 | } |
237 | 259 | ||
238 | /* | 260 | /* |
@@ -245,14 +267,10 @@ static void __machine_kexec(void *data) | |||
245 | tracing_off(); | 267 | tracing_off(); |
246 | debug_locks_off(); | 268 | debug_locks_off(); |
247 | #ifdef CONFIG_CRASH_DUMP | 269 | #ifdef CONFIG_CRASH_DUMP |
248 | if (((struct kimage *) data)->type == KEXEC_TYPE_CRASH) { | 270 | if (((struct kimage *) data)->type == KEXEC_TYPE_CRASH) |
249 | 271 | __machine_kdump(data); | |
250 | lgr_info_log(); | ||
251 | s390_reset_system(setup_regs, __do_machine_kdump, data); | ||
252 | } else | ||
253 | #endif | 272 | #endif |
254 | s390_reset_system(NULL, __do_machine_kexec, data); | 273 | __do_machine_kexec(data); |
255 | disabled_wait((unsigned long) __builtin_return_address(0)); | ||
256 | } | 274 | } |
257 | 275 | ||
258 | /* | 276 | /* |
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index b75a521e4fab..89ea8c213d82 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S | |||
@@ -9,12 +9,11 @@ | |||
9 | #include <asm/sigp.h> | 9 | #include <asm/sigp.h> |
10 | 10 | ||
11 | # | 11 | # |
12 | # store_status | 12 | # Issue "store status" for the current CPU to its prefix page |
13 | # and call passed function afterwards | ||
13 | # | 14 | # |
14 | # Prerequisites to run this function: | 15 | # r2 = Function to be called after store status |
15 | # - Prefix register is set to zero | 16 | # r3 = Parameter for function |
16 | # - Original prefix register is stored in "dump_prefix_page" | ||
17 | # - Lowcore protection is off | ||
18 | # | 17 | # |
19 | ENTRY(store_status) | 18 | ENTRY(store_status) |
20 | /* Save register one and load save area base */ | 19 | /* Save register one and load save area base */ |
@@ -53,23 +52,23 @@ ENTRY(store_status) | |||
53 | /* CPU timer */ | 52 | /* CPU timer */ |
54 | lghi %r1,__LC_CPU_TIMER_SAVE_AREA | 53 | lghi %r1,__LC_CPU_TIMER_SAVE_AREA |
55 | stpt 0(%r1) | 54 | stpt 0(%r1) |
56 | /* Saved prefix register */ | 55 | /* Store prefix register */ |
57 | lghi %r1,__LC_PREFIX_SAVE_AREA | 56 | lghi %r1,__LC_PREFIX_SAVE_AREA |
58 | larl %r2,dump_prefix_page | 57 | stpx 0(%r1) |
59 | mvc 0(4,%r1),0(%r2) | ||
60 | /* Clock comparator - seven bytes */ | 58 | /* Clock comparator - seven bytes */ |
61 | lghi %r1,__LC_CLOCK_COMP_SAVE_AREA | 59 | lghi %r1,__LC_CLOCK_COMP_SAVE_AREA |
62 | larl %r2,.Lclkcmp | 60 | larl %r4,.Lclkcmp |
63 | stckc 0(%r2) | 61 | stckc 0(%r4) |
64 | mvc 1(7,%r1),1(%r2) | 62 | mvc 1(7,%r1),1(%r4) |
65 | /* Program status word */ | 63 | /* Program status word */ |
66 | lghi %r1,__LC_PSW_SAVE_AREA | 64 | lghi %r1,__LC_PSW_SAVE_AREA |
67 | epsw %r2,%r3 | 65 | epsw %r4,%r5 |
68 | st %r2,0(%r1) | 66 | st %r4,0(%r1) |
69 | st %r3,4(%r1) | 67 | st %r5,4(%r1) |
70 | larl %r2,store_status | ||
71 | stg %r2,8(%r1) | 68 | stg %r2,8(%r1) |
72 | br %r14 | 69 | lgr %r1,%r2 |
70 | lgr %r2,%r3 | ||
71 | br %r1 | ||
73 | 72 | ||
74 | .section .bss | 73 | .section .bss |
75 | .align 8 | 74 | .align 8 |
@@ -84,9 +83,11 @@ ENTRY(store_status) | |||
84 | ENTRY(do_reipl_asm) | 83 | ENTRY(do_reipl_asm) |
85 | basr %r13,0 | 84 | basr %r13,0 |
86 | .Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) | 85 | .Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) |
87 | .Lpg1: brasl %r14,store_status | 86 | .Lpg1: lgr %r3,%r2 |
87 | larl %r2,.Lstatus | ||
88 | brasl %r14,store_status | ||
88 | 89 | ||
89 | lctlg %c6,%c6,.Lall-.Lpg0(%r13) | 90 | .Lstatus: lctlg %c6,%c6,.Lall-.Lpg0(%r13) |
90 | lgr %r1,%r2 | 91 | lgr %r1,%r2 |
91 | mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) | 92 | mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) |
92 | stsch .Lschib-.Lpg0(%r13) | 93 | stsch .Lschib-.Lpg0(%r13) |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 8f5107d6ebb3..22756bb0819e 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -865,11 +865,13 @@ void __init setup_arch(char **cmdline_p) | |||
865 | 865 | ||
866 | check_initrd(); | 866 | check_initrd(); |
867 | reserve_crashkernel(); | 867 | reserve_crashkernel(); |
868 | #ifdef CONFIG_CRASH_DUMP | ||
868 | /* | 869 | /* |
869 | * Be aware that smp_save_dump_cpus() triggers a system reset. | 870 | * Be aware that smp_save_dump_cpus() triggers a system reset. |
870 | * Therefore CPU and device initialization should be done afterwards. | 871 | * Therefore CPU and device initialization should be done afterwards. |
871 | */ | 872 | */ |
872 | smp_save_dump_cpus(); | 873 | smp_save_dump_cpus(); |
874 | #endif | ||
873 | 875 | ||
874 | setup_resources(); | 876 | setup_resources(); |
875 | setup_vmcoreinfo(); | 877 | setup_vmcoreinfo(); |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index d49a8cb404c2..2a69077d482c 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -80,6 +80,10 @@ EXPORT_SYMBOL(smp_cpu_mt_shift); | |||
80 | unsigned int smp_cpu_mtid; | 80 | unsigned int smp_cpu_mtid; |
81 | EXPORT_SYMBOL(smp_cpu_mtid); | 81 | EXPORT_SYMBOL(smp_cpu_mtid); |
82 | 82 | ||
83 | #ifdef CONFIG_CRASH_DUMP | ||
84 | __vector128 __initdata boot_cpu_vector_save_area[__NUM_VXRS]; | ||
85 | #endif | ||
86 | |||
83 | static unsigned int smp_max_threads __initdata = -1U; | 87 | static unsigned int smp_max_threads __initdata = -1U; |
84 | 88 | ||
85 | static int __init early_nosmt(char *s) | 89 | static int __init early_nosmt(char *s) |
@@ -105,8 +109,7 @@ DEFINE_MUTEX(smp_cpu_state_mutex); | |||
105 | /* | 109 | /* |
106 | * Signal processor helper functions. | 110 | * Signal processor helper functions. |
107 | */ | 111 | */ |
108 | static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm, | 112 | static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm) |
109 | u32 *status) | ||
110 | { | 113 | { |
111 | int cc; | 114 | int cc; |
112 | 115 | ||
@@ -538,53 +541,24 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); | |||
538 | 541 | ||
539 | #ifdef CONFIG_CRASH_DUMP | 542 | #ifdef CONFIG_CRASH_DUMP |
540 | 543 | ||
541 | static void __init __smp_store_cpu_state(struct save_area_ext *sa_ext, | ||
542 | u16 address, int is_boot_cpu) | ||
543 | { | ||
544 | void *lc = (void *)(unsigned long) store_prefix(); | ||
545 | unsigned long vx_sa; | ||
546 | |||
547 | if (is_boot_cpu) { | ||
548 | /* Copy the registers of the boot CPU. */ | ||
549 | copy_oldmem_kernel(&sa_ext->sa, (void *) __LC_FPREGS_SAVE_AREA, | ||
550 | sizeof(sa_ext->sa)); | ||
551 | if (MACHINE_HAS_VX) | ||
552 | save_vx_regs_safe(sa_ext->vx_regs); | ||
553 | return; | ||
554 | } | ||
555 | /* Get the registers of a non-boot cpu. */ | ||
556 | __pcpu_sigp_relax(address, SIGP_STOP_AND_STORE_STATUS, 0, NULL); | ||
557 | memcpy_real(&sa_ext->sa, lc + __LC_FPREGS_SAVE_AREA, sizeof(sa_ext->sa)); | ||
558 | if (!MACHINE_HAS_VX) | ||
559 | return; | ||
560 | /* Get the VX registers */ | ||
561 | vx_sa = memblock_alloc(PAGE_SIZE, PAGE_SIZE); | ||
562 | if (!vx_sa) | ||
563 | panic("could not allocate memory for VX save area\n"); | ||
564 | __pcpu_sigp_relax(address, SIGP_STORE_ADDITIONAL_STATUS, vx_sa, NULL); | ||
565 | memcpy(sa_ext->vx_regs, (void *) vx_sa, sizeof(sa_ext->vx_regs)); | ||
566 | memblock_free(vx_sa, PAGE_SIZE); | ||
567 | } | ||
568 | |||
569 | int smp_store_status(int cpu) | 544 | int smp_store_status(int cpu) |
570 | { | 545 | { |
571 | unsigned long vx_sa; | 546 | struct pcpu *pcpu = pcpu_devices + cpu; |
572 | struct pcpu *pcpu; | 547 | unsigned long pa; |
573 | 548 | ||
574 | pcpu = pcpu_devices + cpu; | 549 | pa = __pa(&pcpu->lowcore->floating_pt_save_area); |
575 | if (__pcpu_sigp_relax(pcpu->address, SIGP_STOP_AND_STORE_STATUS, | 550 | if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS, |
576 | 0, NULL) != SIGP_CC_ORDER_CODE_ACCEPTED) | 551 | pa) != SIGP_CC_ORDER_CODE_ACCEPTED) |
577 | return -EIO; | 552 | return -EIO; |
578 | if (!MACHINE_HAS_VX) | 553 | if (!MACHINE_HAS_VX) |
579 | return 0; | 554 | return 0; |
580 | vx_sa = __pa(pcpu->lowcore->vector_save_area_addr); | 555 | pa = __pa(pcpu->lowcore->vector_save_area_addr); |
581 | __pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, | 556 | if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, |
582 | vx_sa, NULL); | 557 | pa) != SIGP_CC_ORDER_CODE_ACCEPTED) |
558 | return -EIO; | ||
583 | return 0; | 559 | return 0; |
584 | } | 560 | } |
585 | 561 | ||
586 | #endif /* CONFIG_CRASH_DUMP */ | ||
587 | |||
588 | /* | 562 | /* |
589 | * Collect CPU state of the previous, crashed system. | 563 | * Collect CPU state of the previous, crashed system. |
590 | * There are four cases: | 564 | * There are four cases: |
@@ -593,7 +567,7 @@ int smp_store_status(int cpu) | |||
593 | * The state for all CPUs except the boot CPU needs to be collected | 567 | * The state for all CPUs except the boot CPU needs to be collected |
594 | * with sigp stop-and-store-status. The boot CPU state is located in | 568 | * with sigp stop-and-store-status. The boot CPU state is located in |
595 | * the absolute lowcore of the memory stored in the HSA. The zcore code | 569 | * the absolute lowcore of the memory stored in the HSA. The zcore code |
596 | * will allocate the save area and copy the boot CPU state from the HSA. | 570 | * will copy the boot CPU state from the HSA. |
597 | * 2) stand-alone kdump for SCSI (zfcp dump with swapped memory) | 571 | * 2) stand-alone kdump for SCSI (zfcp dump with swapped memory) |
598 | * condition: OLDMEM_BASE != NULL && ipl_info.type == IPL_TYPE_FCP_DUMP | 572 | * condition: OLDMEM_BASE != NULL && ipl_info.type == IPL_TYPE_FCP_DUMP |
599 | * The state for all CPUs except the boot CPU needs to be collected | 573 | * The state for all CPUs except the boot CPU needs to be collected |
@@ -611,21 +585,49 @@ int smp_store_status(int cpu) | |||
611 | * This case does not exist for s390 anymore, setup_arch explicitly | 585 | * This case does not exist for s390 anymore, setup_arch explicitly |
612 | * deactivates the elfcorehdr= kernel parameter | 586 | * deactivates the elfcorehdr= kernel parameter |
613 | */ | 587 | */ |
588 | static __init void smp_save_cpu_vxrs(struct save_area_ext *sa_ext, u16 addr, | ||
589 | bool is_boot_cpu, unsigned long page) | ||
590 | { | ||
591 | __vector128 *vxrs = (__vector128 *) page; | ||
592 | |||
593 | if (is_boot_cpu) | ||
594 | vxrs = boot_cpu_vector_save_area; | ||
595 | else | ||
596 | __pcpu_sigp_relax(addr, SIGP_STORE_ADDITIONAL_STATUS, page); | ||
597 | memcpy(&sa_ext->vx_regs, vxrs, sizeof(sa_ext->vx_regs)); | ||
598 | } | ||
599 | |||
600 | static __init void smp_save_cpu_regs(struct save_area_ext *sa_ext, u16 addr, | ||
601 | bool is_boot_cpu, unsigned long page) | ||
602 | { | ||
603 | void *regs = (void *) page; | ||
604 | |||
605 | if (is_boot_cpu) | ||
606 | copy_oldmem_kernel(regs, (void *) __LC_FPREGS_SAVE_AREA, 512); | ||
607 | else | ||
608 | __pcpu_sigp_relax(addr, SIGP_STORE_STATUS_AT_ADDRESS, page); | ||
609 | memcpy(&sa_ext->sa, regs, sizeof(sa_ext->sa)); | ||
610 | } | ||
611 | |||
614 | void __init smp_save_dump_cpus(void) | 612 | void __init smp_save_dump_cpus(void) |
615 | { | 613 | { |
616 | #ifdef CONFIG_CRASH_DUMP | ||
617 | int addr, cpu, boot_cpu_addr, max_cpu_addr; | 614 | int addr, cpu, boot_cpu_addr, max_cpu_addr; |
618 | struct save_area_ext *sa_ext; | 615 | struct save_area_ext *sa_ext; |
616 | unsigned long page; | ||
619 | bool is_boot_cpu; | 617 | bool is_boot_cpu; |
620 | 618 | ||
621 | if (!(OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP)) | 619 | if (!(OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP)) |
622 | /* No previous system present, normal boot. */ | 620 | /* No previous system present, normal boot. */ |
623 | return; | 621 | return; |
622 | /* Allocate a page as dumping area for the store status sigps */ | ||
623 | page = memblock_alloc_base(PAGE_SIZE, PAGE_SIZE, 1UL << 31); | ||
624 | if (!page) | ||
625 | panic("could not allocate memory for save area\n"); | ||
624 | /* Set multi-threading state to the previous system. */ | 626 | /* Set multi-threading state to the previous system. */ |
625 | pcpu_set_smt(sclp.mtid_prev); | 627 | pcpu_set_smt(sclp.mtid_prev); |
626 | max_cpu_addr = SCLP_MAX_CORES << sclp.mtid_prev; | 628 | max_cpu_addr = SCLP_MAX_CORES << sclp.mtid_prev; |
627 | for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) { | 629 | for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) { |
628 | if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) == | 630 | if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0) == |
629 | SIGP_CC_NOT_OPERATIONAL) | 631 | SIGP_CC_NOT_OPERATIONAL) |
630 | continue; | 632 | continue; |
631 | cpu += 1; | 633 | cpu += 1; |
@@ -634,7 +636,7 @@ void __init smp_save_dump_cpus(void) | |||
634 | dump_save_areas.count = cpu; | 636 | dump_save_areas.count = cpu; |
635 | boot_cpu_addr = stap(); | 637 | boot_cpu_addr = stap(); |
636 | for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) { | 638 | for (cpu = 0, addr = 0; addr <= max_cpu_addr; addr++) { |
637 | if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0, NULL) == | 639 | if (__pcpu_sigp_relax(addr, SIGP_SENSE, 0) == |
638 | SIGP_CC_NOT_OPERATIONAL) | 640 | SIGP_CC_NOT_OPERATIONAL) |
639 | continue; | 641 | continue; |
640 | sa_ext = (void *) memblock_alloc(sizeof(*sa_ext), 8); | 642 | sa_ext = (void *) memblock_alloc(sizeof(*sa_ext), 8); |
@@ -643,16 +645,24 @@ void __init smp_save_dump_cpus(void) | |||
643 | panic("could not allocate memory for save area\n"); | 645 | panic("could not allocate memory for save area\n"); |
644 | is_boot_cpu = (addr == boot_cpu_addr); | 646 | is_boot_cpu = (addr == boot_cpu_addr); |
645 | cpu += 1; | 647 | cpu += 1; |
646 | if (is_boot_cpu && !OLDMEM_BASE) | 648 | if (MACHINE_HAS_VX) |
647 | /* Skip boot CPU for standard zfcp dump. */ | 649 | /* Get the vector registers */ |
648 | continue; | 650 | smp_save_cpu_vxrs(sa_ext, addr, is_boot_cpu, page); |
649 | /* Get state for this CPU. */ | 651 | /* |
650 | __smp_store_cpu_state(sa_ext, addr, is_boot_cpu); | 652 | * For a zfcp dump OLDMEM_BASE == NULL and the registers |
653 | * of the boot CPU are stored in the HSA. To retrieve | ||
654 | * these registers an SCLP request is required which is | ||
655 | * done by drivers/s390/char/zcore.c:init_cpu_info() | ||
656 | */ | ||
657 | if (!is_boot_cpu || OLDMEM_BASE) | ||
658 | /* Get the CPU registers */ | ||
659 | smp_save_cpu_regs(sa_ext, addr, is_boot_cpu, page); | ||
651 | } | 660 | } |
661 | memblock_free(page, PAGE_SIZE); | ||
652 | diag308_reset(); | 662 | diag308_reset(); |
653 | pcpu_set_smt(0); | 663 | pcpu_set_smt(0); |
654 | #endif /* CONFIG_CRASH_DUMP */ | ||
655 | } | 664 | } |
665 | #endif /* CONFIG_CRASH_DUMP */ | ||
656 | 666 | ||
657 | void smp_cpu_set_polarization(int cpu, int val) | 667 | void smp_cpu_set_polarization(int cpu, int val) |
658 | { | 668 | { |
@@ -676,7 +686,7 @@ static struct sclp_core_info *smp_get_core_info(void) | |||
676 | for (address = 0; | 686 | for (address = 0; |
677 | address < (SCLP_MAX_CORES << smp_cpu_mt_shift); | 687 | address < (SCLP_MAX_CORES << smp_cpu_mt_shift); |
678 | address += (1U << smp_cpu_mt_shift)) { | 688 | address += (1U << smp_cpu_mt_shift)) { |
679 | if (__pcpu_sigp_relax(address, SIGP_SENSE, 0, NULL) == | 689 | if (__pcpu_sigp_relax(address, SIGP_SENSE, 0) == |
680 | SIGP_CC_NOT_OPERATIONAL) | 690 | SIGP_CC_NOT_OPERATIONAL) |
681 | continue; | 691 | continue; |
682 | info->core[info->configured].core_id = | 692 | info->core[info->configured].core_id = |
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 087da775c359..bed191a39c5b 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c | |||
@@ -129,8 +129,6 @@ static int __init init_cpu_info(void) | |||
129 | TRACE("could not copy from HSA\n"); | 129 | TRACE("could not copy from HSA\n"); |
130 | return -EIO; | 130 | return -EIO; |
131 | } | 131 | } |
132 | if (MACHINE_HAS_VX) | ||
133 | save_vx_regs_safe(sa_ext->vx_regs); | ||
134 | return 0; | 132 | return 0; |
135 | } | 133 | } |
136 | 134 | ||
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 690b8547e828..e0d02952a7f4 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -917,7 +917,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid) | |||
917 | { | 917 | { |
918 | struct subchannel_id uninitialized_var(schid); | 918 | struct subchannel_id uninitialized_var(schid); |
919 | 919 | ||
920 | s390_reset_system(NULL, NULL, NULL); | 920 | s390_reset_system(); |
921 | if (reipl_find_schid(devid, &schid) != 0) | 921 | if (reipl_find_schid(devid, &schid) != 0) |
922 | panic("IPL Device not found\n"); | 922 | panic("IPL Device not found\n"); |
923 | do_reipl_asm(*((__u32*)&schid)); | 923 | do_reipl_asm(*((__u32*)&schid)); |