summaryrefslogtreecommitdiffstats
path: root/include/linux/delay.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/delay.h')
-rw-r--r--include/linux/delay.h91
1 files changed, 91 insertions, 0 deletions
diff --git a/include/linux/delay.h b/include/linux/delay.h
new file mode 100644
index 000000000..039e7e0c7
--- /dev/null
+++ b/include/linux/delay.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_DELAY_H
+#define _LINUX_DELAY_H
+
+/*
+ * Copyright (C) 1993 Linus Torvalds
+ *
+ * Delay routines, using a pre-computed "loops_per_jiffy" value.
+ *
+ * Please note that ndelay(), udelay() and mdelay() may return early for
+ * several reasons:
+ * 1. computed loops_per_jiffy too low (due to the time taken to
+ * execute the timer interrupt.)
+ * 2. cache behaviour affecting the time it takes to execute the
+ * loop function.
+ * 3. CPU clock rate changes.
+ *
+ * Please see this thread:
+ * https://lists.openwall.net/linux-kernel/2011/01/09/56
+ */
+
+#include <linux/math.h>
+#include <linux/sched.h>
+
+extern unsigned long loops_per_jiffy;
+
+#include <asm/delay.h>
+
+/*
+ * Using udelay() for intervals greater than a few milliseconds can
+ * risk overflow for high loops_per_jiffy (high bogomips) machines. The
+ * mdelay() provides a wrapper to prevent this. For delays greater
+ * than MAX_UDELAY_MS milliseconds, the wrapper is used. Architecture
+ * specific values can be defined in asm-???/delay.h as an override.
+ * The 2nd mdelay() definition ensures GCC will optimize away the
+ * while loop for the common cases where n <= MAX_UDELAY_MS -- Paul G.
+ */
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_MS 5
+#endif
+
+#ifndef mdelay
+#define mdelay(n) (\
+ (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
+ ({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
+#endif
+
+#ifndef ndelay
+static inline void ndelay(unsigned long x)
+{
+ udelay(DIV_ROUND_UP(x, 1000));
+}
+#define ndelay(x) ndelay(x)
+#endif
+
+extern unsigned long lpj_fine;
+void calibrate_delay(void);
+void __attribute__((weak)) calibration_delay_done(void);
+void msleep(unsigned int msecs);
+unsigned long msleep_interruptible(unsigned int msecs);
+void usleep_range_state(unsigned long min, unsigned long max,
+ unsigned int state);
+
+static inline void usleep_range(unsigned long min, unsigned long max)
+{
+ usleep_range_state(min, max, TASK_UNINTERRUPTIBLE);
+}
+
+static inline void usleep_idle_range(unsigned long min, unsigned long max)
+{
+ usleep_range_state(min, max, TASK_IDLE);
+}
+
+static inline void ssleep(unsigned int seconds)
+{
+ msleep(seconds * 1000);
+}
+
+/* see Documentation/timers/timers-howto.rst for the thresholds */
+static inline void fsleep(unsigned long usecs)
+{
+ if (usecs <= 10)
+ udelay(usecs);
+ else if (usecs <= 20000)
+ usleep_range(usecs, 2 * usecs);
+ else
+ msleep(DIV_ROUND_UP(usecs, 1000));
+}
+
+#endif /* defined(_LINUX_DELAY_H) */