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]>