git: b91c0fc86c7d - stable/15 - pci_iov: Permit non-ARI VFs on a secondary bus

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Sun, 30 Aug 2026 01:42:53 UTC
The branch stable/15 has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=b91c0fc86c7d89124d4fcdeba2ad86e202c76fb8

commit b91c0fc86c7d89124d4fcdeba2ad86e202c76fb8
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-07-28 23:29:35 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-30 01:42:37 +0000

    pci_iov: Permit non-ARI VFs on a secondary bus
    
    A non-zero VF device number does not always require ARI. The Intel
    82576 and I350 [1] explicitly support a non-ARI layout that places VFs
    on the next bus.
    
    Check every requested VF RID and reject a non-zero device only when it
    is on the PF bus. This retains the ARI guard for invalid same-bus
    layouts while permitting the documented second-bus layout.
    
    [1] Intel I350 Datasheet, sections 7.8.2.6.1.2, 9.6.4.6
    
    Sponsored by:   BBOX.io
    
    (cherry picked from commit e795a31cb4d66368bdbe5ac7f61c0899d3ed39f8)
---
 sys/dev/pci/pci_iov.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/sys/dev/pci/pci_iov.c b/sys/dev/pci/pci_iov.c
index 3a1cdeef694e..9fb93f3db114 100644
--- a/sys/dev/pci/pci_iov.c
+++ b/sys/dev/pci/pci_iov.c
@@ -762,9 +762,24 @@ pci_iov_config(struct cdev *cdev, struct pci_iov_arg *arg)
 		}
 	}
 
-	if (!ari_enabled && PCI_RID2SLOT(last_rid) != 0) {
-		error = ENOSPC;
-		goto out;
+	if (!ari_enabled) {
+		uint16_t vf_rid;
+
+		/*
+		 * Without ARI, VFs on the PF's bus must use device 0.
+		 * VFs on another bus use the conventional device/function
+		 * encoding and may have a non-zero device number.  For
+		 * example, Intel 82576 and I350 VFs start at device 16 on
+		 * the next bus when ARI is unavailable.
+		 */
+		vf_rid = first_rid;
+		for (i = 0; i < num_vfs; i++, vf_rid += rid_stride) {
+			if (PCI_RID2BUS(vf_rid) == pci_get_bus(dev) &&
+			    PCI_RID2SLOT(vf_rid) != 0) {
+				error = ENOSPC;
+				goto out;
+			}
+		}
 	}
 
 	iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2);