aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2012-05-24 08:38:26 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-05-30 03:04:51 -0400
commit061da3dfb291570e780169918933ba51c2b7d554 (patch)
tree6f41ed465199eb7c5a8b31ff6b834c0b5aa2565e /arch
parent73bf463efaba6a1efe69349c6d7275d03468adf4 (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.c19
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)
297static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *), 297static 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