Re: [PATCH v3] PCI: Skip Target Speed quirk on clamped ports with no link

Thorsten Leemhuis <[email protected]> Mon, 3 Aug 2026 07:39:49 +0200
Newsgroups dev.linux.lists.regressions,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <[email protected]>
On 8/1/26 22:11, Andreas Wild wrote:
> From: "Maciej W. Rozycki" <[email protected]>
> 
> 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

TWIMC, this patch fixes a regression Edward reported here:
https://bugzilla.kernel.org/show_bug.cgi?id=221801

[side note: the report could be more specific, yes -- I wanted to ask
Edward to clarify a few things (like the actual slowdown) before
forwarding it, but it didn't came to that when I noticed this patch and
asked Edward to just check if it helped -- which is did.]

Ciao, Thorsten
> Where the Link Speed has already been clamped at 2.5GT/s and no link has
> been established there is nothing worth doing, which is what the kerneldoc
> for the quirk already describes: the restriction is to be lifted where
> firmware arranged it "and the port reports its link already being up".
> Bail out early in that case, before either the ASM2824 workaround or the
> removal of the restriction is considered.
> 
> Ports whose link is up are unaffected, and so is the ASM2824 workaround,
> which is reached with the Target Link Speed not clamped.
> 
> With this applied the quirk returns without touching the port: both
> messages are gone, enumeration proceeds from 0000:00:1c.0 to 0000:00:1c.2
> in 1 ms rather than 2 s, and the systemd "kernel" boot phase goes from
> 3.011 s to 1.036 s.
> 
> Fixes: 72780f796468 ("PCI: Always lift 2.5GT/s restriction in PCIe failed link retraining")
> Cc: [email protected]
> Reported-by: Andreas Wild <[email protected]>
> Closes: https://lore.kernel.org/lkml/[email protected]/
> Tested-by: Andreas Wild <[email protected]>
> Signed-off-by: Maciej W. Rozycki <[email protected]>
> Signed-off-by: Andreas Wild <[email protected]>
> ---
> v3:
>  - Replaced with Maciej's much simpler approach: bail out of the quirk
>    entirely when the Target Link Speed is already clamped at 2.5GT/s and no
>    link has been established, rather than programming the speed and skipping
>    only the retraining.  One function, no new API, no bwctrl changes.
>  - Note this leaves the Target Link Speed clamped on such a port, where v2
>    left it at the Port's maximum.  A device hot-plugged there later trains at
>    2.5GT/s: pcie_wait_for_link_delay() only calls the quirk when
>    pcie_wait_for_link_status() fails, so a link that comes up cleanly at
>    2.5GT/s never re-runs it.  Flagging in case that matters; the clamp is
>    firmware's, so honouring it on an unoccupied Port seems defensible.
>  - v2: https://lore.kernel.org/lkml/[email protected]/
>  - v1: https://lore.kernel.org/lkml/[email protected]/
>  drivers/pci/quirks.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index b09f27f..9e407c4 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -108,7 +108,11 @@ int pcie_failed_link_retrain(struct pci_dev *dev)
>  
>  	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)) {
> +	if (lnksta & PCI_EXP_LNKSTA_DLLLA) {
> +		;
> +	} else if (PCIE_LNKCTL2_TLS2SPEED(oldlnkctl2) == PCIE_SPEED_2_5GT) {
> +		return ret;
> +	} else if (pcie_lbms_seen(dev, lnksta)) {
>  		pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n");
>  		ret = pcie_set_target_speed(dev, PCIE_SPEED_2_5GT, false);
>  		if (ret)