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 8 use core::marker::PhantomPinned; 9 10 use crate::alloc::Allocator; 11 use crate::device::{Bound, Device}; 12 use crate::devres::Devres; 13 use crate::error::to_result; 14 use crate::irq::flags::Flags; 15 use crate::prelude::*; 16 use crate::str::CStr; 17 use crate::sync::Arc; 18 19 /// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`]. 20 #[repr(u32)] 21 pub 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. 30 pub 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 42 impl<T: ?Sized + Handler + Send> Handler for Arc<T> { 43 fn handle(&self, device: &Device<Bound>) -> IrqReturn { 44 T::handle(self, device) 45 } 46 } 47 48 impl<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)] 61 struct RegistrationInner { 62 irq: u32, 63 cookie: *mut c_void, 64 } 65 66 impl 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] 74 impl 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. 92 unsafe impl Sync for RegistrationInner {} 93 94 // SAFETY: It is safe to send `RegistrationInner` across threads. 95 unsafe 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. 103 pub struct IrqRequest<'a> { 104 dev: &'a Device<Bound>, 105 irq: u32, 106 } 107 108 impl<'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::device::{Bound, Device}; 143 /// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration}; 144 /// use kernel::prelude::*; 145 /// use kernel::sync::{Arc, Completion}; 146 /// 147 /// // Data shared between process and IRQ context. 148 /// #[pin_data] 149 /// struct Data { 150 /// #[pin] 151 /// completion: Completion, 152 /// } 153 /// 154 /// impl irq::Handler for Data { 155 /// // Executed in IRQ context. 156 /// fn handle(&self, _dev: &Device<Bound>) -> IrqReturn { 157 /// self.completion.complete_all(); 158 /// IrqReturn::Handled 159 /// } 160 /// } 161 /// 162 /// // Registers an IRQ handler for the given IrqRequest. 163 /// // 164 /// // This runs in process context and assumes `request` was previously acquired from a device. 165 /// fn register_irq( 166 /// handler: impl PinInit<Data, Error>, 167 /// request: IrqRequest<'_>, 168 /// ) -> Result<Arc<Registration<Data>>> { 169 /// let registration = Registration::new(request, Flags::SHARED, c"my_device", handler); 170 /// 171 /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 172 /// 173 /// registration.handler().completion.wait_for_completion(); 174 /// 175 /// Ok(registration) 176 /// } 177 /// # Ok::<(), Error>(()) 178 /// ``` 179 /// 180 /// # Invariants 181 /// 182 /// * We own an irq handler whose cookie is a pointer to `Self`. 183 #[pin_data] 184 pub struct Registration<T: Handler + 'static> { 185 #[pin] 186 inner: Devres<RegistrationInner>, 187 188 #[pin] 189 handler: T, 190 191 /// Pinned because we need address stability so that we can pass a pointer 192 /// to the callback. 193 #[pin] 194 _pin: PhantomPinned, 195 } 196 197 impl<T: Handler + 'static> Registration<T> { 198 /// Registers the IRQ handler with the system for the given IRQ number. 199 pub fn new<'a>( 200 request: IrqRequest<'a>, 201 flags: Flags, 202 name: &'static CStr, 203 handler: impl PinInit<T, Error> + 'a, 204 ) -> impl PinInit<Self, Error> + 'a { 205 try_pin_init!(&this in Self { 206 handler <- handler, 207 inner <- Devres::new( 208 request.dev, 209 try_pin_init!(RegistrationInner { 210 // INVARIANT: `this` is a valid pointer to the `Registration` instance 211 cookie: this.as_ptr().cast::<c_void>(), 212 irq: { 213 // SAFETY: 214 // - The callbacks are valid for use with request_irq. 215 // - If this succeeds, the slot is guaranteed to be valid until the 216 // destructor of Self runs, which will deregister the callbacks 217 // before the memory location becomes invalid. 218 // - When request_irq is called, everything that handle_irq_callback will 219 // touch has already been initialized, so it's safe for the callback to 220 // be called immediately. 221 to_result(unsafe { 222 bindings::request_irq( 223 request.irq, 224 Some(handle_irq_callback::<T>), 225 flags.into_inner(), 226 name.as_char_ptr(), 227 this.as_ptr().cast::<c_void>(), 228 ) 229 })?; 230 request.irq 231 } 232 }) 233 ), 234 _pin: PhantomPinned, 235 }) 236 } 237 238 /// Returns a reference to the handler that was registered with the system. 239 pub fn handler(&self) -> &T { 240 &self.handler 241 } 242 243 /// Wait for pending IRQ handlers on other CPUs. 244 /// 245 /// This will attempt to access the inner [`Devres`] container. 246 pub fn try_synchronize(&self) -> Result { 247 let inner = self.inner.try_access().ok_or(ENODEV)?; 248 inner.synchronize(); 249 Ok(()) 250 } 251 252 /// Wait for pending IRQ handlers on other CPUs. 253 pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 254 let inner = self.inner.access(dev)?; 255 inner.synchronize(); 256 Ok(()) 257 } 258 } 259 260 /// # Safety 261 /// 262 /// This function should be only used as the callback in `request_irq`. 263 unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint { 264 // SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new` 265 let registration = unsafe { &*(ptr as *const Registration<T>) }; 266 // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 267 // callback is running implies that the device has not yet been unbound. 268 let device = unsafe { registration.inner.device().as_bound() }; 269 270 T::handle(®istration.handler, device) as c_uint 271 } 272 273 /// The value that can be returned from [`ThreadedHandler::handle`]. 274 #[repr(u32)] 275 pub enum ThreadedIrqReturn { 276 /// The interrupt was not from this device or was not handled. 277 None = bindings::irqreturn_IRQ_NONE, 278 279 /// The interrupt was handled by this device. 280 Handled = bindings::irqreturn_IRQ_HANDLED, 281 282 /// The handler wants the handler thread to wake up. 283 WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD, 284 } 285 286 /// Callbacks for a threaded IRQ handler. 287 pub trait ThreadedHandler: Sync { 288 /// The hard IRQ handler. 289 /// 290 /// This is executed in interrupt context, hence all corresponding 291 /// limitations do apply. All work that does not necessarily need to be 292 /// executed from interrupt context, should be deferred to the threaded 293 /// handler, i.e. [`ThreadedHandler::handle_threaded`]. 294 /// 295 /// The default implementation returns [`ThreadedIrqReturn::WakeThread`]. 296 #[expect(unused_variables)] 297 fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 298 ThreadedIrqReturn::WakeThread 299 } 300 301 /// The threaded IRQ handler. 302 /// 303 /// This is executed in process context. The kernel creates a dedicated 304 /// `kthread` for this purpose. 305 fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn; 306 } 307 308 impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> { 309 fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 310 T::handle(self, device) 311 } 312 313 fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn { 314 T::handle_threaded(self, device) 315 } 316 } 317 318 impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> { 319 fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn { 320 T::handle(self, device) 321 } 322 323 fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn { 324 T::handle_threaded(self, device) 325 } 326 } 327 328 /// A registration of a threaded IRQ handler for a given IRQ line. 329 /// 330 /// Two callbacks are required: one to handle the IRQ, and one to handle any 331 /// other work in a separate thread. 332 /// 333 /// The thread handler is only called if the IRQ handler returns 334 /// [`ThreadedIrqReturn::WakeThread`]. 335 /// 336 /// # Examples 337 /// 338 /// The following is an example of using [`ThreadedRegistration`]. It uses a 339 /// [`Mutex`](kernel::sync::Mutex) to provide interior mutability. 340 /// 341 /// ``` 342 /// use kernel::device::{Bound, Device}; 343 /// use kernel::irq::{ 344 /// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn, 345 /// ThreadedRegistration, 346 /// }; 347 /// use kernel::prelude::*; 348 /// use kernel::sync::{Arc, Mutex}; 349 /// 350 /// // Declare a struct that will be passed in when the interrupt fires. The u32 351 /// // merely serves as an example of some internal data. 352 /// // 353 /// // [`irq::ThreadedHandler::handle`] takes `&self`. This example 354 /// // illustrates how interior mutability can be used when sharing the data 355 /// // between process context and IRQ context. 356 /// #[pin_data] 357 /// struct Data { 358 /// #[pin] 359 /// value: Mutex<u32>, 360 /// } 361 /// 362 /// impl ThreadedHandler for Data { 363 /// // This will run (in a separate kthread) if and only if 364 /// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by 365 /// // default. 366 /// fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn { 367 /// let mut data = self.value.lock(); 368 /// *data += 1; 369 /// IrqReturn::Handled 370 /// } 371 /// } 372 /// 373 /// // Registers a threaded IRQ handler for the given [`IrqRequest`]. 374 /// // 375 /// // This is executing in process context and assumes that `request` was 376 /// // previously acquired from a device. 377 /// fn register_threaded_irq( 378 /// handler: impl PinInit<Data, Error>, 379 /// request: IrqRequest<'_>, 380 /// ) -> Result<Arc<ThreadedRegistration<Data>>> { 381 /// let registration = 382 /// ThreadedRegistration::new(request, Flags::SHARED, c"my_device", handler); 383 /// 384 /// let registration = Arc::pin_init(registration, GFP_KERNEL)?; 385 /// 386 /// { 387 /// // The data can be accessed from process context too. 388 /// let mut data = registration.handler().value.lock(); 389 /// *data += 1; 390 /// } 391 /// 392 /// Ok(registration) 393 /// } 394 /// # Ok::<(), Error>(()) 395 /// ``` 396 /// 397 /// # Invariants 398 /// 399 /// * We own an irq handler whose cookie is a pointer to `Self`. 400 #[pin_data] 401 pub struct ThreadedRegistration<T: ThreadedHandler + 'static> { 402 #[pin] 403 inner: Devres<RegistrationInner>, 404 405 #[pin] 406 handler: T, 407 408 /// Pinned because we need address stability so that we can pass a pointer 409 /// to the callback. 410 #[pin] 411 _pin: PhantomPinned, 412 } 413 414 impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> { 415 /// Registers the IRQ handler with the system for the given IRQ number. 416 pub fn new<'a>( 417 request: IrqRequest<'a>, 418 flags: Flags, 419 name: &'static CStr, 420 handler: impl PinInit<T, Error> + 'a, 421 ) -> impl PinInit<Self, Error> + 'a { 422 try_pin_init!(&this in Self { 423 handler <- handler, 424 inner <- Devres::new( 425 request.dev, 426 try_pin_init!(RegistrationInner { 427 // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance. 428 cookie: this.as_ptr().cast::<c_void>(), 429 irq: { 430 // SAFETY: 431 // - The callbacks are valid for use with request_threaded_irq. 432 // - If this succeeds, the slot is guaranteed to be valid until the 433 // destructor of Self runs, which will deregister the callbacks 434 // before the memory location becomes invalid. 435 // - When request_threaded_irq is called, everything that the two callbacks 436 // will touch has already been initialized, so it's safe for the 437 // callbacks to be called immediately. 438 to_result(unsafe { 439 bindings::request_threaded_irq( 440 request.irq, 441 Some(handle_threaded_irq_callback::<T>), 442 Some(thread_fn_callback::<T>), 443 flags.into_inner(), 444 name.as_char_ptr(), 445 this.as_ptr().cast::<c_void>(), 446 ) 447 })?; 448 request.irq 449 } 450 }) 451 ), 452 _pin: PhantomPinned, 453 }) 454 } 455 456 /// Returns a reference to the handler that was registered with the system. 457 pub fn handler(&self) -> &T { 458 &self.handler 459 } 460 461 /// Wait for pending IRQ handlers on other CPUs. 462 /// 463 /// This will attempt to access the inner [`Devres`] container. 464 pub fn try_synchronize(&self) -> Result { 465 let inner = self.inner.try_access().ok_or(ENODEV)?; 466 inner.synchronize(); 467 Ok(()) 468 } 469 470 /// Wait for pending IRQ handlers on other CPUs. 471 pub fn synchronize(&self, dev: &Device<Bound>) -> Result { 472 let inner = self.inner.access(dev)?; 473 inner.synchronize(); 474 Ok(()) 475 } 476 } 477 478 /// # Safety 479 /// 480 /// This function should be only used as the callback in `request_threaded_irq`. 481 unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>( 482 _irq: i32, 483 ptr: *mut c_void, 484 ) -> c_uint { 485 // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new` 486 let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) }; 487 // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 488 // callback is running implies that the device has not yet been unbound. 489 let device = unsafe { registration.inner.device().as_bound() }; 490 491 T::handle(®istration.handler, device) as c_uint 492 } 493 494 /// # Safety 495 /// 496 /// This function should be only used as the callback in `request_threaded_irq`. 497 unsafe extern "C" fn thread_fn_callback<T: ThreadedHandler>(_irq: i32, ptr: *mut c_void) -> c_uint { 498 // SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new` 499 let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) }; 500 // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq 501 // callback is running implies that the device has not yet been unbound. 502 let device = unsafe { registration.inner.device().as_bound() }; 503 504 T::handle_threaded(®istration.handler, device) as c_uint 505 } 506