Re: [PATCH v3] PCI/PM: Restore BARs after powering up during enumeration

From: Mario Limonciello

Date: Wed Oct 14 2026 - 22:49:08 EST




On 10/14/26 21:08, Keng-Yu Lin wrote:
Commit 4d4c10f763d7 ("PCI: Explicitly put devices into D0 when
initializing") added pci_pm_power_up_and_verify_state() to pci_pm_init().
The helper ignores pci_power_up()'s return value indicating that BARs
need restoring. Its resume callers restore saved configuration
afterwards; pci_pm_init() does not.

D3hot-to-D0 may reset a device and lose its BARs (PCI PM 1.2, sec 5.4.1).
After enumeration powers it up, pci_enable_device() reads D0 and skips
the full power-up path. Previously, a device still in D3hot at enable
time took that path, including BAR restoration.

On AMD Venice SP7, two AMD xHCI controllers [1022:17d2] are in runtime
D3hot with No_Soft_Reset clear before kdump. Diagnostic reads on
v7.3-rc6-37 show the following for 0000:01:00.4 in the crash kernel:

PMCSR BAR0
before the platform power call 0003 f4100004
after the platform power call 0003 f4100004
after native D0 power-up 0000 00000004

The upper BAR DWORD stays zero. pci_power_up() returns 1, but the BAR
address remains zero while dev->resource[0] still contains 0xf4100000.
Without BAR restoration, the crash kernel hangs during boot. The
last console output includes:

pci 0000:01:00.4: enabling device (0000 -> 0002)

Restoring both controllers' BARs gives matching readbacks and allows
kdump to save a vmcore and reboot. An AMD Turin xHCI [1022:1557] shows
the same BAR loss; restoring its BAR also allows kdump to complete.

Read the initial power state first. Otherwise, pci_power_up() may
request a BAR restore based on a cached PCI_UNKNOWN state, even
when the device is already in D0.

For devices already in D0, only synchronize the platform state so
that ACPI calls such as _REG still run. For other states, use
pci_set_full_power_state() to power up the device and restore BARs
when needed.

Suggested-by: Mario Limonciello <mario.limonciello@xxxxxxx>
Suggested-by: Rafael J. Wysocki <rafael@xxxxxxxxxx>
Fixes: 4d4c10f763d7 ("PCI: Explicitly put devices into D0 when initializing")
Link: https://lore.kernel.org/r/CAJZ5v0ie2AvCbdv8-zkpYzHLcTwUPUj+=WWOQjDAPmSepSAQPg@xxxxxxxxxxxxxx/
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Keng-Yu Lin <keng-yu.lin@xxxxxxx>
Reviewed-by: Mario Limonciello (AMD) <superm1@xxxxxxxxxx>> ---

Changes in v3:
- Use Rafael's sequence: sync only the platform state for devices
already in D0, and use pci_set_full_power_state() otherwise.
- The D0 path no longer runs the full helper's ASPM update.

Tested with diagnostic prints on AMD Venice SP7 and Turin. Normal
boots made no BAR writes from this path. The crash kernels restored
only the cleared xHCI BARs (two on Venice, one on Turin), with matching
readbacks. Both systems saved a vmcore and rebooted.

v2: https://lore.kernel.org/r/20261012104645.975190-1-keng-yu.lin@xxxxxxx/

drivers/pci/pci.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8cc6a89130b5..895969fe4520 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3255,7 +3255,15 @@ void pci_pm_init(struct pci_dev *dev)
}
poweron:
- pci_pm_power_up_and_verify_state(dev);
+ pci_update_current_state(dev, PCI_UNKNOWN);
+ if (dev->current_state == PCI_D0) {
+ /* No need to do a full power-up, just sync-up the platform state. */
+ platform_pci_set_power_state(dev, PCI_D0);
+ } else {
+ /* Power up the device and restore BARs if necessary. */
+ pci_set_full_power_state(dev, false);
+ }
+ pci_update_current_state(dev, PCI_D0);
pm_runtime_forbid(&dev->dev);
/*

base-commit: 7b63ef2d55f24519e7e9e5f4d15dbea03f126e40