From: Nika Krasnova <nika@nikableh.moe>
To: "Grumbach, Emmanuel" <emmanuel.grumbach@intel.com>
Cc: "helgaas @ kernel . org" <helgaas@kernel.org>,
"nika @ nikableh . moe" <nika@nikableh.moe>,
"markpearson @ lenovo . com" <markpearson@lenovo.com>,
"bp @ alien8 . de" <bp@alien8.de>,
"x86 @ kernel . org" <x86@kernel.org>,
"hpa @ zytor . com" <hpa@zytor.com>,
"mingo @ redhat . com" <mingo@redhat.com>,
"linux-kernel @ vger . kernel . org"
<linux-kernel@vger.kernel.org>,
"dave . hansen @ linux . intel . com"
<dave.hansen@linux.intel.com>,
"tglx @ kernel . org" <tglx@kernel.org>,
"linux-pci @ vger . kernel . org" <linux-pci@vger.kernel.org>,
"bhelgaas @ google . com" <bhelgaas@google.com>
Subject: Re: [PATCH] x86/PCI: Disable D3cold on Intel BE200 Wi-Fi on Lenovo IdeaPad Pro 5 14IAH10
Date: Wed, 29 Jul 2026 14:52:02 +0200 [thread overview]
Message-ID: <20260729125202.33719-1-nika@nikableh.moe> (raw)
In-Reply-To: <ec2bc0c14bc036a5e81da6e1fab67a20efe53699.camel@intel.com>
On Tue, 28 Jul 2026 20:14:36 +0000, "Grumbach, Emmanuel" <emmanuel.grumbach@intel.com> wrote:
> We try to avoid resetting the firmware during suspend / resume. Out of
> curiosity, can you try to reset it?
I applied your hunk on top of 7.1.3, with my quirk removed, and it makes
no difference. The patched and unpatched runs fail identically:
iwlwifi 0000:01:00.0: timeout waiting for FW reset ACK (inta_hw=0xffffffff, reset_done 1)
ieee80211 phy0: PM: dpm_run_callback(): wiphy_resume [cfg80211] returns -110
ieee80211 phy0: PM: failed to resume async: error -110
On Tue, 28 Jul 2026 15:05:59 -0500, Bjorn Helgaas <helgaas@kernel.org> wrote:
> I guess this means "lspci -xs01:00.0" after resume shows all 0xff?
Yes. Before suspend:
$ lspci -xs01:00.0
01:00.0 Network controller: Intel Corporation Wi-Fi 7(802.11be) AX1775*/AX1790*/BE20*/BE401/BE1750* 2x2 (rev 1a)
00: 86 80 2b 27 06 04 10 00 1a 00 80 02 10 00 80 00
10: 04 00 20 8c 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 86 80 f4 00
30: 00 00 00 00 40 00 00 00 00 00 00 00 ff 01 00 00
and after resume:
$ lspci -xs01:00.0
01:00.0 Network controller: Intel Corporation Wi-Fi 7(802.11be) AX1775*/AX1790*/BE20*/BE401/BE1750* 2x2 (rev 1a)
00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
I've noticed that the root port above the card also never brings the
link back up:
pcieport 0000:00:06.0: Data Link Layer Link Active not set in 100 msec
[...]
iwlwifi 0000:01:00.0: timeout waiting for FW reset ACK (inta_hw=0xffffffff, reset_done 1)
ieee80211 phy0: PM: failed to resume async: error -110
0000:00:06.0 is the parent of 01:00.0. pci_pm_resume_noirq() only
reaches that wait with prev_state == PCI_D3cold, so the root port itself
was in D3cold, not just the endpoint. When the wait fails, everything
below the port is marked disconnected.
$ lspci -PP -s 01:00.0
00:06.0/01:00.0 Network controller: Intel Corporation Wi-Fi 7(802.11be) AX1775*/AX1790*/BE20*/BE401/BE1750* 2x2 (rev 1a)
(The "100 msec" there is the settle delay argument rather than the wait.
pcie_wait_for_link_delay() polls DLLLA for up to a second and also tries
pcie_failed_link_retrain(), so a larger d3cold_delay would not help.)
As far as I can tell the BE200 and its firmware are not involved. By the
time iwlwifi runs, the link is already down and every read returns ones,
which is what I would expect if the card never got its power back. That
also explains why a module reload and a PCI remove/rescan cannot revive
it: a rescan needs a working link.
D3cold on this port means switching off the ACPI power resource
\_SB.PC00.RP10.PXP_. I turned on the AML interpreter's method tracing
(trace_debug_layer=0x80, trace_debug_level=0x10, trace_state=enable) and
ran a suspend/resume where the card did not come back, to see whether
the firmware's power-on sequence runs at all. Other methods interleave
in the raw log, so this is grepped for RP10:
Method Begin [\_SB.PC00.RP10.PXP._OFF] execution.
Method Begin [\_SB.PC00.RP10.GPRS] execution.
Method End [\_SB.PC00.RP10.GPRS] execution.
Method Begin [\_SB.PC00.RP10.DL23] execution.
Method End [\_SB.PC00.RP10.DL23] execution.
Method Begin [\_SB.PC00.RP10.POFF] execution.
Method Begin [\_SB.PC00.RP10.GPPR] execution.
Method End [\_SB.PC00.RP10.GPPR] execution.
Method End [\_SB.PC00.RP10.POFF] execution.
Method End [\_SB.PC00.RP10.PXP._OFF] execution.
Method Begin [\_SB.PC00.RP10.PXP._ON] execution.
Method Begin [\_SB.PC00.RP10.GPRS] execution.
Method End [\_SB.PC00.RP10.GPRS] execution.
Method Begin [\_SB.PC00.RP10.PON] execution.
Method End [\_SB.PC00.RP10.PON] execution.
Method Begin [\_SB.PC00.RP10.L23D] execution.
Method End [\_SB.PC00.RP10.L23D] execution.
Method End [\_SB.PC00.RP10.PXP._ON] execution.
The resume side mirrors the suspend side: PON() and L23D() going up,
DL23() and POFF() coming down. The firmware runs the whole sequence and
reports success. The link still does not train.
Two registers in the port's own config space say more, both named by the
ASL. L23R sits at 0xE2 bit 3; L23D writes it and then polls until the
hardware clears it, and DL23 does the same with L23E on the way down.
LTSM is at 0x32B, which the firmware's own debug strings call the LTSSM
state.
Before suspend:
$ setpci -s 00:06.0 0xe2.b
11
$ for i in $(seq 5); do setpci -s 00:06.0 0x32b.b; done
40
40
40
40
40
After the failed resume:
$ setpci -s 00:06.0 0xe2.b
91
$ for i in $(seq 5); do setpci -s 00:06.0 0x32b.b; done
01
01
01
01
01
L23R (0x08) is clear both times, so the request L23D makes does
complete. For comparison, the sibling root port 0000:00:06.2, whose link
is up:
$ for i in $(seq 3); do setpci -s 00:06.2 0x32b.b; done
33
40
40
I do not know how the values in 0x32B map to LTSSM states, so the only
thing I can point at is the comparison: the failing port sits in a state
it never occupies while a link is up. If anyone has the decode for that
register, I would like to know what 0x01 is.
I can send the full acpidump output, or the decompiled DSDT and SSDTs,
off-list to anyone who wants to look at PON()/POFF() and the GPRS()
helper themselves.
> Another thing.. Does Windows run the same suspend / resume sequence?
> It also uses D3cold? I'd expect Lenovo to run thorough validation on
> those flows on Windows and report possible bugs to us.
I've dualbooted Windows 11 on this machine. The results:
PS C:\Users\user> powercfg /a
The following sleep states are available on this system:
Standby (S0 Low Power Idle) Network Connected
Hibernate
Fast Startup
The following sleep states are not available on this system:
Standby (S1)
The system firmware does not support this standby state.
This standby state is disabled when S0 low power idle is supported.
Standby (S2)
The system firmware does not support this standby state.
This standby state is disabled when S0 low power idle is supported.
Standby (S3)
The system firmware does not support this standby state.
This standby state is disabled when S0 low power idle is supported.
The current Device Guard configuration has disabled this standby
state.
Hybrid Sleep
Standby (S3) is not available.
The hypervisor does not support this standby state.
PS C:\Users\user> powercfg /devicequery wake_armed
USB4 Root Router (1.0)
Intel(R) Wi-Fi 7 BE200 320MHz
Output from devmgmt.msc for our BE200:
Current power state:
D0
Power capabilities:
00000089
PDCAP_D0_SUPPORTED
PDCAP_D3_SUPPORTED
PDCAP_WAKE_FROM_D3_SUPPORTED
Power state mappings:
S0 -> D0
S1 -> D3
S2 -> D3
S3 -> D3
S4 -> D3
S5 -> D3
The device clearly uses D3, but that does not distinguish D3hot from
D3cold. Windows' DEVICE_POWER_STATE enumeration [1] bottoms out at
PowerDeviceD3, and a driver does not initiate the D3hot -> D3cold step
at all: it requests D3hot, and the device reaches D3cold only when the
bus driver or the system firmware removes the power source [2]. So what
Device Manager reports is the requested D-state, not whether the rail
was subsequently removed. This machine also sleeps via S0 Low Power Idle
rather than S3, so the Sx -> Dx table above does not even describe the
flow that matters here.
Entering D3cold while the system stays in S0 has to be enabled by the
power policy owner, through the INF or a SetD3ColdSupport() call [2].
Does the Windows BE200 driver enable D3cold transitions in S0 on
platforms like this one? If it does not, then Windows never takes the
card below D3hot here, and the D3cold->D0 path would never have been
exercised in validation.
Given that the failure is at the link layer above the device rather than
in the device itself, this should probably be a PCI quirk in
drivers/pci/quirks.c instead of arch/x86/pci/fixup.c.
[1] https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-_device_power_state
[2] https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/enabling-transitions-to-d3cold
--
Nika Krasnova
next prev parent reply other threads:[~2026-07-29 12:53 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-22 2:13 [PATCH] x86/PCI: Disable D3cold on Intel BE200 Wi-Fi on Lenovo IdeaPad Pro 5 14IAH10 Nika Krasnova
2026-07-22 2:19 ` sashiko-bot
2026-07-28 20:05 ` Bjorn Helgaas
2026-07-28 20:14 ` Grumbach, Emmanuel
2026-07-29 12:52 ` Nika Krasnova [this message]
2026-08-29 9:39 ` Navon John Lukose
2026-09-23 1:22 ` Navon John Lukose
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=20260729125202.33719-1-nika@nikableh.moe \
--to=nika@nikableh.moe \
--cc=bhelgaas@google.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=emmanuel.grumbach@intel.com \
--cc=helgaas@kernel.org \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=markpearson@lenovo.com \
--cc=mingo@redhat.com \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox