* [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
* [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 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
* 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).