From 8a8afe9349fb91b604f10195984348e65d523daf Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:18:52 +0100 Subject: rust: hrtimer: introduce hrtimer support Add support for intrusive use of the hrtimer system. For now, only add support for embedding one timer per Rust struct. The hrtimer Rust API is based on the intrusive style pattern introduced by the Rust workqueue API. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Benno Lossin Reviewed-by: Tamir Duberstein Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-1-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 351 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 rust/kernel/time/hrtimer.rs (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs new file mode 100644 index 000000000000..a3697622fa17 --- /dev/null +++ b/rust/kernel/time/hrtimer.rs @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Intrusive high resolution timers. +//! +//! Allows running timer callbacks without doing allocations at the time of +//! starting the timer. For now, only one timer per type is allowed. +//! +//! # Vocabulary +//! +//! States: +//! +//! - Stopped: initialized but not started, or cancelled, or not restarted. +//! - Started: initialized and started or restarted. +//! - Running: executing the callback. +//! +//! Operations: +//! +//! * Start +//! * Cancel +//! * Restart +//! +//! Events: +//! +//! * Expire +//! +//! ## State Diagram +//! +//! ```text +//! Return NoRestart +//! +---------------------------------------------------------------------+ +//! | | +//! | | +//! | | +//! | Return Restart | +//! | +------------------------+ | +//! | | | | +//! | | | | +//! v v | | +//! +-----------------+ Start +------------------+ +--------+-----+--+ +//! | +---------------->| | | | +//! Init | | | | Expire | | +//! --------->| Stopped | | Started +---------->| Running | +//! | | Cancel | | | | +//! | |<----------------+ | | | +//! +-----------------+ +---------------+--+ +-----------------+ +//! ^ | +//! | | +//! +---------+ +//! Restart +//! ``` +//! +//! +//! A timer is initialized in the **stopped** state. A stopped timer can be +//! **started** by the `start` operation, with an **expiry** time. After the +//! `start` operation, the timer is in the **started** state. When the timer +//! **expires**, the timer enters the **running** state and the handler is +//! executed. After the handler has returned, the timer may enter the +//! **started* or **stopped** state, depending on the return value of the +//! handler. A timer in the **started** or **running** state may be **canceled** +//! by the `cancel` operation. A timer that is cancelled enters the **stopped** +//! state. +//! +//! A `cancel` or `restart` operation on a timer in the **running** state takes +//! effect after the handler has returned and the timer has transitioned +//! out of the **running** state. +//! +//! A `restart` operation on a timer in the **stopped** state is equivalent to a +//! `start` operation. + +use crate::{init::PinInit, prelude::*, time::Ktime, types::Opaque}; +use core::marker::PhantomData; + +/// A timer backed by a C `struct hrtimer`. +/// +/// # Invariants +/// +/// * `self.timer` is initialized by `bindings::hrtimer_setup`. +#[pin_data] +#[repr(C)] +pub struct HrTimer { + #[pin] + timer: Opaque, + _t: PhantomData, +} + +// SAFETY: Ownership of an `HrTimer` can be moved to other threads and +// used/dropped from there. +unsafe impl Send for HrTimer {} + +// SAFETY: Timer operations are locked on the C side, so it is safe to operate +// on a timer from multiple threads. +unsafe impl Sync for HrTimer {} + +impl HrTimer { + /// Return an initializer for a new timer instance. + pub fn new() -> impl PinInit + where + T: HrTimerCallback, + { + pin_init!(Self { + // INVARIANT: We initialize `timer` with `hrtimer_setup` below. + timer <- Opaque::ffi_init(move |place: *mut bindings::hrtimer| { + // SAFETY: By design of `pin_init!`, `place` is a pointer to a + // live allocation. hrtimer_setup will initialize `place` and + // does not require `place` to be initialized prior to the call. + unsafe { + bindings::hrtimer_setup( + place, + Some(T::Pointer::run), + bindings::CLOCK_MONOTONIC as i32, + bindings::hrtimer_mode_HRTIMER_MODE_REL, + ); + } + }), + _t: PhantomData, + }) + } + + /// Get a pointer to the contained `bindings::hrtimer`. + /// + /// This function is useful to get access to the value without creating + /// intermediate references. + /// + /// # Safety + /// + /// `this` must point to a live allocation of at least the size of `Self`. + unsafe fn raw_get(this: *const Self) -> *mut bindings::hrtimer { + // SAFETY: The field projection to `timer` does not go out of bounds, + // because the caller of this function promises that `this` points to an + // allocation of at least the size of `Self`. + unsafe { Opaque::raw_get(core::ptr::addr_of!((*this).timer)) } + } + + /// Cancel an initialized and potentially running timer. + /// + /// If the timer handler is running, this function will block until the + /// handler returns. + /// + /// Note that the timer might be started by a concurrent start operation. If + /// so, the timer might not be in the **stopped** state when this function + /// returns. + /// + /// Users of the `HrTimer` API would not usually call this method directly. + /// Instead they would use the safe [`HrTimerHandle::cancel`] on the handle + /// returned when the timer was started. + /// + /// This function is useful to get access to the value without creating + /// intermediate references. + /// + /// # Safety + /// + /// `this` must point to a valid `Self`. + #[allow(dead_code)] + pub(crate) unsafe fn raw_cancel(this: *const Self) -> bool { + // SAFETY: `this` points to an allocation of at least `HrTimer` size. + let c_timer_ptr = unsafe { HrTimer::raw_get(this) }; + + // If the handler is running, this will wait for the handler to return + // before returning. + // SAFETY: `c_timer_ptr` is initialized and valid. Synchronization is + // handled on the C side. + unsafe { bindings::hrtimer_cancel(c_timer_ptr) != 0 } + } +} + +/// Implemented by pointer types that point to structs that contain a [`HrTimer`]. +/// +/// `Self` must be [`Sync`] because it is passed to timer callbacks in another +/// thread of execution (hard or soft interrupt context). +/// +/// Starting a timer returns a [`HrTimerHandle`] that can be used to manipulate +/// the timer. Note that it is OK to call the start function repeatedly, and +/// that more than one [`HrTimerHandle`] associated with a [`HrTimerPointer`] may +/// exist. A timer can be manipulated through any of the handles, and a handle +/// may represent a cancelled timer. +pub trait HrTimerPointer: Sync + Sized { + /// A handle representing a started or restarted timer. + /// + /// If the timer is running or if the timer callback is executing when the + /// handle is dropped, the drop method of [`HrTimerHandle`] should not return + /// until the timer is stopped and the callback has completed. + /// + /// Note: When implementing this trait, consider that it is not unsafe to + /// leak the handle. + type TimerHandle: HrTimerHandle; + + /// Start the timer with expiry after `expires` time units. If the timer was + /// already running, it is restarted with the new expiry time. + fn start(self, expires: Ktime) -> Self::TimerHandle; +} + +/// Implemented by [`HrTimerPointer`] implementers to give the C timer callback a +/// function to call. +// This is split from `HrTimerPointer` to make it easier to specify trait bounds. +pub trait RawHrTimerCallback { + /// Type of the parameter passed to [`HrTimerCallback::run`]. It may be + /// [`Self`], or a pointer type derived from [`Self`]. + type CallbackTarget<'a>; + + /// Callback to be called from C when timer fires. + /// + /// # Safety + /// + /// Only to be called by C code in the `hrtimer` subsystem. `this` must point + /// to the `bindings::hrtimer` structure that was used to start the timer. + unsafe extern "C" fn run(this: *mut bindings::hrtimer) -> bindings::hrtimer_restart; +} + +/// Implemented by structs that can be the target of a timer callback. +pub trait HrTimerCallback { + /// The type whose [`RawHrTimerCallback::run`] method will be invoked when + /// the timer expires. + type Pointer<'a>: RawHrTimerCallback; + + /// Called by the timer logic when the timer fires. + fn run(this: as RawHrTimerCallback>::CallbackTarget<'_>) + where + Self: Sized; +} + +/// A handle representing a potentially running timer. +/// +/// More than one handle representing the same timer might exist. +/// +/// # Safety +/// +/// When dropped, the timer represented by this handle must be cancelled, if it +/// is running. If the timer handler is running when the handle is dropped, the +/// drop method must wait for the handler to return before returning. +/// +/// Note: One way to satisfy the safety requirement is to call `Self::cancel` in +/// the drop implementation for `Self.` +pub unsafe trait HrTimerHandle { + /// Cancel the timer. If the timer is in the running state, block till the + /// handler has returned. + /// + /// Note that the timer might be started by a concurrent start operation. If + /// so, the timer might not be in the **stopped** state when this function + /// returns. + fn cancel(&mut self) -> bool; +} + +/// Implemented by structs that contain timer nodes. +/// +/// Clients of the timer API would usually safely implement this trait by using +/// the [`crate::impl_has_hr_timer`] macro. +/// +/// # Safety +/// +/// Implementers of this trait must ensure that the implementer has a +/// [`HrTimer`] field and that all trait methods are implemented according to +/// their documentation. All the methods of this trait must operate on the same +/// field. +pub unsafe trait HasHrTimer { + /// Return a pointer to the [`HrTimer`] within `Self`. + /// + /// This function is useful to get access to the value without creating + /// intermediate references. + /// + /// # Safety + /// + /// `this` must be a valid pointer. + unsafe fn raw_get_timer(this: *const Self) -> *const HrTimer; + + /// Return a pointer to the struct that is containing the [`HrTimer`] pointed + /// to by `ptr`. + /// + /// This function is useful to get access to the value without creating + /// intermediate references. + /// + /// # Safety + /// + /// `ptr` must point to a [`HrTimer`] field in a struct of type `Self`. + unsafe fn timer_container_of(ptr: *mut HrTimer) -> *mut Self + where + Self: Sized; + + /// Get pointer to the contained `bindings::hrtimer` struct. + /// + /// This function is useful to get access to the value without creating + /// intermediate references. + /// + /// # Safety + /// + /// `this` must be a valid pointer. + unsafe fn c_timer_ptr(this: *const Self) -> *const bindings::hrtimer { + // SAFETY: `this` is a valid pointer to a `Self`. + let timer_ptr = unsafe { Self::raw_get_timer(this) }; + + // SAFETY: timer_ptr points to an allocation of at least `HrTimer` size. + unsafe { HrTimer::raw_get(timer_ptr) } + } + + /// Start the timer contained in the `Self` pointed to by `self_ptr`. If + /// it is already running it is removed and inserted. + /// + /// # Safety + /// + /// - `this` must point to a valid `Self`. + /// - Caller must ensure that the pointee of `this` lives until the timer + /// fires or is canceled. + unsafe fn start(this: *const Self, expires: Ktime) { + // SAFETY: By function safety requirement, `this` is a valid `Self`. + unsafe { + bindings::hrtimer_start_range_ns( + Self::c_timer_ptr(this).cast_mut(), + expires.to_ns(), + 0, + bindings::hrtimer_mode_HRTIMER_MODE_REL, + ); + } + } +} + +/// Use to implement the [`HasHrTimer`] trait. +/// +/// See [`module`] documentation for an example. +/// +/// [`module`]: crate::time::hrtimer +#[macro_export] +macro_rules! impl_has_hr_timer { + ( + impl$({$($generics:tt)*})? + HasHrTimer<$timer_type:ty> + for $self:ty + { self.$field:ident } + $($rest:tt)* + ) => { + // SAFETY: This implementation of `raw_get_timer` only compiles if the + // field has the right type. + unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self { + + #[inline] + unsafe fn raw_get_timer( + this: *const Self, + ) -> *const $crate::time::hrtimer::HrTimer<$timer_type> { + // SAFETY: The caller promises that the pointer is not dangling. + unsafe { ::core::ptr::addr_of!((*this).$field) } + } + + #[inline] + unsafe fn timer_container_of( + ptr: *mut $crate::time::hrtimer::HrTimer<$timer_type>, + ) -> *mut Self { + // SAFETY: As per the safety requirement of this function, `ptr` + // is pointing inside a `$timer_type`. + unsafe { ::kernel::container_of!(ptr, $timer_type, $field).cast_mut() } + } + } + } +} -- cgit v1.2.3 From d7bf4786b5250b0e490a937d1f8a16ee3a54adbe Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:18:54 +0100 Subject: rust: hrtimer: implement `HrTimerPointer` for `Arc` Allow the use of intrusive `hrtimer` fields in structs that are managed by an `Arc` by implementing `HrTimerPointer` and `RawTimerCallbck` for `Arc`. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Lyude Paul Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-3-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index a3697622fa17..bfb536f2a490 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -150,7 +150,6 @@ impl HrTimer { /// # Safety /// /// `this` must point to a valid `Self`. - #[allow(dead_code)] pub(crate) unsafe fn raw_cancel(this: *const Self) -> bool { // SAFETY: `this` points to an allocation of at least `HrTimer` size. let c_timer_ptr = unsafe { HrTimer::raw_get(this) }; @@ -349,3 +348,6 @@ macro_rules! impl_has_hr_timer { } } } + +mod arc; +pub use arc::ArcHrTimerHandle; -- cgit v1.2.3 From 94e05a66ea3ebed48e7e1a0dee68d40184386d25 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:18:55 +0100 Subject: rust: hrtimer: allow timer restart from timer handler Allow timer handlers to report that they want a timer to be restarted after the timer handler has finished executing. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Benno Lossin Reviewed-by: Tamir Duberstein Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-4-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index bfb536f2a490..bc8f85cededb 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -212,7 +212,7 @@ pub trait HrTimerCallback { type Pointer<'a>: RawHrTimerCallback; /// Called by the timer logic when the timer fires. - fn run(this: as RawHrTimerCallback>::CallbackTarget<'_>) + fn run(this: as RawHrTimerCallback>::CallbackTarget<'_>) -> HrTimerRestart where Self: Sized; } @@ -311,6 +311,24 @@ pub unsafe trait HasHrTimer { } } +/// Restart policy for timers. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[repr(u32)] +pub enum HrTimerRestart { + /// Timer should not be restarted. + #[allow(clippy::unnecessary_cast)] + NoRestart = bindings::hrtimer_restart_HRTIMER_NORESTART as u32, + /// Timer should be restarted. + #[allow(clippy::unnecessary_cast)] + Restart = bindings::hrtimer_restart_HRTIMER_RESTART as u32, +} + +impl HrTimerRestart { + fn into_c(self) -> bindings::hrtimer_restart { + self as bindings::hrtimer_restart + } +} + /// Use to implement the [`HasHrTimer`] trait. /// /// See [`module`] documentation for an example. -- cgit v1.2.3 From a6968ce3769660658e5c956987dc9e75b369d4b6 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:18:56 +0100 Subject: rust: hrtimer: add `UnsafeHrTimerPointer` Add a trait to allow unsafely queuing stack allocated timers. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Benno Lossin Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-5-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index bc8f85cededb..e1b29cd40397 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -188,6 +188,37 @@ pub trait HrTimerPointer: Sync + Sized { fn start(self, expires: Ktime) -> Self::TimerHandle; } +/// Unsafe version of [`HrTimerPointer`] for situations where leaking the +/// [`HrTimerHandle`] returned by `start` would be unsound. This is the case for +/// stack allocated timers. +/// +/// Typical implementers are pinned references such as [`Pin<&T>`]. +/// +/// # Safety +/// +/// Implementers of this trait must ensure that instances of types implementing +/// [`UnsafeHrTimerPointer`] outlives any associated [`HrTimerPointer::TimerHandle`] +/// instances. +pub unsafe trait UnsafeHrTimerPointer: Sync + Sized { + /// A handle representing a running timer. + /// + /// # Safety + /// + /// If the timer is running, or if the timer callback is executing when the + /// handle is dropped, the drop method of [`Self::TimerHandle`] must not return + /// until the timer is stopped and the callback has completed. + type TimerHandle: HrTimerHandle; + + /// Start the timer after `expires` time units. If the timer was already + /// running, it is restarted at the new expiry time. + /// + /// # Safety + /// + /// Caller promises keep the timer structure alive until the timer is dead. + /// Caller can ensure this by not leaking the returned [`Self::TimerHandle`]. + unsafe fn start(self, expires: Ktime) -> Self::TimerHandle; +} + /// Implemented by [`HrTimerPointer`] implementers to give the C timer callback a /// function to call. // This is split from `HrTimerPointer` to make it easier to specify trait bounds. -- cgit v1.2.3 From f93b0d8360e5e690ca82c3236ba7f7f9d6a6b5e7 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:18:57 +0100 Subject: rust: hrtimer: add `hrtimer::ScopedHrTimerPointer` Add the trait `ScopedHrTimerPointer` to allow safe use of stack allocated timers. Safety is achieved by pinning the stack in place while timers are running. Implement the trait for all types that implement `UnsafeHrTimerPointer`. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Benno Lossin Reviewed-by: Lyude Paul Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-6-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index e1b29cd40397..5c35982f9dcb 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -219,6 +219,39 @@ pub unsafe trait UnsafeHrTimerPointer: Sync + Sized { unsafe fn start(self, expires: Ktime) -> Self::TimerHandle; } +/// A trait for stack allocated timers. +/// +/// # Safety +/// +/// Implementers must ensure that `start_scoped` does not return until the +/// timer is dead and the timer handler is not running. +pub unsafe trait ScopedHrTimerPointer { + /// Start the timer to run after `expires` time units and immediately + /// after call `f`. When `f` returns, the timer is cancelled. + fn start_scoped(self, expires: Ktime, f: F) -> T + where + F: FnOnce() -> T; +} + +// SAFETY: By the safety requirement of [`UnsafeHrTimerPointer`], dropping the +// handle returned by [`UnsafeHrTimerPointer::start`] ensures that the timer is +// killed. +unsafe impl ScopedHrTimerPointer for T +where + T: UnsafeHrTimerPointer, +{ + fn start_scoped(self, expires: Ktime, f: F) -> U + where + F: FnOnce() -> U, + { + // SAFETY: We drop the timer handle below before returning. + let handle = unsafe { UnsafeHrTimerPointer::start(self, expires) }; + let t = f(); + drop(handle); + t + } +} + /// Implemented by [`HrTimerPointer`] implementers to give the C timer callback a /// function to call. // This is split from `HrTimerPointer` to make it easier to specify trait bounds. -- cgit v1.2.3 From 582523d9de9a8875df62a08af7443884ff5d9969 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:18:58 +0100 Subject: rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&T>` Allow pinned references to structs that contain a `HrTimer` node to be scheduled with the `hrtimer` subsystem. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Lyude Paul Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-7-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index 5c35982f9dcb..16b3c0f09579 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -433,3 +433,5 @@ macro_rules! impl_has_hr_timer { mod arc; pub use arc::ArcHrTimerHandle; +mod pin; +pub use pin::PinHrTimerHandle; -- cgit v1.2.3 From 042b0c7947d39aeac34b35fb89034ca1345f1fc3 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:18:59 +0100 Subject: rust: hrtimer: implement `UnsafeHrTimerPointer` for `Pin<&mut T>` Allow pinned mutable references to structs that contain a `HrTimer` node to be scheduled with the `hrtimer` subsystem. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Lyude Paul Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-8-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index 16b3c0f09579..2089170972ef 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -435,3 +435,5 @@ mod arc; pub use arc::ArcHrTimerHandle; mod pin; pub use pin::PinHrTimerHandle; +mod pin_mut; +pub use pin_mut::PinMutHrTimerHandle; -- cgit v1.2.3 From 374b60a0134e4b136f6c3d8b3c9eb99b3b104249 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:19:01 +0100 Subject: rust: hrtimer: implement `HrTimerPointer` for `Pin>` Allow `Pin>` to be the target of a timer callback. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Lyude Paul Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-10-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index 2089170972ef..cab230fb3e6e 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -437,3 +437,6 @@ mod pin; pub use pin::PinHrTimerHandle; mod pin_mut; pub use pin_mut::PinMutHrTimerHandle; +// `box` is a reserved keyword, so prefix with `t` for timer +mod tbox; +pub use tbox::BoxHrTimerHandle; -- cgit v1.2.3 From bfa3a410bf03ca41a7a58dea1e9c2acac9295bf7 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:19:02 +0100 Subject: rust: hrtimer: add `HrTimerMode` Allow selection of timer mode by passing a `HrTimerMode` variant to `HrTimer::new`. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Lyude Paul Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-11-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 82 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index cab230fb3e6e..ed5ccdb71064 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -80,6 +80,7 @@ use core::marker::PhantomData; pub struct HrTimer { #[pin] timer: Opaque, + mode: HrTimerMode, _t: PhantomData, } @@ -93,7 +94,7 @@ unsafe impl Sync for HrTimer {} impl HrTimer { /// Return an initializer for a new timer instance. - pub fn new() -> impl PinInit + pub fn new(mode: HrTimerMode) -> impl PinInit where T: HrTimerCallback, { @@ -108,10 +109,11 @@ impl HrTimer { place, Some(T::Pointer::run), bindings::CLOCK_MONOTONIC as i32, - bindings::hrtimer_mode_HRTIMER_MODE_REL, + mode.into_c(), ); } }), + mode: mode, _t: PhantomData, }) } @@ -369,7 +371,7 @@ pub unsafe trait HasHrTimer { Self::c_timer_ptr(this).cast_mut(), expires.to_ns(), 0, - bindings::hrtimer_mode_HRTIMER_MODE_REL, + (*Self::raw_get_timer(this)).mode.into_c(), ); } } @@ -393,6 +395,80 @@ impl HrTimerRestart { } } +/// Operational mode of [`HrTimer`]. +// NOTE: Some of these have the same encoding on the C side, so we keep +// `repr(Rust)` and convert elsewhere. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum HrTimerMode { + /// Timer expires at the given expiration time. + Absolute, + /// Timer expires after the given expiration time interpreted as a duration from now. + Relative, + /// Timer does not move between CPU cores. + Pinned, + /// Timer handler is executed in soft irq context. + Soft, + /// Timer handler is executed in hard irq context. + Hard, + /// Timer expires at the given expiration time. + /// Timer does not move between CPU cores. + AbsolutePinned, + /// Timer expires after the given expiration time interpreted as a duration from now. + /// Timer does not move between CPU cores. + RelativePinned, + /// Timer expires at the given expiration time. + /// Timer handler is executed in soft irq context. + AbsoluteSoft, + /// Timer expires after the given expiration time interpreted as a duration from now. + /// Timer handler is executed in soft irq context. + RelativeSoft, + /// Timer expires at the given expiration time. + /// Timer does not move between CPU cores. + /// Timer handler is executed in soft irq context. + AbsolutePinnedSoft, + /// Timer expires after the given expiration time interpreted as a duration from now. + /// Timer does not move between CPU cores. + /// Timer handler is executed in soft irq context. + RelativePinnedSoft, + /// Timer expires at the given expiration time. + /// Timer handler is executed in hard irq context. + AbsoluteHard, + /// Timer expires after the given expiration time interpreted as a duration from now. + /// Timer handler is executed in hard irq context. + RelativeHard, + /// Timer expires at the given expiration time. + /// Timer does not move between CPU cores. + /// Timer handler is executed in hard irq context. + AbsolutePinnedHard, + /// Timer expires after the given expiration time interpreted as a duration from now. + /// Timer does not move between CPU cores. + /// Timer handler is executed in hard irq context. + RelativePinnedHard, +} + +impl HrTimerMode { + fn into_c(self) -> bindings::hrtimer_mode { + use bindings::*; + match self { + HrTimerMode::Absolute => hrtimer_mode_HRTIMER_MODE_ABS, + HrTimerMode::Relative => hrtimer_mode_HRTIMER_MODE_REL, + HrTimerMode::Pinned => hrtimer_mode_HRTIMER_MODE_PINNED, + HrTimerMode::Soft => hrtimer_mode_HRTIMER_MODE_SOFT, + HrTimerMode::Hard => hrtimer_mode_HRTIMER_MODE_HARD, + HrTimerMode::AbsolutePinned => hrtimer_mode_HRTIMER_MODE_ABS_PINNED, + HrTimerMode::RelativePinned => hrtimer_mode_HRTIMER_MODE_REL_PINNED, + HrTimerMode::AbsoluteSoft => hrtimer_mode_HRTIMER_MODE_ABS_SOFT, + HrTimerMode::RelativeSoft => hrtimer_mode_HRTIMER_MODE_REL_SOFT, + HrTimerMode::AbsolutePinnedSoft => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT, + HrTimerMode::RelativePinnedSoft => hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT, + HrTimerMode::AbsoluteHard => hrtimer_mode_HRTIMER_MODE_ABS_HARD, + HrTimerMode::RelativeHard => hrtimer_mode_HRTIMER_MODE_REL_HARD, + HrTimerMode::AbsolutePinnedHard => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD, + HrTimerMode::RelativePinnedHard => hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD, + } + } +} + /// Use to implement the [`HasHrTimer`] trait. /// /// See [`module`] documentation for an example. -- cgit v1.2.3 From aa33de03a3d58a8e502ead3ca0d445a4fba22c83 Mon Sep 17 00:00:00 2001 From: Andreas Hindborg Date: Sun, 9 Mar 2025 16:19:03 +0100 Subject: rust: hrtimer: add clocksource selection through `ClockId` Allow selecting a clock source for timers by passing a `ClockId` variant to `HrTimer::new`. Acked-by: Frederic Weisbecker Acked-by: Thomas Gleixner Reviewed-by: Lyude Paul Reviewed-by: Benno Lossin Link: https://lore.kernel.org/r/20250309-hrtimer-v3-v6-12-rc2-v12-12-73586e2bd5f1@kernel.org Signed-off-by: Andreas Hindborg --- rust/kernel/time/hrtimer.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'rust/kernel/time/hrtimer.rs') diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs index ed5ccdb71064..4fc49f193125 100644 --- a/rust/kernel/time/hrtimer.rs +++ b/rust/kernel/time/hrtimer.rs @@ -67,6 +67,7 @@ //! A `restart` operation on a timer in the **stopped** state is equivalent to a //! `start` operation. +use super::ClockId; use crate::{init::PinInit, prelude::*, time::Ktime, types::Opaque}; use core::marker::PhantomData; @@ -94,7 +95,7 @@ unsafe impl Sync for HrTimer {} impl HrTimer { /// Return an initializer for a new timer instance. - pub fn new(mode: HrTimerMode) -> impl PinInit + pub fn new(mode: HrTimerMode, clock: ClockId) -> impl PinInit where T: HrTimerCallback, { @@ -108,7 +109,7 @@ impl HrTimer { bindings::hrtimer_setup( place, Some(T::Pointer::run), - bindings::CLOCK_MONOTONIC as i32, + clock.into_c(), mode.into_c(), ); } -- cgit v1.2.3