From bb115505a9f1f79b888aa0ccb28f42f05edea07f Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 26 Mar 2026 17:13:11 -0500 Subject: PCI: Remove MPS/MRRS Kconfig settings (CONFIG_PCIE_BUS_*) Revert b0e85c3c8554 ("PCI: Add Kconfig options for MPS/MRRS strategy"), which allowed build-time selection of the "off", "default", "safe", "performance", or "peer2peer" strategies for MPS and MRRS configuration. These strategies can be selected at boot-time using the "pci=pcie_bus_tune_*" kernel parameters. Per the discussion mentioned below, these Kconfig options were added to work around a hardware defect in a WiFi device used in a cable modem. The defect occurred only when the device was configured with MPS=128, and Kconfig was a way to avoid that setting. It was easier for the modem vendor to use Kconfig and update the kernel image than to change the kernel parameters. Neither Kconfig nor kernel parameters are a complete solution because the broken WiFi device may be used in other systems where it may be configured with MPS=128 and be susceptible to the defect. Remove the Kconfig settings to simplify the MPS code. If we can identify the WiFi device in question, we may be able to make a generic quirk to avoid the problem on all system. This is not a fix and should not be backported to previous kernels. Link: https://lore.kernel.org/all/CA+-6iNzd0RJO0L021qz8CKrSviSst6QehY-QtJxz_-EVY0Hj0Q@mail.gmail.com Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20260326221311.1356180-1-bhelgaas@google.com --- drivers/pci/Kconfig | 57 ----------------------------------------------------- drivers/pci/pci.c | 10 ---------- 2 files changed, 67 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 33c88432b728..0c7408509ba2 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -251,63 +251,6 @@ config PCI_DYNAMIC_OF_NODES Once this option is selected, the device tree nodes will be generated for all PCI bridges. -choice - prompt "PCI Express hierarchy optimization setting" - default PCIE_BUS_DEFAULT - depends on EXPERT - help - MPS (Max Payload Size) and MRRS (Max Read Request Size) are PCIe - device parameters that affect performance and the ability to - support hotplug and peer-to-peer DMA. - - The following choices set the MPS and MRRS optimization strategy - at compile-time. The choices are the same as those offered for - the kernel command-line parameter 'pci', i.e., - 'pci=pcie_bus_tune_off', 'pci=pcie_bus_safe', - 'pci=pcie_bus_perf', and 'pci=pcie_bus_peer2peer'. - - This is a compile-time setting and can be overridden by the above - command-line parameters. If unsure, choose PCIE_BUS_DEFAULT. - -config PCIE_BUS_TUNE_OFF - bool "Tune Off" - help - Use the BIOS defaults; don't touch MPS at all. This is the same - as booting with 'pci=pcie_bus_tune_off'. - -config PCIE_BUS_DEFAULT - bool "Default" - help - Default choice; ensure that the MPS matches upstream bridge. - -config PCIE_BUS_SAFE - bool "Safe" - help - Use largest MPS that boot-time devices support. If you have a - closed system with no possibility of adding new devices, this - will use the largest MPS that's supported by all devices. This - is the same as booting with 'pci=pcie_bus_safe'. - -config PCIE_BUS_PERFORMANCE - bool "Performance" - help - Use MPS and MRRS for best performance. Ensure that a given - device's MPS is no larger than its parent MPS, which allows us to - keep all switches/bridges to the max MPS supported by their - parent. This is the same as booting with 'pci=pcie_bus_perf'. - -config PCIE_BUS_PEER2PEER - bool "Peer2peer" - help - Set MPS = 128 for all devices. MPS configuration effected by the - other options could cause the MPS on one root port to be - different than that of the MPS on another, which may cause - hot-added devices or peer-to-peer DMA to fail. Set MPS to the - smallest possible value (128B) system-wide to avoid these issues. - This is the same as booting with 'pci=pcie_bus_peer2peer'. - -endchoice - config VGA_ARB bool "VGA Arbitration" if EXPERT default y diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8f7cfcc00090..ee1b0e34231c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -120,17 +120,7 @@ unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE; /* PCIe MPS/MRRS strategy; can be overridden by kernel command-line param */ -#ifdef CONFIG_PCIE_BUS_TUNE_OFF -enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF; -#elif defined CONFIG_PCIE_BUS_SAFE -enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE; -#elif defined CONFIG_PCIE_BUS_PERFORMANCE -enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE; -#elif defined CONFIG_PCIE_BUS_PEER2PEER -enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PEER2PEER; -#else enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT; -#endif /* * The default CLS is used if arch didn't set CLS explicitly and not -- cgit v1.2.3 From 72780f7964684939d7d2f69c348876213b184484 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 8 Dec 2025 19:24:29 +0000 Subject: PCI: Always lift 2.5GT/s restriction in PCIe failed link retraining Discard Vendor:Device ID matching in the PCIe failed link retraining quirk and ignore the link status for the removal of the 2.5GT/s speed clamp, whether applied by the quirk itself or the firmware earlier on. Revert to the original target link speed if this final link retraining has failed. This is so that link training noise in hot-plug scenarios does not make a link remain clamped to the 2.5GT/s speed where an event race has led the quirk to apply the speed clamp for one device, only to leave it in place for a subsequent device to be plugged in. Refer to the Link Capabilities register directly for the maximum link speed determination so as to streamline backporting. Fixes: a89c82249c37 ("PCI: Work around PCIe link training failures") Signed-off-by: Maciej W. Rozycki Signed-off-by: Bjorn Helgaas Tested-by: Alok Tiwari Cc: stable@vger.kernel.org # v6.5+ Link: https://patch.msgid.link/alpine.DEB.2.21.2512080331530.49654@angie.orcam.me.uk --- drivers/pci/quirks.c | 51 ++++++++++++++++++--------------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index caaed1a01dc0..dd0025d3914e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -80,11 +80,10 @@ static bool pcie_lbms_seen(struct pci_dev *dev, u16 lnksta) * Restrict the speed to 2.5GT/s then with the Target Link Speed field, * request a retrain and check the result. * - * If this turns out successful and we know by the Vendor:Device ID it is - * safe to do so, then lift the restriction, letting the devices negotiate - * a higher speed. Also check for a similar 2.5GT/s speed restriction the - * firmware may have already arranged and lift it with ports that already - * report their data link being up. + * If this turns out successful, or where a 2.5GT/s speed restriction has + * been previously arranged by the firmware and the port reports its link + * already being up, lift the restriction, in a hope it is safe to do so, + * letting the devices negotiate a higher speed. * * Otherwise revert the speed to the original setting and request a retrain * again to remove any residual state, ignoring the result as it's supposed @@ -95,51 +94,37 @@ static bool pcie_lbms_seen(struct pci_dev *dev, u16 lnksta) */ int pcie_failed_link_retrain(struct pci_dev *dev) { - static const struct pci_device_id ids[] = { - { PCI_VDEVICE(ASMEDIA, 0x2824) }, /* ASMedia ASM2824 */ - {} - }; - u16 lnksta, lnkctl2; + u16 lnksta, lnkctl2, oldlnkctl2; int ret = -ENOTTY; + u32 lnkcap; if (!pci_is_pcie(dev) || !pcie_downstream_port(dev) || !pcie_cap_has_lnkctl2(dev) || !dev->link_active_reporting) return ret; pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); + pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &oldlnkctl2); if (!(lnksta & PCI_EXP_LNKSTA_DLLLA) && pcie_lbms_seen(dev, lnksta)) { - u16 oldlnkctl2; - pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n"); - - pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &oldlnkctl2); ret = pcie_set_target_speed(dev, PCIE_SPEED_2_5GT, false); - if (ret) { - pci_info(dev, "retraining failed\n"); - pcie_set_target_speed(dev, PCIE_LNKCTL2_TLS2SPEED(oldlnkctl2), - true); - return ret; - } - - pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); + if (ret) + goto err; } pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2); - - if ((lnksta & PCI_EXP_LNKSTA_DLLLA) && - (lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT && - pci_match_id(ids, dev)) { - u32 lnkcap; - + pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap); + if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT && + (lnkcap & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) { pci_info(dev, "removing 2.5GT/s downstream link speed restriction\n"); - pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap); ret = pcie_set_target_speed(dev, PCIE_LNKCAP_SLS2SPEED(lnkcap), false); - if (ret) { - pci_info(dev, "retraining failed\n"); - return ret; - } + if (ret) + goto err; } + return ret; +err: + pci_info(dev, "retraining failed\n"); + pcie_set_target_speed(dev, PCIE_LNKCTL2_TLS2SPEED(oldlnkctl2), true); return ret; } -- cgit v1.2.3 From 30a361308085ebf9a848be2d5828ed913d3572f5 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 8 Dec 2025 19:24:34 +0000 Subject: PCI: Use pcie_get_speed_cap() in PCIe failed link retraining Rewrite a check for the maximum link speed in the Link Capabilities register in terms of pcie_get_speed_cap(). No functional change. Signed-off-by: Maciej W. Rozycki Signed-off-by: Bjorn Helgaas Tested-by: Alok Tiwari Link: https://patch.msgid.link/alpine.DEB.2.21.2512080348310.49654@angie.orcam.me.uk --- drivers/pci/quirks.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index dd0025d3914e..81ee3f69b918 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -95,8 +95,8 @@ static bool pcie_lbms_seen(struct pci_dev *dev, u16 lnksta) int pcie_failed_link_retrain(struct pci_dev *dev) { u16 lnksta, lnkctl2, oldlnkctl2; + enum pci_bus_speed speed_cap; int ret = -ENOTTY; - u32 lnkcap; if (!pci_is_pcie(dev) || !pcie_downstream_port(dev) || !pcie_cap_has_lnkctl2(dev) || !dev->link_active_reporting) @@ -111,12 +111,12 @@ int pcie_failed_link_retrain(struct pci_dev *dev) goto err; } + speed_cap = pcie_get_speed_cap(dev); pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2); - pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap); if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT && - (lnkcap & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) { + speed_cap > PCIE_SPEED_2_5GT) { pci_info(dev, "removing 2.5GT/s downstream link speed restriction\n"); - ret = pcie_set_target_speed(dev, PCIE_LNKCAP_SLS2SPEED(lnkcap), false); + ret = pcie_set_target_speed(dev, speed_cap, false); if (ret) goto err; } -- cgit v1.2.3 From 64d63fd28177abd1bbc3133610771aa15c22c223 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Mon, 8 Dec 2025 19:24:38 +0000 Subject: PCI: Bail out early for 2.5GT/s devices in PCIe failed link retraining There's no point in retraining a failed 2.5GT/s device at 2.5GT/s, so just don't and return early. While such devices might be unlikely to implement Link Active reporting, we need to retrieve the maximum link speed and use it in a conditional later on anyway, so the early check comes for free. Signed-off-by: Maciej W. Rozycki Signed-off-by: Bjorn Helgaas Tested-by: Alok Tiwari Link: https://patch.msgid.link/alpine.DEB.2.21.2512080356070.49654@angie.orcam.me.uk --- drivers/pci/quirks.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/pci') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 81ee3f69b918..1b4ae046dd69 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -102,6 +102,10 @@ int pcie_failed_link_retrain(struct pci_dev *dev) !pcie_cap_has_lnkctl2(dev) || !dev->link_active_reporting) return ret; + speed_cap = pcie_get_speed_cap(dev); + if (speed_cap <= PCIE_SPEED_2_5GT) + return ret; + pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &oldlnkctl2); if (!(lnksta & PCI_EXP_LNKSTA_DLLLA) && pcie_lbms_seen(dev, lnksta)) { @@ -111,10 +115,8 @@ int pcie_failed_link_retrain(struct pci_dev *dev) goto err; } - speed_cap = pcie_get_speed_cap(dev); pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2); - if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT && - speed_cap > PCIE_SPEED_2_5GT) { + if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT) { pci_info(dev, "removing 2.5GT/s downstream link speed restriction\n"); ret = pcie_set_target_speed(dev, speed_cap, false); if (ret) -- cgit v1.2.3