* [PATCH v3 0/2] Add read_poll_timeout_atomic support @ 2025-10-26 12:54 FUJITA Tomonori 2025-10-26 12:54 ` [PATCH v3 1/2] rust: add udelay() function FUJITA Tomonori 2025-10-26 12:54 ` [PATCH v3 2/2] rust: Add read_poll_timeout_atomic function FUJITA Tomonori 0 siblings, 2 replies; 6+ messages in thread From: FUJITA Tomonori @ 2025-10-26 12:54 UTC (permalink / raw) To: a.hindborg, alex.gaynor, aliceryhl, dakr, daniel.almeida, ojeda Cc: anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross Add read_poll_timeout_atomic function which polls periodically until a condition is met, an error occurs, or the attempt limit is reached. This helper is used to wait for a condition in atomic context, mirroring the C's read_poll_timeout_atomic(). In atomic context, the timekeeping infrastructure is unavailable, so reliable time-based timeouts cannot be implemented. So instead, the helper accepts a maximum number of attempts and busy-waits (udelay + cpu_relax) between tries. v2: https://lore.kernel.org/lkml/20251021071146.2357069-1-fujita.tomonori@gmail.com/ - revert the function name - simplify the example code - add debug_assert to check the range for udelay v1: https://lore.kernel.org/lkml/20250821035710.3692455-1-fujita.tomonori@gmail.com/ - use the attempt limit instead of timeout - rename the function to read_poll_count_atomic - add the comment about C's udelay behavior. FUJITA Tomonori (2): rust: add udelay() function rust: Add read_poll_timeout_atomic function rust/helpers/time.c | 5 +++ rust/kernel/io/poll.rs | 72 ++++++++++++++++++++++++++++++++++++++- rust/kernel/time/delay.rs | 39 +++++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) base-commit: 26c1a20bf7ce76e9afe4030f25bec20e3c63dcf8 -- 2.43.0 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 1/2] rust: add udelay() function 2025-10-26 12:54 [PATCH v3 0/2] Add read_poll_timeout_atomic support FUJITA Tomonori @ 2025-10-26 12:54 ` FUJITA Tomonori 2025-10-27 9:48 ` Andreas Hindborg 2025-10-28 9:55 ` Alice Ryhl 2025-10-26 12:54 ` [PATCH v3 2/2] rust: Add read_poll_timeout_atomic function FUJITA Tomonori 1 sibling, 2 replies; 6+ messages in thread From: FUJITA Tomonori @ 2025-10-26 12:54 UTC (permalink / raw) To: a.hindborg, alex.gaynor, aliceryhl, dakr, daniel.almeida, ojeda Cc: anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross Add udelay() function, inserts a delay based on microseconds with busy waiting, in preparation for supporting read_poll_timeout_atomic(). Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> --- rust/helpers/time.c | 5 +++++ rust/kernel/time/delay.rs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/rust/helpers/time.c b/rust/helpers/time.c index a318e9fa4408..67a36ccc3ec4 100644 --- a/rust/helpers/time.c +++ b/rust/helpers/time.c @@ -33,3 +33,8 @@ s64 rust_helper_ktime_to_ms(const ktime_t kt) { return ktime_to_ms(kt); } + +void rust_helper_udelay(unsigned long usec) +{ + udelay(usec); +} diff --git a/rust/kernel/time/delay.rs b/rust/kernel/time/delay.rs index eb8838da62bc..0739b75fb9c3 100644 --- a/rust/kernel/time/delay.rs +++ b/rust/kernel/time/delay.rs @@ -47,3 +47,42 @@ pub fn fsleep(delta: Delta) { bindings::fsleep(delta.as_micros_ceil() as c_ulong) } } + +/// Inserts a delay based on microseconds with busy waiting. +/// +/// Equivalent to the C side [`udelay()`], which delays in microseconds. +/// +/// `delta` must be within `[0, `MAX_UDELAY_MS`]` in milliseconds; +/// otherwise, it is erroneous behavior. That is, it is considered a bug to +/// call this function with an out-of-range value, in which case the function +/// will insert a delay for at least the maximum value in the range and +/// may warn in the future. +/// +/// The behavior above differs from the C side [`udelay()`] for which out-of-range +/// values could lead to an overflow and unexpected behavior. +/// +/// [`udelay()`]: https://docs.kernel.org/timers/delay_sleep_functions.html#c.udelay +pub fn udelay(delta: Delta) { + const MAX_UDELAY_DELTA: Delta = Delta::from_millis(bindings::MAX_UDELAY_MS as i64); + + debug_assert!(delta.as_nanos() >= 0); + debug_assert!(delta <= MAX_UDELAY_DELTA); + + let delta = if (Delta::ZERO..=MAX_UDELAY_DELTA).contains(&delta) { + delta + } else { + MAX_UDELAY_DELTA + }; + + // SAFETY: It is always safe to call `udelay()` with any duration. + // Note that the kernel is compiled with `-fno-strict-overflow` + // so any out-of-range value could lead to unexpected behavior + // but won't lead to undefined behavior. + unsafe { + // Convert the duration to microseconds and round up to preserve + // the guarantee; `udelay()` inserts a delay for at least + // the provided duration, but that it may delay for longer + // under some circumstances. + bindings::udelay(delta.as_micros_ceil() as c_ulong) + } +} -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 1/2] rust: add udelay() function 2025-10-26 12:54 ` [PATCH v3 1/2] rust: add udelay() function FUJITA Tomonori @ 2025-10-27 9:48 ` Andreas Hindborg 2025-10-28 9:55 ` Alice Ryhl 1 sibling, 0 replies; 6+ messages in thread From: Andreas Hindborg @ 2025-10-27 9:48 UTC (permalink / raw) To: FUJITA Tomonori, alex.gaynor, aliceryhl, dakr, daniel.almeida, ojeda Cc: anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross "FUJITA Tomonori" <fujita.tomonori@gmail.com> writes: > Add udelay() function, inserts a delay based on microseconds with busy > waiting, in preparation for supporting read_poll_timeout_atomic(). > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org> Best regards, Andreas Hindborg ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 1/2] rust: add udelay() function 2025-10-26 12:54 ` [PATCH v3 1/2] rust: add udelay() function FUJITA Tomonori 2025-10-27 9:48 ` Andreas Hindborg @ 2025-10-28 9:55 ` Alice Ryhl 1 sibling, 0 replies; 6+ messages in thread From: Alice Ryhl @ 2025-10-28 9:55 UTC (permalink / raw) To: FUJITA Tomonori Cc: a.hindborg, alex.gaynor, dakr, daniel.almeida, ojeda, anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross On Sun, Oct 26, 2025 at 09:54:57PM +0900, FUJITA Tomonori wrote: > Add udelay() function, inserts a delay based on microseconds with busy > waiting, in preparation for supporting read_poll_timeout_atomic(). > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> With below nits addressed: Reviewed-by: Alice Ryhl <aliceryhl@google.com> > --- > rust/helpers/time.c | 5 +++++ > rust/kernel/time/delay.rs | 39 +++++++++++++++++++++++++++++++++++++++ > 2 files changed, 44 insertions(+) > > diff --git a/rust/helpers/time.c b/rust/helpers/time.c > index a318e9fa4408..67a36ccc3ec4 100644 > --- a/rust/helpers/time.c > +++ b/rust/helpers/time.c > @@ -33,3 +33,8 @@ s64 rust_helper_ktime_to_ms(const ktime_t kt) > { > return ktime_to_ms(kt); > } > + > +void rust_helper_udelay(unsigned long usec) > +{ > + udelay(usec); > +} > diff --git a/rust/kernel/time/delay.rs b/rust/kernel/time/delay.rs > index eb8838da62bc..0739b75fb9c3 100644 > --- a/rust/kernel/time/delay.rs > +++ b/rust/kernel/time/delay.rs > @@ -47,3 +47,42 @@ pub fn fsleep(delta: Delta) { > bindings::fsleep(delta.as_micros_ceil() as c_ulong) > } > } > + > +/// Inserts a delay based on microseconds with busy waiting. > +/// > +/// Equivalent to the C side [`udelay()`], which delays in microseconds. > +/// > +/// `delta` must be within `[0, `MAX_UDELAY_MS`]` in milliseconds; We can nest backticks. This should be: `[0, MAX_UDELAY_MS]` > +/// otherwise, it is erroneous behavior. That is, it is considered a bug to > +/// call this function with an out-of-range value, in which case the function > +/// will insert a delay for at least the maximum value in the range and > +/// may warn in the future. There's a debug assertion now so I would remove the "maxmimu value" part. > +/// The behavior above differs from the C side [`udelay()`] for which out-of-range > +/// values could lead to an overflow and unexpected behavior. > +/// > +/// [`udelay()`]: https://docs.kernel.org/timers/delay_sleep_functions.html#c.udelay > +pub fn udelay(delta: Delta) { > + const MAX_UDELAY_DELTA: Delta = Delta::from_millis(bindings::MAX_UDELAY_MS as i64); > + > + debug_assert!(delta.as_nanos() >= 0); > + debug_assert!(delta <= MAX_UDELAY_DELTA); > + > + let delta = if (Delta::ZERO..=MAX_UDELAY_DELTA).contains(&delta) { > + delta > + } else { > + MAX_UDELAY_DELTA > + }; > + > + // SAFETY: It is always safe to call `udelay()` with any duration. > + // Note that the kernel is compiled with `-fno-strict-overflow` > + // so any out-of-range value could lead to unexpected behavior > + // but won't lead to undefined behavior. > + unsafe { > + // Convert the duration to microseconds and round up to preserve > + // the guarantee; `udelay()` inserts a delay for at least > + // the provided duration, but that it may delay for longer > + // under some circumstances. > + bindings::udelay(delta.as_micros_ceil() as c_ulong) > + } > +} > -- > 2.43.0 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 2/2] rust: Add read_poll_timeout_atomic function 2025-10-26 12:54 [PATCH v3 0/2] Add read_poll_timeout_atomic support FUJITA Tomonori 2025-10-26 12:54 ` [PATCH v3 1/2] rust: add udelay() function FUJITA Tomonori @ 2025-10-26 12:54 ` FUJITA Tomonori 2025-10-28 9:56 ` Alice Ryhl 1 sibling, 1 reply; 6+ messages in thread From: FUJITA Tomonori @ 2025-10-26 12:54 UTC (permalink / raw) To: a.hindborg, alex.gaynor, aliceryhl, dakr, daniel.almeida, ojeda Cc: anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross Add read_poll_timeout_atomic function which polls periodically until a condition is met, an error occurs, or the attempt limit is reached. The C's read_poll_timeout_atomic() is used for the similar purpose. In atomic context the timekeeping infrastructure is unavailable, so reliable time-based timeouts cannot be implemented. So instead, the helper accepts a maximum number of attempts and busy-waits (udelay + cpu_relax) between tries. Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> --- rust/kernel/io/poll.rs | 72 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/rust/kernel/io/poll.rs b/rust/kernel/io/poll.rs index 613eb25047ef..65c8ec3fb683 100644 --- a/rust/kernel/io/poll.rs +++ b/rust/kernel/io/poll.rs @@ -8,7 +8,10 @@ error::{code::*, Result}, processor::cpu_relax, task::might_sleep, - time::{delay::fsleep, Delta, Instant, Monotonic}, + time::{ + delay::{fsleep, udelay}, + Delta, Instant, Monotonic, + }, }; /// Polls periodically until a condition is met, an error occurs, @@ -102,3 +105,70 @@ pub fn read_poll_timeout<Op, Cond, T>( 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::{poll::read_poll_timeout_atomic, Io}; +/// use kernel::time::Delta; +/// +/// const HW_READY: u16 = 0x01; +/// +/// fn wait_for_hardware<const SIZE: usize>(io: &Io<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) +} -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/2] rust: Add read_poll_timeout_atomic function 2025-10-26 12:54 ` [PATCH v3 2/2] rust: Add read_poll_timeout_atomic function FUJITA Tomonori @ 2025-10-28 9:56 ` Alice Ryhl 0 siblings, 0 replies; 6+ messages in thread From: Alice Ryhl @ 2025-10-28 9:56 UTC (permalink / raw) To: FUJITA Tomonori Cc: a.hindborg, alex.gaynor, dakr, daniel.almeida, ojeda, anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz, linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross On Sun, Oct 26, 2025 at 09:54:58PM +0900, FUJITA Tomonori wrote: > Add read_poll_timeout_atomic function which polls periodically until a > condition is met, an error occurs, or the attempt limit is reached. > > The C's read_poll_timeout_atomic() is used for the similar purpose. > In atomic context the timekeeping infrastructure is unavailable, so > reliable time-based timeouts cannot be implemented. So instead, the > helper accepts a maximum number of attempts and busy-waits (udelay + > cpu_relax) between tries. > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> Reviewed-by: Alice Ryhl <aliceryhl@google.com> ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-10-28 9:56 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-10-26 12:54 [PATCH v3 0/2] Add read_poll_timeout_atomic support FUJITA Tomonori 2025-10-26 12:54 ` [PATCH v3 1/2] rust: add udelay() function FUJITA Tomonori 2025-10-27 9:48 ` Andreas Hindborg 2025-10-28 9:55 ` Alice Ryhl 2025-10-26 12:54 ` [PATCH v3 2/2] rust: Add read_poll_timeout_atomic function FUJITA Tomonori 2025-10-28 9:56 ` Alice Ryhl
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).