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