Skip to content

Commit 19e2d91

Browse files
anna-marialxKAGA-KOKO
authored andcommitted
delay: Rework udelay and ndelay
udelay() as well as ndelay() are defines and no functions and are using constants to be able to transform a sleep time into loops and to prevent too long udelays/ndelays. There was a compiler error with non-const 8 bit arguments which was fixed by commit a87e553 ("asm-generic: delay.h fix udelay and ndelay for 8 bit args"). When using a function, the non-const 8 bit argument is type casted and the problem would be gone. Transform udelay() and ndelay() into proper functions, remove the no longer and confusing division, add defines for the magic values and add some explanations as well. Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Anna-Maria Behnsen <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Frederic Weisbecker <[email protected]> Link: https://lore.kernel.org/all/20241014-devel-anna-maria-b4-timers-flseep-v3-6-dc8b907cb62f@linutronix.de
1 parent f36eb17 commit 19e2d91

File tree

1 file changed

+37
-28
lines changed

1 file changed

+37
-28
lines changed

include/asm-generic/delay.h

+37-28
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#ifndef __ASM_GENERIC_DELAY_H
33
#define __ASM_GENERIC_DELAY_H
44

5+
#include <linux/math.h>
6+
#include <vdso/time64.h>
7+
58
/* Undefined functions to get compile-time errors */
69
extern void __bad_udelay(void);
710
extern void __bad_ndelay(void);
@@ -12,13 +15,18 @@ extern void __const_udelay(unsigned long xloops);
1215
extern void __delay(unsigned long loops);
1316

1417
/*
15-
* Implementation details:
16-
*
17-
* * The weird n/20000 thing suppresses a "comparison is always false due to
18-
* limited range of data type" warning with non-const 8-bit arguments.
19-
* * 0x10c7 is 2**32 / 1000000 (rounded up) -> udelay
20-
* * 0x5 is 2**32 / 1000000000 (rounded up) -> ndelay
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.
2128
*/
29+
#define DELAY_CONST_MAX 20000
2230

2331
/**
2432
* udelay - Inserting a delay based on microseconds with busy waiting
@@ -45,34 +53,35 @@ extern void __delay(unsigned long loops);
4553
* #. cache behaviour affecting the time it takes to execute the loop function.
4654
* #. CPU clock rate changes.
4755
*/
48-
#define udelay(n) \
49-
({ \
50-
if (__builtin_constant_p(n)) { \
51-
if ((n) / 20000 >= 1) \
52-
__bad_udelay(); \
53-
else \
54-
__const_udelay((n) * 0x10c7ul); \
55-
} else { \
56-
__udelay(n); \
57-
} \
58-
})
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+
}
5967

6068
/**
6169
* ndelay - Inserting a delay based on nanoseconds with busy waiting
6270
* @nsec: requested delay in nanoseconds
6371
*
6472
* See udelay() for basic information about ndelay() and it's variants.
6573
*/
66-
#define ndelay(n) \
67-
({ \
68-
if (__builtin_constant_p(n)) { \
69-
if ((n) / 20000 >= 1) \
70-
__bad_ndelay(); \
71-
else \
72-
__const_udelay((n) * 5ul); \
73-
} else { \
74-
__ndelay(n); \
75-
} \
76-
})
74+
static __always_inline void ndelay(unsigned long nsec)
75+
{
76+
if (__builtin_constant_p(nsec)) {
77+
if (nsec >= DELAY_CONST_MAX)
78+
__bad_udelay();
79+
else
80+
__const_udelay(nsec * NDELAY_CONST_MULT);
81+
} else {
82+
__udelay(nsec);
83+
}
84+
}
85+
#define ndelay(x) ndelay(x)
7786

7887
#endif /* __ASM_GENERIC_DELAY_H */

0 commit comments

Comments
 (0)