git: 9028edf79e50 - stable/15 - pci_iov: Roll back failed VF enumeration
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 24 Aug 2026 00:53:33 UTC
The branch stable/15 has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=9028edf79e50f664dc71c40aaf8ed84d7b5e779e
commit 9028edf79e50f664dc71c40aaf8ed84d7b5e779e
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-10 04:53:55 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-24 00:45:30 +0000
pci_iov: Roll back failed VF enumeration
pci_iov_enumerate_vfs() logged a failed VF creation or driver
configuration but still reported the whole SR-IOV configuration as
successful. The PF remained enabled with the requested NumVFs and
driver state even though one or more VF children were absent.
Make VF enumeration atomic. Delete children created by the failed
attempt, invoke the PF driver cleanup, disable VF memory space and VF
Enable, release the IOV resources, and return the original error to
iovctl. Also treat failure to create a VF child as an error instead
of silently accepting a partial configuration.
(cherry picked from commit 4b195f1a25d5003117653a1a323ad19561dc8705)
---
sys/dev/pci/pci_iov.c | 33 ++++++++++++++++++++++++++-------
1 file changed, 26 insertions(+), 7 deletions(-)
diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c
index 68b18fc15471..3a1cdeef694e 100644
--- a/sys/dev/pci/pci_iov.c
+++ b/sys/dev/pci/pci_iov.c
@@ -619,16 +619,16 @@ pci_iov_setup_bars(struct pci_devinfo *dinfo)
return (0);
}
-static void
+static int
pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const nvlist_t *config,
uint16_t first_rid, uint16_t rid_stride)
{
char device_name[VF_MAX_NAME];
const nvlist_t *device, *driver_config, *iov_config;
- device_t bus, dev, vf;
+ device_t bus, dev, vf, *vfs;
struct pcicfg_iov *iov;
struct pci_devinfo *vfinfo;
- int i, error;
+ int error, i, ncreated;
uint16_t vid, did, next_rid;
iov = dinfo->cfg.iov;
@@ -637,6 +637,9 @@ pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const nvlist_t *config,
next_rid = first_rid;
vid = pci_get_vendor(dev);
did = IOV_READ(dinfo, PCIR_SRIOV_VF_DID, 2);
+ vfs = mallocarray(iov->iov_num_vfs, sizeof(*vfs), M_SRIOV,
+ M_WAITOK | M_ZERO);
+ ncreated = 0;
for (i = 0; i < iov->iov_num_vfs; i++, next_rid += rid_stride) {
snprintf(device_name, sizeof(device_name), VF_PREFIX"%d", i);
@@ -645,8 +648,11 @@ pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const nvlist_t *config,
driver_config = nvlist_get_nvlist(device, DRIVER_CONFIG_NAME);
vf = PCI_CREATE_IOV_CHILD(bus, dev, next_rid, vid, did);
- if (vf == NULL)
- break;
+ if (vf == NULL) {
+ error = ENXIO;
+ goto fail;
+ }
+ vfs[ncreated++] = vf;
/*
* If we are creating passthrough devices then force the ppt
@@ -666,11 +672,19 @@ pci_iov_enumerate_vfs(struct pci_devinfo *dinfo, const nvlist_t *config,
error = PCI_IOV_ADD_VF(dev, i, driver_config);
if (error != 0) {
device_printf(dev, "Failed to add VF %d\n", i);
- device_delete_child(bus, vf);
+ goto fail;
}
}
bus_attach_children(bus);
+ free(vfs, M_SRIOV);
+ return (0);
+
+fail:
+ for (i = 0; i < ncreated; i++)
+ device_delete_child(bus, vfs[i]);
+ free(vfs, M_SRIOV);
+ return (error);
}
static int
@@ -773,7 +787,9 @@ pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg)
/* Per specification, we must wait 100ms before accessing VFs. */
pause("iov", roundup(hz, 10));
- pci_iov_enumerate_vfs(dinfo, config, first_rid, rid_stride);
+ error = pci_iov_enumerate_vfs(dinfo, config, first_rid, rid_stride);
+ if (error != 0)
+ goto out;
nvlist_destroy(config);
iov->iov_flags &= ~IOV_BUSY;
@@ -783,6 +799,9 @@ pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg)
out:
if (iov_inited) {
PCI_IOV_UNINIT(dev);
+ iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2);
+ iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE);
+ IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2);
IOV_WRITE(dinfo, PCIR_SRIOV_NUM_VFS, 0, 2);
}