Linux USB
 help / color / mirror / Atom feed
From: Mario Limonciello <mario.limonciello@amd.com>
To: Bjorn Helgaas <bhelgaas@google.com>
Cc: "open list:PCI SUBSYSTEM" <linux-pci@vger.kernel.org>,
	"open list:PCI SUBSYSTEM" <linux-usb@vger.kernel.org>,
	open list <linux-kernel@vger.kernel.org>,
	Mario Limonciello <mario.limonciello@amd.com>, <mrh@frame.work>,
	<stern@rowland.harvard.edu>, <hannes@vonhaugwitz.com>,
	<jase_harley@protonmail.com>, <superveridical@gmail.com>,
	<david.c.hubbard@gmail.com>, <bugzilla@logical.ink>,
	<michal.pecio@gmail.com>
Subject: [PATCH] PCI: Apply mandatory recovery delay on return from D3cold
Date: Wed, 8 Jul 2026 10:26:50 -0500	[thread overview]
Message-ID: <20260708152650.536604-2-mario.limonciello@amd.com> (raw)
In-Reply-To: <20260708152650.536604-1-mario.limonciello@amd.com>

Per the "PCI Bus Power Management Interface Specification", rev. 1.2,
sec. 5.4, there is a minimum recovery time between programming a function
from D3 to D0 and accessing it.  The spec does not limit this to D3hot; it
applies to the D3cold to D0 transition as well.

pci_power_up() only honors this delay on the D3hot branch.  When a device
returns from D3cold, platform_pci_set_power_state() has already restored
main power before PCI_PM_CTRL is read, so the state read from the register
is D0 and the transition delay block is skipped by the

	if (state == PCI_D0)
		goto end;

early return.  The register value is masked with PCI_PM_CTRL_STATE_MASK
and cannot represent D3cold, so only dev->current_state still reflects the
D3cold origin at this point.

Apply the delay based on dev->current_state, ahead of the early return, so
it takes effect on the D3cold to D0 path before the device is accessed.
Use the device's d3cold_delay, which the platform may tune via _DSM and
quirks may raise, rather than the D3hot delay.

To keep the existing D3hot callers unchanged, pci_dev_d3_sleep() now takes
the delay in milliseconds and a pci_dev_d3hot_sleep() wrapper supplies the
D3hot delay as before.

Reported-by: mrh@frame.work
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221073
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
Cc: mrh@frame.work
Cc: stern@rowland.harvard.edu
Cc: hannes@vonhaugwitz.com
Cc: jase_harley@protonmail.com
Cc: superveridical@gmail.com
Cc: david.c.hubbard@gmail.com
Cc: bugzilla@logical.ink
Cc: michal.pecio@gmail.com
---
 drivers/pci/pci.c | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 77b17b13ee615..e09cfb28fe61c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -81,9 +81,8 @@ struct pci_pme_device {
  */
 #define PCIE_RESET_READY_POLL_MS 60000 /* msec */
 
-static void pci_dev_d3_sleep(struct pci_dev *dev)
+static void pci_dev_d3_sleep(unsigned int delay_ms)
 {
-	unsigned int delay_ms = max(dev->d3hot_delay, pci_pm_d3hot_delay);
 	unsigned int upper;
 
 	if (delay_ms) {
@@ -94,6 +93,11 @@ static void pci_dev_d3_sleep(struct pci_dev *dev)
 	}
 }
 
+static void pci_dev_d3hot_sleep(struct pci_dev *dev)
+{
+	pci_dev_d3_sleep(max(dev->d3hot_delay, pci_pm_d3hot_delay));
+}
+
 bool pci_reset_supported(struct pci_dev *dev)
 {
 	return dev->reset_methods[0] != 0;
@@ -1333,6 +1337,16 @@ int pci_power_up(struct pci_dev *dev)
 	need_restore = (state == PCI_D3hot || dev->current_state >= PCI_D3hot) &&
 			!(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET);
 
+	/*
+	 * A device returning from D3cold has already been powered back on by
+	 * platform_pci_set_power_state() above, so PCI_PM_CTRL now reads back
+	 * as D0 and the transition delays below are skipped.  PCI PM 1.2 still
+	 * requires a minimum recovery time on the D3 to D0 transition, so apply
+	 * the device's D3cold recovery delay here before it is accessed.
+	 */
+	if (dev->current_state == PCI_D3cold)
+		pci_dev_d3_sleep(dev->d3cold_delay);
+
 	if (state == PCI_D0)
 		goto end;
 
@@ -1344,7 +1358,7 @@ int pci_power_up(struct pci_dev *dev)
 
 	/* Mandatory transition delays; see PCI PM 1.2. */
 	if (state == PCI_D3hot) {
-		pci_dev_d3_sleep(dev);
+		pci_dev_d3hot_sleep(dev);
 		if (!(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) {
 			ret = pci_dev_wait(dev, "power up D3hot->D0uninitialized",
 					   PCIE_RESET_READY_POLL_MS);
@@ -1514,7 +1528,7 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool
 
 	/* Mandatory power management transition delays; see PCI PM 1.2. */
 	if (state == PCI_D3hot)
-		pci_dev_d3_sleep(dev);
+		pci_dev_d3hot_sleep(dev);
 	else if (state == PCI_D2)
 		udelay(PCI_PM_D2_DELAY);
 
@@ -4511,12 +4525,12 @@ static int pci_pm_reset(struct pci_dev *dev, bool probe)
 	csr &= ~PCI_PM_CTRL_STATE_MASK;
 	csr |= PCI_D3hot;
 	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
-	pci_dev_d3_sleep(dev);
+	pci_dev_d3hot_sleep(dev);
 
 	csr &= ~PCI_PM_CTRL_STATE_MASK;
 	csr |= PCI_D0;
 	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
-	pci_dev_d3_sleep(dev);
+	pci_dev_d3hot_sleep(dev);
 
 	ret = pci_dev_wait(dev, "PM D3hot->D0", PCIE_RESET_READY_POLL_MS);
 	pci_dev_reset_iommu_done(dev);
-- 
2.43.0


  reply	other threads:[~2026-07-08 15:27 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-08 15:26 [PATCH 0/1] PCI: Add mandatory delay for D3cold resume Mario Limonciello
2026-07-08 15:26 ` Mario Limonciello [this message]
2026-07-10 20:16   ` [PATCH] PCI: Apply mandatory recovery delay on return from D3cold Bjorn Helgaas
2026-07-10 20:19     ` Mario Limonciello

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=20260708152650.536604-2-mario.limonciello@amd.com \
    --to=mario.limonciello@amd.com \
    --cc=bhelgaas@google.com \
    --cc=bugzilla@logical.ink \
    --cc=david.c.hubbard@gmail.com \
    --cc=hannes@vonhaugwitz.com \
    --cc=jase_harley@protonmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=michal.pecio@gmail.com \
    --cc=mrh@frame.work \
    --cc=stern@rowland.harvard.edu \
    --cc=superveridical@gmail.com \
    /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