Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/include/asm-generic/delay.h
26285 views
1
/* SPDX-License-Identifier: GPL-2.0 */
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
/* Undefined functions to get compile-time errors */
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 /* __ASM_GENERIC_DELAY_H */
88
89