All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andreas Wild <andiwild@gmail.com>
To: linux-pci@vger.kernel.org
Cc: bhelgaas@google.com, macro@orcam.me.uk,
	linux-kernel@vger.kernel.org, Andreas Wild <andiwild@gmail.com>
Subject: [PATCH] PCI: Avoid link retraining on empty ports when lifting speed restriction
Date: Sat,  1 Aug 2026 11:21:33 +0200	[thread overview]
Message-ID: <20260801092152.5643-1-andiwild@gmail.com> (raw)

Since commit 72780f796468 ("PCI: Always lift 2.5GT/s restriction in PCIe
failed link retraining") the Target Speed quirk lifts a firmware-imposed
2.5GT/s restriction on any downstream port, without checking whether the
link is up.  Where nothing is plugged in, the retraining that follows can
never complete, so each attempt costs PCIE_LINK_RETRAIN_TIMEOUT_MS.  The
quirk makes two of them -- the initial one and the restore on the error
path -- adding a fixed 2 s to every boot.

On an MSI PRO Z690-A WIFI DDR4 (Intel 600 Series PCH) with one empty x1
slot, running v7.2-rc5:

 0.541 pci 0000:00:1c.0: removing 2.5GT/s downstream link speed restriction
 1.541 pci 0000:00:1c.0: retraining failed
 2.541 pci 0000:00:1c.2: [8086:7aba] type 01 class 0x060400

The kerneldoc above the quirk already contemplates this case ("For a port
that has been left unconnected both bits will be clear") and describes
lifting the restriction where firmware arranged it "and the port reports
its link already being up".  The code stopped checking the latter.

Program the Target Link Speed directly when Data Link Layer Link Active
is clear, and skip the retraining.  The restriction is still lifted, so a
device plugged into the port later trains at the full speed the port
supports, which is what the original change set out to ensure.

The check cannot be hoisted down into pcie_bwctrl_change_speed(): the
ASM2824 workaround earlier in this function deliberately retrains a link
whose DLLLA is clear, and would break.

Measured on v7.2-rc5, same tree and same config with and without this
patch: the interval after the quirk logs drops from 1000 ms to 3 ms, the
second timeout disappears along with "retraining failed", and the systemd
"kernel" boot phase goes from 3.011 s to 1.024 s.  The restriction is
still lifted -- on the still-empty port afterwards:

 LnkCap:  Port #1, Speed 8GT/s, Width x1
 LnkSta:  Speed 2.5GT/s, Width x0
 LnkCtl2: Target Link Speed: 8GT/s

Fixes: 72780f796468 ("PCI: Always lift 2.5GT/s restriction in PCIe failed link retraining")
Cc: stable@vger.kernel.org
Signed-off-by: Andreas Wild <andiwild@gmail.com>
---
 drivers/pci/quirks.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index b09f27f..d0c8b09 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -97,6 +97,7 @@ 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)
@@ -115,9 +116,25 @@ int pcie_failed_link_retrain(struct pci_dev *dev)
 			goto err;
 	}
 
+	pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
 	pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2);
 	if ((lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT) {
 		pci_info(dev, "removing 2.5GT/s downstream link speed restriction\n");
+
+		/*
+		 * With no link partner the retraining can never complete and
+		 * every attempt costs PCIE_LINK_RETRAIN_TIMEOUT_MS.  Program
+		 * the Target Link Speed directly and skip the retraining; the
+		 * link will train at that speed once a device shows up.
+		 */
+		if (!(lnksta & PCI_EXP_LNKSTA_DLLLA)) {
+			pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+			pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL2,
+							   PCI_EXP_LNKCTL2_TLS,
+							   lnkcap & PCI_EXP_LNKCAP_SLS);
+			return ret;
+		}
+
 		ret = pcie_set_target_speed(dev, speed_cap, false);
 		if (ret)
 			goto err;
-- 
2.55.0


             reply	other threads:[~2026-08-01  9:25 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-01  9:21 Andreas Wild [this message]
2026-08-01  9:39 ` [PATCH] PCI: Avoid link retraining on empty ports when lifting speed restriction sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260801092152.5643-1-andiwild@gmail.com \
    --to=andiwild@gmail.com \
    --cc=bhelgaas@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=macro@orcam.me.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.