Expose a safe Rust wrapper for the `cfg_size` field of `struct pci_dev`,
allowing drivers to query the size of a device's configuration space.
This is useful for code that needs to know whether the device supports
extended configuration space (e.g. 256 vs 4096 bytes) when accessing PCI
configuration registers and apply runtime checks.
Cc: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Zhi Wang <zhiw@nvidia.com>
---
rust/kernel/pci.rs | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 77a8eb39ad32..9ebba8e08d2e 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -418,6 +418,19 @@ fn as_raw(&self) -> *mut bindings::pci_dev {
}
}
+/// Represents the size of a PCI configuration space.
+///
+/// PCI devices can have either a *normal* (legacy) configuration space of 256 bytes,
+/// or an *extended* configuration space of 4096 bytes as defined in the PCI Express
+/// specification.
+pub enum ConfigSpaceSize {
+ /// 256-byte legacy PCI configuration space.
+ Normal = 256,
+
+ /// 4096-byte PCIe extended configuration space.
+ Extended = 4096,
+}
+
impl Device {
/// Returns the PCI vendor ID as [`Vendor`].
///
@@ -514,6 +527,17 @@ pub fn pci_class(&self) -> Class {
// SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.
Class::from_raw(unsafe { (*self.as_raw()).class })
}
+
+ /// Returns the size of configuration space.
+ pub fn cfg_size(&self) -> Result<ConfigSpaceSize> {
+ // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.
+ let size = unsafe { (*self.as_raw()).cfg_size };
+ match size {
+ 256 => Ok(ConfigSpaceSize::Normal),
+ 4096 => Ok(ConfigSpaceSize::Extended),
+ _ => Err(EINVAL),
+ }
+ }
}
impl Device<device::Bound> {
--
2.47.3
On Thu, Oct 30, 2025 at 03:48:40PM +0000, Zhi Wang wrote: > Expose a safe Rust wrapper for the `cfg_size` field of `struct pci_dev`, > allowing drivers to query the size of a device's configuration space. > > This is useful for code that needs to know whether the device supports > extended configuration space (e.g. 256 vs 4096 bytes) when accessing PCI > configuration registers and apply runtime checks. What is the value of knowing the config space size, as opposed to just having config space accessors return PCIBIOS_BAD_REGISTER_NUMBER or similar when trying to read past the implemented size? Apart from pci-sysfs and vfio, I don't really see any drivers that use pdev->cfg_size today.
On Thu, 30 Oct 2025 11:51:15 -0500 Bjorn Helgaas <helgaas@kernel.org> wrote: > On Thu, Oct 30, 2025 at 03:48:40PM +0000, Zhi Wang wrote: > > Expose a safe Rust wrapper for the `cfg_size` field of `struct > > pci_dev`, allowing drivers to query the size of a device's > > configuration space. > > > > This is useful for code that needs to know whether the device > > supports extended configuration space (e.g. 256 vs 4096 bytes) when > > accessing PCI configuration registers and apply runtime checks. > > What is the value of knowing the config space size, as opposed to just > having config space accessors return PCIBIOS_BAD_REGISTER_NUMBER or > similar when trying to read past the implemented size? > Per my understading, the Io trait aims to provide a generic I/O validation that can be reused across different transports - MMIO, PCI, SPI, and others - with each backend implementing its own region boundaries while sharing the same pre-access validation logic. By design, the framework needs to know the valid address range before performing the actual access. Without exposing cfg_size(), we would have to add PCI configuration-specific handling inside the framework. > Apart from pci-sysfs and vfio, I don't really see any drivers that use > pdev->cfg_size today. It is for the framework so far. If we believe that driver doesn't need this in the near term, I can make it private in the next re-spin. Z.
On Fri Oct 31, 2025 at 1:16 PM CET, Zhi Wang wrote: > On Thu, 30 Oct 2025 11:51:15 -0500 > Bjorn Helgaas <helgaas@kernel.org> wrote: >> Apart from pci-sysfs and vfio, I don't really see any drivers that use >> pdev->cfg_size today. > > It is for the framework so far. If we believe that driver doesn't need > this in the near term, I can make it private in the next re-spin. Device::cfg_size() should indeed be private, I don't see a reason for drivers to call this directly. However, enum ConfigSpaceSize has to be public, such that we can implement a method: pub fn config_space<'a, const SIZE: usize>(&'a self) -> Result<ConfigSpace<'a, SIZE>> so the driver can assert whether it requires the normal or extended configuration space size with e.g.: // Fails if the configuration space does not have an extended size. let cfg = pdev.config_space::<ConfigSpaceSize::Extended>()?; Subsequently, we can do infallible accesses within the corresponding guaranteed range. Given that there are only two options, normal or extended, we can also drop the const generic and just provide two separate methods: pub fn config_space<'a>(&'a self) -> Result<ConfigSpace<'a, ConfigSpaceSize::Normal>> and pub fn config_space_extended<'a>(&'a self) -> Result<ConfigSpace<'a, ConfigSpaceSize::Extended>> Allowing drivers to request a ConfigSpace<'a, 0> with only runtime checks makes no sense, ConfigSpaceSize::Normal is always the minimum. - Danilo
© 2016 - 2026 Red Hat, Inc.