xref: /linux-6.15/include/asm-generic/delay.h (revision 19e2d91d)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2aafe4dbeSArnd Bergmann #ifndef __ASM_GENERIC_DELAY_H
3aafe4dbeSArnd Bergmann #define __ASM_GENERIC_DELAY_H
4aafe4dbeSArnd Bergmann 
5*19e2d91dSAnna-Maria Behnsen #include <linux/math.h>
6*19e2d91dSAnna-Maria Behnsen #include <vdso/time64.h>
7*19e2d91dSAnna-Maria Behnsen 
830ab2b03SJonas Bonn /* Undefined functions to get compile-time errors */
930ab2b03SJonas Bonn extern void __bad_udelay(void);
1030ab2b03SJonas Bonn extern void __bad_ndelay(void);
1130ab2b03SJonas Bonn 
12aafe4dbeSArnd Bergmann extern void __udelay(unsigned long usecs);
1330ab2b03SJonas Bonn extern void __ndelay(unsigned long nsecs);
1430ab2b03SJonas Bonn extern void __const_udelay(unsigned long xloops);
15aafe4dbeSArnd Bergmann extern void __delay(unsigned long loops);
16aafe4dbeSArnd Bergmann 
17a87e553fSAndrew Morton /*
18*19e2d91dSAnna-Maria Behnsen  * The microseconds/nanosecond delay multiplicators are used to convert a
19*19e2d91dSAnna-Maria Behnsen  * constant microseconds/nanoseconds value to a value which can be used by the
20*19e2d91dSAnna-Maria Behnsen  * architectures specific implementation to transform it into loops.
21a87e553fSAndrew Morton  */
22*19e2d91dSAnna-Maria Behnsen #define UDELAY_CONST_MULT	((unsigned long)DIV_ROUND_UP(1ULL << 32, USEC_PER_SEC))
23*19e2d91dSAnna-Maria Behnsen #define NDELAY_CONST_MULT	((unsigned long)DIV_ROUND_UP(1ULL << 32, NSEC_PER_SEC))
24*19e2d91dSAnna-Maria Behnsen 
25*19e2d91dSAnna-Maria Behnsen /*
26*19e2d91dSAnna-Maria Behnsen  * The maximum constant udelay/ndelay value picked out of thin air to prevent
27*19e2d91dSAnna-Maria Behnsen  * too long constant udelays/ndelays.
28*19e2d91dSAnna-Maria Behnsen  */
29*19e2d91dSAnna-Maria Behnsen #define DELAY_CONST_MAX   20000
30a87e553fSAndrew Morton 
31f36eb171SAnna-Maria Behnsen /**
32f36eb171SAnna-Maria Behnsen  * udelay - Inserting a delay based on microseconds with busy waiting
33f36eb171SAnna-Maria Behnsen  * @usec:	requested delay in microseconds
34f36eb171SAnna-Maria Behnsen  *
35f36eb171SAnna-Maria Behnsen  * When delaying in an atomic context ndelay(), udelay() and mdelay() are the
36f36eb171SAnna-Maria Behnsen  * only valid variants of delaying/sleeping to go with.
37f36eb171SAnna-Maria Behnsen  *
38f36eb171SAnna-Maria Behnsen  * When inserting delays in non atomic context which are shorter than the time
39f36eb171SAnna-Maria Behnsen  * which is required to queue e.g. an hrtimer and to enter then the scheduler,
40f36eb171SAnna-Maria Behnsen  * it is also valuable to use udelay(). But it is not simple to specify a
41f36eb171SAnna-Maria Behnsen  * generic threshold for this which will fit for all systems. An approximation
42f36eb171SAnna-Maria Behnsen  * is a threshold for all delays up to 10 microseconds.
43f36eb171SAnna-Maria Behnsen  *
44f36eb171SAnna-Maria Behnsen  * When having a delay which is larger than the architecture specific
45f36eb171SAnna-Maria Behnsen  * %MAX_UDELAY_MS value, please make sure mdelay() is used. Otherwise a overflow
46f36eb171SAnna-Maria Behnsen  * risk is given.
47f36eb171SAnna-Maria Behnsen  *
48f36eb171SAnna-Maria Behnsen  * Please note that ndelay(), udelay() and mdelay() may return early for several
49f36eb171SAnna-Maria Behnsen  * reasons (https://lists.openwall.net/linux-kernel/2011/01/09/56):
50f36eb171SAnna-Maria Behnsen  *
51f36eb171SAnna-Maria Behnsen  * #. computed loops_per_jiffy too low (due to the time taken to execute the
52f36eb171SAnna-Maria Behnsen  *    timer interrupt.)
53f36eb171SAnna-Maria Behnsen  * #. cache behaviour affecting the time it takes to execute the loop function.
54f36eb171SAnna-Maria Behnsen  * #. CPU clock rate changes.
55f36eb171SAnna-Maria Behnsen  */
56*19e2d91dSAnna-Maria Behnsen static __always_inline void udelay(unsigned long usec)
57*19e2d91dSAnna-Maria Behnsen {
58*19e2d91dSAnna-Maria Behnsen 	if (__builtin_constant_p(usec)) {
59*19e2d91dSAnna-Maria Behnsen 		if (usec >= DELAY_CONST_MAX)
60*19e2d91dSAnna-Maria Behnsen 			__bad_udelay();
61*19e2d91dSAnna-Maria Behnsen 		else
62*19e2d91dSAnna-Maria Behnsen 			__const_udelay(usec * UDELAY_CONST_MULT);
63*19e2d91dSAnna-Maria Behnsen 	} else {
64*19e2d91dSAnna-Maria Behnsen 		__udelay(usec);
65*19e2d91dSAnna-Maria Behnsen 	}
66*19e2d91dSAnna-Maria Behnsen }
6730ab2b03SJonas Bonn 
68f36eb171SAnna-Maria Behnsen /**
69f36eb171SAnna-Maria Behnsen  * ndelay - Inserting a delay based on nanoseconds with busy waiting
70f36eb171SAnna-Maria Behnsen  * @nsec:	requested delay in nanoseconds
71f36eb171SAnna-Maria Behnsen  *
72f36eb171SAnna-Maria Behnsen  * See udelay() for basic information about ndelay() and it's variants.
73f36eb171SAnna-Maria Behnsen  */
74*19e2d91dSAnna-Maria Behnsen static __always_inline void ndelay(unsigned long nsec)
75*19e2d91dSAnna-Maria Behnsen {
76*19e2d91dSAnna-Maria Behnsen 	if (__builtin_constant_p(nsec)) {
77*19e2d91dSAnna-Maria Behnsen 		if (nsec >= DELAY_CONST_MAX)
78*19e2d91dSAnna-Maria Behnsen 			__bad_udelay();
79*19e2d91dSAnna-Maria Behnsen 		else
80*19e2d91dSAnna-Maria Behnsen 			__const_udelay(nsec * NDELAY_CONST_MULT);
81*19e2d91dSAnna-Maria Behnsen 	} else {
82*19e2d91dSAnna-Maria Behnsen 		__udelay(nsec);
83*19e2d91dSAnna-Maria Behnsen 	}
84*19e2d91dSAnna-Maria Behnsen }
85*19e2d91dSAnna-Maria Behnsen #define ndelay(x) ndelay(x)
86aafe4dbeSArnd Bergmann 
87aafe4dbeSArnd Bergmann #endif /* __ASM_GENERIC_DELAY_H */
88