Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] Force PSW restart on online CPU

PSW restart can be triggered on offline CPUs. If this happens, currently
the PSW restart code fails, because functions like smp_processor_id()
do not work on offline CPUs. This patch fixes this as follows:

If PSW restart is triggered on an offline CPU, the PSW restart (sigp restart)
is done a second time on another CPU that is online and the old CPU is
stopped afterwards.

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Michael Holzheu and committed by
Martin Schwidefsky
1943f53c d3bf3795

+29
+5
arch/s390/include/asm/smp.h
··· 33 33 extern void smp_switch_to_ipl_cpu(void (*func)(void *), void *); 34 34 extern void smp_switch_to_cpu(void (*)(void *), void *, unsigned long sp, 35 35 int from, int to); 36 + extern void smp_restart_with_online_cpu(void); 36 37 extern void smp_restart_cpu(void); 37 38 38 39 /* ··· 63 62 static inline void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) 64 63 { 65 64 func(data); 65 + } 66 + 67 + static inline void smp_restart_with_online_cpu(void) 68 + { 66 69 } 67 70 68 71 #define smp_vcpu_scheduled (1)
+1
arch/s390/kernel/ipl.c
··· 1738 1738 1739 1739 void do_restart(void) 1740 1740 { 1741 + smp_restart_with_online_cpu(); 1741 1742 smp_send_stop(); 1742 1743 on_restart_trigger.action->fn(&on_restart_trigger); 1743 1744 stop_run(&on_restart_trigger);
+23
arch/s390/kernel/smp.c
··· 97 97 return raw_cpu_stopped(cpu_logical_map(cpu)); 98 98 } 99 99 100 + /* 101 + * Ensure that PSW restart is done on an online CPU 102 + */ 103 + void smp_restart_with_online_cpu(void) 104 + { 105 + int cpu; 106 + 107 + for_each_online_cpu(cpu) { 108 + if (stap() == __cpu_logical_map[cpu]) { 109 + /* We are online: Enable DAT again and return */ 110 + __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK); 111 + return; 112 + } 113 + } 114 + /* We are not online: Do PSW restart on an online CPU */ 115 + while (sigp(cpu, sigp_restart) == sigp_busy) 116 + cpu_relax(); 117 + /* And stop ourself */ 118 + while (raw_sigp(stap(), sigp_stop) == sigp_busy) 119 + cpu_relax(); 120 + for (;;); 121 + } 122 + 100 123 void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) 101 124 { 102 125 struct _lowcore *lc, *current_lc;