// SPDX-License-Identifier: GPL-2.012//! Devres abstraction3//!4//! [`Devres`] represents an abstraction for the kernel devres (device resource management)5//! implementation.67use crate::{8alloc::Flags,9bindings,10device::{Bound, Device},11error::{to_result, Error, Result},12ffi::c_void,13prelude::*,14revocable::{Revocable, RevocableGuard},15sync::{aref::ARef, rcu, Completion},16types::{ForeignOwnable, Opaque, ScopeGuard},17};1819use pin_init::Wrapper;2021/// [`Devres`] inner data accessed from [`Devres::callback`].22#[pin_data]23struct Inner<T: Send> {24#[pin]25data: Revocable<T>,26/// Tracks whether [`Devres::callback`] has been completed.27#[pin]28devm: Completion,29/// Tracks whether revoking [`Self::data`] has been completed.30#[pin]31revoke: Completion,32}3334/// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to35/// manage their lifetime.36///37/// [`Device`] bound resources should be freed when either the resource goes out of scope or the38/// [`Device`] is unbound respectively, depending on what happens first. In any case, it is always39/// guaranteed that revoking the device resource is completed before the corresponding [`Device`]40/// is unbound.41///42/// To achieve that [`Devres`] registers a devres callback on creation, which is called once the43/// [`Device`] is unbound, revoking access to the encapsulated resource (see also [`Revocable`]).44///45/// After the [`Devres`] has been unbound it is not possible to access the encapsulated resource46/// anymore.47///48/// [`Devres`] users should make sure to simply free the corresponding backing resource in `T`'s49/// [`Drop`] implementation.50///51/// # Examples52///53/// ```no_run54/// use kernel::{55/// bindings,56/// device::{57/// Bound,58/// Device,59/// },60/// devres::Devres,61/// io::{62/// Io,63/// IoRaw,64/// PhysAddr,65/// },66/// };67/// use core::ops::Deref;68///69/// // See also [`pci::Bar`] for a real example.70/// struct IoMem<const SIZE: usize>(IoRaw<SIZE>);71///72/// impl<const SIZE: usize> IoMem<SIZE> {73/// /// # Safety74/// ///75/// /// [`paddr`, `paddr` + `SIZE`) must be a valid MMIO region that is mappable into the CPUs76/// /// virtual address space.77/// unsafe fn new(paddr: usize) -> Result<Self>{78/// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is79/// // valid for `ioremap`.80/// let addr = unsafe { bindings::ioremap(paddr as PhysAddr, SIZE) };81/// if addr.is_null() {82/// return Err(ENOMEM);83/// }84///85/// Ok(IoMem(IoRaw::new(addr as usize, SIZE)?))86/// }87/// }88///89/// impl<const SIZE: usize> Drop for IoMem<SIZE> {90/// fn drop(&mut self) {91/// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.92/// unsafe { bindings::iounmap(self.0.addr() as *mut c_void); };93/// }94/// }95///96/// impl<const SIZE: usize> Deref for IoMem<SIZE> {97/// type Target = Io<SIZE>;98///99/// fn deref(&self) -> &Self::Target {100/// // SAFETY: The memory range stored in `self` has been properly mapped in `Self::new`.101/// unsafe { Io::from_raw(&self.0) }102/// }103/// }104/// # fn no_run(dev: &Device<Bound>) -> Result<(), Error> {105/// // SAFETY: Invalid usage for example purposes.106/// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? };107/// let devres = KBox::pin_init(Devres::new(dev, iomem), GFP_KERNEL)?;108///109/// let res = devres.try_access().ok_or(ENXIO)?;110/// res.write8(0x42, 0x0);111/// # Ok(())112/// # }113/// ```114///115/// # Invariants116///117/// `Self::inner` is guaranteed to be initialized and is always accessed read-only.118#[pin_data(PinnedDrop)]119pub struct Devres<T: Send> {120dev: ARef<Device>,121/// Pointer to [`Self::devres_callback`].122///123/// Has to be stored, since Rust does not guarantee to always return the same address for a124/// function. However, the C API uses the address as a key.125callback: unsafe extern "C" fn(*mut c_void),126/// Contains all the fields shared with [`Self::callback`].127// TODO: Replace with `UnsafePinned`, once available.128//129// Subsequently, the `drop_in_place()` in `Devres::drop` and `Devres::new` as well as the130// explicit `Send` and `Sync' impls can be removed.131#[pin]132inner: Opaque<Inner<T>>,133_add_action: (),134}135136impl<T: Send> Devres<T> {137/// Creates a new [`Devres`] instance of the given `data`.138///139/// The `data` encapsulated within the returned `Devres` instance' `data` will be140/// (revoked)[`Revocable`] once the device is detached.141pub fn new<'a, E>(142dev: &'a Device<Bound>,143data: impl PinInit<T, E> + 'a,144) -> impl PinInit<Self, Error> + 'a145where146T: 'a,147Error: From<E>,148{149try_pin_init!(&this in Self {150dev: dev.into(),151callback: Self::devres_callback,152// INVARIANT: `inner` is properly initialized.153inner <- Opaque::pin_init(try_pin_init!(Inner {154devm <- Completion::new(),155revoke <- Completion::new(),156data <- Revocable::new(data),157})),158// TODO: Replace with "initializer code blocks" [1] once available.159//160// [1] https://github.com/Rust-for-Linux/pin-init/pull/69161_add_action: {162// SAFETY: `this` is a valid pointer to uninitialized memory.163let inner = unsafe { &raw mut (*this.as_ptr()).inner };164165// SAFETY:166// - `dev.as_raw()` is a pointer to a valid bound device.167// - `inner` is guaranteed to be a valid for the duration of the lifetime of `Self`.168// - `devm_add_action()` is guaranteed not to call `callback` until `this` has been169// properly initialized, because we require `dev` (i.e. the *bound* device) to170// live at least as long as the returned `impl PinInit<Self, Error>`.171to_result(unsafe {172bindings::devm_add_action(dev.as_raw(), Some(*callback), inner.cast())173}).inspect_err(|_| {174let inner = Opaque::cast_into(inner);175176// SAFETY: `inner` is a valid pointer to an `Inner<T>` and valid for both reads177// and writes.178unsafe { core::ptr::drop_in_place(inner) };179})?;180},181})182}183184fn inner(&self) -> &Inner<T> {185// SAFETY: By the type invairants of `Self`, `inner` is properly initialized and always186// accessed read-only.187unsafe { &*self.inner.get() }188}189190fn data(&self) -> &Revocable<T> {191&self.inner().data192}193194#[allow(clippy::missing_safety_doc)]195unsafe extern "C" fn devres_callback(ptr: *mut kernel::ffi::c_void) {196// SAFETY: In `Self::new` we've passed a valid pointer to `Inner` to `devm_add_action()`,197// hence `ptr` must be a valid pointer to `Inner`.198let inner = unsafe { &*ptr.cast::<Inner<T>>() };199200// Ensure that `inner` can't be used anymore after we signal completion of this callback.201let inner = ScopeGuard::new_with_data(inner, |inner| inner.devm.complete_all());202203if !inner.data.revoke() {204// If `revoke()` returns false, it means that `Devres::drop` already started revoking205// `data` for us. Hence we have to wait until `Devres::drop` signals that it206// completed revoking `data`.207inner.revoke.wait_for_completion();208}209}210211fn remove_action(&self) -> bool {212// SAFETY:213// - `self.dev` is a valid `Device`,214// - the `action` and `data` pointers are the exact same ones as given to215// `devm_add_action()` previously,216(unsafe {217bindings::devm_remove_action_nowarn(218self.dev.as_raw(),219Some(self.callback),220core::ptr::from_ref(self.inner()).cast_mut().cast(),221)222} == 0)223}224225/// Return a reference of the [`Device`] this [`Devres`] instance has been created with.226pub fn device(&self) -> &Device {227&self.dev228}229230/// Obtain `&'a T`, bypassing the [`Revocable`].231///232/// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting233/// a `&'a Device<Bound>` of the same [`Device`] this [`Devres`] instance has been created with.234///235/// # Errors236///237/// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance238/// has been created with.239///240/// # Examples241///242/// ```no_run243/// # #![cfg(CONFIG_PCI)]244/// # use kernel::{device::Core, devres::Devres, pci};245///246/// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result {247/// let bar = devres.access(dev.as_ref())?;248///249/// let _ = bar.read32(0x0);250///251/// // might_sleep()252///253/// bar.write32(0x42, 0x0);254///255/// Ok(())256/// }257/// ```258pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> {259if self.dev.as_raw() != dev.as_raw() {260return Err(EINVAL);261}262263// SAFETY: `dev` being the same device as the device this `Devres` has been created for264// proves that `self.data` hasn't been revoked and is guaranteed to not be revoked as long265// as `dev` lives; `dev` lives at least as long as `self`.266Ok(unsafe { self.data().access() })267}268269/// [`Devres`] accessor for [`Revocable::try_access`].270pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {271self.data().try_access()272}273274/// [`Devres`] accessor for [`Revocable::try_access_with`].275pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R> {276self.data().try_access_with(f)277}278279/// [`Devres`] accessor for [`Revocable::try_access_with_guard`].280pub fn try_access_with_guard<'a>(&'a self, guard: &'a rcu::Guard) -> Option<&'a T> {281self.data().try_access_with_guard(guard)282}283}284285// SAFETY: `Devres` can be send to any task, if `T: Send`.286unsafe impl<T: Send> Send for Devres<T> {}287288// SAFETY: `Devres` can be shared with any task, if `T: Sync`.289unsafe impl<T: Send + Sync> Sync for Devres<T> {}290291#[pinned_drop]292impl<T: Send> PinnedDrop for Devres<T> {293fn drop(self: Pin<&mut Self>) {294// SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data295// anymore, hence it is safe not to wait for the grace period to finish.296if unsafe { self.data().revoke_nosync() } {297// We revoked `self.data` before the devres action did, hence try to remove it.298if !self.remove_action() {299// We could not remove the devres action, which means that it now runs concurrently,300// hence signal that `self.data` has been revoked by us successfully.301self.inner().revoke.complete_all();302303// Wait for `Self::devres_callback` to be done using this object.304self.inner().devm.wait_for_completion();305}306} else {307// `Self::devres_callback` revokes `self.data` for us, hence wait for it to be done308// using this object.309self.inner().devm.wait_for_completion();310}311312// INVARIANT: At this point it is guaranteed that `inner` can't be accessed any more.313//314// SAFETY: `inner` is valid for dropping.315unsafe { core::ptr::drop_in_place(self.inner.get()) };316}317}318319/// Consume `data` and [`Drop::drop`] `data` once `dev` is unbound.320fn register_foreign<P>(dev: &Device<Bound>, data: P) -> Result321where322P: ForeignOwnable + Send + 'static,323{324let ptr = data.into_foreign();325326#[allow(clippy::missing_safety_doc)]327unsafe extern "C" fn callback<P: ForeignOwnable>(ptr: *mut kernel::ffi::c_void) {328// SAFETY: `ptr` is the pointer to the `ForeignOwnable` leaked above and hence valid.329drop(unsafe { P::from_foreign(ptr.cast()) });330}331332// SAFETY:333// - `dev.as_raw()` is a pointer to a valid and bound device.334// - `ptr` is a valid pointer the `ForeignOwnable` devres takes ownership of.335to_result(unsafe {336// `devm_add_action_or_reset()` also calls `callback` on failure, such that the337// `ForeignOwnable` is released eventually.338bindings::devm_add_action_or_reset(dev.as_raw(), Some(callback::<P>), ptr.cast())339})340}341342/// Encapsulate `data` in a [`KBox`] and [`Drop::drop`] `data` once `dev` is unbound.343///344/// # Examples345///346/// ```no_run347/// use kernel::{device::{Bound, Device}, devres};348///349/// /// Registration of e.g. a class device, IRQ, etc.350/// struct Registration;351///352/// impl Registration {353/// fn new() -> Self {354/// // register355///356/// Self357/// }358/// }359///360/// impl Drop for Registration {361/// fn drop(&mut self) {362/// // unregister363/// }364/// }365///366/// fn from_bound_context(dev: &Device<Bound>) -> Result {367/// devres::register(dev, Registration::new(), GFP_KERNEL)368/// }369/// ```370pub fn register<T, E>(dev: &Device<Bound>, data: impl PinInit<T, E>, flags: Flags) -> Result371where372T: Send + 'static,373Error: From<E>,374{375let data = KBox::pin_init(data, flags)?;376377register_foreign(dev, data)378}379380381