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