Commit 85ac7ca5 authored by Martin Schwidefsky's avatar Martin Schwidefsky

[S390] outstanding interrupts vs. smp_send_stop

The panic function will first print the panic message to the console,
then stop additional cpus with smp_send_stop and finally call the
function on the panic notifier list.
In case of an I/O based console the panic message will cause I/O to
be started and a function on the panic notifier list will wait for the
completion of the I/O. That does not work if an I/O completion interrupt
has already been delivered to a cpu that is then stopped by smp_send_stop.
To break this cyclic dependency add code to smp_send_stop that gives
the additional cpu the opportunity to complete outstanding interrupts.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 3a3954ce
...@@ -56,6 +56,7 @@ enum { ...@@ -56,6 +56,7 @@ enum {
ec_schedule = 0, ec_schedule = 0,
ec_call_function, ec_call_function,
ec_call_function_single, ec_call_function_single,
ec_stop_cpu,
}; };
/* /*
......
...@@ -154,22 +154,52 @@ void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) ...@@ -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 */ cpumask_copy(&cpumask, cpu_online_mask);
for_each_online_cpu(cpu) { cpumask_clear_cpu(smp_processor_id(), &cpumask);
if (cpu == smp_processor_id())
continue; if (oops_in_progress) {
do { /*
rc = sigp(cpu, sigp_stop); * Give the other cpus the opportunity to complete
} while (rc == sigp_busy); * 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, ...@@ -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, ...@@ -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();
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment