From: Birk Skyum <birk.skyum@pm.me>
To: Jingoo Han <jingoohan1@gmail.com>,
Manivannan Sadhasivam <mani@kernel.org>,
Bjorn Helgaas <bhelgaas@google.com>
Cc: "Lorenzo Pieralisi" <lpieralisi@kernel.org>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Krishna Chaitanya Chundru" <krishna.chundru@oss.qualcomm.com>,
linux-pci@vger.kernel.org, linux-arm-msm@vger.kernel.org,
linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [RFC PATCH] PCI: dwc: Power the controller down when hibernating
Date: Fri, 09 Oct 2026 20:24:32 +0000 [thread overview]
Message-ID: <179157746908.73485.2343672865542690797@pm.me> (raw)
dw_pcie_suspend_noirq() leaves the controller powered, with
pci->suspended false, when a device below it cannot go to D3cold.
dw_pcie_resume_noirq() then returns early and the driver carries on
with the controller as it was.
That is fine for suspend. Drivers use the same two functions for
hibernation, where they run as freeze_noirq and restore_noirq. Devices
are normally still in D0 at freeze, so a controller with a device
behind it is left powered and the image records it as running. That
image is resumed after a power cycle, by a kernel that may never have
brought the controller up.
On a Lenovo Yoga Slim 7x (X1E80100) this resets the machine on every
resume from hibernation. The Wi-Fi card is behind pcie4, whose link
only comes up once the power sequencing drivers have been loaded from
the root file system. The kernel that loads the image resumes before
that, so it never powers pcie4, and the restored kernel then reads the
DBI registers of that controller:
qcom_pcie_resume_noirq()
qcom_pcie_icc_opp_update()
dw_pcie_find_capability()
dw_pcie_read_dbi()
The machine resets at that read. pcie6a, which holds the NVMe drive and
is brought up by both kernels, gets through the same path.
Take the shortcut only while a suspend is in progress. A hibernation
image then always holds a controller that is down, and thaw and restore
bring it up through dw_pcie_resume_noirq(), like after any other loss
of power.
Signed-off-by: Birk Skyum <birk.skyum@pm.me>
---
RFC because this changes the freeze path of every driver that uses
dw_pcie_suspend_noirq(), and I can only test qcom. If you would rather
have it in pcie-qcom alone, or solved on the restore side, I am happy
to redo it.
Tested on a Lenovo Yoga Slim 7x with Arch Linux ARM's v7.2 kernel plus
this patch, booted both for the image and for the resume.
dw_pcie_suspend_noirq() is the same in v7.3-rc6 and in pci/next, which
this is based on.
- A hibernation with a real power-off resumes (one run). Before, every
attempt reset the machine.
- pm_test=core and test_resume pass.
- pcie4 and pcie6a both go down at freeze and their links come back at
thaw and at restore. NVMe and Wi-Fi work afterwards.
- A suspend (deep) and wake still works, and neither link is retrained
across it.
Two things to know about the test:
- I unloaded ath12k and the Bluetooth UART driver for the hibernation.
With the Bluetooth UART open the resume stops later, in the GENI
serial driver, and the remote processors do not come back after a
resume either. Both are separate from this and still open.
- With ath12k unloaded the Wi-Fi card is in D0 at freeze, and the wait
for L2 times out on pcie4 ("Timeout waiting for L2 entry! LTSSM:
0x11"). pcie6a does not show that.
Nothing survives the reset, so to find the read a test module wrote
each step of the restored kernel to an EFI variable before it ran. The
last record is the entry into dw_pcie_read() for pcie4, after
gdsc_enable() and icc_enable() had returned.
drivers/pci/controller/dwc/pcie-designware-host.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 77aa79ef0..458e4c6e7 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -19,6 +19,7 @@
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/platform_device.h>
+#include <linux/suspend.h>
#include "../pci-host-common.h"
#include "../../pci.h"
@@ -1231,7 +1232,14 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci)
if (!dw_pcie_link_up(pci))
goto stop_link;
- if (!pci_host_common_d3cold_possible(pci->pp.bridge, &pme_capable))
+ /*
+ * Leaving the controller powered is only safe if it keeps its state
+ * until resume. A hibernation image is resumed after a power cycle, by
+ * a kernel that may not have brought this controller up, so only a
+ * suspend may leave it powered.
+ */
+ if (pm_suspend_in_progress() &&
+ !pci_host_common_d3cold_possible(pci->pp.bridge, &pme_capable))
return 0;
if (pci->pp.ops->pme_turn_off) {
base-commit: 591d89f23a7cbc668579521513c7f53b0968754c
--
2.53.0
next reply other threads:[~2026-10-09 20:24 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-09 20:24 Birk Skyum [this message]
[not found] ` <sashiko-outbox-166041@kernel.org>
2026-10-09 21:07 ` Birk Skyum
2026-10-12 8:48 ` Krishna Chaitanya Chundru
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=179157746908.73485.2343672865542690797@pm.me \
--to=birk.skyum@pm.me \
--cc=bhelgaas@google.com \
--cc=jingoohan1@gmail.com \
--cc=krishna.chundru@oss.qualcomm.com \
--cc=kwilczynski@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=mani@kernel.org \
--cc=robh@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
all inboxes | Powered by JetHome®