xref: /linux/rust/kernel/io/poll.rs (revision eb3289fc474f74105e0627bf508e3f9742fd3b63)
1*349a6425SFUJITA Tomonori // SPDX-License-Identifier: GPL-2.0
2*349a6425SFUJITA Tomonori 
3*349a6425SFUJITA Tomonori //! IO polling.
4*349a6425SFUJITA Tomonori //!
5*349a6425SFUJITA Tomonori //! C header: [`include/linux/iopoll.h`](srctree/include/linux/iopoll.h).
6*349a6425SFUJITA Tomonori 
7*349a6425SFUJITA Tomonori use crate::{
8*349a6425SFUJITA Tomonori     error::{code::*, Result},
9*349a6425SFUJITA Tomonori     processor::cpu_relax,
10*349a6425SFUJITA Tomonori     task::might_sleep,
11*349a6425SFUJITA Tomonori     time::{delay::fsleep, Delta, Instant, Monotonic},
12*349a6425SFUJITA Tomonori };
13*349a6425SFUJITA Tomonori 
14*349a6425SFUJITA Tomonori /// Polls periodically until a condition is met, an error occurs,
15*349a6425SFUJITA Tomonori /// or the timeout is reached.
16*349a6425SFUJITA Tomonori ///
17*349a6425SFUJITA Tomonori /// The function repeatedly executes the given operation `op` closure and
18*349a6425SFUJITA Tomonori /// checks its result using the condition closure `cond`.
19*349a6425SFUJITA Tomonori ///
20*349a6425SFUJITA Tomonori /// If `cond` returns `true`, the function returns successfully with
21*349a6425SFUJITA Tomonori /// the result of `op`. Otherwise, it waits for a duration specified
22*349a6425SFUJITA Tomonori /// by `sleep_delta` before executing `op` again.
23*349a6425SFUJITA Tomonori ///
24*349a6425SFUJITA Tomonori /// This process continues until either `op` returns an error, `cond`
25*349a6425SFUJITA Tomonori /// returns `true`, or the timeout specified by `timeout_delta` is
26*349a6425SFUJITA Tomonori /// reached.
27*349a6425SFUJITA Tomonori ///
28*349a6425SFUJITA Tomonori /// This function can only be used in a nonatomic context.
29*349a6425SFUJITA Tomonori ///
30*349a6425SFUJITA Tomonori /// # Errors
31*349a6425SFUJITA Tomonori ///
32*349a6425SFUJITA Tomonori /// If `op` returns an error, then that error is returned directly.
33*349a6425SFUJITA Tomonori ///
34*349a6425SFUJITA Tomonori /// If the timeout specified by `timeout_delta` is reached, then
35*349a6425SFUJITA Tomonori /// `Err(ETIMEDOUT)` is returned.
36*349a6425SFUJITA Tomonori ///
37*349a6425SFUJITA Tomonori /// # Examples
38*349a6425SFUJITA Tomonori ///
39*349a6425SFUJITA Tomonori /// ```no_run
40*349a6425SFUJITA Tomonori /// use kernel::io::{Io, poll::read_poll_timeout};
41*349a6425SFUJITA Tomonori /// use kernel::time::Delta;
42*349a6425SFUJITA Tomonori ///
43*349a6425SFUJITA Tomonori /// const HW_READY: u16 = 0x01;
44*349a6425SFUJITA Tomonori ///
45*349a6425SFUJITA Tomonori /// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result<()> {
46*349a6425SFUJITA Tomonori ///     match read_poll_timeout(
47*349a6425SFUJITA Tomonori ///         // The `op` closure reads the value of a specific status register.
48*349a6425SFUJITA Tomonori ///         || io.try_read16(0x1000),
49*349a6425SFUJITA Tomonori ///         // The `cond` closure takes a reference to the value returned by `op`
50*349a6425SFUJITA Tomonori ///         // and checks whether the hardware is ready.
51*349a6425SFUJITA Tomonori ///         |val: &u16| *val == HW_READY,
52*349a6425SFUJITA Tomonori ///         Delta::from_millis(50),
53*349a6425SFUJITA Tomonori ///         Delta::from_secs(3),
54*349a6425SFUJITA Tomonori ///     ) {
55*349a6425SFUJITA Tomonori ///         Ok(_) => {
56*349a6425SFUJITA Tomonori ///             // The hardware is ready. The returned value of the `op` closure
57*349a6425SFUJITA Tomonori ///             // isn't used.
58*349a6425SFUJITA Tomonori ///             Ok(())
59*349a6425SFUJITA Tomonori ///         }
60*349a6425SFUJITA Tomonori ///         Err(e) => Err(e),
61*349a6425SFUJITA Tomonori ///     }
62*349a6425SFUJITA Tomonori /// }
63*349a6425SFUJITA Tomonori /// ```
64*349a6425SFUJITA Tomonori #[track_caller]
65*349a6425SFUJITA Tomonori pub fn read_poll_timeout<Op, Cond, T>(
66*349a6425SFUJITA Tomonori     mut op: Op,
67*349a6425SFUJITA Tomonori     mut cond: Cond,
68*349a6425SFUJITA Tomonori     sleep_delta: Delta,
69*349a6425SFUJITA Tomonori     timeout_delta: Delta,
70*349a6425SFUJITA Tomonori ) -> Result<T>
71*349a6425SFUJITA Tomonori where
72*349a6425SFUJITA Tomonori     Op: FnMut() -> Result<T>,
73*349a6425SFUJITA Tomonori     Cond: FnMut(&T) -> bool,
74*349a6425SFUJITA Tomonori {
75*349a6425SFUJITA Tomonori     let start: Instant<Monotonic> = Instant::now();
76*349a6425SFUJITA Tomonori 
77*349a6425SFUJITA Tomonori     // Unlike the C version, we always call `might_sleep()` unconditionally,
78*349a6425SFUJITA Tomonori     // as conditional calls are error-prone. We clearly separate
79*349a6425SFUJITA Tomonori     // `read_poll_timeout()` and `read_poll_timeout_atomic()` to aid
80*349a6425SFUJITA Tomonori     // tools like klint.
81*349a6425SFUJITA Tomonori     might_sleep();
82*349a6425SFUJITA Tomonori 
83*349a6425SFUJITA Tomonori     loop {
84*349a6425SFUJITA Tomonori         let val = op()?;
85*349a6425SFUJITA Tomonori         if cond(&val) {
86*349a6425SFUJITA Tomonori             // Unlike the C version, we immediately return.
87*349a6425SFUJITA Tomonori             // We know the condition is met so we don't need to check again.
88*349a6425SFUJITA Tomonori             return Ok(val);
89*349a6425SFUJITA Tomonori         }
90*349a6425SFUJITA Tomonori 
91*349a6425SFUJITA Tomonori         if start.elapsed() > timeout_delta {
92*349a6425SFUJITA Tomonori             // Unlike the C version, we immediately return.
93*349a6425SFUJITA Tomonori             // We have just called `op()` so we don't need to call it again.
94*349a6425SFUJITA Tomonori             return Err(ETIMEDOUT);
95*349a6425SFUJITA Tomonori         }
96*349a6425SFUJITA Tomonori 
97*349a6425SFUJITA Tomonori         if !sleep_delta.is_zero() {
98*349a6425SFUJITA Tomonori             fsleep(sleep_delta);
99*349a6425SFUJITA Tomonori         }
100*349a6425SFUJITA Tomonori 
101*349a6425SFUJITA Tomonori         // `fsleep()` could be a busy-wait loop so we always call `cpu_relax()`.
102*349a6425SFUJITA Tomonori         cpu_relax();
103*349a6425SFUJITA Tomonori     }
104*349a6425SFUJITA Tomonori }
105