Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 07 Aug 2026 05:50:14 +0000
From:      Kevin Bowling <kbowling@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 114f4a68f213 - main - pci: Optionally disable endpoints with unsafe MPS
Message-ID:  <6a757216.37567.1c1a1bf0@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kbowling:

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

commit 114f4a68f21345e1e6680b7acf1bf733d9047002
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-06 06:42:26 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-07 05:49:55 +0000

    pci: Optionally disable endpoints with unsafe MPS
    
    Keep warn-only behavior as the default. Add an opt-in policy that
    clears endpoint decoding and bus mastering when a newly discovered
    function cannot match its active path, while never disabling bridge
    functions and their subtrees.
    
    MFC after:      2 weeks
---
 share/man/man4/pci.4 | 13 +++++++++++++
 sys/dev/pci/pci.c    | 43 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/share/man/man4/pci.4 b/share/man/man4/pci.4
index dc4bf4387057..c84051b1b988 100644
--- a/share/man/man4/pci.4
+++ b/share/man/man4/pci.4
@@ -617,6 +617,19 @@ The maximum amount of memory permitted for the configuration parameters
 used when creating Virtual Functions via SR-IOV.
 This tunable can also be changed at runtime via
 .Xr sysctl 8 .
+.It Va hw.pci.mps_enforce Pq Defaults to 0
+Disable a newly discovered PCI-express endpoint if its MPS cannot be safely
+reconciled with the active hierarchy.
+The default behavior reports the conflict and leaves the device enabled.
+When enforcement is enabled, an under-capable endpoint below a PCI-express
+switch is disabled rather than retuning the shared path.
+PCI bridge functions are never disabled by this policy because doing so could
+disconnect otherwise compatible devices in their downstream subtrees.
+An administrator can explicitly override the policy with the
+.Cm enable
+command of
+.Xr devctl 8 ;
+the device is then attached without repeating the MPS safety check.
 .It Va hw.pci.mps_limit Pq Defaults to 0
 Limit the MPS selected while reconciling a PCI-express hierarchy during
 cold enumeration.
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 02642ad40239..4663fe043073 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -442,6 +442,11 @@ SYSCTL_INT(_hw_pci, OID_AUTO, mps_limit, CTLFLAG_RDTUN, &pci_mps_limit, 0,
     "Limit PCIe MPS to this many bytes (power of two from 128 to 4096)");
 static bool pci_mps_limit_warned;
 
+static bool pci_mps_enforce;
+SYSCTL_BOOL(_hw_pci, OID_AUTO, mps_enforce, CTLFLAG_RDTUN,
+    &pci_mps_enforce, 0,
+    "Disable PCIe endpoints with an MPS incompatible with their shared path");
+
 static bool pci_intx_reroute = true;
 SYSCTL_BOOL(_hw_pci, OID_AUTO, intx_reroute, CTLFLAG_RWTUN,
     &pci_intx_reroute, 0, "Re-route INTx interrupts when scanning devices");
@@ -4518,26 +4523,60 @@ pcie_mps_conflict(device_t dev, uint16_t path_mps, uint16_t max_mps)
 	    pcie_mps_bytes(max_mps), pcie_mps_bytes(path_mps));
 }
 
+static bool
+pcie_mps_is_bridge(struct pci_devinfo *dinfo)
+{
+	uint8_t hdrtype;
+
+	hdrtype = dinfo->cfg.hdrtype & PCIM_HDRTYPE;
+	return (hdrtype == PCIM_HDRTYPE_BRIDGE ||
+	    hdrtype == PCIM_HDRTYPE_CARDBUS);
+}
+
 static void
 pcie_mps_active_conflict(device_t dev, uint16_t path_mps,
     uint16_t device_mps)
 {
+	struct pci_devinfo *dinfo;
+	const char *action;
 
 	if (!pcie_mps_first_warning(dev))
 		return;
+	dinfo = device_get_ivars(dev);
+	if (pci_mps_enforce && !pcie_mps_is_bridge(dinfo))
+		action = "disabling device";
+	else
+		action = "leaving device unchanged";
 	device_printf(dev,
 	    "configured MPS %d does not match path MPS %d while bus "
-	    "mastering is enabled; leaving device unchanged\n",
-	    pcie_mps_bytes(device_mps), pcie_mps_bytes(path_mps));
+	    "mastering is enabled; %s\n", pcie_mps_bytes(device_mps),
+	    pcie_mps_bytes(path_mps), action);
 }
 
 static void
 pcie_mps_mark_unreconciled(device_t dev)
 {
 	struct pci_devinfo *dinfo;
+	uint16_t cmd;
 
 	dinfo = device_get_ivars(dev);
+	if ((dinfo->cfg.flags & PCICFG_MPS_UNRECONCILED) != 0)
+		return;
 	dinfo->cfg.flags |= PCICFG_MPS_UNRECONCILED;
+	if (!pci_mps_enforce)
+		return;
+	if (pcie_mps_is_bridge(dinfo)) {
+		device_printf(dev,
+		    "not disabled by hw.pci.mps_enforce because it is a bridge\n");
+		return;
+	}
+	cmd = pci_read_config(dev, PCIR_COMMAND, 2);
+	cmd &= ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
+	pci_write_config(dev, PCIR_COMMAND, cmd, 2);
+	dinfo->cfg.cmdreg = cmd;
+	device_disable(dev);
+	device_printf(dev,
+	    "disabled because its MPS cannot be safely configured\n");
 }
 
 static void


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a757216.37567.1c1a1bf0>