public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/2] Add read_poll_timeout_atomic support
@ 2025-11-03 11:29 FUJITA Tomonori
  2025-11-03 11:29 ` [PATCH v4 1/2] rust: add udelay() function FUJITA Tomonori
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: FUJITA Tomonori @ 2025-11-03 11:29 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.

v4:
- update the comment on udelay
- add Alice and Andreas' Reviewed-by
v3: https://lore.kernel.org/lkml/20251026125458.2772103-1-fujita.tomonori@gmail.com/
- revert the function name
- simplify the example code
- add debug_assert to check the range for udelay
v2: https://lore.kernel.org/lkml/20251021071146.2357069-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.
v1: https://lore.kernel.org/lkml/20250821035710.3692455-1-fujita.tomonori@gmail.com/

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 | 37 ++++++++++++++++++++
 3 files changed, 113 insertions(+), 1 deletion(-)


base-commit: b0b7301b004301afe920b3d08caa6171dd3f4011
-- 
2.43.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v4 1/2] rust: add udelay() function
  2025-11-03 11:29 [PATCH v4 0/2] Add read_poll_timeout_atomic support FUJITA Tomonori
@ 2025-11-03 11:29 ` FUJITA Tomonori
  2025-11-03 11:29 ` [PATCH v4 2/2] rust: Add read_poll_timeout_atomic function FUJITA Tomonori
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: FUJITA Tomonori @ 2025-11-03 11:29 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().

Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 rust/helpers/time.c       |  5 +++++
 rust/kernel/time/delay.rs | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 42 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..b5b1b42797a0 100644
--- a/rust/kernel/time/delay.rs
+++ b/rust/kernel/time/delay.rs
@@ -47,3 +47,40 @@ 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.
+///
+/// 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 v4 2/2] rust: Add read_poll_timeout_atomic function
  2025-11-03 11:29 [PATCH v4 0/2] Add read_poll_timeout_atomic support FUJITA Tomonori
  2025-11-03 11:29 ` [PATCH v4 1/2] rust: add udelay() function FUJITA Tomonori
@ 2025-11-03 11:29 ` FUJITA Tomonori
  2025-11-03 11:34 ` [PATCH v4 0/2] Add read_poll_timeout_atomic support Danilo Krummrich
  2025-11-04 13:09 ` Danilo Krummrich
  3 siblings, 0 replies; 6+ messages in thread
From: FUJITA Tomonori @ 2025-11-03 11:29 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.

Reviewed-by: Alice Ryhl <aliceryhl@google.com>
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 8f8886543f34..18bed3e78ef7 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,
@@ -96,3 +99,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 v4 0/2] Add read_poll_timeout_atomic support
  2025-11-03 11:29 [PATCH v4 0/2] Add read_poll_timeout_atomic support FUJITA Tomonori
  2025-11-03 11:29 ` [PATCH v4 1/2] rust: add udelay() function FUJITA Tomonori
  2025-11-03 11:29 ` [PATCH v4 2/2] rust: Add read_poll_timeout_atomic function FUJITA Tomonori
@ 2025-11-03 11:34 ` Danilo Krummrich
  2025-11-04 11:26   ` Andreas Hindborg
  2025-11-04 13:09 ` Danilo Krummrich
  3 siblings, 1 reply; 6+ messages in thread
From: Danilo Krummrich @ 2025-11-03 11:34 UTC (permalink / raw)
  To: a.hindborg
  Cc: FUJITA Tomonori, alex.gaynor, aliceryhl, daniel.almeida, ojeda,
	anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz,
	linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross

On 11/3/25 12:29 PM, FUJITA Tomonori wrote:
>   rust: add udelay() function
>   rust: Add read_poll_timeout_atomic function

@Andreas: Mind providing an ACK so I can pick this one up including the udelay()
patch?

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/2] Add read_poll_timeout_atomic support
  2025-11-03 11:34 ` [PATCH v4 0/2] Add read_poll_timeout_atomic support Danilo Krummrich
@ 2025-11-04 11:26   ` Andreas Hindborg
  0 siblings, 0 replies; 6+ messages in thread
From: Andreas Hindborg @ 2025-11-04 11:26 UTC (permalink / raw)
  To: Danilo Krummrich
  Cc: FUJITA Tomonori, alex.gaynor, aliceryhl, daniel.almeida, ojeda,
	anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz,
	linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross

Danilo Krummrich <dakr@kernel.org> writes:

> On 11/3/25 12:29 PM, FUJITA Tomonori wrote:
>>   rust: add udelay() function
>>   rust: Add read_poll_timeout_atomic function
>
> @Andreas: Mind providing an ACK so I can pick this one up including the udelay()
> patch?

Acked-by: Andreas Hindborg <a.hindborg@kernel.org>


Best regards,
Andreas Hindborg



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/2] Add read_poll_timeout_atomic support
  2025-11-03 11:29 [PATCH v4 0/2] Add read_poll_timeout_atomic support FUJITA Tomonori
                   ` (2 preceding siblings ...)
  2025-11-03 11:34 ` [PATCH v4 0/2] Add read_poll_timeout_atomic support Danilo Krummrich
@ 2025-11-04 13:09 ` Danilo Krummrich
  3 siblings, 0 replies; 6+ messages in thread
From: Danilo Krummrich @ 2025-11-04 13:09 UTC (permalink / raw)
  To: FUJITA Tomonori
  Cc: a.hindborg, alex.gaynor, aliceryhl, daniel.almeida, ojeda,
	anna-maria, bjorn3_gh, boqun.feng, frederic, gary, jstultz,
	linux-kernel, lossin, lyude, rust-for-linux, sboyd, tglx, tmgross

On Mon Nov 3, 2025 at 12:29 PM CET, FUJITA Tomonori wrote:

Applied to driver-core-testing, thanks!

> FUJITA Tomonori (2):
>   rust: add udelay() function
>   rust: Add read_poll_timeout_atomic function

    [ Adjust imports to use "kernel vertical" style. - Danilo ]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-11-04 13:09 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-03 11:29 [PATCH v4 0/2] Add read_poll_timeout_atomic support FUJITA Tomonori
2025-11-03 11:29 ` [PATCH v4 1/2] rust: add udelay() function FUJITA Tomonori
2025-11-03 11:29 ` [PATCH v4 2/2] rust: Add read_poll_timeout_atomic function FUJITA Tomonori
2025-11-03 11:34 ` [PATCH v4 0/2] Add read_poll_timeout_atomic support Danilo Krummrich
2025-11-04 11:26   ` Andreas Hindborg
2025-11-04 13:09 ` Danilo Krummrich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox