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