Re: [PATCH v6 08/20] rust: pci: io: make `ConfigSpace` a view

Daniel Almeida <[email protected]>
Newsgroups org.kernel.vger.linux-pwm,dev.linux.lists.driver-core,dev.linux.lists.nova-gpu,org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci,org.kernel.vger.rust-for-linux
Message-ID <[email protected]>

> On 6 Jul 2026, at 09:44, Gary Guo <[email protected]> wrote:
> 
> In order to support I/O projection, we are splitting I/O types into two
> categories: owned objects and views. Owned objects have a specific type
> that is related to setting up and tearing down, while views can have their
> type changed with I/O projection.
> 
> Things like `IoMem` or `Bar` are owned objects, which requires setting up
> mapping and cleaning up on drop. On the other side, `ConfigSpace` is really
> just a view, as the resource is associated with the `pci::Device`.
> 
> Remove the `ConfigSpaceKind` bound on `ConfigSpace` and make it a generic
> view. This means that `ConfigSpace` object now represents a subregion and
> therefore encodes offset (as address of pointers) and size (as metadata of
> pointers) itself. The full region case is still supported with offset 0 and
> size of `cfg_size`.
> 
> Reviewed-by: Alexandre Courbot <[email protected]>
> Signed-off-by: Gary Guo <[email protected]>
> ---
> rust/kernel/pci/io.rs | 64 +++++++++++++++++++++++++++++----------------------
> 1 file changed, 36 insertions(+), 28 deletions(-)
> 
> diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
> index e0acb62f58a2..89f4bb483a7f 100644
> --- a/rust/kernel/pci/io.rs
> +++ b/rust/kernel/pci/io.rs
> @@ -18,7 +18,6 @@
>     ptr::KnownSize, //
> };
> use core::{
> -    marker::PhantomData,
>     ops::Deref, //
> };
> 
> @@ -53,33 +52,42 @@ pub const fn into_raw(self) -> usize {
> /// Alias for extended (4096-byte) PCIe configuration space.
> pub type Extended = Region<4096>;
> 
> -/// Trait for PCI configuration space size markers.
> -///
> -/// This trait is implemented by [`Normal`] and [`Extended`] to provide
> -/// compile-time knowledge of the configuration space size.
> -pub trait ConfigSpaceKind: KnownSize {}
> -
> -impl ConfigSpaceKind for Normal {}
> -
> -impl ConfigSpaceKind for Extended {}
> -
> -/// The PCI configuration space of a device.
> +/// A view of PCI configuration space of a device.
> ///
> /// Provides typed read and write accessors for configuration registers
> /// using the standard `pci_read_config_*` and `pci_write_config_*` helpers.
> ///
> -/// The generic parameter `S` indicates the maximum size of the configuration space.
> -/// Use [`Normal`] for 256-byte legacy configuration space or [`Extended`] for
> -/// 4096-byte PCIe extended configuration space (default).
> -pub struct ConfigSpace<'a, S: ?Sized + ConfigSpaceKind = Extended> {
> +/// The generic parameter `T` is the type of the view. The full configuration space is also a
> +/// special type of view; in such cases, `T` can be [`Normal`] for 256-byte legacy configuration
> +/// space or [`Extended`] for 4096-byte PCIe extended configuration space (default).
> +///
> +/// # Invariants
> +///
> +/// `ptr` is aligned and range `ptr..ptr + KnownSize::size(ptr)` is within
> +/// `0..pdev.cfg_size().into_raw()`.
> +pub struct ConfigSpace<'a, T: ?Sized = Extended> {
>     pub(crate) pdev: &'a Device<device::Bound>,
> -    _marker: PhantomData<S>,
> +    ptr: *mut T,
> }
> 
> +impl<T: ?Sized> Copy for ConfigSpace<'_, T> {}
> +impl<T: ?Sized> Clone for ConfigSpace<'_, T> {
> +    #[inline]
> +    fn clone(&self) -> Self {
> +        *self
> +    }
> +}
> +
> +// SAFETY: `ConfigSpace<'_, T>` is conceptually `&T` but in I/O memory.
> +unsafe impl<T: ?Sized + Sync> Send for ConfigSpace<'_, T> {}
> +
> +// SAFETY: `ConfigSpace<'_, T>` is conceptually `&T` but in I/O memory.
> +unsafe impl<T: ?Sized + Sync> Sync for ConfigSpace<'_, T> {}
> +
> /// Implements [`IoCapable`] on [`ConfigSpace`] for `$ty` using `$read_fn` and `$write_fn`.
> macro_rules! impl_config_space_io_capable {
>     ($ty:ty, $read_fn:ident, $write_fn:ident) => {
> -        impl<'a, S: ?Sized + ConfigSpaceKind> IoCapable<$ty> for &ConfigSpace<'a, S> {
> +        impl<'a, T: ?Sized> IoCapable<$ty> for ConfigSpace<'a, T> {
>             unsafe fn io_read(self, address: usize) -> $ty {
>                 let mut val: $ty = 0;
> 
> @@ -112,19 +120,17 @@ unsafe fn io_write(self, value: $ty, address: usize) {
> impl_config_space_io_capable!(u16, pci_read_config_word, pci_write_config_word);
> impl_config_space_io_capable!(u32, pci_read_config_dword, pci_write_config_dword);
> 
> -impl<'a, S: ?Sized + ConfigSpaceKind> Io for &ConfigSpace<'a, S> {
> -    type Target = S;
> +impl<'a, T: ?Sized + KnownSize> Io for ConfigSpace<'a, T> {
> +    type Target = T;
> 
> -    /// Returns the base address of the I/O region. It is always 0 for configuration space.
>     #[inline]
>     fn addr(self) -> usize {
> -        0
> +        self.ptr.addr()
>     }
> 
> -    /// Returns the maximum size of the configuration space.
>     #[inline]
>     fn maxsize(self) -> usize {
> -        self.pdev.cfg_size().into_raw()
> +        KnownSize::size(self.ptr)
>     }
> }
> 
> @@ -281,23 +287,25 @@ pub fn cfg_size(&self) -> ConfigSpaceSize {
>         }
>     }
> 
> -    /// Return an initialized normal (256-byte) config space object.
> +    /// Return a view of the normal (256-byte) config space.
>     pub fn config_space<'a>(&'a self) -> ConfigSpace<'a, Normal> {
> +        // INVARIANT: null is aligned and the range is within config space.
>         ConfigSpace {
>             pdev: self,
> -            _marker: PhantomData,
> +            ptr: Normal::ptr_from_raw_parts_mut(core::ptr::null_mut(), self.cfg_size().into_raw()),
>         }
>     }
> 
> -    /// Return an initialized extended (4096-byte) config space object.
> +    /// Return a view of the extended (4096-byte) config space.
>     pub fn config_space_extended<'a>(&'a self) -> Result<ConfigSpace<'a, Extended>> {
>         if self.cfg_size() != ConfigSpaceSize::Extended {
>             return Err(EINVAL);
>         }
> 
> +        // INVARIANT: null is aligned and we just checked the `cfg_size`.
>         Ok(ConfigSpace {
>             pdev: self,
> -            _marker: PhantomData,
> +            ptr: Extended::ptr_from_raw_parts_mut(core::ptr::null_mut(), 4096),
>         })
>     }
> }
> 
> -- 
> 2.54.0
> 

Reviewed-by: Daniel Almeida <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.