public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] rust: irq: request: touch up the documentation
@ 2025-09-09 20:46 Daniel Almeida
  2025-09-10  6:38 ` Alice Ryhl
  0 siblings, 1 reply; 3+ messages in thread
From: Daniel Almeida @ 2025-09-09 20:46 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor,
	Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
	Andreas Hindborg, Trevor Gross
  Cc: rust-for-linux, linux-kernel, Daniel Almeida

Parts of the documentation are either unclear or misplaced and can
otherwise be improved. This commit fixes them.

This is specially important in the context of the safety requirements of
functions or type invariants, as users have to uphold the former and may
rely on the latter, so we should avoid anything that may create
confusion.

Suggested-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
---
 rust/kernel/irq/request.rs | 44 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs
index b150563fdef809899c7ca39221c4928238e31110..a1d0e934972fa555968dba5731077cb11606a0d3 100644
--- a/rust/kernel/irq/request.rs
+++ b/rust/kernel/irq/request.rs
@@ -30,6 +30,11 @@ pub enum IrqReturn {
 pub trait Handler: Sync {
     /// The hard IRQ handler.
     ///
+    /// A "hard" handler in the context of the Linux kernel is the part of an
+    /// interrupt handler that runs in interrupt context. The hard handler
+    /// usually defers time consuming processing to run in process context, for
+    /// instance by queuing the work on a work queue for later execution.
+    ///
     /// This is executed in interrupt context, hence all corresponding
     /// limitations do apply.
     ///
@@ -54,9 +59,7 @@ fn handle(&self, device: &Device<Bound>) -> IrqReturn {
 /// # Invariants
 ///
 /// - `self.irq` is the same as the one passed to `request_{threaded}_irq`.
-/// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique
-///   by the type system, since each call to `new` will return a different instance of
-///   `Registration`.
+/// - `cookie` is unique.
 #[pin_data(PinnedDrop)]
 struct RegistrationInner {
     irq: u32,
@@ -91,7 +94,9 @@ fn drop(self: Pin<&mut Self>) {
 // concurrent access.
 unsafe impl Sync for RegistrationInner {}
 
-// SAFETY: It is safe to send `RegistrationInner` across threads.
+// SAFETY: It is safe to transfer ownership of `RegistrationInner` from another
+// thread, because it has no shared mutable state. The IRQ owned by
+// `RegistrationInner` via `cookie` can be dropped from any thread.
 unsafe impl Send for RegistrationInner {}
 
 /// A request for an IRQ line for a given device.
@@ -112,7 +117,7 @@ impl<'a> IrqRequest<'a> {
     ///
     /// - `irq` should be a valid IRQ number for `dev`.
     pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self {
-        // INVARIANT: `irq` is a valid IRQ number for `dev`.
+        // By function safety requirement, irq` is a valid IRQ number for `dev`.
         IrqRequest { dev, irq }
     }
 
@@ -183,6 +188,8 @@ pub fn irq(&self) -> u32 {
 /// * We own an irq handler whose cookie is a pointer to `Self`.
 #[pin_data]
 pub struct Registration<T: Handler + 'static> {
+    /// We need to drop inner before handler, as we must ensure that the handler
+    /// is valid until `free_irq` is called.
     #[pin]
     inner: Devres<RegistrationInner>,
 
@@ -196,7 +203,8 @@ pub struct Registration<T: Handler + 'static> {
 }
 
 impl<T: Handler + 'static> Registration<T> {
-    /// Registers the IRQ handler with the system for the given IRQ number.
+    /// Registers the IRQ handler with the system for the IRQ number represented
+    /// by `request`.
     pub fn new<'a>(
         request: IrqRequest<'a>,
         flags: Flags,
@@ -208,7 +216,11 @@ pub fn new<'a>(
             inner <- Devres::new(
                 request.dev,
                 try_pin_init!(RegistrationInner {
-                    // INVARIANT: `this` is a valid pointer to the `Registration` instance
+                    // INVARIANT: `this` is a valid pointer to the `Registration` instance.
+                    // INVARIANT: `cookie` is being passed to `request_irq` as
+                    // the cookie. It is guaranteed to be unique by the type
+                    // system, since each call to `new` will return a different
+                    // instance of `Registration`.
                     cookie: this.as_ptr().cast::<c_void>(),
                     irq: {
                         // SAFETY:
@@ -260,7 +272,8 @@ pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
 
 /// # Safety
 ///
-/// This function should be only used as the callback in `request_irq`.
+/// - This function should be only used as the callback in `request_irq`.
+/// - `ptr` must be valid for use as a reference to `T`
 unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
     // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new`
     let registration = unsafe { &*(ptr as *const Registration<T>) };
@@ -288,6 +301,11 @@ pub enum ThreadedIrqReturn {
 pub trait ThreadedHandler: Sync {
     /// The hard IRQ handler.
     ///
+    /// A "hard" handler in the context of the Linux kernel is the part of an
+    /// interrupt handler that runs in interrupt context. The hard handler
+    /// usually defers time consuming processing to run in process context, for
+    /// instance by queuing the work on a work queue for later execution.
+    ///
     /// This is executed in interrupt context, hence all corresponding
     /// limitations do apply. All work that does not necessarily need to be
     /// executed from interrupt context, should be deferred to the threaded
@@ -427,6 +445,10 @@ pub fn new<'a>(
                 request.dev,
                 try_pin_init!(RegistrationInner {
                     // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance.
+                    // INVARIANT: `cookie` is being passed to
+                    // `request_threaded_irq` as the cookie. It is guaranteed to
+                    // be unique by the type system, since each call to `new`
+                    // will return a different instance of `Registration`.
                     cookie: this.as_ptr().cast::<c_void>(),
                     irq: {
                         // SAFETY:
@@ -479,7 +501,8 @@ pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
 
 /// # Safety
 ///
-/// This function should be only used as the callback in `request_threaded_irq`.
+/// - This function should be only used as the callback in `request_threaded_irq`.
+/// - `ptr` must be valid for use as a reference to `T`
 unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
     _irq: i32,
     ptr: *mut c_void,
@@ -495,7 +518,8 @@ pub fn synchronize(&self, dev: &Device<Bound>) -> Result {
 
 /// # Safety
 ///
-/// This function should be only used as the callback in `request_threaded_irq`.
+/// - This function should be only used as the callback in `request_threaded_irq`.
+/// - `ptr` must be valid for use as a reference to `T`
 unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint {
     // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
     let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };

---
base-commit: 4c48aed6dfcd32ea23e52adc1072405a62facf46
change-id: 20250909-irq-andreas-fixes-4773537cdb81

Best regards,
-- 
Daniel Almeida <daniel.almeida@collabora.com>


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

end of thread, other threads:[~2025-09-10 14:43 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-09 20:46 [PATCH] rust: irq: request: touch up the documentation Daniel Almeida
2025-09-10  6:38 ` Alice Ryhl
2025-09-10 14:43   ` Daniel Almeida

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