aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2021-04-05 14:34:40 +0000
committerAlexander Motin <mav@FreeBSD.org>2021-05-05 00:53:55 +0000
commit22b9f618e873140127570e629c19e25d13edc568 (patch)
tree8ba7e3742d679ad56cedf0a58f6efa0ef8cb05b6
parent972fcfb34b0d84dc1d869c351da8e19c702a3c35 (diff)
downloadsrc-22b9f618e873140127570e629c19e25d13edc568.tar.gz
src-22b9f618e873140127570e629c19e25d13edc568.zip
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)
-rw-r--r--sys/dev/pci/pci.c40
1 files changed, 40 insertions, 0 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index d85ce5baa7bc..54d7957dcbf1 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -4267,6 +4267,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)
{
@@ -4354,6 +4393,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)