// SPDX-License-Identifier: GPL-2.0 /* * Precise Delay Loops for i386 * * Copyright (C) 1993 Linus Torvalds * Copyright (C) 1997 Martin Mares <[email protected]> * Copyright (C) 2008 Jiri Hladky <hladky _dot_ jiri _at_ gmail _dot_ com> * * The __delay function must _NOT_ be inlined as its execution time * depends wildly on alignment on many x86 processors. The additional * jump magic is needed to get the timing stable on all the CPU's * we have to worry about. */ #include <linux/export.h> #include <linux/sched.h> #include <linux/timex.h> #include <linux/preempt.h> #include <linux/delay.h> #include <asm/processor.h> #include <asm/delay.h> #include <asm/timer.h> #include <asm/mwait.h> #ifdef CONFIG_SMP # include <asm/smp.h> #endif static void delay_loop(u64 __loops); /* * Calibration and selection of the delay mechanism happens only once * during boot. */ static void (*delay_fn)(u64) __ro_after_init = …; static void (*delay_halt_fn)(u64 start, u64 cycles) __ro_after_init; /* simple loop based delay: */ static void delay_loop(u64 __loops) { … } /* TSC based delay: */ static void delay_tsc(u64 cycles) { … } /* * On Intel the TPAUSE instruction waits until any of: * 1) the TSC counter exceeds the value provided in EDX:EAX * 2) global timeout in IA32_UMWAIT_CONTROL is exceeded * 3) an external interrupt occurs */ static void delay_halt_tpause(u64 start, u64 cycles) { … } /* * On some AMD platforms, MWAITX has a configurable 32-bit timer, that * counts with TSC frequency. The input value is the number of TSC cycles * to wait. MWAITX will also exit when the timer expires. */ static void delay_halt_mwaitx(u64 unused, u64 cycles) { … } /* * Call a vendor specific function to delay for a given amount of time. Because * these functions may return earlier than requested, check for actual elapsed * time and call again until done. */ static void delay_halt(u64 __cycles) { … } void __init use_tsc_delay(void) { … } void __init use_tpause_delay(void) { … } void use_mwaitx_delay(void) { … } int read_current_timer(unsigned long *timer_val) { … } void __delay(unsigned long loops) { … } EXPORT_SYMBOL(…); noinline void __const_udelay(unsigned long xloops) { … } EXPORT_SYMBOL(…); void __udelay(unsigned long usecs) { … } EXPORT_SYMBOL(…); void __ndelay(unsigned long nsecs) { … } EXPORT_SYMBOL(…);