|
@@ -154,22 +154,52 @@ void smp_switch_to_ipl_cpu(void (*func)(void *), void *data)
|
|
smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]);
|
|
smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void smp_stop_cpu(void)
|
|
|
|
+{
|
|
|
|
+ while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
|
|
|
|
+ cpu_relax();
|
|
|
|
+}
|
|
|
|
+
|
|
void smp_send_stop(void)
|
|
void smp_send_stop(void)
|
|
{
|
|
{
|
|
- int cpu, rc;
|
|
|
|
|
|
+ cpumask_t cpumask;
|
|
|
|
+ int cpu;
|
|
|
|
+ u64 end;
|
|
|
|
|
|
/* Disable all interrupts/machine checks */
|
|
/* Disable all interrupts/machine checks */
|
|
__load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
|
|
__load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
|
|
trace_hardirqs_off();
|
|
trace_hardirqs_off();
|
|
|
|
|
|
- /* stop all processors */
|
|
|
|
- for_each_online_cpu(cpu) {
|
|
|
|
- if (cpu == smp_processor_id())
|
|
|
|
- continue;
|
|
|
|
- do {
|
|
|
|
- rc = sigp(cpu, sigp_stop);
|
|
|
|
- } while (rc == sigp_busy);
|
|
|
|
|
|
+ cpumask_copy(&cpumask, cpu_online_mask);
|
|
|
|
+ cpumask_clear_cpu(smp_processor_id(), &cpumask);
|
|
|
|
+
|
|
|
|
+ if (oops_in_progress) {
|
|
|
|
+ /*
|
|
|
|
+ * Give the other cpus the opportunity to complete
|
|
|
|
+ * outstanding interrupts before stopping them.
|
|
|
|
+ */
|
|
|
|
+ end = get_clock() + (1000000UL << 12);
|
|
|
|
+ for_each_cpu(cpu, &cpumask) {
|
|
|
|
+ set_bit(ec_stop_cpu, (unsigned long *)
|
|
|
|
+ &lowcore_ptr[cpu]->ext_call_fast);
|
|
|
|
+ while (sigp(cpu, sigp_emergency_signal) == sigp_busy &&
|
|
|
|
+ get_clock() < end)
|
|
|
|
+ cpu_relax();
|
|
|
|
+ }
|
|
|
|
+ while (get_clock() < end) {
|
|
|
|
+ for_each_cpu(cpu, &cpumask)
|
|
|
|
+ if (cpu_stopped(cpu))
|
|
|
|
+ cpumask_clear_cpu(cpu, &cpumask);
|
|
|
|
+ if (cpumask_empty(&cpumask))
|
|
|
|
+ break;
|
|
|
|
+ cpu_relax();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ /* stop all processors */
|
|
|
|
+ for_each_cpu(cpu, &cpumask) {
|
|
|
|
+ while (sigp(cpu, sigp_stop) == sigp_busy)
|
|
|
|
+ cpu_relax();
|
|
while (!cpu_stopped(cpu))
|
|
while (!cpu_stopped(cpu))
|
|
cpu_relax();
|
|
cpu_relax();
|
|
}
|
|
}
|
|
@@ -194,6 +224,9 @@ static void do_ext_call_interrupt(unsigned int ext_int_code,
|
|
*/
|
|
*/
|
|
bits = xchg(&S390_lowcore.ext_call_fast, 0);
|
|
bits = xchg(&S390_lowcore.ext_call_fast, 0);
|
|
|
|
|
|
|
|
+ if (test_bit(ec_stop_cpu, &bits))
|
|
|
|
+ smp_stop_cpu();
|
|
|
|
+
|
|
if (test_bit(ec_schedule, &bits))
|
|
if (test_bit(ec_schedule, &bits))
|
|
scheduler_ipi();
|
|
scheduler_ipi();
|
|
|
|
|
|
@@ -202,6 +235,7 @@ static void do_ext_call_interrupt(unsigned int ext_int_code,
|
|
|
|
|
|
if (test_bit(ec_call_function_single, &bits))
|
|
if (test_bit(ec_call_function_single, &bits))
|
|
generic_smp_call_function_single_interrupt();
|
|
generic_smp_call_function_single_interrupt();
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|