diff options
author | Michael Holzheu <holzheu@linux.vnet.ibm.com> | 2012-05-24 08:38:26 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-05-30 03:04:51 -0400 |
commit | 061da3dfb291570e780169918933ba51c2b7d554 (patch) | |
tree | 6f41ed465199eb7c5a8b31ff6b834c0b5aa2565e /arch | |
parent | 73bf463efaba6a1efe69349c6d7275d03468adf4 (diff) |
s390/kernel: Fix smp_call_ipl_cpu() for offline CPUs
If the IPL CPU is offline, currently the pcpu_delegate() function
used by smp_call_ipl_cpu() does not work because pcpu_delegate()
modifies the lowcore of the target CPU. In case of an offline
IPL CPU currently the prefix register is zero but pcpu->lowcore
still points to the old prefix page. Therefore the lowcore changes
done by pcpu_delegate() have no effect.
With this fix pcpu_delegate() now uses memcpy_absolute() and therefore
also prepares the absolute zero lowcore if the target CPU has prefix
register zero.
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/kernel/smp.c | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 9948bd09ee57..5c7bf24849b2 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -297,26 +297,27 @@ static void pcpu_start_fn(struct pcpu *pcpu, void (*func)(void *), void *data) | |||
297 | static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), | 297 | static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), |
298 | void *data, unsigned long stack) | 298 | void *data, unsigned long stack) |
299 | { | 299 | { |
300 | struct _lowcore *lc = pcpu->lowcore; | 300 | struct _lowcore *lc = lowcore_ptr[pcpu - pcpu_devices]; |
301 | unsigned short this_cpu; | 301 | struct { |
302 | unsigned long stack; | ||
303 | void *func; | ||
304 | void *data; | ||
305 | unsigned long source; | ||
306 | } restart = { stack, func, data, stap() }; | ||
302 | 307 | ||
303 | __load_psw_mask(psw_kernel_bits); | 308 | __load_psw_mask(psw_kernel_bits); |
304 | this_cpu = stap(); | 309 | if (pcpu->address == restart.source) |
305 | if (pcpu->address == this_cpu) | ||
306 | func(data); /* should not return */ | 310 | func(data); /* should not return */ |
307 | /* Stop target cpu (if func returns this stops the current cpu). */ | 311 | /* Stop target cpu (if func returns this stops the current cpu). */ |
308 | pcpu_sigp_retry(pcpu, sigp_stop, 0); | 312 | pcpu_sigp_retry(pcpu, sigp_stop, 0); |
309 | /* Restart func on the target cpu and stop the current cpu. */ | 313 | /* Restart func on the target cpu and stop the current cpu. */ |
310 | lc->restart_stack = stack; | 314 | memcpy_absolute(&lc->restart_stack, &restart, sizeof(restart)); |
311 | lc->restart_fn = (unsigned long) func; | ||
312 | lc->restart_data = (unsigned long) data; | ||
313 | lc->restart_source = (unsigned long) this_cpu; | ||
314 | asm volatile( | 315 | asm volatile( |
315 | "0: sigp 0,%0,6 # sigp restart to target cpu\n" | 316 | "0: sigp 0,%0,6 # sigp restart to target cpu\n" |
316 | " brc 2,0b # busy, try again\n" | 317 | " brc 2,0b # busy, try again\n" |
317 | "1: sigp 0,%1,5 # sigp stop to current cpu\n" | 318 | "1: sigp 0,%1,5 # sigp stop to current cpu\n" |
318 | " brc 2,1b # busy, try again\n" | 319 | " brc 2,1b # busy, try again\n" |
319 | : : "d" (pcpu->address), "d" (this_cpu) : "0", "1", "cc"); | 320 | : : "d" (pcpu->address), "d" (restart.source) : "0", "1", "cc"); |
320 | for (;;) ; | 321 | for (;;) ; |
321 | } | 322 | } |
322 | 323 | ||