Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ enum {
	ec_schedule = 0,
	ec_call_function,
	ec_call_function_single,
	ec_stop_cpu,
};

/*
+42 −8
Original line number Diff line number Diff line
@@ -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();

}

/*