diff options
| -rw-r--r-- | arch/s390/include/asm/sigp.h | 1 | ||||
| -rw-r--r-- | arch/s390/kernel/smp.c | 50 | 
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 {  	ec_schedule = 0,  	ec_call_function,  	ec_call_function_single, +	ec_stop_cpu,  };  /* 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)  	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(); +  }  /*  | 
