Skip to main content

kernel/
devres.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Devres abstraction
4//!
5//! [`Devres`] represents an abstraction for the kernel devres (device resource management)
6//! implementation.
7
8use crate::{
9    alloc::Flags,
10    bindings,
11    device::{
12        Bound,
13        Device, //
14    },
15    error::to_result,
16    prelude::*,
17    revocable::{
18        Revocable,
19        RevocableGuard, //
20    },
21    sync::{
22        aref::ARef,
23        rcu,
24        Arc,
25        Completion, //
26    },
27    types::{
28        CovariantForLt,
29        ForLt,
30        ForeignOwnable,
31        Opaque, //
32    },
33};
34
35/// Inner type that embeds a `struct devres_node` and the `Revocable<T>`.
36#[repr(C)]
37#[pin_data]
38struct Inner<T> {
39    #[pin]
40    node: Opaque<bindings::devres_node>,
41    #[pin]
42    data: Revocable<T>,
43    #[pin]
44    revocation: Completion,
45}
46
47/// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to
48/// manage their lifetime.
49///
50/// [`Device`] bound resources should be freed when either the resource goes out of scope or the
51/// [`Device`] is unbound respectively, depending on what happens first. In any case, it is always
52/// guaranteed that revoking the device resource is completed before the corresponding [`Device`]
53/// is unbound.
54///
55/// To achieve that [`Devres`] registers a devres callback on creation, which is called once the
56/// [`Device`] is unbound, revoking access to the encapsulated resource (see also [`Revocable`]).
57///
58/// After the [`Devres`] has been unbound it is not possible to access the encapsulated resource
59/// anymore.
60///
61/// When a [`Devres`] is dropped, it is guaranteed that `T` has been fully dropped by the time
62/// [`Devres::drop`] returns, even if a concurrent revocation through the release callback is in
63/// progress.
64///
65/// [`Devres`] users should make sure to simply free the corresponding backing resource in `T`'s
66/// [`Drop`] implementation.
67///
68/// # Examples
69///
70/// ```no_run
71/// use kernel::{
72///     bindings,
73///     device::{
74///         Bound,
75///         Device,
76///     },
77///     devres::Devres,
78///     io::{
79///         Io,
80///         IoBase,
81///         Mmio,
82///         MmioRaw,
83///         MmioBackend,
84///         PhysAddr,
85///         Region, //
86///     },
87///     prelude::*,
88/// };
89/// use core::ops::Deref;
90///
91/// // See also [`pci::Bar`] for a real example.
92/// struct IoMem<const SIZE: usize>(MmioRaw<Region<SIZE>>);
93///
94/// impl<const SIZE: usize> IoMem<SIZE> {
95///     /// # Safety
96///     ///
97///     /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs
98///     /// virtual address space.
99///     unsafe fn new(paddr: usize) -> Result<Self>{
100///         // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is
101///         // valid for `ioremap`.
102///         let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) };
103///         if addr.is_null() {
104///             return Err(ENOMEM);
105///         }
106///
107///         Ok(IoMem(MmioRaw::new_region(addr as usize, SIZE)?))
108///     }
109/// }
110///
111/// impl<const SIZE: usize> Drop for IoMem<SIZE> {
112///     fn drop(&mut self) {
113///         // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
114///         unsafe { bindings::iounmap(self.0.addr() as *mut c_void); };
115///     }
116/// }
117///
118/// impl<'a, const SIZE: usize> IoBase<'a> for &'a IoMem<SIZE> {
119///    type Backend = MmioBackend;
120///    type Target = Region<SIZE>;
121///
122///    fn as_view(self) -> Mmio<'a, Region<SIZE>> {
123///         // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`.
124///         unsafe { Mmio::from_raw(self.0) }
125///    }
126/// }
127/// # fn no_run(dev: &Device<Bound>) -> Result<(), Error> {
128/// // SAFETY: Invalid usage for example purposes.
129/// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? };
130/// let devres = Devres::new(dev, iomem)?;
131///
132/// let res = devres.try_access().ok_or(ENXIO)?;
133/// res.write8(0x42, 0x0);
134/// # Ok(())
135/// # }
136/// ```
137pub struct Devres<T: Send + 'static> {
138    dev: ARef<Device>,
139    inner: Arc<Inner<T>>,
140}
141
142// Calling the FFI functions from the `base` module directly from the `Devres<T>` impl may result in
143// them being called directly from driver modules. This happens since the Rust compiler will use
144// monomorphisation, so it might happen that functions are instantiated within the calling driver
145// module. For now, work around this with `#[inline(never)]` helpers.
146//
147// TODO: Remove once a more generic solution has been implemented. For instance, we may be able to
148// leverage `bindgen` to take care of this depending on whether a symbol is (already) exported.
149mod base {
150    use kernel::{
151        bindings,
152        prelude::*, //
153    };
154
155    #[inline(never)]
156    #[allow(clippy::missing_safety_doc)]
157    pub(super) unsafe fn devres_node_init(
158        node: *mut bindings::devres_node,
159        release: bindings::dr_node_release_t,
160        free: bindings::dr_node_free_t,
161    ) {
162        // SAFETY: Safety requirements are the same as `bindings::devres_node_init`.
163        unsafe { bindings::devres_node_init(node, release, free) }
164    }
165
166    #[inline(never)]
167    #[allow(clippy::missing_safety_doc)]
168    pub(super) unsafe fn devres_set_node_dbginfo(
169        node: *mut bindings::devres_node,
170        name: *const c_char,
171        size: usize,
172    ) {
173        // SAFETY: Safety requirements are the same as `bindings::devres_set_node_dbginfo`.
174        unsafe { bindings::devres_set_node_dbginfo(node, name, size) }
175    }
176
177    #[inline(never)]
178    #[allow(clippy::missing_safety_doc)]
179    pub(super) unsafe fn devres_node_add(
180        dev: *mut bindings::device,
181        node: *mut bindings::devres_node,
182    ) {
183        // SAFETY: Safety requirements are the same as `bindings::devres_node_add`.
184        unsafe { bindings::devres_node_add(dev, node) }
185    }
186
187    #[must_use]
188    #[inline(never)]
189    #[allow(clippy::missing_safety_doc)]
190    pub(super) unsafe fn devres_node_remove(
191        dev: *mut bindings::device,
192        node: *mut bindings::devres_node,
193    ) -> bool {
194        // SAFETY: Safety requirements are the same as `bindings::devres_node_remove`.
195        unsafe { bindings::devres_node_remove(dev, node) }
196    }
197}
198
199impl<T: Send + 'static> Devres<T> {
200    /// Creates a new [`Devres`] instance of the given `data`.
201    ///
202    /// The `data` encapsulated within the returned `Devres` instance' `data` will be
203    /// (revoked)[`Revocable`] once the device is detached.
204    pub fn new<E>(dev: &Device<Bound>, data: impl PinInit<T, E>) -> Result<Self>
205    where
206        Error: From<E>,
207    {
208        let inner = Arc::pin_init::<Error>(
209            try_pin_init!(Inner {
210                node <- Opaque::ffi_init(|node: *mut bindings::devres_node| {
211                    // SAFETY: `node` is a valid pointer to an uninitialized `struct devres_node`.
212                    unsafe {
213                        base::devres_node_init(
214                            node,
215                            Some(Self::devres_node_release),
216                            Some(Self::devres_node_free_node),
217                        )
218                    };
219
220                    // SAFETY: `node` is a valid pointer to an uninitialized `struct devres_node`.
221                    unsafe {
222                        base::devres_set_node_dbginfo(
223                            node,
224                            // TODO: Use `core::any::type_name::<T>()` once it is a `const fn`,
225                            // such that we can convert the `&str` to a `&CStr` at compile-time.
226                            c"Devres<T>".as_char_ptr(),
227                            core::mem::size_of::<Revocable<T>>(),
228                        )
229                    };
230                }),
231                data <- Revocable::new(data),
232                revocation <- Completion::new(),
233            }),
234            GFP_KERNEL,
235        )?;
236
237        // SAFETY:
238        // - `dev` is a valid pointer to a bound `struct device`.
239        // - `node` is a valid pointer to a `struct devres_node`.
240        // - `devres_node_add()` is guaranteed not to call `devres_node_release()` for the entire
241        //    lifetime of `dev`.
242        unsafe { base::devres_node_add(dev.as_raw(), inner.node.get()) };
243
244        // Take additional reference count for `devres_node_add()`.
245        core::mem::forget(inner.clone());
246
247        Ok(Self {
248            dev: dev.into(),
249            inner,
250        })
251    }
252
253    fn data(&self) -> &Revocable<T> {
254        &self.inner.data
255    }
256
257    #[allow(clippy::missing_safety_doc)]
258    unsafe extern "C" fn devres_node_release(
259        _dev: *mut bindings::device,
260        node: *mut bindings::devres_node,
261    ) {
262        let node = Opaque::cast_from(node);
263
264        // SAFETY: `node` is in the same allocation as its container.
265        let inner = unsafe { kernel::container_of!(node, Inner<T>, node) };
266
267        // SAFETY: `inner` is a valid `Inner<T>` pointer.
268        let inner = unsafe { &*inner };
269
270        if inner.data.revoke() {
271            inner.revocation.complete_all();
272        } else {
273            // Devres::drop() is concurrently revoking; wait for it to finish `drop_in_place()`
274            // before returning to `devres_release_all()`, ensuring `T` is fully torn down before
275            // the device finishes unbinding.
276            inner.revocation.wait_for_completion();
277        }
278    }
279
280    #[allow(clippy::missing_safety_doc)]
281    unsafe extern "C" fn devres_node_free_node(node: *mut bindings::devres_node) {
282        let node = Opaque::cast_from(node);
283
284        // SAFETY: `node` is in the same allocation as its container.
285        let inner = unsafe { kernel::container_of!(node, Inner<T>, node) };
286
287        // SAFETY: `inner` points to the entire `Inner<T>` allocation.
288        drop(unsafe { Arc::from_raw(inner) });
289    }
290
291    fn remove_node(&self) -> bool {
292        // SAFETY:
293        // - `self.device().as_raw()` is a valid pointer to a bound `struct device`.
294        // - `self.inner.node.get()` is a valid pointer to a `struct devres_node`.
295        unsafe { base::devres_node_remove(self.device().as_raw(), self.inner.node.get()) }
296    }
297
298    /// Return a reference of the [`Device`] this [`Devres`] instance has been created with.
299    pub fn device(&self) -> &Device {
300        &self.dev
301    }
302
303    /// Obtain `&'a T`, bypassing the [`Revocable`].
304    ///
305    /// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting
306    /// a `&'a Device<Bound>` of the same [`Device`] this [`Devres`] instance has been created with.
307    ///
308    /// # Errors
309    ///
310    /// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance
311    /// has been created with.
312    ///
313    /// # Examples
314    ///
315    /// ```no_run
316    /// #![cfg(CONFIG_PCI)]
317    /// use kernel::{
318    ///     device::Core,
319    ///     devres::Devres,
320    ///     io::Io,
321    ///     pci, //
322    /// };
323    ///
324    /// fn from_core(dev: &pci::Device<Core<'_>>, devres: Devres<pci::Bar<'_, 0x4>>) -> Result {
325    ///     let bar = devres.access(dev.as_ref())?;
326    ///
327    ///     let _ = bar.read32(0x0);
328    ///
329    ///     // might_sleep()
330    ///
331    ///     bar.write32(0x42, 0x0);
332    ///
333    ///     Ok(())
334    /// }
335    /// ```
336    pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> {
337        if self.dev.as_raw() != dev.as_raw() {
338            return Err(EINVAL);
339        }
340
341        // SAFETY: `dev` being the same device as the device this `Devres` has been created for
342        // proves that `self.data` hasn't been revoked and is guaranteed to not be revoked as long
343        // as `dev` lives; `dev` lives at least as long as `self`.
344        Ok(unsafe { self.data().access() })
345    }
346
347    /// [`Devres`] accessor for [`Revocable::try_access`].
348    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
349        self.data().try_access()
350    }
351
352    /// [`Devres`] accessor for [`Revocable::try_access_with`].
353    pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R> {
354        self.data().try_access_with(f)
355    }
356
357    /// [`Devres`] accessor for [`Revocable::try_access_with_guard`].
358    pub fn try_access_with_guard<'a>(&'a self, guard: &'a rcu::Guard) -> Option<&'a T> {
359        self.data().try_access_with_guard(guard)
360    }
361}
362
363// SAFETY: `Devres` can be send to any task, if `T: Send`.
364unsafe impl<T: Send> Send for Devres<T> {}
365
366// SAFETY: `Devres` can be shared with any task, if `T: Sync`.
367unsafe impl<T: Send + Sync> Sync for Devres<T> {}
368
369impl<T: Send + 'static> Drop for Devres<T> {
370    fn drop(&mut self) {
371        // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data
372        // anymore, hence it is safe not to wait for the grace period to finish.
373        if unsafe { self.data().revoke_nosync() } {
374            self.inner.revocation.complete_all();
375
376            // We revoked `self.data` before devres did, hence try to remove it.
377            if self.remove_node() {
378                // SAFETY: In `Self::new` we have taken an additional reference count of `self.data`
379                // for `devres_node_add()`. Since `remove_node()` was successful, we have to drop
380                // this additional reference count.
381                drop(unsafe { Arc::from_raw(Arc::as_ptr(&self.inner)) });
382            }
383        } else {
384            // The release callback is concurrently revoking; wait for it to finish
385            // `drop_in_place()` of the wrapped object before returning.
386            self.inner.revocation.wait_for_completion();
387        }
388    }
389}
390
391/// Guard returned by [`DevresLt::try_access`].
392///
393/// Dereferences to `F::Of<'a>`, shortening the lifetime of the stored data to the guard's borrow
394/// lifetime.
395pub struct DevresGuard<'a, F: CovariantForLt>(RevocableGuard<'a, F::Of<'static>>);
396
397impl<'a, F: CovariantForLt> core::ops::Deref for DevresGuard<'a, F> {
398    type Target = F::Of<'a>;
399
400    #[inline]
401    fn deref(&self) -> &Self::Target {
402        F::cast_ref(&*self.0)
403    }
404}
405
406/// Device-managed resource with [`ForLt`](trait@ForLt)-aware access.
407///
408/// `DevresLt` wraps [`Devres`] and shortens the stored `'static` lifetime to the caller's borrow
409/// lifetime in all access methods.
410///
411/// Types that implement [`trait@CovariantForLt`] get direct-reference accessors ([`Self::access`],
412/// [`Self::try_access`]). Plain [`ForLt`](trait@ForLt) types use closure-based accessors
413/// ([`Self::access_with`], [`Self::try_access_with`]).
414pub struct DevresLt<F: ForLt>(Devres<F::Of<'static>>)
415where
416    for<'a> F::Of<'a>: Send;
417
418impl<F: ForLt> DevresLt<F>
419where
420    for<'a> F::Of<'a>: Send,
421{
422    /// Creates a new [`DevresLt`] instance of the given `data`.
423    ///
424    /// # Safety
425    ///
426    /// The data must remain valid for the device's full bound scope. [`DevresLt`] allows
427    /// access until the device is unbound, which may outlast `'a`.
428    pub unsafe fn new<'a, E>(
429        dev: &'a Device<Bound>,
430        data: impl PinInit<F::Of<'a>, E>,
431    ) -> Result<Self>
432    where
433        Error: From<E>,
434    {
435        // SAFETY: The caller guarantees the data is valid for the device's full bound scope.
436        // Lifetimes do not affect layout, so F::Of<'a> and F::Of<'static> have identical
437        // representation; casting the slot pointer is sound.
438        let data = unsafe {
439            pin_init::pin_init_from_closure::<F::Of<'static>, E>(move |slot| {
440                data.__pinned_init(slot.cast())
441            })
442        };
443
444        Ok(Self(Devres::new(dev, data)?))
445    }
446
447    /// Return a reference of the [`Device`] this [`DevresLt`] instance has been created with.
448    #[inline]
449    pub fn device(&self) -> &Device {
450        self.0.device()
451    }
452
453    /// Obtain `&F::Of<'_>`, bypassing the [`Revocable`], through a closure.
454    ///
455    /// This method works like [`DevresLt::access`](DevresLt::access) but accepts any
456    /// [`trait@ForLt`] type, not just [`trait@CovariantForLt`].
457    #[inline]
458    pub fn access_with<R, G>(&self, dev: &Device<Bound>, f: G) -> Result<R>
459    where
460        G: for<'a> FnOnce(&F::Of<'a>) -> R,
461    {
462        self.0.access(dev).map(f)
463    }
464
465    /// [`DevresLt`] accessor for [`Revocable::try_access_with`].
466    #[inline]
467    pub fn try_access_with<R, G>(&self, f: G) -> Option<R>
468    where
469        G: for<'a> FnOnce(&F::Of<'a>) -> R,
470    {
471        self.0.data().try_access_with(f)
472    }
473}
474
475impl<F: CovariantForLt> DevresLt<F>
476where
477    for<'a> F::Of<'a>: Send,
478{
479    /// Obtain `&'a F::Of<'a>`, bypassing the [`Revocable`].
480    ///
481    /// This method works like [`Devres::access`], but shortens the returned reference's lifetime
482    /// from `'static` to `'a` via [`CovariantForLt::cast_ref`].
483    #[inline]
484    pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a F::Of<'a>> {
485        self.0.access(dev).map(F::cast_ref)
486    }
487
488    /// [`DevresLt`] accessor for [`Revocable::try_access`].
489    #[inline]
490    pub fn try_access(&self) -> Option<DevresGuard<'_, F>> {
491        self.0.data().try_access().map(DevresGuard)
492    }
493}
494
495/// Consume `data` and [`Drop::drop`] `data` once `dev` is unbound.
496fn register_foreign<P>(dev: &Device<Bound>, data: P) -> Result
497where
498    P: ForeignOwnable + Send + 'static,
499{
500    let ptr = data.into_foreign();
501
502    #[allow(clippy::missing_safety_doc)]
503    unsafe extern "C" fn callback<P: ForeignOwnable>(ptr: *mut kernel::ffi::c_void) {
504        // SAFETY: `ptr` is the pointer to the `ForeignOwnable` leaked above and hence valid.
505        drop(unsafe { P::from_foreign(ptr.cast()) });
506    }
507
508    // SAFETY:
509    // - `dev.as_raw()` is a pointer to a valid and bound device.
510    // - `ptr` is a valid pointer the `ForeignOwnable` devres takes ownership of.
511    to_result(unsafe {
512        // `devm_add_action_or_reset()` also calls `callback` on failure, such that the
513        // `ForeignOwnable` is released eventually.
514        bindings::devm_add_action_or_reset(dev.as_raw(), Some(callback::<P>), ptr.cast())
515    })
516}
517
518/// Encapsulate `data` in a [`KBox`] and [`Drop::drop`] `data` once `dev` is unbound.
519///
520/// # Examples
521///
522/// ```no_run
523/// use kernel::{
524///     device::{
525///         Bound,
526///         Device, //
527///     },
528///     devres, //
529/// };
530///
531/// /// Registration of e.g. a class device, IRQ, etc.
532/// struct Registration;
533///
534/// impl Registration {
535///     fn new() -> Self {
536///         // register
537///
538///         Self
539///     }
540/// }
541///
542/// impl Drop for Registration {
543///     fn drop(&mut self) {
544///        // unregister
545///     }
546/// }
547///
548/// fn from_bound_context(dev: &Device<Bound>) -> Result {
549///     devres::register(dev, Registration::new(), GFP_KERNEL)
550/// }
551/// ```
552pub fn register<T, E>(dev: &Device<Bound>, data: impl PinInit<T, E>, flags: Flags) -> Result
553where
554    T: Send + 'static,
555    Error: From<E>,
556{
557    let data = KBox::pin_init(data, flags)?;
558
559    register_foreign(dev, data)
560}