FILE
request.rs
File preview with syntax highlighting.
linux-6.19.14/rust/kernel/irq/request.rs
1// SPDX-License-Identifier: GPL-2.0 2// SPDX-FileCopyrightText: Copyright 2025 Collabora ltd. 3 4//! This module provides types like [`Registration`] and 5//! [`ThreadedRegistration`], which allow users to register handlers for a given 6//! IRQ line. 7 8use core::marker::PhantomPinned; 9 10use crate::alloc::Allocator; 11use crate::device::{Bound, Device}; 12use crate::devres::Devres; 13use crate::error::to_result; 14use crate::irq::flags::Flags; 15use crate::prelude::*; 16use crate::str::CStr; 17use crate::sync::Arc; 18 19/// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`]. 20#[repr(u32)] 21pub enum IrqReturn { 22 /// The interrupt was not from this device or was not handled. 23 None = bindings::irqreturn_IRQ_NONE, 24 25 /// The interrupt was handled by this device. 26 Handled = bindings::irqreturn_IRQ_HANDLED, 27} 28 29/// Callbacks for an IRQ handler. 30pub trait Handler: Sync { 31 /// The hard IRQ handler. 32 /// 33 /// This is executed in interrupt context, hence all corresponding 34 /// limitations do apply. 35 /// 36 /// All work that does not necessarily need to be executed from 37 /// interrupt context, should be deferred to a threaded handler. 38 /// See also [`ThreadedRegistration`]. 39 fn handle(&self, device: &Device<Bound>) -> IrqReturn; 40} 41 42impl<T: ?Sized + Handler + Send> Handler for Arc<T> { 43 fn handle(&self, device: &Device<Bound>) -> IrqReturn { 44 T::handle(self, device) 45 } 46} 47 48impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> { 49 fn handle(&self, device: &Device<Bound>) -> IrqReturn { 50 T::handle(self, device) 51 } 52} 53 54/// # Invariants 55/// 56/// - `self.irq` is the same as the one passed to `request_{threaded}_irq`. 57/// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique 58/// by the type system, since each call to `new` will return a different instance of 59/// `Registration`. 60#[pin_data(PinnedDrop)] 61struct RegistrationInner { 62 irq: u32, 63 cookie: *mut c_void, 64} 65 66impl RegistrationInner { 67 fn synchronize(&self) { 68 // SAFETY: safe as per the invariants of `RegistrationInner` 69 unsafe { bindings::synchronize_irq(self.irq) }; 70 } 71} 72 73#[pinned_drop] 74impl PinnedDrop for RegistrationInner { 75 fn drop(self: Pin<&mut Self>) { 76 // SAFETY: 77 // 78 // Safe as per the invariants of `RegistrationInner` and: 79 // 80 // - The containing struct is `!Unpin` and was initialized using 81 // pin-init, so it occupied the same memory location for the entirety of 82 // its lifetime. 83 // 84 // Notice that this will block until all handlers finish executing, 85 // i.e.: at no point will &self be invalid while the handler is running. 86 unsafe { bindings::free_irq(self.irq, self.cookie) }; 87 } 88} 89 90// SAFETY: We only use `inner` on drop, which called at most once with no 91// concurrent access. 92unsafe impl Sync for RegistrationInner {} 93 94// SAFETY: It is safe to send `RegistrationInner` across threads. 95unsafe impl Send for RegistrationInner {} 96 97/// A request for an IRQ line for a given device. 98/// 99/// # Invariants 100/// 101/// - `ìrq` is the number of an interrupt source of `dev`. 102/// - `irq` has not been registered yet. 103pub struct IrqRequest<'a> { 104 dev: &'a Device<Bound>, 105 irq: u32, 106} 107 108impl<'a> IrqRequest<'a> { 109 /// Creates a new IRQ request for the given device and IRQ number. 110 /// 111 /// # Safety 112 /// 113 /// - `irq` should be a valid IRQ number for `dev`. 114 pub(crate) unsafe fn new(dev: &'a Device<Bound>, irq: u32) -> Self { 115 // INVARIANT: `irq` is a valid IRQ number for `dev`. 116 IrqRequest { dev, irq } 117 } 118 119 /// Returns the IRQ number of an [`IrqRequest`]. 120 pub fn irq(&self) -> u32 { 121 self.irq 122 } 123} 124 125/// A registration of an IRQ handler for a given IRQ line. 126/// 127/// # Examples 128/// 129/// The following is an example of using `Registration`. It uses a 130/// [`Completion`] to coordinate between the IRQ 131/// handler and process context. [`Completion`] uses interior mutability, so the 132/// handler can signal with [`Completion::complete_all()`] and the process 133/// context can wait with [`Completion::wait_for_completion()`] even though 134/// there is no way to get a mutable reference to the any of the fields in 135/// `Data`. 136/// 137/// [`Completion`]: kernel::sync::Completion 138/// [`Completion::complete_all()`]: kernel::sync::Completion::complete_all 139/// [`Completion::wait_for_completion()`]: kernel::sync::Completion::wait_for_completion 140/// 141/// ``` 142/// use kernel::c_str; 143/// use kernel::device::{Bound, Device}; 144/// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration}; 145/// use kernel::prelude::*; 146/// use kernel::sync::{Arc, Completion}; 147/// 148/// // Data shared between process and IRQ context. 149/// #[pin_data] 150/// struct Data { 151/// #[pin] 152/// completion: Completion, 153/// } 154/// 155/// impl irq::Handler for Data { 156/// // Executed in IRQ context. 157/// fn handle(&self, _dev: &Device<Bound>) -> IrqReturn { 158/// self.completion.complete_all(); 159/// IrqReturn::Handled 160/// } 161/// } 162/// 163/// // Registers an IRQ handler for the given IrqRequest. 164/// // 165/// // This runs in process context and assumes `request` was previously acquired from a device. 166/// fn register_irq( 167/// handler: impl PinInit<Data, Error>, 168/// request: IrqRequest<'_>, 169/// ) -> Result<Arc<Registration<Data>>> { 170/// let registration = Registration::new(request, Flags::SHARED, c_str!("my_device"), handler); 171/// 172/// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 173/// 174/// registration.handler().completion.wait_for_completion(); 175/// 176/// Ok(registration) 177/// } 178/// # Ok::<(), Error>(()) 179/// ``` 180/// 181/// # Invariants 182/// 183/// * We own an irq handler whose cookie is a pointer to `Self`. 184#[pin_data] 185pub struct Registration<T: Handler + 'static> { 186 #[pin] 187 inner: Devres<RegistrationInner>, 188 189 #[pin] 190 handler: T, 191 192 /// Pinned because we need address stability so that we can pass a pointer 193 /// to the callback. 194 #[pin] 195 _pin: PhantomPinned, 196} 197 198impl<T: Handler + 'static> Registration<T> { 199 /// Registers the IRQ handler with the system for the given IRQ number. 200 pub fn new<'a>( 201 request: IrqRequest<'a>, 202 flags: Flags, 203 name: &'static CStr, 204 handler: impl PinInit<T, Error> + 'a, 205 ) -> impl PinInit<Self, Error> + 'a { 206 try_pin_init!(&this in Self { 207 handler <- handler, 208 inner <- Devres::new( 209 request.dev, 210 try_pin_init!(RegistrationInner { 211 // INVARIANT: `this` is a valid pointer to the `Registration` instance 212 cookie: this.as_ptr().cast::<c_void>(), 213 irq: { 214 // SAFETY: 215 // - The callbacks are valid for use with request_irq. 216 // - If this succeeds, the slot is guaranteed to be valid until the 217 // destructor of Self runs, which will deregister the callbacks 218 // before the memory location becomes invalid. 219 // - When request_irq is called, everything that handle_irq_callback will 220 // touch has already been initialized, so it's safe for the callback to 221 // be called immediately. 222 to_result(unsafe { 223 bindings::request_irq( 224 request.irq, 225 Some(handle_irq_callback::<T>), 226 flags.into_inner(), 227 name.as_char_ptr(), 228 this.as_ptr().cast::<c_void>(), 229 ) 230 })?; 231 request.irq 232 } 233 }) 234 ), 235 _pin: PhantomPinned, 236 }) 237 } 238 239 /// Returns a reference to the handler that was registered with the system. 240 pub fn handler(&self) -> &T { 241 &self.handler 242 } 243 244 /// Wait for pending IRQ handlers on other CPUs. 245 /// 246 /// This will attempt to access the inner [`Devres`] container. 247 pub fn try_synchronize(&self) -> Result { 248 let inner = self.inner.try_access().ok_or(ENODEV)?; 249 inner.synchronize(); 250 Ok(()) 251 } 252 253 /// Wait for pending IRQ handlers on other CPUs. 254 pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 255 let inner = self.inner.access(dev)?; 256 inner.synchronize(); 257 Ok(()) 258 } 259} 260 261/// # Safety 262/// 263/// This function should be only used as the callback in `request_irq`. 264unsafe extern "C" fn handle_irq_callback<T: Handler + 'static>( 265 _irq: i32, 266 ptr: *mut c_void, 267) -> c_uint { 268 // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new` 269 let registration = unsafe { &*(ptr as *const Registration<T>) }; 270 // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 271 // callback is running implies that the device has not yet been unbound. 272 let device = unsafe { registration.inner.device().as_bound() }; 273 274 T::handle(®istration.handler, device) as c_uint 275} 276 277/// The value that can be returned from [`ThreadedHandler::handle`]. 278#[repr(u32)] 279pub enum ThreadedIrqReturn { 280 /// The interrupt was not from this device or was not handled. 281 None = bindings::irqreturn_IRQ_NONE, 282 283 /// The interrupt was handled by this device. 284 Handled = bindings::irqreturn_IRQ_HANDLED, 285 286 /// The handler wants the handler thread to wake up. 287 WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD, 288} 289 290/// Callbacks for a threaded IRQ handler. 291pub trait ThreadedHandler: Sync { 292 /// The hard IRQ handler. 293 /// 294 /// This is executed in interrupt context, hence all corresponding 295 /// limitations do apply. All work that does not necessarily need to be 296 /// executed from interrupt context, should be deferred to the threaded 297 /// handler, i.e. [`ThreadedHandler::handle_threaded`]. 298 /// 299 /// The default implementation returns [`ThreadedIrqReturn::WakeThread`]. 300 #[expect(unused_variables)] 301 fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 302 ThreadedIrqReturn::WakeThread 303 } 304 305 /// The threaded IRQ handler. 306 /// 307 /// This is executed in process context. The kernel creates a dedicated 308 /// `kthread` for this purpose. 309 fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn; 310} 311 312impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> { 313 fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 314 T::handle(self, device) 315 } 316 317 fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn { 318 T::handle_threaded(self, device) 319 } 320} 321 322impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> { 323 fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 324 T::handle(self, device) 325 } 326 327 fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn { 328 T::handle_threaded(self, device) 329 } 330} 331 332/// A registration of a threaded IRQ handler for a given IRQ line. 333/// 334/// Two callbacks are required: one to handle the IRQ, and one to handle any 335/// other work in a separate thread. 336/// 337/// The thread handler is only called if the IRQ handler returns 338/// [`ThreadedIrqReturn::WakeThread`]. 339/// 340/// # Examples 341/// 342/// The following is an example of using [`ThreadedRegistration`]. It uses a 343/// [`Mutex`](kernel::sync::Mutex) to provide interior mutability. 344/// 345/// ``` 346/// use kernel::c_str; 347/// use kernel::device::{Bound, Device}; 348/// use kernel::irq::{ 349/// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn, 350/// ThreadedRegistration, 351/// }; 352/// use kernel::prelude::*; 353/// use kernel::sync::{Arc, Mutex}; 354/// 355/// // Declare a struct that will be passed in when the interrupt fires. The u32 356/// // merely serves as an example of some internal data. 357/// // 358/// // [`irq::ThreadedHandler::handle`] takes `&self`. This example 359/// // illustrates how interior mutability can be used when sharing the data 360/// // between process context and IRQ context. 361/// #[pin_data] 362/// struct Data { 363/// #[pin] 364/// value: Mutex<u32>, 365/// } 366/// 367/// impl ThreadedHandler for Data { 368/// // This will run (in a separate kthread) if and only if 369/// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by 370/// // default. 371/// fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn { 372/// let mut data = self.value.lock(); 373/// *data += 1; 374/// IrqReturn::Handled 375/// } 376/// } 377/// 378/// // Registers a threaded IRQ handler for the given [`IrqRequest`]. 379/// // 380/// // This is executing in process context and assumes that `request` was 381/// // previously acquired from a device. 382/// fn register_threaded_irq( 383/// handler: impl PinInit<Data, Error>, 384/// request: IrqRequest<'_>, 385/// ) -> Result<Arc<ThreadedRegistration<Data>>> { 386/// let registration = 387/// ThreadedRegistration::new(request, Flags::SHARED, c_str!("my_device"), handler); 388/// 389/// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 390/// 391/// { 392/// // The data can be accessed from process context too. 393/// let mut data = registration.handler().value.lock(); 394/// *data += 1; 395/// } 396/// 397/// Ok(registration) 398/// } 399/// # Ok::<(), Error>(()) 400/// ``` 401/// 402/// # Invariants 403/// 404/// * We own an irq handler whose cookie is a pointer to `Self`. 405#[pin_data] 406pub struct ThreadedRegistration<T: ThreadedHandler + 'static> { 407 #[pin] 408 inner: Devres<RegistrationInner>, 409 410 #[pin] 411 handler: T, 412 413 /// Pinned because we need address stability so that we can pass a pointer 414 /// to the callback. 415 #[pin] 416 _pin: PhantomPinned, 417} 418 419impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> { 420 /// Registers the IRQ handler with the system for the given IRQ number. 421 pub fn new<'a>( 422 request: IrqRequest<'a>, 423 flags: Flags, 424 name: &'static CStr, 425 handler: impl PinInit<T, Error> + 'a, 426 ) -> impl PinInit<Self, Error> + 'a { 427 try_pin_init!(&this in Self { 428 handler <- handler, 429 inner <- Devres::new( 430 request.dev, 431 try_pin_init!(RegistrationInner { 432 // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance. 433 cookie: this.as_ptr().cast::<c_void>(), 434 irq: { 435 // SAFETY: 436 // - The callbacks are valid for use with request_threaded_irq. 437 // - If this succeeds, the slot is guaranteed to be valid until the 438 // destructor of Self runs, which will deregister the callbacks 439 // before the memory location becomes invalid. 440 // - When request_threaded_irq is called, everything that the two callbacks 441 // will touch has already been initialized, so it's safe for the 442 // callbacks to be called immediately. 443 to_result(unsafe { 444 bindings::request_threaded_irq( 445 request.irq, 446 Some(handle_threaded_irq_callback::<T>), 447 Some(thread_fn_callback::<T>), 448 flags.into_inner(), 449 name.as_char_ptr(), 450 this.as_ptr().cast::<c_void>(), 451 ) 452 })?; 453 request.irq 454 } 455 }) 456 ), 457 _pin: PhantomPinned, 458 }) 459 } 460 461 /// Returns a reference to the handler that was registered with the system. 462 pub fn handler(&self) -> &T { 463 &self.handler 464 } 465 466 /// Wait for pending IRQ handlers on other CPUs. 467 /// 468 /// This will attempt to access the inner [`Devres`] container. 469 pub fn try_synchronize(&self) -> Result { 470 let inner = self.inner.try_access().ok_or(ENODEV)?; 471 inner.synchronize(); 472 Ok(()) 473 } 474 475 /// Wait for pending IRQ handlers on other CPUs. 476 pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 477 let inner = self.inner.access(dev)?; 478 inner.synchronize(); 479 Ok(()) 480 } 481} 482 483/// # Safety 484/// 485/// This function should be only used as the callback in `request_threaded_irq`. 486unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler + 'static>( 487 _irq: i32, 488 ptr: *mut c_void, 489) -> c_uint { 490 // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new` 491 let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) }; 492 // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 493 // callback is running implies that the device has not yet been unbound. 494 let device = unsafe { registration.inner.device().as_bound() }; 495 496 T::handle(®istration.handler, device) as c_uint 497} 498 499/// # Safety 500/// 501/// This function should be only used as the callback in `request_threaded_irq`. 502unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler + 'static>( 503 _irq: i32, 504 ptr: *mut c_void, 505) -> c_uint { 506 // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new` 507 let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) }; 508 // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 509 // callback is running implies that the device has not yet been unbound. 510 let device = unsafe { registration.inner.device().as_bound() }; 511 512 T::handle_threaded(®istration.handler, device) as c_uint 513}
~/
Read-only file preview.