aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/sigp.h1
-rw-r--r--arch/s390/kernel/smp.c50
2 files changed, 43 insertions, 8 deletions
diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h
index e3bffd4e2d66..7040b8567cd0 100644
--- a/arch/s390/include/asm/sigp.h
+++ b/arch/s390/include/asm/sigp.h
@@ -56,6 +56,7 @@ enum {
56 ec_schedule = 0, 56 ec_schedule = 0,
57 ec_call_function, 57 ec_call_function,
58 ec_call_function_single, 58 ec_call_function_single,
59 ec_stop_cpu,
59}; 60};
60 61
61/* 62/*
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 8aba77df68a9..b1cd32936712 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -154,22 +154,52 @@ void smp_switch_to_ipl_cpu(void (*func)(void *), void *data)
154 smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); 154 smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]);
155} 155}
156 156
157static void smp_stop_cpu(void)
158{
159 while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
160 cpu_relax();
161}
162
157void smp_send_stop(void) 163void smp_send_stop(void)
158{ 164{
159 int cpu, rc; 165 cpumask_t cpumask;
166 int cpu;
167 u64 end;
160 168
161 /* Disable all interrupts/machine checks */ 169 /* Disable all interrupts/machine checks */
162 __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); 170 __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
163 trace_hardirqs_off(); 171 trace_hardirqs_off();
164 172
165 /* stop all processors */ 173 cpumask_copy(&cpumask, cpu_online_mask);
166 for_each_online_cpu(cpu) { 174 cpumask_clear_cpu(smp_processor_id(), &cpumask);
167 if (cpu == smp_processor_id()) 175
168 continue; 176 if (oops_in_progress) {
169 do { 177 /*
170 rc = sigp(cpu, sigp_stop); 178 * Give the other cpus the opportunity to complete
171 } while (rc == sigp_busy); 179 * outstanding interrupts before stopping them.
180 */
181 end = get_clock() + (1000000UL << 12);
182 for_each_cpu(cpu, &cpumask) {
183 set_bit(ec_stop_cpu, (unsigned long *)
184 &lowcore_ptr[cpu]->ext_call_fast);
185 while (sigp(cpu, sigp_emergency_signal) == sigp_busy &&
186 get_clock() < end)
187 cpu_relax();
188 }
189 while (get_clock() < end) {
190 for_each_cpu(cpu, &cpumask)
191 if (cpu_stopped(cpu))
192 cpumask_clear_cpu(cpu, &cpumask);
193 if (cpumask_empty(&cpumask))
194 break;
195 cpu_relax();
196 }
197 }
172 198
199 /* stop all processors */
200 for_each_cpu(cpu, &cpumask) {
201 while (sigp(cpu, sigp_stop) == sigp_busy)
202 cpu_relax();
173 while (!cpu_stopped(cpu)) 203 while (!cpu_stopped(cpu))
174 cpu_relax(); 204 cpu_relax();
175 } 205 }
@@ -194,6 +224,9 @@ static void do_ext_call_interrupt(unsigned int ext_int_code,
194 */ 224 */
195 bits = xchg(&S390_lowcore.ext_call_fast, 0); 225 bits = xchg(&S390_lowcore.ext_call_fast, 0);
196 226
227 if (test_bit(ec_stop_cpu, &bits))
228 smp_stop_cpu();
229
197 if (test_bit(ec_schedule, &bits)) 230 if (test_bit(ec_schedule, &bits))
198 scheduler_ipi(); 231 scheduler_ipi();
199 232
@@ -202,6 +235,7 @@ static void do_ext_call_interrupt(unsigned int ext_int_code,
202 235
203 if (test_bit(ec_call_function_single, &bits)) 236 if (test_bit(ec_call_function_single, &bits))
204 generic_smp_call_function_single_interrupt(); 237 generic_smp_call_function_single_interrupt();
238
205} 239}
206 240
207/* 241/*