|
@@ -0,0 +1,105 @@
|
|
|
+delays - Information on the various kernel delay / sleep mechanisms
|
|
|
+-------------------------------------------------------------------
|
|
|
+
|
|
|
+This document seeks to answer the common question: "What is the
|
|
|
+RightWay (TM) to insert a delay?"
|
|
|
+
|
|
|
+This question is most often faced by driver writers who have to
|
|
|
+deal with hardware delays and who may not be the most intimately
|
|
|
+familiar with the inner workings of the Linux Kernel.
|
|
|
+
|
|
|
+
|
|
|
+Inserting Delays
|
|
|
+----------------
|
|
|
+
|
|
|
+The first, and most important, question you need to ask is "Is my
|
|
|
+code in an atomic context?" This should be followed closely by "Does
|
|
|
+it really need to delay in atomic context?" If so...
|
|
|
+
|
|
|
+ATOMIC CONTEXT:
|
|
|
+ You must use the *delay family of functions. These
|
|
|
+ functions use the jiffie estimation of clock speed
|
|
|
+ and will busy wait for enough loop cycles to achieve
|
|
|
+ the desired delay:
|
|
|
+
|
|
|
+ ndelay(unsigned long nsecs)
|
|
|
+ udelay(unsigned long usecs)
|
|
|
+ mdelay(unsgined long msecs)
|
|
|
+
|
|
|
+ udelay is the generally preferred API; ndelay-level
|
|
|
+ precision may not actually exist on many non-PC devices.
|
|
|
+
|
|
|
+ mdelay is macro wrapper around udelay, to account for
|
|
|
+ possible overflow when passing large arguments to udelay.
|
|
|
+ In general, use of mdelay is discouraged and code should
|
|
|
+ be refactored to allow for the use of msleep.
|
|
|
+
|
|
|
+NON-ATOMIC CONTEXT:
|
|
|
+ You should use the *sleep[_range] family of functions.
|
|
|
+ There are a few more options here, while any of them may
|
|
|
+ work correctly, using the "right" sleep function will
|
|
|
+ help the scheduler, power management, and just make your
|
|
|
+ driver better :)
|
|
|
+
|
|
|
+ -- Backed by busy-wait loop:
|
|
|
+ udelay(unsigned long usecs)
|
|
|
+ -- Backed by hrtimers:
|
|
|
+ usleep_range(unsigned long min, unsigned long max)
|
|
|
+ -- Backed by jiffies / legacy_timers
|
|
|
+ msleep(unsigned long msecs)
|
|
|
+ msleep_interruptible(unsigned long msecs)
|
|
|
+
|
|
|
+ Unlike the *delay family, the underlying mechanism
|
|
|
+ driving each of these calls varies, thus there are
|
|
|
+ quirks you should be aware of.
|
|
|
+
|
|
|
+
|
|
|
+ SLEEPING FOR "A FEW" USECS ( < ~10us? ):
|
|
|
+ * Use udelay
|
|
|
+
|
|
|
+ - Why not usleep?
|
|
|
+ On slower systems, (embedded, OR perhaps a speed-
|
|
|
+ stepped PC!) the overhead of setting up the hrtimers
|
|
|
+ for usleep *may* not be worth it. Such an evaluation
|
|
|
+ will obviously depend on your specific situation, but
|
|
|
+ it is something to be aware of.
|
|
|
+
|
|
|
+ SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms):
|
|
|
+ * Use usleep_range
|
|
|
+
|
|
|
+ - Why not msleep for (1ms - 20ms)?
|
|
|
+ Explained originally here:
|
|
|
+ http://lkml.org/lkml/2007/8/3/250
|
|
|
+ msleep(1~20) may not do what the caller intends, and
|
|
|
+ will often sleep longer (~20 ms actual sleep for any
|
|
|
+ value given in the 1~20ms range). In many cases this
|
|
|
+ is not the desired behavior.
|
|
|
+
|
|
|
+ - Why is there no "usleep" / What is a good range?
|
|
|
+ Since usleep_range is built on top of hrtimers, the
|
|
|
+ wakeup will be very precise (ish), thus a simple
|
|
|
+ usleep function would likely introduce a large number
|
|
|
+ of undesired interrupts.
|
|
|
+
|
|
|
+ With the introduction of a range, the scheduler is
|
|
|
+ free to coalesce your wakeup with any other wakeup
|
|
|
+ that may have happened for other reasons, or at the
|
|
|
+ worst case, fire an interrupt for your upper bound.
|
|
|
+
|
|
|
+ The larger a range you supply, the greater a chance
|
|
|
+ that you will not trigger an interrupt; this should
|
|
|
+ be balanced with what is an acceptable upper bound on
|
|
|
+ delay / performance for your specific code path. Exact
|
|
|
+ tolerances here are very situation specific, thus it
|
|
|
+ is left to the caller to determine a reasonable range.
|
|
|
+
|
|
|
+ SLEEPING FOR LARGER MSECS ( 10ms+ )
|
|
|
+ * Use msleep or possibly msleep_interruptible
|
|
|
+
|
|
|
+ - What's the difference?
|
|
|
+ msleep sets the current task to TASK_UNINTERRUPTIBLE
|
|
|
+ whereas msleep_interruptible sets the current task to
|
|
|
+ TASK_INTERRUPTIBLE before scheduling the sleep. In
|
|
|
+ short, the difference is whether the sleep can be ended
|
|
|
+ early by a signal. In general, just use msleep unless
|
|
|
+ you know you have a need for the interruptible variant.
|