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