@@ -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
4242impl < 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
4848impl < 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]
185185pub 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`.
261264unsafe 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
301309impl < 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
311319impl < 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]
395403pub 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`.
484499unsafe 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