s390/udelay: make it work for the early code
authorVasily Gorbik <gor@linux.ibm.com>
Tue, 13 Oct 2020 20:35:27 +0000 (22:35 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Mon, 9 Nov 2020 10:20:58 +0000 (11:20 +0100)
Currently udelay relies on working EXT interrupts handler, which is not
the case during early startup. In such cases udelay_simple() has to be
used instead.

To avoid mistakes of calling udelay too early, which could happen from
the common code as well - make udelay work for the early code by
introducing static branch and redirecting all udelay calls to
udelay_simple until EXT interrupts handler is fully initialized and
async stack is allocated.

Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/delay.h
arch/s390/kernel/setup.c
arch/s390/lib/delay.c

index 898323fd93d2b9b0885bda17cd097ab6dfef20dc..4a08379cd1eb75067b729fd68a91932a1cebc7b1 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef _S390_DELAY_H
 #define _S390_DELAY_H
 
+void udelay_enable(void);
 void __ndelay(unsigned long long nsecs);
 void __udelay(unsigned long long usecs);
 void udelay_simple(unsigned long long usecs);
index 4d843e64496f4d582b50737d6e00d950b39ec42d..2076415aee4b667f5e8a38b04d9914a1290830e7 100644 (file)
@@ -336,6 +336,7 @@ int __init arch_early_irq_init(void)
        if (!stack)
                panic("Couldn't allocate async stack");
        S390_lowcore.async_stack = stack + STACK_INIT_OFFSET;
+       udelay_enable();
        return 0;
 }
 
index daca7bad66de3e6a5ca68d3a14f3270069e3ecf9..1734a5c19834f858d48e91c49cee0e8957ef3727 100644 (file)
 #include <linux/export.h>
 #include <linux/irqflags.h>
 #include <linux/interrupt.h>
+#include <linux/jump_label.h>
 #include <linux/irq.h>
 #include <asm/vtimer.h>
 #include <asm/div64.h>
 #include <asm/idle.h>
 
+static DEFINE_STATIC_KEY_FALSE(udelay_ready);
+
+void __init udelay_enable(void)
+{
+       static_branch_enable(&udelay_ready);
+}
+
 void __delay(unsigned long loops)
 {
         /*
@@ -77,6 +85,11 @@ void __udelay(unsigned long long usecs)
 {
        unsigned long flags;
 
+       if (!static_branch_likely(&udelay_ready)) {
+               udelay_simple(usecs);
+               return;
+       }
+
        preempt_disable();
        local_irq_save(flags);
        if (in_irq()) {