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::{ 49 /// Io, 50 /// Mmio, 51 /// Region, 52 /// poll::read_poll_timeout, // 53 /// }; 54 /// use kernel::time::Delta; 55 /// 56 /// const HW_READY: u16 = 0x01; 57 /// 58 /// fn wait_for_hardware<const SIZE: usize>(io: Mmio<'_, Region<SIZE>>) -> Result { 59 /// read_poll_timeout( 60 /// // The `op` closure reads the value of a specific status register. 61 /// || io.try_read16(0x1000), 62 /// // The `cond` closure takes a reference to the value returned by `op` 63 /// // and checks whether the hardware is ready. 64 /// |val: &u16| *val == HW_READY, 65 /// Delta::from_millis(50), 66 /// Delta::from_secs(3), 67 /// )?; 68 /// Ok(()) 69 /// } 70 /// ``` 71 #[track_caller] 72 pub fn read_poll_timeout<Op, Cond, T>( 73 mut op: Op, 74 mut cond: Cond, 75 sleep_delta: Delta, 76 timeout_delta: Delta, 77 ) -> Result<T> 78 where 79 Op: FnMut() -> Result<T>, 80 Cond: FnMut(&T) -> bool, 81 { 82 let start: Instant<Monotonic> = Instant::now(); 83 84 // Unlike the C version, we always call `might_sleep()` unconditionally, 85 // as conditional calls are error-prone. We clearly separate 86 // `read_poll_timeout()` and `read_poll_timeout_atomic()` to aid 87 // tools like klint. 88 might_sleep(); 89 90 loop { 91 let val = op()?; 92 if cond(&val) { 93 // Unlike the C version, we immediately return. 94 // We know the condition is met so we don't need to check again. 95 return Ok(val); 96 } 97 98 if start.elapsed() > timeout_delta { 99 // Unlike the C version, we immediately return. 100 // We have just called `op()` so we don't need to call it again. 101 return Err(ETIMEDOUT); 102 } 103 104 if !sleep_delta.is_zero() { 105 fsleep(sleep_delta); 106 } 107 108 // `fsleep()` could be a busy-wait loop so we always call `cpu_relax()`. 109 cpu_relax(); 110 } 111 } 112 113 /// Polls periodically until a condition is met, an error occurs, 114 /// or the attempt limit is reached. 115 /// 116 /// The function repeatedly executes the given operation `op` closure and 117 /// checks its result using the condition closure `cond`. 118 /// 119 /// If `cond` returns `true`, the function returns successfully with the result of `op`. 120 /// Otherwise, it performs a busy wait for a duration specified by `delay_delta` 121 /// before executing `op` again. 122 /// 123 /// This process continues until either `op` returns an error, `cond` 124 /// returns `true`, or the attempt limit specified by `retry` is reached. 125 /// 126 /// # Errors 127 /// 128 /// If `op` returns an error, then that error is returned directly. 129 /// 130 /// If the attempt limit specified by `retry` is reached, then 131 /// `Err(ETIMEDOUT)` is returned. 132 /// 133 /// # Examples 134 /// 135 /// ```no_run 136 /// use kernel::io::{ 137 /// Io, 138 /// Mmio, 139 /// Region, 140 /// poll::read_poll_timeout_atomic, // 141 /// }; 142 /// use kernel::time::Delta; 143 /// 144 /// const HW_READY: u16 = 0x01; 145 /// 146 /// fn wait_for_hardware<const SIZE: usize>(io: Mmio<'_, Region<SIZE>>) -> Result { 147 /// read_poll_timeout_atomic( 148 /// // The `op` closure reads the value of a specific status register. 149 /// || io.try_read16(0x1000), 150 /// // The `cond` closure takes a reference to the value returned by `op` 151 /// // and checks whether the hardware is ready. 152 /// |val: &u16| *val == HW_READY, 153 /// Delta::from_micros(50), 154 /// 1000, 155 /// )?; 156 /// Ok(()) 157 /// } 158 /// ``` 159 pub fn read_poll_timeout_atomic<Op, Cond, T>( 160 mut op: Op, 161 mut cond: Cond, 162 delay_delta: Delta, 163 retry: usize, 164 ) -> Result<T> 165 where 166 Op: FnMut() -> Result<T>, 167 Cond: FnMut(&T) -> bool, 168 { 169 for _ in 0..retry { 170 let val = op()?; 171 if cond(&val) { 172 return Ok(val); 173 } 174 175 if !delay_delta.is_zero() { 176 udelay(delay_delta); 177 } 178 179 cpu_relax(); 180 } 181 182 Err(ETIMEDOUT) 183 } 184