[PATCH 1/3] rust: irq: declare cfi_encoding for irqreturn

From: Sami Tolvanen

Date: Mon Oct 19 2026 - 19:41:06 EST


The IRQ callbacks return c_uint. C calls them through irq_handler_t,
which returns enum irqreturn. kCFI encodes enum types by name even with
integer normalization, so the type ids never match and every call fails
the CFI check.

Generate irqreturn as a newtype with a cfi_encoding, as is done for
lru_status, and return bindings::irqreturn_t from the callbacks.

Fixes: 0851d34a8cc3 ("rust: irq: add support for non-threaded IRQs and handlers")
Fixes: 135d40523244 ("rust: irq: add support for threaded IRQs and handlers")
Signed-off-by: Sami Tolvanen <samitolvanen@xxxxxxxxxx>
---
rust/bindgen_parameters | 2 ++
rust/kernel/irq/request.rs | 28 +++++++++++++++++-----------
2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters
index 8402b0c93545..5059cc74cb3c 100644
--- a/rust/bindgen_parameters
+++ b/rust/bindgen_parameters
@@ -27,6 +27,8 @@
--opaque-type spinlock

# enums that appear in indirect function calls should specify a cfi type
+--newtype-enum irqreturn
+--with-attribute-custom-enum=irqreturn='#[cfi_encoding="9irqreturn"]'
--newtype-enum lru_status
--with-attribute-custom-enum=lru_status='#[cfi_encoding="10lru_status"]'

diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs
index c1c6525a676a..1afa9fcaad1f 100644
--- a/rust/kernel/irq/request.rs
+++ b/rust/kernel/irq/request.rs
@@ -25,10 +25,10 @@
#[repr(u32)]
pub enum IrqReturn {
/// The interrupt was not from this device or was not handled.
- None = bindings::irqreturn_IRQ_NONE,
+ None = bindings::irqreturn::IRQ_NONE.0,

/// The interrupt was handled by this device.
- Handled = bindings::irqreturn_IRQ_HANDLED,
+ Handled = bindings::irqreturn::IRQ_HANDLED.0,
}

/// Callbacks for an IRQ handler.
@@ -240,25 +240,28 @@ fn drop(self: Pin<&mut Self>) {
/// # Safety
///
/// This function should be only used as the callback in `request_irq`.
-unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
+unsafe extern "C" fn handle_irq_callback<T: Handler>(
+ _irq: i32,
+ ptr: *mut c_void,
+) -> bindings::irqreturn_t {
let ptr = ptr.cast_const().cast::<Registration<'_, T>>();
// SAFETY: `ptr` is a pointer to `Registration<'_, T>` set in `Registration::new()`.
let registration = unsafe { &*ptr };

- T::handle(&registration.handler) as c_uint
+ bindings::irqreturn_t(T::handle(&registration.handler) as c_uint)
}

/// The value that can be returned from [`ThreadedHandler::handle`].
#[repr(u32)]
pub enum ThreadedIrqReturn {
/// The interrupt was not from this device or was not handled.
- None = bindings::irqreturn_IRQ_NONE,
+ None = bindings::irqreturn::IRQ_NONE.0,

/// The interrupt was handled by this device.
- Handled = bindings::irqreturn_IRQ_HANDLED,
+ Handled = bindings::irqreturn::IRQ_HANDLED.0,

/// The handler wants the handler thread to wake up.
- WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD,
+ WakeThread = bindings::irqreturn::IRQ_WAKE_THREAD.0,
}

/// Callbacks for a threaded IRQ handler.
@@ -461,23 +464,26 @@ fn drop(self: Pin<&mut Self>) {
unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
_irq: i32,
ptr: *mut c_void,
-) -> c_uint {
+) -> bindings::irqreturn_t {
let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T>>();
// SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T>` set in
// `ThreadedRegistration::new()`.
let registration = unsafe { &*ptr };

- T::handle(&registration.handler) as c_uint
+ bindings::irqreturn_t(T::handle(&registration.handler) as c_uint)
}

/// # Safety
///
/// This function should be only used as the callback in `request_threaded_irq`.
-unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint {
+unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(
+ _irq: i32,
+ ptr: *mut c_void,
+) -> bindings::irqreturn_t {
let ptr = ptr.cast_const().cast::<ThreadedRegistration<'_, T>>();
// SAFETY: `ptr` is a pointer to `ThreadedRegistration<'_, T>` set in
// `ThreadedRegistration::new()`.
let registration = unsafe { &*ptr };

- T::handle_threaded(&registration.handler) as c_uint
+ bindings::irqreturn_t(T::handle_threaded(&registration.handler) as c_uint)
}

--
2.56.0.212.g129ede20d9-goog