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