Skip to content

Commit 29e16fc

Browse files
DarksonnDanilo Krummrich
authored andcommitted
rust: irq: add &Device<Bound> argument to irq callbacks
When working with a bus device, many operations are only possible while the device is still bound. The &Device<Bound> type represents a proof in the type system that you are in a scope where the device is guaranteed to still be bound. Since we deregister irq callbacks when unbinding a device, if an irq callback is running, that implies that the device has not yet been unbound. To allow drivers to take advantage of that, add an additional argument to irq callbacks. Signed-off-by: Alice Ryhl <[email protected]> Reviewed-by: Boqun Feng <[email protected]> Signed-off-by: Daniel Almeida <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Danilo Krummrich <[email protected]>
1 parent 9b6d4fb commit 29e16fc

1 file changed

Lines changed: 57 additions & 38 deletions

File tree

rust/kernel/irq/request.rs

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ pub trait Handler: Sync {
3636
/// All work that does not necessarily need to be executed from
3737
/// interrupt context, should be deferred to a threaded handler.
3838
/// See also [`ThreadedRegistration`].
39-
fn handle(&self) -> IrqReturn;
39+
fn handle(&self, device: &Device<Bound>) -> IrqReturn;
4040
}
4141

4242
impl<T: ?Sized + Handler + Send> Handler for Arc<T> {
43-
fn handle(&self) -> IrqReturn {
44-
T::handle(self)
43+
fn handle(&self, device: &Device<Bound>) -> IrqReturn {
44+
T::handle(self, device)
4545
}
4646
}
4747

4848
impl<T: ?Sized + Handler, A: Allocator> Handler for Box<T, A> {
49-
fn handle(&self) -> IrqReturn {
50-
T::handle(self)
49+
fn handle(&self, device: &Device<Bound>) -> IrqReturn {
50+
T::handle(self, device)
5151
}
5252
}
5353

@@ -140,7 +140,7 @@ impl<'a> IrqRequest<'a> {
140140
///
141141
/// ```
142142
/// use kernel::c_str;
143-
/// use kernel::device::Bound;
143+
/// use kernel::device::{Bound, Device};
144144
/// use kernel::irq::{self, Flags, IrqRequest, IrqReturn, Registration};
145145
/// use kernel::prelude::*;
146146
/// use kernel::sync::{Arc, Completion};
@@ -154,7 +154,7 @@ impl<'a> IrqRequest<'a> {
154154
///
155155
/// impl irq::Handler for Data {
156156
/// // Executed in IRQ context.
157-
/// fn handle(&self) -> IrqReturn {
157+
/// fn handle(&self, _dev: &Device<Bound>) -> IrqReturn {
158158
/// self.completion.complete_all();
159159
/// IrqReturn::Handled
160160
/// }
@@ -180,7 +180,7 @@ impl<'a> IrqRequest<'a> {
180180
///
181181
/// # Invariants
182182
///
183-
/// * We own an irq handler using `&self.handler` as its private data.
183+
/// * We own an irq handler whose cookie is a pointer to `Self`.
184184
#[pin_data]
185185
pub struct Registration<T: Handler + 'static> {
186186
#[pin]
@@ -208,21 +208,24 @@ impl<T: Handler + 'static> Registration<T> {
208208
inner <- Devres::new(
209209
request.dev,
210210
try_pin_init!(RegistrationInner {
211-
// SAFETY: `this` is a valid pointer to the `Registration` instance
212-
cookie: unsafe { &raw mut (*this.as_ptr()).handler }.cast(),
211+
// INVARIANT: `this` is a valid pointer to the `Registration` instance
212+
cookie: this.as_ptr().cast::<c_void>(),
213213
irq: {
214214
// SAFETY:
215215
// - The callbacks are valid for use with request_irq.
216216
// - If this succeeds, the slot is guaranteed to be valid until the
217217
// destructor of Self runs, which will deregister the callbacks
218218
// 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.
219222
to_result(unsafe {
220223
bindings::request_irq(
221224
request.irq,
222225
Some(handle_irq_callback::<T>),
223226
flags.into_inner(),
224227
name.as_char_ptr(),
225-
(&raw mut (*this.as_ptr()).handler).cast(),
228+
this.as_ptr().cast::<c_void>(),
226229
)
227230
})?;
228231
request.irq
@@ -259,9 +262,13 @@ impl<T: Handler + 'static> Registration<T> {
259262
///
260263
/// This function should be only used as the callback in `request_irq`.
261264
unsafe extern "C" fn handle_irq_callback<T: Handler>(_irq: i32, ptr: *mut c_void) -> c_uint {
262-
// SAFETY: `ptr` is a pointer to T set in `Registration::new`
263-
let handler = unsafe { &*(ptr as *const T) };
264-
T::handle(handler) as c_uint
265+
// SAFETY: `ptr` is a pointer to `Registration<T>` set in `Registration::new`
266+
let registration = unsafe { &*(ptr as *const Registration<T>) };
267+
// SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
268+
// callback is running implies that the device has not yet been unbound.
269+
let device = unsafe { registration.inner.device().as_bound() };
270+
271+
T::handle(&registration.handler, device) as c_uint
265272
}
266273

267274
/// The value that can be returned from [`ThreadedHandler::handle`].
@@ -287,34 +294,35 @@ pub trait ThreadedHandler: Sync {
287294
/// handler, i.e. [`ThreadedHandler::handle_threaded`].
288295
///
289296
/// The default implementation returns [`ThreadedIrqReturn::WakeThread`].
290-
fn handle(&self) -> ThreadedIrqReturn {
297+
#[expect(unused_variables)]
298+
fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
291299
ThreadedIrqReturn::WakeThread
292300
}
293301

294302
/// The threaded IRQ handler.
295303
///
296304
/// This is executed in process context. The kernel creates a dedicated
297305
/// `kthread` for this purpose.
298-
fn handle_threaded(&self) -> IrqReturn;
306+
fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn;
299307
}
300308

301309
impl<T: ?Sized + ThreadedHandler + Send> ThreadedHandler for Arc<T> {
302-
fn handle(&self) -> ThreadedIrqReturn {
303-
T::handle(self)
310+
fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
311+
T::handle(self, device)
304312
}
305313

306-
fn handle_threaded(&self) -> IrqReturn {
307-
T::handle_threaded(self)
314+
fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
315+
T::handle_threaded(self, device)
308316
}
309317
}
310318

311319
impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
312-
fn handle(&self) -> ThreadedIrqReturn {
313-
T::handle(self)
320+
fn handle(&self, device: &Device<Bound>) -> ThreadedIrqReturn {
321+
T::handle(self, device)
314322
}
315323

316-
fn handle_threaded(&self) -> IrqReturn {
317-
T::handle_threaded(self)
324+
fn handle_threaded(&self, device: &Device<Bound>) -> IrqReturn {
325+
T::handle_threaded(self, device)
318326
}
319327
}
320328

@@ -333,7 +341,7 @@ impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
333341
///
334342
/// ```
335343
/// use kernel::c_str;
336-
/// use kernel::device::Bound;
344+
/// use kernel::device::{Bound, Device};
337345
/// use kernel::irq::{
338346
/// self, Flags, IrqRequest, IrqReturn, ThreadedHandler, ThreadedIrqReturn,
339347
/// ThreadedRegistration,
@@ -357,7 +365,7 @@ impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
357365
/// // This will run (in a separate kthread) if and only if
358366
/// // [`ThreadedHandler::handle`] returns [`WakeThread`], which it does by
359367
/// // default.
360-
/// fn handle_threaded(&self) -> IrqReturn {
368+
/// fn handle_threaded(&self, _dev: &Device<Bound>) -> IrqReturn {
361369
/// let mut data = self.value.lock();
362370
/// *data += 1;
363371
/// IrqReturn::Handled
@@ -390,7 +398,7 @@ impl<T: ?Sized + ThreadedHandler, A: Allocator> ThreadedHandler for Box<T, A> {
390398
///
391399
/// # Invariants
392400
///
393-
/// * We own an irq handler using `&T` as its private data.
401+
/// * We own an irq handler whose cookie is a pointer to `Self`.
394402
#[pin_data]
395403
pub struct ThreadedRegistration<T: ThreadedHandler + 'static> {
396404
#[pin]
@@ -418,22 +426,25 @@ impl<T: ThreadedHandler + 'static> ThreadedRegistration<T> {
418426
inner <- Devres::new(
419427
request.dev,
420428
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(),
429+
// INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance.
430+
cookie: this.as_ptr().cast::<c_void>(),
423431
irq: {
424432
// SAFETY:
425433
// - The callbacks are valid for use with request_threaded_irq.
426434
// - 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.
435+
// destructor of Self runs, which will deregister the callbacks
436+
// before the memory location becomes invalid.
437+
// - When request_threaded_irq is called, everything that the two callbacks
438+
// will touch has already been initialized, so it's safe for the
439+
// callbacks to be called immediately.
429440
to_result(unsafe {
430441
bindings::request_threaded_irq(
431442
request.irq,
432443
Some(handle_threaded_irq_callback::<T>),
433444
Some(thread_fn_callback::<T>),
434445
flags.into_inner(),
435446
name.as_char_ptr(),
436-
(&raw mut (*this.as_ptr()).handler).cast(),
447+
this.as_ptr().cast::<c_void>(),
437448
)
438449
})?;
439450
request.irq
@@ -473,16 +484,24 @@ unsafe extern "C" fn handle_threaded_irq_callback<T: ThreadedHandler>(
473484
_irq: i32,
474485
ptr: *mut c_void,
475486
) -> 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
487+
// SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
488+
let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
489+
// SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
490+
// callback is running implies that the device has not yet been unbound.
491+
let device = unsafe { registration.inner.device().as_bound() };
492+
493+
T::handle(&registration.handler, device) as c_uint
479494
}
480495

481496
/// # Safety
482497
///
483498
/// This function should be only used as the callback in `request_threaded_irq`.
484499
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
500+
// SAFETY: `ptr` is a pointer to `ThreadedRegistration<T>` set in `ThreadedRegistration::new`
501+
let registration = unsafe { &*(ptr as *const ThreadedRegistration<T>) };
502+
// SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq
503+
// callback is running implies that the device has not yet been unbound.
504+
let device = unsafe { registration.inner.device().as_bound() };
505+
506+
T::handle_threaded(&registration.handler, device) as c_uint
488507
}

0 commit comments

Comments
 (0)