mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 07:23:14 +00:00
[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: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
3a3954ceae
commit
85ac7ca597
@ -56,6 +56,7 @@ enum {
|
||||
ec_schedule = 0,
|
||||
ec_call_function,
|
||||
ec_call_function_single,
|
||||
ec_stop_cpu,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
static void smp_stop_cpu(void)
|
||||
{
|
||||
while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
void smp_send_stop(void)
|
||||
{
|
||||
int cpu, rc;
|
||||
cpumask_t cpumask;
|
||||
int cpu;
|
||||
u64 end;
|
||||
|
||||
/* Disable all interrupts/machine checks */
|
||||
__load_psw_mask(psw_kernel_bits | PSW_MASK_DAT);
|
||||
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))
|
||||
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);
|
||||
|
||||
if (test_bit(ec_stop_cpu, &bits))
|
||||
smp_stop_cpu();
|
||||
|
||||
if (test_bit(ec_schedule, &bits))
|
||||
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))
|
||||
generic_smp_call_function_single_interrupt();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user