Commit 8117b017 authored by Danilo Krummrich's avatar Danilo Krummrich
Browse files

Merge tag 'topic/device-context-2025-04-17' into driver-core-next

Introduce "Bound" device context

Introduce the "Bound" device context, such that it can be ensured to only
ever pass a bound device to APIs that require this precondition. [1]

This tag exists to share the patches from [1] between multiple trees.

[1] https://lore.kernel.org/lkml/20250413173758.12068-1-dakr@kernel.org/
parents 9bec9445 7bd1710a
Loading
Loading
Loading
Loading
+88 −2
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@
    str::CStr,
    types::{ARef, Opaque},
};
use core::{fmt, ptr};
use core::{fmt, marker::PhantomData, ptr};

#[cfg(CONFIG_PRINTK)]
use crate::c_str;
@@ -42,7 +42,7 @@
/// `bindings::device::release` is valid to be called from any thread, hence `ARef<Device>` can be
/// dropped from any thread.
#[repr(transparent)]
pub struct Device(Opaque<bindings::device>);
pub struct Device<Ctx: DeviceContext = Normal>(Opaque<bindings::device>, PhantomData<Ctx>);

impl Device {
    /// Creates a new reference-counted abstraction instance of an existing `struct device` pointer.
@@ -59,7 +59,9 @@ pub unsafe fn get_device(ptr: *mut bindings::device) -> ARef<Self> {
        // SAFETY: By the safety requirements ptr is valid
        unsafe { Self::as_ref(ptr) }.into()
    }
}

