aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2015-10-29 05:28:26 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2015-11-27 03:24:14 -0500
commit1a36a39e225d3558fb3776a3d3d7736cf1ec9f60 (patch)
tree63a1c8892ff95dac939beb6e7a13456fcec20cb7
parentf08b8414632c9f256e33f0a18104d8d5e103d204 (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.h10
-rw-r--r--arch/s390/include/asm/ipl.h3
-rw-r--r--arch/s390/include/asm/reset.h3
-rw-r--r--arch/s390/include/asm/smp.h2
-rw-r--r--arch/s390/kernel/early.c9
-rw-r--r--arch/s390/kernel/ipl.c17
-rw-r--r--arch/s390/kernel/machine_kexec.c104
-rw-r--r--arch/s390/kernel/reipl.S37
-rw-r--r--arch/s390/kernel/setup.c2
-rw-r--r--arch/s390/kernel/smp.c112
-rw-r--r--drivers/s390/char/zcore.c2
-rw-r--r--drivers/s390/cio/cio.c2
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
15static inline void save_vx_regs_safe(__vector128 *vxrs) 15static 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
32static inline void convert_vx_to_fp(freg_t *fprs, __vector128 *vxrs) 24static 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 */
89extern u32 ipl_flags; 89extern u32 ipl_flags;
90extern u32 dump_prefix_page;
91 90
92struct dump_save_areas { 91struct dump_save_areas {
93 struct save_area_ext **areas; 92 struct save_area_ext **areas;
@@ -176,7 +175,7 @@ enum diag308_rc {
176 175
177extern int diag308(unsigned long subcode, void *addr); 176extern int diag308(unsigned long subcode, void *addr);
178extern void diag308_reset(void); 177extern void diag308_reset(void);
179extern void store_status(void); 178extern void store_status(void (*fn)(void *), void *data);
180extern void lgr_info_log(void); 179extern 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
16extern void register_reset_call(struct reset_call *reset); 16extern void register_reset_call(struct reset_call *reset);
17extern void unregister_reset_call(struct reset_call *reset); 17extern void unregister_reset_call(struct reset_call *reset);
18extern void s390_reset_system(void (*fn_pre)(void), 18extern 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 @@
18extern struct mutex smp_cpu_state_mutex; 18extern struct mutex smp_cpu_state_mutex;
19extern unsigned int smp_cpu_mt_shift; 19extern unsigned int smp_cpu_mt_shift;
20extern unsigned int smp_cpu_mtid; 20extern unsigned int smp_cpu_mtid;
21extern __vector128 __initdata boot_cpu_vector_save_area[__NUM_VXRS];
21 22
22extern int __cpu_up(unsigned int cpu, struct task_struct *tidle); 23extern 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; }
55static inline int smp_vcpu_scheduled(int cpu) { return 1; } 56static inline int smp_vcpu_scheduled(int cpu) { return 1; }
56static inline void smp_yield_cpu(int cpu) { } 57static inline void smp_yield_cpu(int cpu) { }
57static inline void smp_fill_possible_mask(void) { } 58static inline void smp_fill_possible_mask(void) { }
58static 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
338static 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
338static int __init disable_vector_extension(char *str) 346static 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
2042u32 dump_prefix_page; 2042void s390_reset_system(void)
2043
2044void 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 */
40static 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 */
74static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action, 40static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action,
@@ -99,14 +65,66 @@ static int __init machine_kdump_pm_init(void)
99arch_initcall(machine_kdump_pm_init); 65arch_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 */
104static void __do_machine_kdump(void *image) 71static 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 */
102static 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#
19ENTRY(store_status) 18ENTRY(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)
84ENTRY(do_reipl_asm) 83ENTRY(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);
80unsigned int smp_cpu_mtid; 80unsigned int smp_cpu_mtid;
81EXPORT_SYMBOL(smp_cpu_mtid); 81EXPORT_SYMBOL(smp_cpu_mtid);
82 82
83#ifdef CONFIG_CRASH_DUMP
84__vector128 __initdata boot_cpu_vector_save_area[__NUM_VXRS];
85#endif
86
83static unsigned int smp_max_threads __initdata = -1U; 87static unsigned int smp_max_threads __initdata = -1U;
84 88
85static int __init early_nosmt(char *s) 89static 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 */
108static inline int __pcpu_sigp_relax(u16 addr, u8 order, unsigned long parm, 112static 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
541static 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
569int smp_store_status(int cpu) 544int 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 */
588static __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
600static __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
614void __init smp_save_dump_cpus(void) 612void __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
657void smp_cpu_set_polarization(int cpu, int val) 667void 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));