^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Precise Delay Loops for S390
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright IBM Corp. 1999, 2008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Heiko Carstens <heiko.carstens@de.ibm.com>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/timex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/irqflags.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/vtimer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/div64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/idle.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) void __delay(unsigned long loops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * To end the bloody studid and useless discussion about the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * BogoMips number I took the liberty to define the __delay
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * function in a way that that resulting BogoMips number will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * yield the megahertz number of the cpu. The important function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * is udelay and that is done using the tod clock. -- martin.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) EXPORT_SYMBOL(__delay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static void __udelay_disabled(unsigned long long usecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned long cr0, cr0_new, psw_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct s390_idle_data idle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) u64 end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) end = get_tod_clock() + (usecs << 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) __ctl_store(cr0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) cr0_new = cr0 & ~CR0_IRQ_SUBCLASS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) cr0_new |= (1UL << (63 - 52)); /* enable clock comparator irq */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) __ctl_load(cr0_new, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) psw_mask = __extract_psw() | PSW_MASK_EXT | PSW_MASK_WAIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) set_clock_comparator(end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) set_cpu_flag(CIF_IGNORE_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) psw_idle(&idle, psw_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) trace_hardirqs_off();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) clear_cpu_flag(CIF_IGNORE_IRQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) set_clock_comparator(S390_lowcore.clock_comparator);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) __ctl_load(cr0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void __udelay_enabled(unsigned long long usecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) u64 clock_saved, end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) end = get_tod_clock_fast() + (usecs << 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) clock_saved = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (tod_after(S390_lowcore.clock_comparator, end)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) clock_saved = local_tick_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) set_clock_comparator(end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) enabled_wait();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (clock_saved)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) local_tick_enable(clock_saved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) } while (get_tod_clock_fast() < end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * Waits for 'usecs' microseconds using the TOD clock comparator.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) void __udelay(unsigned long long usecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) preempt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (in_irq()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) __udelay_disabled(usecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if (in_softirq()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (raw_irqs_disabled_flags(flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) __udelay_disabled(usecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) __udelay_enabled(usecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (raw_irqs_disabled_flags(flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) __udelay_disabled(usecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) _local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) __udelay_enabled(usecs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) EXPORT_SYMBOL(__udelay);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * Simple udelay variant. To be used on startup and reboot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * when the interrupt handler isn't working.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) void udelay_simple(unsigned long long usecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) u64 end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) end = get_tod_clock_fast() + (usecs << 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) while (get_tod_clock_fast() < end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) void __ndelay(unsigned long long nsecs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) u64 end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) nsecs <<= 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) do_div(nsecs, 125);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) end = get_tod_clock_fast() + nsecs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (nsecs & ~0xfffUL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) __udelay(nsecs >> 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) while (get_tod_clock_fast() < end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) barrier();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) EXPORT_SYMBOL(__ndelay);