mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
rust: pci: io: make ConfigSpace a view
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 <acourbot@nvidia.com> Signed-off-by: Gary Guo <gary@garyguo.net> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com> Link: https://patch.msgid.link/20260706-io_projection-v6-8-72cd5d055d54@garyguo.net Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
parent
9f64c84af0
commit
6e5f28968d
|
|
@ -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),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user