diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-12-27 05:27:22 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-12-27 05:27:13 -0500 |
commit | 85ac7ca5972d63d23aa5ea75c3834a33b951f89d (patch) | |
tree | 851ff1a5500bce5964336960594cb72bff369d13 /arch/s390 | |
parent | 3a3954ceae756ed2a5d53b45c67db6dde3c0c126 (diff) |
[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>
Diffstat (limited to 'arch/s390')
-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 { | |||
56 | ec_schedule = 0, | 56 | ec_schedule = 0, |
57 | ec_call_function, | 57 | ec_call_function, |
58 | ec_call_function_single, | 58 | ec_call_function_single, |
59 | ec_stop_cpu, | ||
59 | }; | 60 | }; |
60 | 61 | ||
61 | /* | 62 | /* |
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) | |||
154 | smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); | 154 | smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); |
155 | } | 155 | } |
156 | 156 | ||
157 | static void smp_stop_cpu(void) | ||
158 | { | ||
159 | while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) | ||
160 | cpu_relax(); | ||
161 | } | ||
162 | |||
157 | void smp_send_stop(void) | 163 | void smp_send_stop(void) |
158 | { | 164 | { |
159 | int cpu, rc; | 165 | cpumask_t cpumask; |
166 | int cpu; | ||
167 | u64 end; | ||
160 | 168 | ||
161 | /* Disable all interrupts/machine checks */ | 169 | /* Disable all interrupts/machine checks */ |
162 | __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); | 170 | __load_psw_mask(psw_kernel_bits | PSW_MASK_DAT); |
163 | trace_hardirqs_off(); | 171 | trace_hardirqs_off(); |
164 | 172 | ||
165 | /* stop all processors */ | 173 | cpumask_copy(&cpumask, cpu_online_mask); |
166 | for_each_online_cpu(cpu) { | 174 | cpumask_clear_cpu(smp_processor_id(), &cpumask); |
167 | if (cpu == smp_processor_id()) | 175 | |
168 | continue; | 176 | if (oops_in_progress) { |
169 | do { | 177 | /* |
170 | rc = sigp(cpu, sigp_stop); | 178 | * Give the other cpus the opportunity to complete |
171 | } while (rc == sigp_busy); | 179 | * outstanding interrupts before stopping them. |
180 | */ | ||
181 | end = get_clock() + (1000000UL << 12); | ||
182 | for_each_cpu(cpu, &cpumask) { | ||
183 | set_bit(ec_stop_cpu, (unsigned long *) | ||
184 | &lowcore_ptr[cpu]->ext_call_fast); | ||
185 | while (sigp(cpu, sigp_emergency_signal) == sigp_busy && | ||
186 | get_clock() < end) | ||
187 | cpu_relax(); | ||
188 | } | ||
189 | while (get_clock() < end) { | ||
190 | for_each_cpu(cpu, &cpumask) | ||
191 | if (cpu_stopped(cpu)) | ||
192 | cpumask_clear_cpu(cpu, &cpumask); | ||
193 | if (cpumask_empty(&cpumask)) | ||
194 | break; | ||
195 | cpu_relax(); | ||
196 | } | ||
197 | } | ||
172 | 198 | ||
199 | /* stop all processors */ | ||
200 | for_each_cpu(cpu, &cpumask) { | ||
201 | while (sigp(cpu, sigp_stop) == sigp_busy) | ||
202 | cpu_relax(); | ||
173 | while (!cpu_stopped(cpu)) | 203 | while (!cpu_stopped(cpu)) |
174 | cpu_relax(); | 204 | cpu_relax(); |
175 | } | 205 | } |
@@ -194,6 +224,9 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, | |||
194 | */ | 224 | */ |
195 | bits = xchg(&S390_lowcore.ext_call_fast, 0); | 225 | bits = xchg(&S390_lowcore.ext_call_fast, 0); |
196 | 226 | ||
227 | if (test_bit(ec_stop_cpu, &bits)) | ||
228 | smp_stop_cpu(); | ||
229 | |||
197 | if (test_bit(ec_schedule, &bits)) | 230 | if (test_bit(ec_schedule, &bits)) |
198 | scheduler_ipi(); | 231 | scheduler_ipi(); |
199 | 232 | ||
@@ -202,6 +235,7 @@ static void do_ext_call_interrupt(unsigned int ext_int_code, | |||
202 | 235 | ||
203 | if (test_bit(ec_call_function_single, &bits)) | 236 | if (test_bit(ec_call_function_single, &bits)) |
204 | generic_smp_call_function_single_interrupt(); | 237 | generic_smp_call_function_single_interrupt(); |
238 | |||
205 | } | 239 | } |
206 | 240 | ||
207 | /* | 241 | /* |