Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: irq: add support for threaded IRQs and handlers

This patch adds support for threaded IRQs and handlers through
irq::ThreadedRegistration and the irq::ThreadedHandler trait.

Threaded interrupts are more permissive in the sense that further
processing is possible in a kthread. This means that said execution takes
place outside of interrupt context, which is rather restrictive in many
ways.

Registering a threaded irq is dependent upon having an IrqRequest that
was previously allocated by a given device. This will be introduced in
subsequent patches.

Tested-by: Joel Fernandes <joelagnelf@nvidia.com>
Tested-by: Dirk Behme <dirk.behme@de.bosch.com>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Daniel Almeida <daniel.almeida@collabora.com>
Link: https://lore.kernel.org/r/20250811-topics-tyr-request_irq2-v9-4-0485dcd9bcbf@collabora.com
[ Add now available intra-doc links back in. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

authored by

Daniel Almeida and committed by
Danilo Krummrich
135d4052 0851d34a

+232 -5
+4 -1
rust/kernel/irq.rs
··· 18 18 19 19 pub use flags::Flags; 20 20 21 - pub use request::{Handler, IrqRequest, IrqReturn, Registration}; 21 + pub use request::{ 22 + Handler, IrqRequest, IrqReturn, Registration, ThreadedHandler, ThreadedIrqReturn, 23 + ThreadedRegistration, 24 + };
+228 -4
rust/kernel/irq/request.rs
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 // SPDX-FileCopyrightText: Copyright 2025 Collabora ltd. 3 3 4 - //! This module provides types like [`Registration`] which allow users to 5 - //! register handlers for a given IRQ line. 4 + //! This module provides types like [`Registration`] and 5 + //! [`ThreadedRegistration`], which allow users to register handlers for a given 6 + //! IRQ line. 6 7 7 8 use core::marker::PhantomPinned; 8 9 ··· 16 15 use crate::str::CStr; 17 16 use crate::sync::Arc; 18 17 19 - /// The value that can be returned from a [`Handler`] or a `ThreadedHandler`. 18 + /// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`]. 20 19 #[repr(u32)] 21 20 pub enum IrqReturn { 22 21 /// The interrupt was not from this device or was not handled. ··· 35 34 /// 36 35 /// All work that does not necessarily need to be executed from 37 36 /// interrupt context, should be deferred to a threaded handler. 38 - /// See also `ThreadedRegistration`. 37 + /// See also [`ThreadedRegistration`]. 39 38 fn handle(&self) -> IrqReturn; 40 39 } 41 40 ··· 263 262 // SAFETY: `ptr` is a pointer to T set in `Registration::new` 264 263 let handler = unsafe { &*(ptr as *const T) }; 265 264 T::handle(handler) as c_uint 265 + } 266 + 267 + /// The value that can be returned from [`ThreadedHandler::handle`]. 268 + #[repr(u32)] 269 + pub enum ThreadedIrqReturn { 270 + /// The interrupt was not from this device or was not handled. 271 + None = bindings::irqreturn_IRQ_NONE, 272 + 273 + /// The interrupt was handled by this device. 274 + Handled = bindings::irqreturn_IRQ_HANDLED, 275 + 276 + /// The handler wants the handler thread to wake up. 277 + WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD, 278 + } 279 + 280 + /// Callbacks for a threaded IRQ handler. 281 + pub trait ThreadedHandler: Sync { 282 + /// The hard IRQ handler. 283 + /// 284 + /// This is executed in interrupt context, hence all corresponding 285 + /// limitations do apply. All work that does not necessarily need to be 286 + /// executed from interrupt context, should be deferred to the threaded 287 + /// handler, i.e. [`ThreadedHandler::handle_threaded`]. 288 + /// 289 + /// The default implementation returns [`ThreadedIrqReturn::WakeThread`]. 290 + fn handle(&self) -> ThreadedIrqReturn { 291 + ThreadedIrqReturn::WakeThread 292 + } 293 + 294 + /// The threaded IRQ handler. 295 + /// 296 + /// This is executed in process context. The kernel creates a dedicated 297 + /// `kthread` for this purpose. 298 + fn handle_threaded(&self) -> IrqReturn; 299 + } 300 + 301 + impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> { 302 + fn handle(&self) -> ThreadedIrqReturn { 303 + T::handle(self) 304 + } 305 + 306 + fn handle_threaded(&self) -> IrqReturn { 307 + T::handle_threaded(self) 308 + } 309 + } 310 + 311 + impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> { 312 + fn handle(&self) -> ThreadedIrqReturn { 313 + T::handle(self) 314 + } 315 + 316 + fn handle_threaded(&self) -> IrqReturn { 317 + T::handle_threaded(self) 318 + } 319 + } 320 + 321 + /// A registration of a threaded IRQ handler for a given IRQ line. 322 + /// 323 + /// Two callbacks are required: one to handle the IRQ, and one to handle any 324 + /// other work in a separate thread. 325 + /// 326 + /// The thread handler is only called if the IRQ handler returns 327 + /// [`ThreadedIrqReturn::WakeThread`]. 328 + /// 329 + /// # Examples 330 + /// 331 + /// The following is an example of using [`ThreadedRegistration`]. It uses a 332 + /// [`Mutex`](kernel::sync::Mutex) to provide interior mutability. 333 + /// 334 + /// ``` 335 + /// use kernel::c_str; 336 + /// use kernel::device::Bound; 337 + /// use kernel::irq::{ 338 + /// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn, 339 + /// ThreadedRegistration, 340 + /// }; 341 + /// use kernel::prelude::*; 342 + /// use kernel::sync::{Arc, Mutex}; 343 + /// 344 + /// // Declare a struct that will be passed in when the interrupt fires. The u32 345 + /// // merely serves as an example of some internal data. 346 + /// // 347 + /// // [`irq::ThreadedHandler::handle`] takes `&self`. This example 348 + /// // illustrates how interior mutability can be used when sharing the data 349 + /// // between process context and IRQ context. 350 + /// #[pin_data] 351 + /// struct Data { 352 + /// #[pin] 353 + /// value: Mutex<u32>, 354 + /// } 355 + /// 356 + /// impl ThreadedHandler for Data { 357 + /// // This will run (in a separate kthread) if and only if 358 + /// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by 359 + /// // default. 360 + /// fn handle_threaded(&self) -> IrqReturn { 361 + /// let mut data = self.value.lock(); 362 + /// *data += 1; 363 + /// IrqReturn::Handled 364 + /// } 365 + /// } 366 + /// 367 + /// // Registers a threaded IRQ handler for the given [`IrqRequest`]. 368 + /// // 369 + /// // This is executing in process context and assumes that `request` was 370 + /// // previously acquired from a device. 371 + /// fn register_threaded_irq( 372 + /// handler: impl PinInit<Data, Error>, 373 + /// request: IrqRequest<'_>, 374 + /// ) -> Result<Arc<ThreadedRegistration<Data>>> { 375 + /// let registration = 376 + /// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler); 377 + /// 378 + /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 379 + /// 380 + /// { 381 + /// // The data can be accessed from process context too. 382 + /// let mut data = registration.handler().value.lock(); 383 + /// *data += 1; 384 + /// } 385 + /// 386 + /// Ok(registration) 387 + /// } 388 + /// # Ok::<(), Error>(()) 389 + /// ``` 390 + /// 391 + /// # Invariants 392 + /// 393 + /// * We own an irq handler using `&T` as its private data. 394 + #[pin_data] 395 + pub struct ThreadedRegistration<T: ThreadedHandler + 'static> { 396 + #[pin] 397 + inner: Devres<RegistrationInner>, 398 + 399 + #[pin] 400 + handler: T, 401 + 402 + /// Pinned because we need address stability so that we can pass a pointer 403 + /// to the callback. 404 + #[pin] 405 + _pin: PhantomPinned, 406 + } 407 + 408 + impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> { 409 + /// Registers the IRQ handler with the system for the given IRQ number. 410 + pub fn new<'a>( 411 + request: IrqRequest<'a>, 412 + flags: Flags, 413 + name: &'static CStr, 414 + handler: impl PinInit<T, Error> + 'a, 415 + ) -> impl PinInit<Self, Error> + 'a { 416 + try_pin_init!(&this in Self { 417 + handler <- handler, 418 + inner <- Devres::new( 419 + request.dev, 420 + try_pin_init!(RegistrationInner { 421 + // SAFETY: `this` is a valid pointer to the `ThreadedRegistration` instance. 422 + cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(), 423 + irq: { 424 + // SAFETY: 425 + // - The callbacks are valid for use with request_threaded_irq. 426 + // - If this succeeds, the slot is guaranteed to be valid until the 427 + // destructor of Self runs, which will deregister the callbacks 428 + // before the memory location becomes invalid. 429 + to_result(unsafe { 430 + bindings::request_threaded_irq( 431 + request.irq, 432 + Some(handle_threaded_irq_callback::<T>), 433 + Some(thread_fn_callback::<T>), 434 + flags.into_inner(), 435 + name.as_char_ptr(), 436 + (&raw mut (*this.as_ptr()).handler).cast(), 437 + ) 438 + })?; 439 + request.irq 440 + } 441 + }) 442 + ), 443 + _pin: PhantomPinned, 444 + }) 445 + } 446 + 447 + /// Returns a reference to the handler that was registered with the system. 448 + pub fn handler(&self) -> &T { 449 + &self.handler 450 + } 451 + 452 + /// Wait for pending IRQ handlers on other CPUs. 453 + /// 454 + /// This will attempt to access the inner [`Devres`] container. 455 + pub fn try_synchronize(&self) -> Result { 456 + let inner = self.inner.try_access().ok_or(ENODEV)?; 457 + inner.synchronize(); 458 + Ok(()) 459 + } 460 + 461 + /// Wait for pending IRQ handlers on other CPUs. 462 + pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 463 + let inner = self.inner.access(dev)?; 464 + inner.synchronize(); 465 + Ok(()) 466 + } 467 + } 468 + 469 + /// # Safety 470 + /// 471 + /// This function should be only used as the callback in `request_threaded_irq`. 472 + unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>( 473 + _irq: i32, 474 + ptr: *mut c_void, 475 + ) -> c_uint { 476 + // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new` 477 + let handler = unsafe { &*(ptr as *const T) }; 478 + T::handle(handler) as c_uint 479 + } 480 + 481 + /// # Safety 482 + /// 483 + /// This function should be only used as the callback in `request_threaded_irq`. 484 + unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint { 485 + // SAFETY: `ptr` is a pointer to T set in `ThreadedRegistration::new` 486 + let handler = unsafe { &*(ptr as *const T) }; 487 + T::handle_threaded(handler) as c_uint 266 488 }