1 // SPDX-License-Identifier: GPL-2.0 2 3 //! IO polling. 4 //! 5 //! C header: [`include/linux/iopoll.h`](srctree/include/linux/iopoll.h). 6 7 use crate::{ 8 prelude::*, 9 processor::cpu_relax, 10 task::might_sleep, 11 time::{ 12 delay::{ 13 fsleep, 14 udelay, // 15 }, 16 Delta, 17 Instant, 18 Monotonic, // 19 }, 20 }; 21 22 /// Polls periodically until a condition is met, an error occurs, 23 /// or the timeout is reached. 24 /// 25 /// The function repeatedly executes the given operation `op` closure and 26 /// checks its result using the condition closure `cond`. 27 /// 28 /// If `cond` returns `true`, the function returns successfully with 29 /// the result of `op`. Otherwise, it waits for a duration specified 30 /// by `sleep_delta` before executing `op` again. 31 /// 32 /// This process continues until either `op` returns an error, `cond` 33 /// returns `true`, or the timeout specified by `timeout_delta` is 34 /// reached. 35 /// 36 /// This function can only be used in a nonatomic context. 37 /// 38 /// # Errors 39 /// 40 /// If `op` returns an error, then that error is returned directly. 41 /// 42 /// If the timeout specified by `timeout_delta` is reached, then 43 /// `Err(ETIMEDOUT)` is returned. 44 /// 45 /// # Examples 46 /// 47 /// ```no_run 48 /// use kernel::io::{Io, poll::read_poll_timeout}; 49 /// use kernel::time::Delta; 50 /// 51 /// const HW_READY: u16 = 0x01; 52 /// 53 /// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result { 54 /// read_poll_timeout( 55 /// // The `op` closure reads the value of a specific status register. 56 /// || io.try_read16(0x1000), 57 /// // The `cond` closure takes a reference to the value returned by `op` 58 /// // and checks whether the hardware is ready. 59 /// |val: &u16| *val == HW_READY, 60 /// Delta::from_millis(50), 61 /// Delta::from_secs(3), 62 /// )?; 63 /// Ok(()) 64 /// } 65 /// ``` 66 #[track_caller] 67 pub fn read_poll_timeout<Op, Cond, T>( 68 mut op: Op, 69 mut cond: Cond, 70 sleep_delta: Delta, 71 timeout_delta: Delta, 72 ) -> Result<T> 73 where 74 Op: FnMut() -> Result<T>, 75 Cond: FnMut(&T) -> bool, 76 { 77 let start: Instant<Monotonic> = Instant::now(); 78 79 // Unlike the C version, we always call `might_sleep()` unconditionally, 80 // as conditional calls are error-prone. We clearly separate 81 // `read_poll_timeout()` and `read_poll_timeout_atomic()` to aid 82 // tools like klint. 83 might_sleep(); 84 85 loop { 86 let val = op()?; 87 if cond(&val) { 88 // Unlike the C version, we immediately return. 89 // We know the condition is met so we don't need to check again. 90 return Ok(val); 91 } 92 93 if start.elapsed() > timeout_delta { 94 // Unlike the C version, we immediately return. 95 // We have just called `op()` so we don't need to call it again. 96 return Err(ETIMEDOUT); 97 } 98 99 if !sleep_delta.is_zero() { 100 fsleep(sleep_delta); 101 } 102 103 // `fsleep()` could be a busy-wait loop so we always call `cpu_relax()`. 104 cpu_relax(); 105 } 106 } 107 108 /// Polls periodically until a condition is met, an error occurs, 109 /// or the attempt limit is reached. 110 /// 111 /// The function repeatedly executes the given operation `op` closure and 112 /// checks its result using the condition closure `cond`. 113 /// 114 /// If `cond` returns `true`, the function returns successfully with the result of `op`. 115 /// Otherwise, it performs a busy wait for a duration specified by `delay_delta` 116 /// before executing `op` again. 117 /// 118 /// This process continues until either `op` returns an error, `cond` 119 /// returns `true`, or the attempt limit specified by `retry` is reached. 120 /// 121 /// # Errors 122 /// 123 /// If `op` returns an error, then that error is returned directly. 124 /// 125 /// If the attempt limit specified by `retry` is reached, then 126 /// `Err(ETIMEDOUT)` is returned. 127 /// 128 /// # Examples 129 /// 130 /// ```no_run 131 /// use kernel::io::{poll::read_poll_timeout_atomic, Io}; 132 /// use kernel::time::Delta; 133 /// 134 /// const HW_READY: u16 = 0x01; 135 /// 136 /// fn wait_for_hardware<const SIZE: usize>(io: &Io<SIZE>) -> Result { 137 /// read_poll_timeout_atomic( 138 /// // The `op` closure reads the value of a specific status register. 139 /// || io.try_read16(0x1000), 140 /// // The `cond` closure takes a reference to the value returned by `op` 141 /// // and checks whether the hardware is ready. 142 /// |val: &u16| *val == HW_READY, 143 /// Delta::from_micros(50), 144 /// 1000, 145 /// )?; 146 /// Ok(()) 147 /// } 148 /// ``` 149 pub fn read_poll_timeout_atomic<Op, Cond, T>( 150 mut op: Op, 151 mut cond: Cond, 152 delay_delta: Delta, 153 retry: usize, 154 ) -> Result<T> 155 where 156 Op: FnMut() -> Result<T>, 157 Cond: FnMut(&T) -> bool, 158 { 159 for _ in 0..retry { 160 let val = op()?; 161 if cond(&val) { 162 return Ok(val); 163 } 164 165 if !delay_delta.is_zero() { 166 udelay(delay_delta); 167 } 168 169 cpu_relax(); 170 } 171 172 Err(ETIMEDOUT) 173 } 174