Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182// SPDX-License-Identifier: GPL-2.0
//! IO polling.//!//! C header: [`include/linux/iopoll.h`](srctree/include/linux/iopoll.h).
use crate::{ prelude::*, processor::cpu_relax, task::might_sleep, time::{ delay::{ fsleep, udelay, // }, Delta, Instant, Monotonic, // },};
/// Polls periodically until a condition is met, an error occurs,/// or the timeout is reached.////// The function repeatedly executes the given operation `op` closure and/// checks its result using the condition closure `cond`.////// If `cond` returns `true`, the function returns successfully with/// the result of `op`. Otherwise, it waits for a duration specified/// by `sleep_delta` before executing `op` again.////// This process continues until either `op` returns an error, `cond`/// returns `true`, or the timeout specified by `timeout_delta` is/// reached.////// This function can only be used in a nonatomic context.////// # Errors////// If `op` returns an error, then that error is returned directly.////// If the timeout specified by `timeout_delta` is reached, then/// `Err(ETIMEDOUT)` is returned.////// # Examples////// ```no_run/// use kernel::io::{/// Io,/// Mmio,/// poll::read_poll_timeout, ///// };/// use kernel::time::Delta;////// const HW_READY: u16 = 0x01;////// fn wait_for_hardware<const SIZE: usize>(io: &Mmio<SIZE>) -> Result {/// read_poll_timeout(/// // The `op` closure reads the value of a specific status register./// || io.try_read16(0x1000),/// // The `cond` closure takes a reference to the value returned by `op`/// // and checks whether the hardware is ready./// |val: &u16| *val == HW_READY,/// Delta::from_millis(50),/// Delta::from_secs(3),/// )?;/// Ok(())/// }/// ```#[track_caller]pub fn read_poll_timeout<Op, Cond, T>( mut op: Op, mut cond: Cond, sleep_delta: Delta, timeout_delta: Delta,) -> Result<T>where Op: FnMut() -> Result<T>, Cond: FnMut(&T) -> bool,{ let start: Instant<Monotonic> = Instant::now();
// Unlike the C version, we always call `might_sleep()` unconditionally, // as conditional calls are error-prone. We clearly separate // `read_poll_timeout()` and `read_poll_timeout_atomic()` to aid // tools like klint. might_sleep();
loop { let val = op()?; if cond(&val) { // Unlike the C version, we immediately return. // We know the condition is met so we don't need to check again. return Ok(val); }
if start.elapsed() > timeout_delta { // Unlike the C version, we immediately return. // We have just called `op()` so we don't need to call it again. return Err(ETIMEDOUT); }
if !sleep_delta.is_zero() { fsleep(sleep_delta); }
// `fsleep()` could be a busy-wait loop so we always call `cpu_relax()`. cpu_relax(); }}
/// Polls periodically until a condition is met, an error occurs,/// or the attempt limit is reached.////// The function repeatedly executes the given operation `op` closure and/// checks its result using the condition closure `cond`.////// If `cond` returns `true`, the function returns successfully with the result of `op`./// Otherwise, it performs a busy wait for a duration specified by `delay_delta`/// before executing `op` again.////// This process continues until either `op` returns an error, `cond`/// returns `true`, or the attempt limit specified by `retry` is reached.////// # Errors////// If `op` returns an error, then that error is returned directly.////// If the attempt limit specified by `retry` is reached, then/// `Err(ETIMEDOUT)` is returned.////// # Examples////// ```no_run/// use kernel::io::{/// Io,/// Mmio,/// poll::read_poll_timeout_atomic, ///// };/// use kernel::time::Delta;////// const HW_READY: u16 = 0x01;////// fn wait_for_hardware<const SIZE: usize>(io: &Mmio<SIZE>) -> Result {/// read_poll_timeout_atomic(/// // The `op` closure reads the value of a specific status register./// || io.try_read16(0x1000),/// // The `cond` closure takes a reference to the value returned by `op`/// // and checks whether the hardware is ready./// |val: &u16| *val == HW_READY,/// Delta::from_micros(50),/// 1000,/// )?;/// Ok(())/// }/// ```pub fn read_poll_timeout_atomic<Op, Cond, T>( mut op: Op, mut cond: Cond, delay_delta: Delta, retry: usize,) -> Result<T>where Op: FnMut() -> Result<T>, Cond: FnMut(&T) -> bool,{ for _ in 0..retry { let val = op()?; if cond(&val) { return Ok(val); }
if !delay_delta.is_zero() { udelay(delay_delta); }
cpu_relax(); }
Err(ETIMEDOUT)}