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