From: Danilo Krummrich <dakr@kernel.org>
To: Daniel Almeida <daniel.almeida@collabora.com>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
"Thomas Gleixner" <tglx@linutronix.de>,
"Benno Lossin" <lossin@kernel.org>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
linux-pci@vger.kernel.org
Subject: Re: [PATCH v4 4/6] rust: irq: add support for threaded IRQs and handlers
Date: Mon, 9 Jun 2025 14:27:38 +0200 [thread overview]
Message-ID: <aEbTOhdfmYmhPiiS@pollux> (raw)
In-Reply-To: <20250608-topics-tyr-request_irq-v4-4-81cb81fb8073@collabora.com>
On Sun, Jun 08, 2025 at 07:51:09PM -0300, Daniel Almeida wrote:
> +/// Callbacks for a threaded IRQ handler.
> +pub trait ThreadedHandler: Sync {
> + /// The actual handler function. As usual, sleeps are not allowed in IRQ
> + /// context.
> + fn handle_irq(&self) -> ThreadedIrqReturn;
> +
> + /// The threaded handler function. This function is called from the irq
> + /// handler thread, which is automatically created by the system.
> + fn thread_fn(&self) -> IrqReturn;
> +}
> +
> +impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
> + fn handle_irq(&self) -> ThreadedIrqReturn {
> + T::handle_irq(self)
> + }
> +
> + fn thread_fn(&self) -> IrqReturn {
> + T::thread_fn(self)
> + }
> +}
In case you intend to be consistent with the function pointer names in
request_threaded_irq(), it'd need to be handler() and thread_fn(). But I don't
think there's a need for that, both aren't really nice for names of trait
methods.
What about irq::Handler::handle() and irq::Handler::handle_threaded() for
instance?
Alternatively, why not just
trait Handler {
fn handle(&self);
}
trait ThreadedHandler {
fn handle(&self);
}
and then we ask for `T: Handler + ThreadedHandler`.
> +
> +impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
> + fn handle_irq(&self) -> ThreadedIrqReturn {
> + T::handle_irq(self)
> + }
> +
> + fn thread_fn(&self) -> IrqReturn {
> + T::thread_fn(self)
> + }
> +}
> +
> +/// A registration of a threaded IRQ handler for a given IRQ line.
> +///
> +/// Two callbacks are required: one to handle the IRQ, and one to handle any
> +/// other work in a separate thread.
> +///
> +/// The thread handler is only called if the IRQ handler returns `WakeThread`.
> +///
> +/// # Examples
> +///
> +/// The following is an example of using `ThreadedRegistration`. It uses a
> +/// [`AtomicU32`](core::sync::AtomicU32) to provide the interior mutability.
> +///
> +/// ```
> +/// use core::sync::atomic::AtomicU32;
> +/// use core::sync::atomic::Ordering;
> +///
> +/// use kernel::prelude::*;
> +/// use kernel::device::Bound;
> +/// use kernel::irq::flags;
> +/// use kernel::irq::ThreadedIrqReturn;
> +/// use kernel::irq::ThreadedRegistration;
> +/// use kernel::irq::IrqReturn;
> +/// use kernel::platform;
> +/// use kernel::sync::Arc;
> +/// use kernel::sync::SpinLock;
> +/// use kernel::alloc::flags::GFP_KERNEL;
> +/// use kernel::c_str;
> +///
> +/// // Declare a struct that will be passed in when the interrupt fires. The u32
> +/// // merely serves as an example of some internal data.
> +/// struct Data(AtomicU32);
> +///
> +/// // [`handle_irq`] takes &self. This example illustrates interior
> +/// // mutability can be used when share the data between process context and IRQ
> +/// // context.
> +///
> +/// type Handler = Data;
> +///
> +/// impl kernel::irq::request::ThreadedHandler for Handler {
> +/// // This is executing in IRQ context in some CPU. Other CPUs can still
> +/// // try to access to data.
> +/// fn handle_irq(&self) -> ThreadedIrqReturn {
> +/// self.0.fetch_add(1, Ordering::Relaxed);
> +///
> +/// // By returning `WakeThread`, we indicate to the system that the
> +/// // thread function should be called. Otherwise, return
> +/// // ThreadedIrqReturn::Handled.
> +/// ThreadedIrqReturn::WakeThread
> +/// }
> +///
> +/// // This will run (in a separate kthread) if and only if `handle_irq`
> +/// // returns `WakeThread`.
> +/// fn thread_fn(&self) -> IrqReturn {
> +/// self.0.fetch_add(1, Ordering::Relaxed);
> +///
> +/// IrqReturn::Handled
> +/// }
> +/// }
> +///
> +/// // This is running in process context.
> +/// fn register_threaded_irq(handler: Handler, dev: &platform::Device<Bound>) -> Result<Arc<ThreadedRegistration<Handler>>> {
> +/// let registration = dev.threaded_irq_by_index(0, flags::SHARED, c_str!("my-device"), handler)?;
This doesn't compile (yet). I think this should be a "raw" example, i.e. the
function should take an IRQ number.
The example you sketch up here is for platform::Device::threaded_irq_by_index().
> +///
> +/// // You can have as many references to the registration as you want, so
> +/// // multiple parts of the driver can access it.
> +/// let registration = Arc::pin_init(registration, GFP_KERNEL)?;
> +///
> +/// // The handler may be called immediately after the function above
> +/// // returns, possibly in a different CPU.
> +///
> +/// {
> +/// // The data can be accessed from the process context too.
> +/// registration.handler().0.fetch_add(1, Ordering::Relaxed);
> +/// }
Why the extra scope?
> +///
> +/// Ok(registration)
> +/// }
> +///
> +///
> +/// # Ok::<(), Error>(())
> +///```
> +///
> +/// # Invariants
> +///
> +/// * We own an irq handler using `&self` as its private data.
> +///
> +#[pin_data]
> +pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {
> + inner: Devres<RegistrationInner>,
> +
> + #[pin]
> + handler: T,
> +
> + /// Pinned because we need address stability so that we can pass a pointer
> + /// to the callback.
> + #[pin]
> + _pin: PhantomPinned,
> +}
Most of the code in this file is a duplicate of the non-threaded registration.
I think this would greatly generalize with specialization and an HandlerInternal
trait.
Without specialization I think we could use enums to generalize.
The most trivial solution would be to define the Handler trait as
trait Handler {
fn handle(&self);
fn handle_threaded(&self) {};
}
but that's pretty dodgy.
> +impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {
> + /// Registers the IRQ handler with the system for the given IRQ number.
> + pub(crate) fn register<'a>(
> + dev: &'a Device<Bound>,
> + irq: u32,
> + flags: Flags,
> + name: &'static CStr,
> + handler: T,
> + ) -> impl PinInit<Self, Error> + 'a {
What happens if `dev` does not match `irq`? The caller is responsible to only
provide an IRQ number that was obtained from this device.
This should be a safety requirement and a type invariant.
next prev parent reply other threads:[~2025-06-09 12:27 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-08 22:51 [PATCH v4 0/6] rust: add support for request_irq Daniel Almeida
2025-06-08 22:51 ` [PATCH v4 1/6] rust: irq: add irq module Daniel Almeida
2025-06-08 22:51 ` [PATCH v4 2/6] rust: irq: add flags module Daniel Almeida
2025-06-08 22:51 ` [PATCH v4 3/6] rust: irq: add support for non-threaded IRQs and handlers Daniel Almeida
2025-06-09 11:47 ` Danilo Krummrich
2025-06-23 15:10 ` Alice Ryhl
2025-06-23 15:23 ` Danilo Krummrich
2025-06-23 15:25 ` Alice Ryhl
2025-06-23 15:26 ` Benno Lossin
2025-06-23 17:31 ` Boqun Feng
2025-06-23 19:18 ` Boqun Feng
2025-06-23 19:28 ` Benno Lossin
2025-06-24 12:31 ` Daniel Almeida
2025-06-24 12:46 ` Benno Lossin
2025-06-24 13:50 ` Alice Ryhl
2025-06-24 14:33 ` Boqun Feng
2025-06-24 14:42 ` Boqun Feng
2025-06-24 14:56 ` Danilo Krummrich
2025-06-24 15:17 ` Benno Lossin
2025-06-23 19:25 ` Benno Lossin
2025-06-23 19:27 ` Benno Lossin
2025-06-08 22:51 ` [PATCH v4 4/6] rust: irq: add support for threaded " Daniel Almeida
2025-06-09 12:27 ` Danilo Krummrich [this message]
2025-06-09 16:24 ` Daniel Almeida
2025-06-09 18:13 ` Danilo Krummrich
2025-06-09 18:30 ` Miguel Ojeda
2025-06-16 13:33 ` Alice Ryhl
2025-06-16 13:43 ` Danilo Krummrich
2025-06-16 17:49 ` Danilo Krummrich
2025-06-22 20:53 ` Benno Lossin
2025-06-16 13:48 ` Daniel Almeida
2025-06-16 15:45 ` Danilo Krummrich
2025-06-16 13:52 ` Daniel Almeida
2025-06-08 22:51 ` [PATCH v4 5/6] rust: platform: add irq accessors Daniel Almeida
2025-06-09 12:51 ` Danilo Krummrich
2025-06-08 22:51 ` [PATCH v4 6/6] rust: pci: " Daniel Almeida
2025-06-09 12:53 ` Danilo Krummrich
2025-06-09 23:22 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aEbTOhdfmYmhPiiS@pollux \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=daniel.almeida@collabora.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rafael@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tglx@linutronix.de \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.