* [PATCH v3 01/10] PCI: add driver flag to opt into disabling SR-IOV on remove()
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 02/10] fpga: dfl-pci: set driver flag to disable " Peter Colberg
` (9 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Add a flag managed_sriov to the pci_driver structure that allows a
driver to opt into disabling the Single Root I/O Virtualization (SR-IOV)
capability of the device when the driver is unbound.
Add a new function pci_iov_disable() that is invoked before the remove()
callback of a PCI driver and checks for the presence of the new flag.
If the flag is set, invoke the sriov_configure() callback to allow the
driver to gracefully disable SR-IOV. Warn if the driver fails to do so
and forcibly disable SR-IOV using sriov_disable().
Since a (broken) driver may theoretically re-enable SR-IOV during its
remove() callback, extend pci_iov_remove() to forcibly disable SR-IOV
after remove() if needed and only if the flag managed_sriov is set.
Altogether the flag ensures that when a Virtual Function (VF) is bound
to a driver, the corresponding Physical Function (PF) is bound to a
driver, too, since the VF devices are destroyed when the PF driver is
unbound. This guarantee is a prerequisite for exposing a safe Rust
API that allows a VF driver to obtain the PF device for a VF device
and subsequently access the device private data of the PF device.
Suggested-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
Changes in v2:
- Move logic to disable SR-IOV on remove() from Rust to C.
- Add driver flag managed_sriov to opt into disabling SR-IOV on remove().
---
drivers/pci/iov.c | 41 ++++++++++++++++++++++++++++++++++++++++-
drivers/pci/pci-driver.c | 3 ++-
drivers/pci/pci.h | 2 ++
include/linux/pci.h | 8 ++++++++
4 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 91ac4e37ecb9c0c5265aa40c235e84b430f43a96..da64d6ce5d30de8a52089b36fcb013937cf8b6fe 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -1010,20 +1010,59 @@ void pci_iov_release(struct pci_dev *dev)
sriov_release(dev);
}
+/**
+ * pci_iov_disable - disable SR-IOV before PF driver is detached
+ * @dev: the PCI device
+ *
+ * Invoke sriov_configure() callback to allow the driver to gracefully disable
+ * SR-IOV. Warn if the driver fails to do so and forcibly disable SR-IOV.
+ */
+void pci_iov_disable(struct pci_dev *dev)
+{
+ struct pci_driver *drv = dev->driver;
+ struct pci_sriov *iov = dev->sriov;
+
+ if (WARN_ON(!drv))
+ return;
+
+ if (!dev->is_physfn || !iov->num_VFs || !drv->managed_sriov)
+ return;
+
+ if (!drv->sriov_configure) {
+ sriov_disable(dev);
+ return;
+ }
+
+ drv->sriov_configure(dev, 0);
+
+ if (WARN_ON(iov->num_VFs))
+ sriov_disable(dev);
+}
+
/**
* pci_iov_remove - clean up SR-IOV state after PF driver is detached
* @dev: the PCI device
*/
void pci_iov_remove(struct pci_dev *dev)
{
+ struct pci_driver *drv = dev->driver;
struct pci_sriov *iov = dev->sriov;
+ if (WARN_ON(!drv))
+ return;
+
if (!dev->is_physfn)
return;
iov->driver_max_VFs = iov->total_VFs;
- if (iov->num_VFs)
+
+ if (iov->num_VFs && !drv->managed_sriov) {
pci_warn(dev, "driver left SR-IOV enabled after remove\n");
+ return;
+ }
+
+ if (WARN_ON(iov->num_VFs))
+ sriov_disable(dev);
}
/**
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index dd9075403987d84e068014b35745e8872e93fdae..3fe43711565a3eb61a06cc3700e5ca953961fbe9 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -491,6 +491,7 @@ static void pci_device_remove(struct device *dev)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *drv = pci_dev->driver;
+ pci_iov_disable(pci_dev);
if (drv->remove) {
pm_runtime_get_sync(dev);
/*
@@ -504,8 +505,8 @@ static void pci_device_remove(struct device *dev)
pm_runtime_put_noidle(dev);
}
pcibios_free_irq(pci_dev);
- pci_dev->driver = NULL;
pci_iov_remove(pci_dev);
+ pci_dev->driver = NULL;
/* Undo the runtime PM settings in local_pci_probe() */
pm_runtime_put_sync(dev);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 13d998fbacce6698514d92500dfea03cc562cdc2..66308f5126ff9e4bebb537a541f1dd8717bccbfa 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -943,6 +943,7 @@ static inline void pci_restore_pasid_state(struct pci_dev *pdev) { }
#ifdef CONFIG_PCI_IOV
int pci_iov_init(struct pci_dev *dev);
void pci_iov_release(struct pci_dev *dev);
+void pci_iov_disable(struct pci_dev *dev);
void pci_iov_remove(struct pci_dev *dev);
void pci_iov_update_resource(struct pci_dev *dev, int resno);
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
@@ -977,6 +978,7 @@ static inline int pci_iov_init(struct pci_dev *dev)
return -ENODEV;
}
static inline void pci_iov_release(struct pci_dev *dev) { }
+static inline void pci_iov_disable(struct pci_dev *dev) { }
static inline void pci_iov_remove(struct pci_dev *dev) { }
static inline void pci_iov_update_resource(struct pci_dev *dev, int resno) { }
static inline resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1c270f1d512301de4d462fe7e5097c32af5c6f8d..859f767b30f726bd157a6080f5977c17c4827a1d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1015,6 +1015,13 @@ struct module;
* how to manage the DMA themselves and set this flag so that
* the IOMMU layer will allow them to setup and manage their
* own I/O address space.
+ * @managed_sriov: Disable SR-IOV on remove().
+ * If set, the Single Root I/O Virtualization (SR-IOV)
+ * capability of the device is disabled when the driver is
+ * unbound from the device, by calling sriov_configure()
+ * before remove(). The presence of this flag guarantees
+ * that when a Virtual Function (VF) is bound to a driver,
+ * the Physical Function (PF) is bound to a driver, too.
*/
struct pci_driver {
const char *name;
@@ -1033,6 +1040,7 @@ struct pci_driver {
struct device_driver driver;
struct pci_dynids dynids;
bool driver_managed_dma;
+ bool managed_sriov;
};
#define to_pci_driver(__drv) \
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Claude review: PCI: add driver flag to opt into disabling SR-IOV on remove()
2026-03-03 21:15 ` [PATCH v3 01/10] PCI: add driver flag to opt into disabling SR-IOV on remove() Peter Colberg
@ 2026-03-03 22:40 ` Claude Code Review Bot
0 siblings, 0 replies; 22+ messages in thread
From: Claude Code Review Bot @ 2026-03-03 22:40 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
This is the linchpin of the series. The design is well thought out.
**`pci_iov_disable()` logic** is correct: short-circuit evaluation in `if (!dev->is_physfn || !iov->num_VFs || !drv->managed_sriov)` protects against dereferencing `iov` when `dev->sriov` is actually the `physfn` union member on VF devices.
**Ordering change in `pci_device_remove()`** is necessary and correct:
```c
+ pci_iov_disable(pci_dev);
if (drv->remove) {
...
}
pcibios_free_irq(pci_dev);
- pci_dev->driver = NULL;
pci_iov_remove(pci_dev);
+ pci_dev->driver = NULL;
```
`pci_iov_remove()` now needs `dev->driver` to check `managed_sriov`, so the `driver = NULL` assignment must move after it. This is safe since the driver pointer was already valid during the preceding `drv->remove()` call.
**`pci_iov_remove()` behavior change**: For non-`managed_sriov` drivers, behavior is preserved (warn and return). For `managed_sriov` drivers, the `WARN_ON(iov->num_VFs)` + `sriov_disable()` at the end catches broken drivers that re-enable SR-IOV during `remove()`. Good defensive coding.
**Minor**: The `WARN_ON(!drv)` checks added to both functions are a good defensive addition, though if `drv` were ever NULL at this point there would be larger problems.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 02/10] fpga: dfl-pci: set driver flag to disable SR-IOV on remove()
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
2026-03-03 21:15 ` [PATCH v3 01/10] PCI: add driver flag to opt into disabling SR-IOV on remove() Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 03/10] rust: pci: add {enable,disable}_sriov(), to control SR-IOV capability Peter Colberg
` (8 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Set the flag managed_sriov in the pci_driver structure to show how a
PCI driver may opt into disabling the Single Root I/O Virtualization
(SR-IOV) capability of the device when the driver is removed.
Merge the function cci_remove_feature_devs() into cci_pci_remove().
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
Changes in v2:
- Demonstrate flag managed_sriov for dfl-pci driver.
---
drivers/fpga/dfl-pci.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c
index e25205c6d8f00cec579016acade28e743812c924..2410e6f3efe100a635eebfdb21f28f62a3759890 100644
--- a/drivers/fpga/dfl-pci.c
+++ b/drivers/fpga/dfl-pci.c
@@ -125,15 +125,6 @@ static int cci_init_drvdata(struct pci_dev *pcidev)
return 0;
}
-static void cci_remove_feature_devs(struct pci_dev *pcidev)
-{
- struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
-
- /* remove all children feature devices */
- dfl_fpga_feature_devs_remove(drvdata->cdev);
- cci_pci_free_irq(pcidev);
-}
-
static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec)
{
unsigned int i;
@@ -425,10 +416,11 @@ static int cci_pci_sriov_configure(struct pci_dev *pcidev, int num_vfs)
static void cci_pci_remove(struct pci_dev *pcidev)
{
- if (dev_is_pf(&pcidev->dev))
- cci_pci_sriov_configure(pcidev, 0);
+ struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
- cci_remove_feature_devs(pcidev);
+ /* remove all children feature devices */
+ dfl_fpga_feature_devs_remove(drvdata->cdev);
+ cci_pci_free_irq(pcidev);
}
static struct pci_driver cci_pci_driver = {
@@ -437,6 +429,7 @@ static struct pci_driver cci_pci_driver = {
.probe = cci_pci_probe,
.remove = cci_pci_remove,
.sriov_configure = cci_pci_sriov_configure,
+ .managed_sriov = true,
};
module_pci_driver(cci_pci_driver);
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Claude review: fpga: dfl-pci: set driver flag to disable SR-IOV on remove()
2026-03-03 21:15 ` [PATCH v3 02/10] fpga: dfl-pci: set driver flag to disable " Peter Colberg
@ 2026-03-03 22:40 ` Claude Code Review Bot
0 siblings, 0 replies; 22+ messages in thread
From: Claude Code Review Bot @ 2026-03-03 22:40 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Clean conversion. The explicit `cci_pci_sriov_configure(pcidev, 0)` call in `cci_pci_remove()` is correctly removed since the framework now handles it. Inlining `cci_remove_feature_devs()` into `cci_pci_remove()` is reasonable since the function was a trivial wrapper.
**One observation**: The old code guarded the disable call with `dev_is_pf()`, while the framework's `pci_iov_disable()` checks `dev->is_physfn` — these are equivalent, so the behavior is preserved.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 03/10] rust: pci: add {enable,disable}_sriov(), to control SR-IOV capability
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
2026-03-03 21:15 ` [PATCH v3 01/10] PCI: add driver flag to opt into disabling SR-IOV on remove() Peter Colberg
2026-03-03 21:15 ` [PATCH v3 02/10] fpga: dfl-pci: set driver flag to disable " Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 04/10] rust: pci: add vtable attribute to pci::Driver trait Peter Colberg
` (7 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Add methods to enable and disable the Single Root I/O Virtualization
(SR-IOV) capability for a PCI device. The wrapped C methods take care
of validating whether the device is a Physical Function (PF), whether
SR-IOV is currently disabled (or enabled), and whether the number of
requested VFs does not exceed the total number of supported VFs.
Set the flag managed_sriov to always disable SR-IOV when a Rust PCI
driver is unbound from a PF device. This ensures that when a Virtual
Function (VF) is bound to a driver, the corresponding Physical Function
(PF) is bound to a driver, too, which is a prerequisite for exposing a
safe Rust API that allows a VF driver to obtain the PF device for a VF
device and subsequently access the private data of the PF driver.
Suggested-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
Changes in v2:
- Set flag managed_sriov to disable SR-IOV on remove().
- Use to_result() to handle error in enable_sriov().
- Note Bound device context in SAFETY comments.
---
rust/kernel/pci.rs | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index af74ddff6114db3c2ce8e228c5a953cd0769e8a5..e1cab1574a3d309d25bf5267c0b0d8da8fb66d44 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -82,6 +82,7 @@ unsafe fn register(
(*pdrv.get()).probe = Some(Self::probe_callback);
(*pdrv.get()).remove = Some(Self::remove_callback);
(*pdrv.get()).id_table = T::ID_TABLE.as_ptr();
+ (*pdrv.get()).managed_sriov = true;
}
// SAFETY: `pdrv` is guaranteed to be a valid `DriverType`.
@@ -458,6 +459,38 @@ pub fn set_master(&self) {
// SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`.
unsafe { bindings::pci_set_master(self.as_raw()) };
}
+
+ /// Enable the Single Root I/O Virtualization (SR-IOV) capability for this device,
+ /// where `nr_virtfn` is number of Virtual Functions (VF) to enable.
+ #[cfg(CONFIG_PCI_IOV)]
+ pub fn enable_sriov(&self, nr_virtfn: i32) -> Result {
+ // SAFETY:
+ // `self.as_raw` returns a valid pointer to a `struct pci_dev`.
+ //
+ // `pci_enable_sriov()` checks that the enable operation is valid:
+ // - the device is a Physical Function (PF),
+ // - SR-IOV is currently disabled, and
+ // - `nr_virtfn` does not exceed the total number of supported VFs.
+ //
+ // The Core device context inherits from the Bound device context,
+ // which guarantees that the PF device is bound to a driver.
+ to_result(unsafe { bindings::pci_enable_sriov(self.as_raw(), nr_virtfn) })
+ }
+
+ /// Disable the Single Root I/O Virtualization (SR-IOV) capability for this device.
+ #[cfg(CONFIG_PCI_IOV)]
+ pub fn disable_sriov(&self) {
+ // SAFETY:
+ // `self.as_raw` returns a valid pointer to a `struct pci_dev`.
+ //
+ // `pci_disable_sriov()` checks that the disable operation is valid:
+ // - the device is a Physical Function (PF), and
+ // - SR-IOV is currently enabled.
+ //
+ // The Core device context inherits from the Bound device context,
+ // which guarantees that the PF device is bound to a driver.
+ unsafe { bindings::pci_disable_sriov(self.as_raw()) };
+ }
}
// SAFETY: `pci::Device` is a transparent wrapper of `struct pci_dev`.
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Claude review: rust: pci: add {enable,disable}_sriov(), to control SR-IOV capability
2026-03-03 21:15 ` [PATCH v3 03/10] rust: pci: add {enable,disable}_sriov(), to control SR-IOV capability Peter Colberg
@ 2026-03-03 22:40 ` Claude Code Review Bot
0 siblings, 0 replies; 22+ messages in thread
From: Claude Code Review Bot @ 2026-03-03 22:40 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Setting `managed_sriov = true` unconditionally for all Rust PCI drivers is the right call. For non-SR-IOV devices, `pci_iov_disable()` returns immediately on `!dev->is_physfn`, so there's no overhead.
The methods are correctly placed on `Device<device::Core>` and gated with `#[cfg(CONFIG_PCI_IOV)]`.
```rust
+ pub fn enable_sriov(&self, nr_virtfn: i32) -> Result {
```
**Minor**: `nr_virtfn` as `i32` matches the C API, but semantically VF counts are non-negative. A `u16` would be more idiomatic since SR-IOV is limited to 16 bits in the PCIe spec. However, matching the C signature avoids conversion overhead and is consistent with the rest of the Rust PCI bindings.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 04/10] rust: pci: add vtable attribute to pci::Driver trait
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
` (2 preceding siblings ...)
2026-03-03 21:15 ` [PATCH v3 03/10] rust: pci: add {enable,disable}_sriov(), to control SR-IOV capability Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 05/10] rust: pci: add bus callback sriov_configure(), to control SR-IOV from sysfs Peter Colberg
` (6 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Add the #[vtable] attribute to pci::Driver trait and implementations,
to prepare a subsequent patch that adds an optional bus callback
sriov_configure() to enable or disable the SR-IOV capability.
Suggested-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
Changes in v2:
- Add missing #[vtable] attribute in PCI driver trait example.
- Add missing #[vtable] attribute in nova-core driver.
---
drivers/gpu/nova-core/driver.rs | 1 +
rust/kernel/pci.rs | 2 ++
samples/rust/rust_dma.rs | 1 +
samples/rust/rust_driver_auxiliary.rs | 1 +
samples/rust/rust_driver_pci.rs | 1 +
5 files changed, 6 insertions(+)
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 5a4cc047bcfc9fcef61373ace84ed43958a3bcbd..66a68048006fb33477bb00f61856c1aa92c0a8f1 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -64,6 +64,7 @@ pub(crate) struct NovaCore {
]
);
+#[vtable]
impl pci::Driver for NovaCore {
type IdInfo = ();
const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index e1cab1574a3d309d25bf5267c0b0d8da8fb66d44..a4c27c674bd8bdf5e3316789d38d566e90b93fe2 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -278,6 +278,7 @@ macro_rules! pci_device_table {
/// ]
/// );
///
+/// #[vtable]
/// impl pci::Driver for MyDriver {
/// type IdInfo = ();
/// const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
@@ -292,6 +293,7 @@ macro_rules! pci_device_table {
///```
/// Drivers must implement this trait in order to get a PCI driver registered. Please refer to the
/// `Adapter` documentation for an example.
+#[vtable]
pub trait Driver: Send {
/// The type holding information about each device id supported by the driver.
// TODO: Use `associated_type_defaults` once stabilized:
diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
index 9c45851c876ef33414eb0071c42a2fb4ac3f1e78..ae6f7328b830e32bcaf7f8b5f8b1f117135ebf8e 100644
--- a/samples/rust/rust_dma.rs
+++ b/samples/rust/rust_dma.rs
@@ -51,6 +51,7 @@ unsafe impl kernel::transmute::FromBytes for MyStruct {}
[(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
);
+#[vtable]
impl pci::Driver for DmaSampleDriver {
type IdInfo = ();
const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
index 5c5a5105a3fff90f5e396186776e1b3ffdf479b4..2f7ac8f7391f45827c086b704950fd01907c1825 100644
--- a/samples/rust/rust_driver_auxiliary.rs
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -65,6 +65,7 @@ struct ParentDriver {
[(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
);
+#[vtable]
impl pci::Driver for ParentDriver {
type IdInfo = ();
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index d3d4a7931deb0c1085cfd817990737717f466ea9..27e603a9509c19b6845c10ef06a0af897aa0e84b 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -92,6 +92,7 @@ fn config_space(pdev: &pci::Device<Bound>) {
}
}
+#[vtable]
impl pci::Driver for SampleDriver {
type IdInfo = TestIndex;
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 05/10] rust: pci: add bus callback sriov_configure(), to control SR-IOV from sysfs
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
` (3 preceding siblings ...)
2026-03-03 21:15 ` [PATCH v3 04/10] rust: pci: add vtable attribute to pci::Driver trait Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 06/10] rust: pci: add is_virtfn(), to check for VFs Peter Colberg
` (5 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Add an optional bus callback sriov_configure() to pci::Driver trait,
using the vtable attribute to query if the driver implements the
callback. The callback is invoked when a user-space application
writes the number of VFs to the sysfs file `sriov_numvfs` to
enable SR-IOV, or zero to disable SR-IOV for a PCI device.
Suggested-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
rust/kernel/pci.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index a4c27c674bd8bdf5e3316789d38d566e90b93fe2..88bd114970431bf8c3edef94c1d48567d895eaf6 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -83,6 +83,10 @@ unsafe fn register(
(*pdrv.get()).remove = Some(Self::remove_callback);
(*pdrv.get()).id_table = T::ID_TABLE.as_ptr();
(*pdrv.get()).managed_sriov = true;
+ #[cfg(CONFIG_PCI_IOV)]
+ if T::HAS_SRIOV_CONFIGURE {
+ (*pdrv.get()).sriov_configure = Some(Self::sriov_configure_callback);
+ }
}
// SAFETY: `pdrv` is guaranteed to be a valid `DriverType`.
@@ -135,6 +139,20 @@ extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) {
T::unbind(pdev, data);
}
+
+ #[cfg(CONFIG_PCI_IOV)]
+ extern "C" fn sriov_configure_callback(
+ pdev: *mut bindings::pci_dev,
+ nr_virtfn: c_int,
+ ) -> c_int {
+ // SAFETY: The PCI bus only ever calls the sriov_configure callback with a valid pointer to
+ // a `struct pci_dev`.
+ //
+ // INVARIANT: `pdev` is valid for the duration of `sriov_configure_callback()`.
+ let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal>>() };
+
+ from_result(|| T::sriov_configure(pdev, nr_virtfn))
+ }
}
/// Declares a kernel module that exposes a single PCI driver.
@@ -325,6 +343,44 @@ pub trait Driver: Send {
fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) {
let _ = (dev, this);
}
+
+ /// Single Root I/O Virtualization (SR-IOV) configure.
+ ///
+ /// Called when a user-space application enables or disables the SR-IOV capability for a
+ /// [`Device`] by writing the number of Virtual Functions (VF), `nr_virtfn` or zero to the
+ /// sysfs file `sriov_numvfs` for this device. Implementing this callback is optional.
+ ///
+ /// Further, and unlike for a PCI driver written in C, when a PF device with enabled VFs is
+ /// unbound from its bound [`Driver`], the `sriov_configure()` callback is invoked to disable
+ /// SR-IOV before the `unbind()` callback. This guarantees that when a VF device is bound to a
+ /// driver, the underlying PF device is bound to a driver, too.
+ ///
+ /// Upon success, this callback must return the number of VFs that were enabled, or zero if
+ /// SR-IOV was disabled.
+ ///
+ /// See [PCI Express I/O Virtualization].
+ ///
+ /// [PCI Express I/O Virtualization]: https://docs.kernel.org/PCI/pci-iov-howto.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use kernel::{device::Core, pci, prelude::*};
+ /// #[cfg(CONFIG_PCI_IOV)]
+ /// fn sriov_configure(dev: &pci::Device<Core>, nr_virtfn: i32) -> Result<i32> {
+ /// if nr_virtfn == 0 {
+ /// dev.disable_sriov();
+ /// } else {
+ /// dev.enable_sriov(nr_virtfn)?;
+ /// }
+ /// Ok(nr_virtfn)
+ /// }
+ /// ```
+ #[cfg(CONFIG_PCI_IOV)]
+ fn sriov_configure(dev: &Device<device::Core>, nr_virtfn: i32) -> Result<i32> {
+ let _ = (dev, nr_virtfn);
+ build_error!(crate::error::VTABLE_DEFAULT_ERROR)
+ }
}
/// The PCI device representation.
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Claude review: rust: pci: add bus callback sriov_configure(), to control SR-IOV from sysfs
2026-03-03 21:15 ` [PATCH v3 05/10] rust: pci: add bus callback sriov_configure(), to control SR-IOV from sysfs Peter Colberg
@ 2026-03-03 22:40 ` Claude Code Review Bot
0 siblings, 0 replies; 22+ messages in thread
From: Claude Code Review Bot @ 2026-03-03 22:40 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
The callback plumbing is correct. The `sriov_configure_callback` uses `from_result()` which correctly maps `Result<i32>` to C int (negative for error, non-negative for success).
```rust
+ #[cfg(CONFIG_PCI_IOV)]
+ if T::HAS_SRIOV_CONFIGURE {
+ (*pdrv.get()).sriov_configure = Some(Self::sriov_configure_callback);
+ }
```
The conditional registration using `HAS_SRIOV_CONFIGURE` (from the `#[vtable]` attribute) means `sriov_configure` is only set in the C `pci_driver` when the Rust driver actually implements it. This is important because `pci_iov_disable()` checks `!drv->sriov_configure` to decide whether to call the callback or fall back to `sriov_disable()` directly.
The doc comment example correctly shows usage but the `#[cfg(CONFIG_PCI_IOV)]` on the free function is mildly confusing since the method itself is already cfg-gated on the trait.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 06/10] rust: pci: add is_virtfn(), to check for VFs
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
` (4 preceding siblings ...)
2026-03-03 21:15 ` [PATCH v3 05/10] rust: pci: add bus callback sriov_configure(), to control SR-IOV from sysfs Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 07/10] rust: pci: add is_physfn(), to check for PFs Peter Colberg
` (4 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
From: John Hubbard <jhubbard@nvidia.com>
Add a method to check if a PCI device is a Virtual Function (VF) created
through Single Root I/O Virtualization (SR-IOV).
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
Reviewed-by: Alistair Popple <apopple@nvidia.com>
Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com>
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
Changes in v2:
- Add #[inline] to is_virtfn().
This patch was originally part of the series "rust: pci: expose
is_virtfn() and reject VFs in nova-core" and modified as follows:
- Replace true -> `true` in doc comment.
- Shorten description and omit justification specific to nova-core.
Link: https://lore.kernel.org/rust-for-linux/20250930220759.288528-2-jhubbard@nvidia.com/
---
rust/kernel/pci.rs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 88bd114970431bf8c3edef94c1d48567d895eaf6..db05641186c3a42922e2b6a463de9c1b099a4673 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -484,6 +484,13 @@ pub fn resource_start(&self, bar: u32) -> Result<bindings::resource_size_t> {
Ok(unsafe { bindings::pci_resource_start(self.as_raw(), bar.try_into()?) })
}
+ /// Returns `true` if this device is a Virtual Function (VF).
+ #[inline]
+ pub fn is_virtfn(&self) -> bool {
+ // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.
+ unsafe { (*self.as_raw()).is_virtfn() != 0 }
+ }
+
/// Returns the size of the given PCI BAR resource.
pub fn resource_len(&self, bar: u32) -> Result<bindings::resource_size_t> {
if !Bar::index_is_valid(bar) {
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 07/10] rust: pci: add is_physfn(), to check for PFs
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
` (5 preceding siblings ...)
2026-03-03 21:15 ` [PATCH v3 06/10] rust: pci: add is_virtfn(), to check for VFs Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 08/10] rust: pci: add num_vf(), to return number of VFs Peter Colberg
` (3 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Add a method to check if a PCI device is a Physical Function (PF).
Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com>
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
Changes in v2:
- Replace VF -> PF in doc comment of is_physfn().
- Add #[inline] to is_physfn().
---
rust/kernel/pci.rs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index db05641186c3a42922e2b6a463de9c1b099a4673..df39ad3f0d5fd898b034609efb03368f83c2a2e9 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -484,6 +484,13 @@ pub fn resource_start(&self, bar: u32) -> Result<bindings::resource_size_t> {
Ok(unsafe { bindings::pci_resource_start(self.as_raw(), bar.try_into()?) })
}
+ /// Returns `true` if this device is a Physical Function (PF).
+ #[inline]
+ pub fn is_physfn(&self) -> bool {
+ // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.
+ unsafe { (*self.as_raw()).is_physfn() != 0 }
+ }
+
/// Returns `true` if this device is a Virtual Function (VF).
#[inline]
pub fn is_virtfn(&self) -> bool {
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 08/10] rust: pci: add num_vf(), to return number of VFs
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
` (6 preceding siblings ...)
2026-03-03 21:15 ` [PATCH v3 07/10] rust: pci: add is_physfn(), to check for PFs Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 09/10] rust: pci: add physfn(), to return PF device for VF device Peter Colberg
` (2 subsequent siblings)
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Add a method to return the number of Virtual Functions (VF) enabled for
a Physical Function (PF).
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
rust/kernel/pci.rs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index df39ad3f0d5fd898b034609efb03368f83c2a2e9..581930d0afe98ccc29d729e4d9aab75b4144e46c 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -498,6 +498,13 @@ pub fn is_virtfn(&self) -> bool {
unsafe { (*self.as_raw()).is_virtfn() != 0 }
}
+ /// Returns the number of Virtual Functions (VF) enabled for a Physical Function (PF).
+ #[cfg(CONFIG_PCI_IOV)]
+ pub fn num_vf(&self) -> i32 {
+ // SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.
+ unsafe { bindings::pci_num_vf(self.as_raw()) }
+ }
+
/// Returns the size of the given PCI BAR resource.
pub fn resource_len(&self, bar: u32) -> Result<bindings::resource_size_t> {
if !Bar::index_is_valid(bar) {
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 09/10] rust: pci: add physfn(), to return PF device for VF device
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
` (7 preceding siblings ...)
2026-03-03 21:15 ` [PATCH v3 08/10] rust: pci: add num_vf(), to return number of VFs Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 21:15 ` [PATCH v3 10/10] samples: rust: add SR-IOV driver sample Peter Colberg
2026-03-03 22:40 ` Claude review: rust: pci: add abstractions for SR-IOV capability Claude Code Review Bot
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Add a method to return the Physical Function (PF) device for a Virtual
Function (VF) device in the bound device context.
Unlike for a PCI driver written in C, guarantee that when a VF device is
bound to a driver, the underlying PF device is bound to a driver, too,
by always setting the flag managed_sriov in the pci_driver structure.
In case SR-IOV has been enabled by a C driver that has not set the flag
managed_sriov in pci_driver, return an error from physfn().
This change depends on commit a995fe1a3aa7 ("rust: driver: drop device
private data post unbind") to also uphold the safety guarantee in case
a (broken) PF driver re-enables SR-IOV in its unbind() callback. That
commit extends the lifetime of the device private data beyond the
remove_callback() wrapper. In particular, that commit ensures that the
device private data for the PF device is still alive until after the
function pci_iov_remove() is called and forcibly re-disables SR-IOV,
which means the data can be safely accessed by VF drivers until then.
Suggested-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
Changes in v3:
- Replace SR_IOV -> SR-IOV in description.
Changes in v2:
- Uphold safety guarantee when PF driver is written in C.
- Let physfn() return error if driver flag managed_sriov is unset.
---
rust/kernel/pci.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 581930d0afe98ccc29d729e4d9aab75b4144e46c..3b11f73a9f2b69a02fe003b8feadd61864adc8c0 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -525,6 +525,59 @@ pub fn pci_class(&self) -> Class {
}
}
+impl Device<device::Bound> {
+ /// Returns the Physical Function (PF) device for a Virtual Function (VF) device.
+ ///
+ /// # Examples
+ ///
+ /// The following example illustrates how to obtain the private driver data of the PF device,
+ /// where `vf_pdev` is the VF device of reference type `&Device<Core>` or `&Device<Bound>`.
+ ///
+ /// ```
+ /// # use kernel::{device::Core, pci};
+ /// /// A PCI driver that binds to both the PF and its VF devices.
+ /// struct MyDriver;
+ ///
+ /// impl MyDriver {
+ /// fn connect(vf_pdev: &pci::Device<Core>) -> Result {
+ /// let pf_pdev = vf_pdev.physfn()?;
+ /// let pf_drvdata = pf_pdev.as_ref().drvdata::<Self>()?;
+ /// Ok(())
+ /// }
+ /// }
+ /// ```
+ #[cfg(CONFIG_PCI_IOV)]
+ pub fn physfn(&self) -> Result<&Device<device::Bound>> {
+ if !self.is_virtfn() {
+ return Err(EINVAL);
+ }
+
+ // SAFETY: `self.as_raw()` returns a valid pointer to a `struct pci_dev`.
+ // `physfn` is a valid pointer to a `struct pci_dev` since `is_virtfn()` is `true`.
+ let pf_dev = unsafe { (*self.as_raw()).__bindgen_anon_1.physfn };
+
+ // SAFETY: `pf_dev` is a valid pointer to a `struct pci_dev`.
+ // `driver` is either NULL or a valid pointer to a `struct pci_driver`.
+ let pf_drv = unsafe { (*pf_dev).driver };
+ if pf_drv.is_null() {
+ return Err(EINVAL);
+ }
+
+ // SAFETY: `pf_drv` is a valid pointer to a `struct pci_driver`.
+ if !unsafe { (*pf_drv).managed_sriov } {
+ return Err(EINVAL);
+ }
+
+ // SAFETY: `physfn` may be cast to a `Device<device::Bound>` since the
+ // driver flag `managed_sriov` forces SR-IOV to be disabled when the
+ // PF driver is unbound, i.e., all VF devices are destroyed. This
+ // guarantees that the underlying PF device is bound to a driver
+ // when the VF device is bound to a driver, which is the case since
+ // `Device::physfn()` requires a `&Device<Bound>` reference.
+ Ok(unsafe { &*pf_dev.cast() })
+ }
+}
+
impl Device<device::Core> {
/// Enable memory resources for this device.
pub fn enable_device_mem(&self) -> Result {
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Claude review: rust: pci: add physfn(), to return PF device for VF device
2026-03-03 21:15 ` [PATCH v3 09/10] rust: pci: add physfn(), to return PF device for VF device Peter Colberg
@ 2026-03-03 22:40 ` Claude Code Review Bot
0 siblings, 0 replies; 22+ messages in thread
From: Claude Code Review Bot @ 2026-03-03 22:40 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
This is the most interesting patch. The safety argument is well-constructed:
```rust
+ pub fn physfn(&self) -> Result<&Device<device::Bound>> {
```
The method is on `Device<device::Bound>` (not `Device<Core>`), which means it's callable from any bound context. Three defensive checks ensure soundness:
1. `is_virtfn()` — confirms the union field `physfn` is valid
2. `pf_drv.is_null()` — PF has a driver bound
3. `!(*pf_drv).managed_sriov` — the binding guarantee is upheld
The runtime check for `managed_sriov` on the PF's driver is essential for the case where SR-IOV was enabled by a C driver that hasn't opted in. This correctly returns `EINVAL` rather than producing an unsound reference.
**One consideration**: All three error cases return `EINVAL`. For debugging, it might be helpful if `!is_virtfn()` returned a different error (e.g., `ENODEV`), but this is minor.
The reference lifetime is tied to `&self` (the VF device), which is sound: the VF can only exist while the PF is bound (guaranteed by `managed_sriov`), so the PF reference is valid for at least as long as the VF reference.
The commit message correctly notes the dependency on "rust: driver: drop device private data post unbind" for handling the pathological case of a PF driver re-enabling SR-IOV in `unbind()`.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 10/10] samples: rust: add SR-IOV driver sample
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
` (8 preceding siblings ...)
2026-03-03 21:15 ` [PATCH v3 09/10] rust: pci: add physfn(), to return PF device for VF device Peter Colberg
@ 2026-03-03 21:15 ` Peter Colberg
2026-03-03 22:40 ` Claude review: " Claude Code Review Bot
2026-03-03 22:40 ` Claude review: rust: pci: add abstractions for SR-IOV capability Claude Code Review Bot
10 siblings, 1 reply; 22+ messages in thread
From: Peter Colberg @ 2026-03-03 21:15 UTC (permalink / raw)
To: Danilo Krummrich, Bjorn Helgaas, Krzysztof Wilczyński,
Miguel Ojeda, Alex Gaynor, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Abdiel Janulgue, Daniel Almeida, Robin Murphy, Greg Kroah-Hartman,
Dave Ertman, Ira Weiny, Leon Romanovsky, David Airlie,
Simona Vetter, Jonathan Corbet, Xu Yilun, Tom Rix, Moritz Fischer,
Rafael J. Wysocki, Boqun Feng
Cc: linux-pci, rust-for-linux, linux-kernel, Alexandre Courbot,
Alistair Popple, Joel Fernandes, John Hubbard, Zhi Wang, nouveau,
dri-devel, linux-doc, linux-fpga, driver-core, Peter Colberg,
Jason Gunthorpe
Add a new SR-IOV driver sample that demonstrates how to enable and
disable the Single Root I/O Virtualization capability for a PCI device.
The sample may be exercised using QEMU's 82576 (igb) emulation.
Link: https://www.qemu.org/docs/master/system/devices/igb.html
Signed-off-by: Peter Colberg <pcolberg@redhat.com>
---
Changes in v3:
- Drop redundant `.as_ref()` for `dev_*` prints.
Changes in v2:
- Use "kernel vertical" style on imports.
- Demonstrate how to reach driver data of PF device from VF device.
---
MAINTAINERS | 1 +
samples/rust/Kconfig | 11 ++++
samples/rust/Makefile | 1 +
samples/rust/rust_driver_sriov.rs | 127 ++++++++++++++++++++++++++++++++++++++
4 files changed, 140 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 61bf550fd37c274843e516e00068bb2ab1e152ac..8551a9474fc26309d0714aafa104a5e1ed29156b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20454,6 +20454,7 @@ F: rust/helpers/pci.c
F: rust/kernel/pci.rs
F: rust/kernel/pci/
F: samples/rust/rust_driver_pci.rs
+F: samples/rust/rust_driver_sriov.rs
PCIE BANDWIDTH CONTROLLER
M: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index c49ab910634596aea4a1a73dac87585e084f420a..f244df89c4fc9d741915f581de76107e8eb0121b 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -128,6 +128,17 @@ config SAMPLE_RUST_DRIVER_PLATFORM
If unsure, say N.
+config SAMPLE_RUST_DRIVER_SRIOV
+ tristate "SR-IOV Driver"
+ depends on PCI_IOV
+ help
+ This option builds the Rust SR-IOV driver sample.
+
+ To compile this as a module, choose M here:
+ the module will be called rust_driver_sriov.
+
+ If unsure, say N.
+
config SAMPLE_RUST_DRIVER_USB
tristate "USB Driver"
depends on USB = y
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 6c0aaa58ccccfd12ef019f68ca784f6d977bc668..19d700f8210151e298cc049dacc249a121d0f2c4 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SAMPLE_RUST_DRIVER_I2C) += rust_driver_i2c.o
obj-$(CONFIG_SAMPLE_RUST_I2C_CLIENT) += rust_i2c_client.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) += rust_driver_pci.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) += rust_driver_platform.o
+obj-$(CONFIG_SAMPLE_RUST_DRIVER_SRIOV) += rust_driver_sriov.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_USB) += rust_driver_usb.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) += rust_driver_faux.o
obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) += rust_driver_auxiliary.o
diff --git a/samples/rust/rust_driver_sriov.rs b/samples/rust/rust_driver_sriov.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a4f7b99d9490f8fed2ab1fedb238c53304af89ee
--- /dev/null
+++ b/samples/rust/rust_driver_sriov.rs
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust SR-IOV driver sample based on QEMU's 82576 ([igb]) emulation.
+//!
+//! To make this driver probe, QEMU must be run with `-device igb`.
+//!
+//! Further, enable [vIOMMU] with interrupt remapping using, e.g.,
+//!
+//! `-M q35,accel=kvm,kernel-irqchip=split -device intel-iommu,intremap=on,caching-mode=on`
+//!
+//! and append `intel_iommu=on` to the guest kernel arguments.
+//!
+//! [igb]: https://www.qemu.org/docs/master/system/devices/igb.html
+//! [vIOMMU]: https://wiki.qemu.org/Features/VT-d
+
+use kernel::{
+ device::Core,
+ pci,
+ prelude::*,
+ sync::aref::ARef, //
+};
+
+use core::any::TypeId;
+
+#[pin_data(PinnedDrop)]
+struct SampleDriver {
+ pdev: ARef<pci::Device>,
+ private: TypeId,
+}
+
+kernel::pci_device_table!(
+ PCI_TABLE,
+ MODULE_PCI_TABLE,
+ <SampleDriver as pci::Driver>::IdInfo,
+ [
+ // E1000_DEV_ID_82576
+ (pci::DeviceId::from_id(pci::Vendor::INTEL, 0x10c9), ()),
+ // E1000_DEV_ID_82576_VF
+ (pci::DeviceId::from_id(pci::Vendor::INTEL, 0x10ca), ())
+ ]
+);
+
+#[vtable]
+impl pci::Driver for SampleDriver {
+ type IdInfo = ();
+
+ const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
+
+ fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, Error> {
+ pin_init::pin_init_scope(move || {
+ dev_info!(
+ pdev,
+ "Probe Rust SR-IOV driver sample (PCI ID: {}, 0x{:x}).\n",
+ pdev.vendor_id(),
+ pdev.device_id()
+ );
+
+ if pdev.is_virtfn() {
+ let physfn = pdev.physfn()?;
+ let drvdata = physfn.as_ref().drvdata::<Self>()?;
+
+ assert!(physfn.is_physfn());
+
+ dev_info!(
+ pdev,
+ "Parent device is PF (PCI ID: {}, 0x{:x}).\n",
+ physfn.vendor_id(),
+ physfn.device_id()
+ );
+
+ dev_info!(
+ pdev,
+ "We have access to the private data of {:?}.\n",
+ drvdata.private
+ );
+ }
+
+ pdev.enable_device_mem()?;
+ pdev.set_master();
+
+ Ok(try_pin_init!(Self {
+ pdev: pdev.into(),
+ private: TypeId::of::<Self>()
+ }))
+ })
+ }
+
+ fn sriov_configure(pdev: &pci::Device<Core>, nr_virtfn: i32) -> Result<i32> {
+ assert!(pdev.is_physfn());
+
+ if nr_virtfn == 0 {
+ dev_info!(
+ pdev,
+ "Disable SR-IOV (PCI ID: {}, 0x{:x}).\n",
+ pdev.vendor_id(),
+ pdev.device_id()
+ );
+ pdev.disable_sriov();
+ } else {
+ dev_info!(
+ pdev,
+ "Enable SR-IOV (PCI ID: {}, 0x{:x}).\n",
+ pdev.vendor_id(),
+ pdev.device_id()
+ );
+ pdev.enable_sriov(nr_virtfn)?;
+ }
+
+ assert_eq!(pdev.num_vf(), nr_virtfn);
+ Ok(nr_virtfn)
+ }
+}
+
+#[pinned_drop]
+impl PinnedDrop for SampleDriver {
+ fn drop(self: Pin<&mut Self>) {
+ dev_info!(self.pdev, "Remove Rust SR-IOV driver sample.\n");
+ }
+}
+
+kernel::module_pci_driver! {
+ type: SampleDriver,
+ name: "rust_driver_sriov",
+ authors: ["Peter Colberg"],
+ description: "Rust SR-IOV driver",
+ license: "GPL v2",
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Claude review: samples: rust: add SR-IOV driver sample
2026-03-03 21:15 ` [PATCH v3 10/10] samples: rust: add SR-IOV driver sample Peter Colberg
@ 2026-03-03 22:40 ` Claude Code Review Bot
0 siblings, 0 replies; 22+ messages in thread
From: Claude Code Review Bot @ 2026-03-03 22:40 UTC (permalink / raw)
To: dri-devel-reviews
Patch Review
Good sample that exercises the full API: `enable_sriov`, `disable_sriov`, `physfn`, `drvdata`, `is_virtfn`, `is_physfn`, `num_vf`.
```rust
+use core::any::TypeId;
```
Using `TypeId` as dummy private data is a clever way to demonstrate the `drvdata` access without needing actual meaningful state.
The `assert!()` calls (e.g., `assert!(physfn.is_physfn())`, `assert_eq!(pdev.num_vf(), nr_virtfn)`) will panic in the kernel if they fail. For a sample this is fine to clearly demonstrate invariants, but it's worth noting these would be inappropriate in a production driver.
The sample correctly does **not** call `disable_sriov()` in its `PinnedDrop` — the `managed_sriov` mechanism handles this via `pci_iov_disable()` before the driver's remove callback runs.
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 22+ messages in thread
* Claude review: rust: pci: add abstractions for SR-IOV capability
2026-03-03 21:15 [PATCH v3 00/10] rust: pci: add abstractions for SR-IOV capability Peter Colberg
` (9 preceding siblings ...)
2026-03-03 21:15 ` [PATCH v3 10/10] samples: rust: add SR-IOV driver sample Peter Colberg
@ 2026-03-03 22:40 ` Claude Code Review Bot
10 siblings, 0 replies; 22+ messages in thread
From: Claude Code Review Bot @ 2026-03-03 22:40 UTC (permalink / raw)
To: dri-devel-reviews
Overall Series Review
Subject: rust: pci: add abstractions for SR-IOV capability
Author: Peter Colberg <pcolberg@redhat.com>
Patches: 11
Reviewed: 2026-03-04T08:40:15.108262
---
This is a well-structured series adding Rust abstractions for PCI SR-IOV. The key architectural decision is sound: introducing a C-side `managed_sriov` driver flag that guarantees VFs are destroyed before the PF driver unbinds, which allows the Rust side to provide a safe `physfn()` API. The series builds incrementally with clean separation of concerns.
The C-side changes (patches 1-2) are the foundation, the Rust wrappers (patches 3, 6-8) are straightforward, the vtable/callback plumbing (patches 4-5) is mechanical, and the `physfn()` safety argument (patch 9) is the centerpiece. The sample (patch 10) demonstrates the full lifecycle.
No blocking issues found. A few observations and minor items below.
---
---
Generated by Claude Code Patch Reviewer
^ permalink raw reply [flat|nested] 22+ messages in thread