diff options
Diffstat (limited to 'arch/s390/lib/delay.c')
-rw-r--r-- | arch/s390/lib/delay.c | 105 |
1 files changed, 9 insertions, 96 deletions
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 68d61f2835df..f289afeb3f31 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -19,13 +19,6 @@ #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) { /* @@ -39,105 +32,25 @@ void __delay(unsigned long loops) } EXPORT_SYMBOL(__delay); -static void __udelay_disabled(unsigned long long usecs) +static void delay_loop(unsigned long delta) { - unsigned long cr0, cr0_new, psw_mask; - struct s390_idle_data idle; - u64 end; + unsigned long end; - end = get_tod_clock() + (usecs << 12); - __ctl_store(cr0, 0, 0); - cr0_new = cr0 & ~CR0_IRQ_SUBCLASS_MASK; - cr0_new |= (1UL << (63 - 52)); /* enable clock comparator irq */ - __ctl_load(cr0_new, 0, 0); - psw_mask = __extract_psw() | PSW_MASK_EXT | PSW_MASK_WAIT; - set_clock_comparator(end); - set_cpu_flag(CIF_IGNORE_IRQ); - psw_idle(&idle, psw_mask); - trace_hardirqs_off(); - clear_cpu_flag(CIF_IGNORE_IRQ); - set_clock_comparator(S390_lowcore.clock_comparator); - __ctl_load(cr0, 0, 0); + end = get_tod_clock_monotonic() + delta; + while (!tod_after(get_tod_clock_monotonic(), end)) + cpu_relax(); } -static void __udelay_enabled(unsigned long long usecs) +void __udelay(unsigned long usecs) { - u64 clock_saved, end; - - end = get_tod_clock_fast() + (usecs << 12); - do { - clock_saved = 0; - if (tod_after(S390_lowcore.clock_comparator, end)) { - clock_saved = local_tick_disable(); - set_clock_comparator(end); - } - enabled_wait(); - if (clock_saved) - local_tick_enable(clock_saved); - } while (get_tod_clock_fast() < end); -} - -/* - * Waits for 'usecs' microseconds using the TOD clock comparator. - */ -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()) { - __udelay_disabled(usecs); - goto out; - } - if (in_softirq()) { - if (raw_irqs_disabled_flags(flags)) - __udelay_disabled(usecs); - else - __udelay_enabled(usecs); - goto out; - } - if (raw_irqs_disabled_flags(flags)) { - local_bh_disable(); - __udelay_disabled(usecs); - _local_bh_enable(); - goto out; - } - __udelay_enabled(usecs); -out: - local_irq_restore(flags); - preempt_enable(); + delay_loop(usecs << 12); } EXPORT_SYMBOL(__udelay); -/* - * Simple udelay variant. To be used on startup and reboot - * when the interrupt handler isn't working. - */ -void udelay_simple(unsigned long long usecs) -{ - u64 end; - - end = get_tod_clock_fast() + (usecs << 12); - while (get_tod_clock_fast() < end) - cpu_relax(); -} - -void __ndelay(unsigned long long nsecs) +void __ndelay(unsigned long nsecs) { - u64 end; - nsecs <<= 9; do_div(nsecs, 125); - end = get_tod_clock_fast() + nsecs; - if (nsecs & ~0xfffUL) - __udelay(nsecs >> 12); - while (get_tod_clock_fast() < end) - barrier(); + delay_loop(nsecs); } EXPORT_SYMBOL(__ndelay); |