Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 5 May 2021 00:58:42 GMT
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 96033da5c38e - stable/12 - Set PCIe device's Max_Payload_Size to match PCIe root's.
Message-ID:  <202105050058.1450wgbE028390@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by mav:

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

commit 96033da5c38e20c27e2ca9007cca8bfab7e350cc
Author:     Alexander Motin <mav@FreeBSD.org>
AuthorDate: 2021-04-05 14:34:40 +0000
Commit:     Alexander Motin <mav@FreeBSD.org>
CommitDate: 2021-05-05 00:57:07 +0000

    Set PCIe device's Max_Payload_Size to match PCIe root's.
    
    Usually on boot the MPS is already configured by BIOS.  But we've
    found that on hot-plug it is not true at least for our Supermicro
    X11 boards.  As result, mismatch between root's configuration of
    256 bytes and device's default of 128 bytes cause problems for some
    devices, while others seem to work fine.
    
    MFC after:      1 month
    Sponsored by:   iXsystems, Inc.
    
    (cherry picked from commit 5a898b2b78ce04d608bbaaa0813424b11f921ae7)
---
 sys/dev/pci/pci.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index f3a0309c5202..e167465db9b3 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -4248,6 +4248,45 @@ pci_create_iov_child_method(device_t bus, device_t pf, uint16_t rid,
 }
 #endif
 
+/*
+ * For PCIe device set Max_Payload_Size to match PCIe root's.
+ */
+static void
+pcie_setup_mps(device_t dev)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(dev);
+	device_t root;
+	uint16_t rmps, mmps, mps;
+
+	if (dinfo->cfg.pcie.pcie_location == 0)
+		return;
+	root = pci_find_pcie_root_port(dev);
+	if (root == NULL)
+		return;
+	/* Check whether the MPS is already configured. */
+	rmps = pcie_read_config(root, PCIER_DEVICE_CTL, 2) &
+	    PCIEM_CTL_MAX_PAYLOAD;
+	mps = pcie_read_config(dev, PCIER_DEVICE_CTL, 2) &
+	    PCIEM_CTL_MAX_PAYLOAD;
+	if (mps == rmps)
+		return;
+	/* Check whether the device is capable of the root's MPS. */
+	mmps = (pcie_read_config(dev, PCIER_DEVICE_CAP, 2) &
+	    PCIEM_CAP_MAX_PAYLOAD) << 5;
+	if (rmps > mmps) {
+		/*
+		 * The device is unable to handle root's MPS.  Limit root.
+		 * XXX: We should traverse through all the tree, applying
+		 * it to all the devices.
+		 */
+		pcie_adjust_config(root, PCIER_DEVICE_CTL,
+		    PCIEM_CTL_MAX_PAYLOAD, mmps, 2);
+	} else {
+		pcie_adjust_config(dev, PCIER_DEVICE_CTL,
+		    PCIEM_CTL_MAX_PAYLOAD, rmps, 2);
+	}
+}
+
 static void
 pci_add_child_clear_aer(device_t dev, struct pci_devinfo *dinfo)
 {
@@ -4335,6 +4374,7 @@ pci_add_child(device_t bus, struct pci_devinfo *dinfo)
 	pci_cfg_restore(dev, dinfo);
 	pci_print_verbose(dinfo);
 	pci_add_resources(bus, dev, 0, 0);
+	pcie_setup_mps(dev);
 	pci_child_added(dinfo->cfg.dev);
 
 	if (pci_clear_aer_on_attach)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202105050058.1450wgbE028390>