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

[S390] Make sure enabled wait psw is loaded in default_idle.

If both NO_IDLE_HZ and VIRT_TIMER are disabled default_idle won't load
an enabled wait psw and busy loop instead. This is because the
idle_chain is empty and the return value of atomic_notifier_call_chain
will be NOTIFY_DONE, which causes default_idle to return instead of
loading an enabled wait psw.
Fix this by calling __atomic_notifier_call_chain instead and add proper
return value handling.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Heiko Carstens and committed by
Martin Schwidefsky
11ab244c 057c5cb3

+9 -6
+9 -6
arch/s390/kernel/process.c
··· 114 114 static void default_idle(void) 115 115 { 116 116 int cpu, rc; 117 + int nr_calls = 0; 118 + void *hcpu; 117 119 #ifdef CONFIG_SMP 118 120 struct s390_idle_data *idle; 119 121 #endif 120 122 121 123 /* CPU is going idle. */ 122 124 cpu = smp_processor_id(); 123 - 125 + hcpu = (void *)(long)cpu; 124 126 local_irq_disable(); 125 127 if (need_resched()) { 126 128 local_irq_enable(); 127 129 return; 128 130 } 129 131 130 - rc = atomic_notifier_call_chain(&idle_chain, 131 - S390_CPU_IDLE, (void *)(long) cpu); 132 - if (rc != NOTIFY_OK && rc != NOTIFY_DONE) 133 - BUG(); 134 - if (rc != NOTIFY_OK) { 132 + rc = __atomic_notifier_call_chain(&idle_chain, S390_CPU_IDLE, hcpu, -1, 133 + &nr_calls); 134 + if (rc == NOTIFY_BAD) { 135 + nr_calls--; 136 + __atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, 137 + hcpu, nr_calls, NULL); 135 138 local_irq_enable(); 136 139 return; 137 140 }