mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Francisco Beltrán Millalén" <fbeltranmillalen@gmail.com>
To: Bjorn Helgaas <bhelgaas@google.com>, linux-pci@vger.kernel.org
Cc: Bjorn Helgaas <helgaas@kernel.org>,
	Alan Stern <stern@rowland.harvard.edu>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Lukas Wunner <lukas@wunner.de>, Farhan Ali <alifm@linux.ibm.com>,
	Andreas Noever <andreas.noever@gmail.com>,
	Mika Westerberg <westeri@kernel.org>,
	Yehezkel Bernat <YehezkelShB@gmail.com>, Darrell Gum <d@rrell.co>,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v3 1/2] PCI/PM: Keep the saved config space of an inaccessible device
Date: Mon, 19 Oct 2026 17:24:44 -0300	[thread overview]
Message-ID: <20261019202445.38259-2-fbeltranmillalen@gmail.com> (raw)
In-Reply-To: <20261019202445.38259-1-fbeltranmillalen@gmail.com>

pci_save_state() saves the standard header without checking whether the
device responded.  For an inaccessible device, each read returns all
ones, overwriting the previous snapshot, which pci_restore_state()
writes back after resume.  On a bridge, that sets every writable bit of
the Bridge Control register, Secondary Bus Reset included, and sets the
primary, secondary and subordinate bus numbers to 0xff, which cuts off
everything below it.  This was seen on a MacBookPro14,3, where a bridge
that stopped responding during system suspend came back after resume
with bus numbers ff/ff/ff.

Commit e18d1abc3bff ("PCI: Avoid saving config space state if
inaccessible") added pci_dev_config_accessible() and checks it before a
reset.  Check it in pci_save_state() itself, so that system suspend is
covered as well.

If it is not accessible, keep the previous snapshot, mark the state as
saved and return 0.  This avoids changing callers or making the PM core
warn about a low-power device without saved state.  pci_bus_add_device()
saves the state when the device is added, so normally a snapshot exists.
That snapshot can be older than the last values the device had, for
example if its driver changed the Command register after the last
successful save.

Assisted-by: LLM
Signed-off-by: Francisco Beltrán Millalén <fbeltranmillalen@gmail.com>
---
v3:
- Keep the previous snapshot and return 0 instead of returning -EIO, so
  that callers see no change.  Returning -EIO changed what some drivers
  do, as described on v2:
  https://lore.kernel.org/all/20261011210451.12129-1-fbeltranmillalen@gmail.com/
- Check accessibility only once, at the start of pci_save_state(), and
  drop the temporary copy of the header and the second check, as Bjorn
  suggested.
- pci_dev_save_and_disable() is left as it is.  Bjorn suggested using
  the return value of pci_save_state() there, and on v2 I said I would.
  This version returns 0 for an inaccessible device, so the existing
  check stays.  It also keeps that function from clearing the Command
  register of a device that does not respond.
- The commit message no longer presents this as a fix for the
  Thunderbolt controller dropping off during suspend.
- Darrell's Tested-by from v2 is not carried over, as the code changed.
- Farhan pointed out [1] that in 2025 Lukas was concerned about checking
  in pci_save_state() itself, as callers that don't need the check pay
  for it [2].  The check is one config read on top of the 16 for the
  header and those for the capabilities.  System suspend saves the state
  both from the PCI core and from the suspend callbacks of many drivers,
  so checking in every caller isn't practical.

About the snapshot that is kept, which I have not tested beyond the
case in the cover letter:
- For a bridge, bus numbers and windows changed after the last
  successful save, for example by hotplug, would be written back with
  their older values.
- The snapshot from pci_bus_add_device() is taken before the driver
  probes, so a device that was never saved again since then gets the
  pre-probe values.
- A device that became inaccessible before it was added has no real
  snapshot: the saved header is all zeros, which is what would be
  written back.

[1] https://lore.kernel.org/all/7ed02ff5-d7f8-42e4-bca9-b3d3ce7b6795@linux.ibm.com/
[2] https://lore.kernel.org/all/aOQX6ZTMvekd6gWy@wunner.de/

v2:
- Use pci_dev_config_accessible() instead of reading the Vendor ID,
  which always reads as all ones on SR-IOV VFs: v1 refused to save the
  state of every VF.
- Do the second check after saving the capabilities, and set
  state_saved only if both checks pass.

 drivers/pci/pci.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a62af7320539..eacaa1e71a83 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1794,10 +1794,23 @@ static void pci_restore_pcix_state(struct pci_dev *dev)
  * pci_save_state - save the PCI configuration space of a device before
  *		    suspending
  * @dev: PCI device that we're dealing with
+ *
+ * If the config space of @dev is not accessible, the previous snapshot is
+ * kept and reported as saved, as writing back the all-ones values read from
+ * such a device would corrupt it once it is accessible again.
+ *
+ * Return: 0 on success, or a negative errno if a capability could not be
+ * saved.
  */
 int pci_save_state(struct pci_dev *dev)
 {
 	int i;
+
+	if (!pci_dev_config_accessible(dev, "save state")) {
+		dev->state_saved = true;
+		return 0;
+	}
+
 	/* XXX: 100% dword access ok here? */
 	for (i = 0; i < 16; i++) {
 		pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]);

  reply	other threads:[~2026-10-19 20:25 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-19 20:24 [PATCH v3 0/2] " Francisco Beltrán Millalén
2026-10-19 20:24 ` Francisco Beltrán Millalén [this message]
2026-10-19 20:24 ` [PATCH v3 2/2] PCI: Do not mistake an absent device for an active link Francisco Beltrán Millalén

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=20261019202445.38259-2-fbeltranmillalen@gmail.com \
    --to=fbeltranmillalen@gmail.com \
    --cc=YehezkelShB@gmail.com \
    --cc=alifm@linux.ibm.com \
    --cc=andreas.noever@gmail.com \
    --cc=bhelgaas@google.com \
    --cc=d@rrell.co \
    --cc=gregkh@linuxfoundation.org \
    --cc=helgaas@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=stern@rowland.harvard.edu \
    --cc=westeri@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®