impl<Ctx: DeviceContext> Device<Ctx> {
    /// Obtain the raw `struct device *`.
    pub(crate) fn as_raw(&self) -> *mut bindings::device {
        self.0.get()
@@ -189,6 +191,11 @@ pub fn property_present(&self, name: &CStr) -> bool {
    }
}

// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
// argument.
kernel::impl_device_context_deref!(unsafe { Device });
kernel::impl_device_context_into_aref!(Device);

// SAFETY: Instances of `Device` are always reference-counted.
unsafe impl crate::types::AlwaysRefCounted for Device {
    fn inc_ref(&self) {
@@ -225,16 +232,95 @@ pub trait DeviceContext: private::Sealed {}
/// any of the bus callbacks, such as `probe()`.
pub struct Core;

/// The [`Bound`] context is the context of a bus specific device reference when it is guaranteed to
/// be bound for the duration of its lifetime.
pub struct Bound;

mod private {
    pub trait Sealed {}

    impl Sealed for super::Bound {}
    impl Sealed for super::Core {}
    impl Sealed for super::Normal {}
}

impl DeviceContext for Bound {}
impl DeviceContext for Core {}
impl DeviceContext for Normal {}

/// # Safety
///
/// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the
/// generic argument of `$device`.
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_device_context_deref {
    (unsafe { $device:ident, $src:ty => $dst:ty }) => {
        impl ::core::ops::Deref for $device<$src> {
            type Target = $device<$dst>;

            fn deref(&self) -> &Self::Target {
                let ptr: *const Self = self;

                // CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the
                // safety requirement of the macro.
                let ptr = ptr.cast::<Self::Target>();

                // SAFETY: `ptr` was derived from `&self`.
                unsafe { &*ptr }
            }
        }
    };
}

/// Implement [`core::ops::Deref`] traits for allowed [`DeviceContext`] conversions of a (bus
/// specific) device.
///
/// # Safety
///
/// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the
/// generic argument of `$device`.
#[macro_export]
macro_rules! impl_device_context_deref {
    (unsafe { $device:ident }) => {
        // SAFETY: This macro has the exact same safety requirement as
        // `__impl_device_context_deref!`.
        ::kernel::__impl_device_context_deref!(unsafe {
            $device,
            $crate::device::Core => $crate::device::Bound
        });

        // SAFETY: This macro has the exact same safety requirement as
        // `__impl_device_context_deref!`.
        ::kernel::__impl_device_context_deref!(unsafe {
            $device,
            $crate::device::Bound => $crate::device::Normal
        });
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __impl_device_context_into_aref {
    ($src:ty, $device:tt) => {
        impl ::core::convert::From<&$device<$src>> for $crate::types::ARef<$device> {
            fn from(dev: &$device<$src>) -> Self {
                (&**dev).into()
            }
        }
    };
}

/// Implement [`core::convert::From`], such that all `&Device<Ctx>` can be converted to an
/// `ARef<Device>`.
#[macro_export]
macro_rules! impl_device_context_into_aref {
    ($device:tt) => {
        ::kernel::__impl_device_context_into_aref!($crate::device::Core, $device);
        ::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device);
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! dev_printk {
+7 −10
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@
use crate::{
    alloc::Flags,
    bindings,
    device::Device,
    device::{Bound, Device},
    error::{Error, Result},
    ffi::c_void,
    prelude::*,
@@ -45,7 +45,7 @@ struct DevresInner<T> {
/// # Example
///
/// ```no_run
/// # use kernel::{bindings, c_str, device::Device, devres::Devres, io::{Io, IoRaw}};
/// # use kernel::{bindings, c_str, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}};
/// # use core::ops::Deref;
///
/// // See also [`pci::Bar`] for a real example.
@@ -83,13 +83,10 @@ struct DevresInner<T> {
///         unsafe { Io::from_raw(&self.0) }
///    }
/// }
/// # fn no_run() -> Result<(), Error> {
/// # // SAFETY: Invalid usage; just for the example to get an `ARef<Device>` instance.
/// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) };
///
/// # fn no_run(dev: &Device<Bound>) -> Result<(), Error> {
/// // SAFETY: Invalid usage for example purposes.
/// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? };
/// let devres = Devres::new(&dev, iomem, GFP_KERNEL)?;
/// let devres = Devres::new(dev, iomem, GFP_KERNEL)?;
///
/// let res = devres.try_access().ok_or(ENXIO)?;
/// res.write8(0x42, 0x0);
@@ -99,7 +96,7 @@ struct DevresInner<T> {
pub struct Devres<T>(Arc<DevresInner<T>>);

impl<T> DevresInner<T> {
    fn new(dev: &Device, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> {
    fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> {
        let inner = Arc::pin_init(
            pin_init!( DevresInner {
                dev: dev.into(),
@@ -171,7 +168,7 @@ fn remove_action(this: &Arc<Self>) {
impl<T> Devres<T> {
    /// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the
    /// returned `Devres` instance' `data` will be revoked once the device is detached.
    pub fn new(dev: &Device, data: T, flags: Flags) -> Result<Self> {
    pub fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Self> {
        let inner = DevresInner::new(dev, data, flags)?;

        Ok(Devres(inner))
@@ -179,7 +176,7 @@ pub fn new(dev: &Device, data: T, flags: Flags) -> Result<Self> {

    /// Same as [`Devres::new`], but does not return a `Devres` instance. Instead the given `data`
    /// is owned by devres and will be revoked / dropped, once the device is detached.
    pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result {
    pub fn new_foreign_owned(dev: &Device<Bound>, data: T, flags: Flags) -> Result {
        let _ = DevresInner::new(dev, data, flags)?;

        Ok(())
+7 −7
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@

use crate::{
    bindings, build_assert,
    device::Device,
    device::{Bound, Device},
    error::code::*,
    error::Result,
    transmute::{AsBytes, FromBytes},
@@ -22,10 +22,10 @@
/// # Examples
///
/// ```
/// use kernel::device::Device;
/// # use kernel::device::{Bound, Device};
/// use kernel::dma::{attrs::*, CoherentAllocation};
///
/// # fn test(dev: &Device) -> Result {
/// # fn test(dev: &Device<Bound>) -> Result {
/// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;
/// let c: CoherentAllocation<u64> =
///     CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?;
@@ -143,16 +143,16 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
    /// # Examples
    ///
    /// ```
    /// use kernel::device::Device;
    /// # use kernel::device::{Bound, Device};
    /// use kernel::dma::{attrs::*, CoherentAllocation};
    ///
    /// # fn test(dev: &Device) -> Result {
    /// # fn test(dev: &Device<Bound>) -> Result {
    /// let c: CoherentAllocation<u64> =
    ///     CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
    /// # Ok::<(), Error>(()) }
    /// ```
    pub fn alloc_attrs(
        dev: &Device,
        dev: &Device<Bound>,
        count: usize,
        gfp_flags: kernel::alloc::Flags,
        dma_attrs: Attrs,
@@ -194,7 +194,7 @@ pub fn alloc_attrs(
    /// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the
    /// `dma_attrs` is 0 by default.
    pub fn alloc_coherent(
        dev: &Device,
        dev: &Device<Bound>,
        count: usize,
        gfp_flags: kernel::alloc::Flags,
    ) -> Result<CoherentAllocation<T>> {
+11 −22
Original line number Diff line number Diff line
@@ -360,11 +360,13 @@ fn deref(&self) -> &Self::Target {
    }
}

impl Device {
impl<Ctx: device::DeviceContext> Device<Ctx> {
    fn as_raw(&self) -> *mut bindings::pci_dev {
        self.0.get()
    }
}

impl Device {
    /// Returns the PCI vendor ID.
    pub fn vendor_id(&self) -> u16 {
        // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.
@@ -388,7 +390,9 @@ pub fn resource_len(&self, bar: u32) -> Result<bindings::resource_size_t> {
        // - by its type invariant `self.as_raw` is always a valid pointer to a `struct pci_dev`.
        Ok(unsafe { bindings::pci_resource_len(self.as_raw(), bar.try_into()?) })
    }
}

impl Device<device::Bound> {
    /// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks
    /// can be performed on compile time for offsets (plus the requested type size) < SIZE.
    pub fn iomap_region_sized<const SIZE: usize>(
@@ -422,25 +426,10 @@ pub fn set_master(&self) {
    }
}

impl Deref for Device<device::Core> {
    type Target = Device;

    fn deref(&self) -> &Self::Target {
        let ptr: *const Self = self;

        // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::pci_dev>`.
        let ptr = ptr.cast::<Device>();

        // SAFETY: `ptr` was derived from `&self`.
        unsafe { &*ptr }
    }
}

impl From<&Device<device::Core>> for ARef<Device> {
    fn from(dev: &Device<device::Core>) -> Self {
        (&**dev).into()
    }
}
// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
// argument.
kernel::impl_device_context_deref!(unsafe { Device });
kernel::impl_device_context_into_aref!(Device);

// SAFETY: Instances of `Device` are always reference-counted.
unsafe impl crate::types::AlwaysRefCounted for Device {
@@ -455,8 +444,8 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
    }
}

impl AsRef<device::Device> for Device {
    fn as_ref(&self) -> &device::Device {
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
    fn as_ref(&self) -> &device::Device<Ctx> {
        // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
        // `struct pci_dev`.
        let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) };
+8 −24
Original line number Diff line number Diff line
@@ -10,13 +10,12 @@
    of,
    prelude::*,
    str::CStr,
    types::{ARef, ForeignOwnable, Opaque},
    types::{ForeignOwnable, Opaque},
    ThisModule,
};

use core::{
    marker::PhantomData,
    ops::Deref,
    ptr::{addr_of_mut, NonNull},
};

@@ -184,31 +183,16 @@ pub struct Device<Ctx: device::DeviceContext = device::Normal>(
    PhantomData<Ctx>,
);

impl Device {
impl<Ctx: device::DeviceContext> Device<Ctx> {
    fn as_raw(&self) -> *mut bindings::platform_device {
        self.0.get()
    }
}

impl Deref for Device<device::Core> {
    type Target = Device;

    fn deref(&self) -> &Self::Target {
        let ptr: *const Self = self;

        // CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::platform_device>`.
        let ptr = ptr.cast::<Device>();

        // SAFETY: `ptr` was derived from `&self`.
        unsafe { &*ptr }
    }
}

impl From<&Device<device::Core>> for ARef<Device> {
    fn from(dev: &Device<device::Core>) -> Self {
        (&**dev).into()
    }
}
// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
// argument.
kernel::impl_device_context_deref!(unsafe { Device });
kernel::impl_device_context_into_aref!(Device);

// SAFETY: Instances of `Device` are always reference-counted.
unsafe impl crate::types::AlwaysRefCounted for Device {
@@ -223,8 +207,8 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
    }
}

impl AsRef<device::Device> for Device {
    fn as_ref(&self) -> &device::Device {
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
    fn as_ref(&self) -> &device::Device<Ctx> {
        // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
        // `struct platform_device`.
        let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) };