mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Lukas Wunner <lukas@wunner.de>
To: Bjorn Helgaas <helgaas@kernel.org>
Cc: Jennifer Chan <jenniferchan@meta.com>,
	bhelgaas@google.com, linux-pci@vger.kernel.org,
	linux-kernel@vger.kernel.org, Jason Gunthorpe <jgg@nvidia.com>
Subject: Re: [PATCH] PCI: Add d3cold delay quirk for NVIDIA LR10 NVSwitch
Date: Fri, 6 Nov 2026 11:57:35 +0100	[thread overview]
Message-ID: <au2yn5QLQo1ziw0Y@wunner.de> (raw)
In-Reply-To: <20261105215148.GA1566818@bhelgaas>

On Thu, Nov 05, 2026 at 03:51:48PM -0600, Bjorn Helgaas wrote:
> On Thu, Nov 05, 2026 at 12:10:10PM -0800, Jennifer Chan wrote:
> > On a Supermicro HGX A100 system (X12DGO-6), each of the six LR10
> > NVSwitches (10de:1af1) sits alone behind a PLX PEX 8725 (10b5:8725)
> > downstream port.  "nvidia-smi -r" resets all GPUs: NVML unbinds the
> > switches from the nvidia-nvswitch driver, resets each one through sysfs
> > (reset_method "bus", a Secondary Bus Reset of its port) and binds them
> > again.  The PCI core waits 100 ms after the link comes back, the switch
> > answers config reads and the reset completes.

Broadcom PEX 89xxx switches support a "virtual switch" feature whereby
the switch spoofs responses from downstream devices when they're
inaccessible.  I just checked the datasheet of the PEX 8725 and it
seems to support this feature as well.

This feature makes the kernel believe that the downstream device is
ready even though it actually isn't.

I was made aware of this internally because a Supermicro server used
for testing contained two PEX 89xxx switches which had that feature
enabled.  I see you're using a Supermicro server as well, so perhaps
it has the same problem.

I developed a patch (included below, goes on top of v7.4-rc1) to work
around this misbehavior.  You may want to give it a spin and see if
it helps.  I never upstreamed the patch because after a lengthy
back and forth with Broadcom it turned out that the Supermicro server
shipped with an outdated firmware on the PEX 89xxx switches.  Updating
to a newer firmware made the issue go away.  The BIOS of the Supermicro
server was up to date, but it does not include the switch firmware.
I had to obtain a separate firmware update specifically for the switches
and install it through an EFI shell.

Obviously, a blanket wait of 1 second will work around Broadcom's virtual
switch feature as well, but it's not a proper fix.

The amdgpu driver contains a workaround for the virtual switch feature,
see 1dd2fa0e00f1.  Obviously, this only helps amdgpu and other drivers
don't benefit.  So we'd need to solve this for everyone in the PCI core,
as my patch below does.  I kind of hate putting a workaround for this
vendor-specific misbehavior in core code, but problem reports caused
by it keep landing on my desk, so maybe I should amend the patch with
a commit message and submit it.  But please test it first because perhaps
the issue you're seeing has some entirely different cause.

Thanks,

Lukas

-- >8 --

From 6ae81de682389f8522e96cea309e5e5304829b55 Mon Sep 17 00:00:00 2001
From: Lukas Wunner <lukas@wunner.de>
Date: Thu, 16 Oct 2025 10:56:15 +0200
Subject: [PATCH] PCI: Check for Broadcom placeholder device in pci_dev_wait()

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/pci/pci.c | 70 +++++++++++++++++++++++++++++------------------
 1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 9f82b0bc72ff..437e82cb47ac 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1225,18 +1225,19 @@ void pci_resume_bus(struct pci_bus *bus)
 		pci_walk_bus(bus, pci_resume_one, NULL);
 }
 
-static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
+static bool pci_dev_ready(struct pci_dev *dev, struct pci_dev *root,
+			  struct pci_dev *bridge)
 {
-	int delay = 1;
-	bool retrain = false;
-	struct pci_dev *root, *bridge;
-
-	root = pcie_find_root_port(dev);
+	u32 id;
 
-	if (pci_is_pcie(dev)) {
-		bridge = pci_upstream_bridge(dev);
-		if (bridge)
-			retrain = true;
+	/*
+	 * Broadcom (LSI Logic) PEX 89000 PCIe switches spoof responses from a
+	 * placeholder device with ID 0x02b2 if the real device is not ready.
+	 */
+	if (bridge && bridge->vendor == PCI_VENDOR_ID_LSI_LOGIC) {
+		pci_read_config_dword(dev, PCI_VENDOR_ID, &id);
+		if (id == (PCI_VENDOR_ID_LSI_LOGIC | 0x02b2 << 16))
+			return false;
 	}
 
 	/*
@@ -1260,28 +1261,45 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
 	 * ID for VFs and non-existent devices also returns ~0, so read the
 	 * Command register until it returns something other than ~0.
 	 */
-	for (;;) {
-		u32 id;
+	if (root && root->config_rrs_sv) {
+		pci_read_config_dword(dev, PCI_VENDOR_ID, &id);
+		if (!pci_bus_rrs_vendor_id(id)) {
+			if (PCI_POSSIBLE_ERROR(id) && dev->is_virtfn)
+				pci_read_config_dword(dev, PCI_COMMAND, &id);
+			if (!PCI_POSSIBLE_ERROR(id))
+				return true;
+		}
+	} else {
+		pci_read_config_dword(dev, PCI_COMMAND, &id);
+		if (!PCI_POSSIBLE_ERROR(id))
+			return true;
+	}
+
+	return false;
+}
+
+static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
+{
+	int delay = 1;
+	bool retrain = false;
+	struct pci_dev *root, *bridge = NULL;
 
+	root = pcie_find_root_port(dev);
+
+	if (pci_is_pcie(dev)) {
+		bridge = pci_upstream_bridge(dev);
+		if (bridge)
+			retrain = true;
+	}
+
+	for (;;) {
 		if (pci_dev_is_disconnected(dev)) {
 			pci_dbg(dev, "disconnected; not waiting\n");
 			return -ENOTTY;
 		}
 
-		if (root && root->config_rrs_sv) {
-			pci_read_config_dword(dev, PCI_VENDOR_ID, &id);
-			if (!pci_bus_rrs_vendor_id(id)) {
-				if (PCI_POSSIBLE_ERROR(id) && dev->is_virtfn)
-					pci_read_config_dword(dev, PCI_COMMAND,
-							      &id);
-				if (!PCI_POSSIBLE_ERROR(id))
-					break;
-			}
-		} else {
-			pci_read_config_dword(dev, PCI_COMMAND, &id);
-			if (!PCI_POSSIBLE_ERROR(id))
-				break;
-		}
+		if (pci_dev_ready(dev, root, bridge))
+			break;
 
 		if (delay > timeout) {
 			pci_err(dev, "not ready %dms after %s; giving up\n",
-- 
2.53.0


  parent reply	other threads:[~2026-11-06 10:57 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05 20:10 Jennifer Chan
2026-11-05 21:51 ` Bjorn Helgaas
2026-11-05 23:21   ` Jennifer Chan
2026-11-06 10:57   ` Lukas Wunner [this message]
2026-11-06 17:43   ` Jason Gunthorpe

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=au2yn5QLQo1ziw0Y@wunner.de \
    --to=lukas@wunner.de \
    --cc=bhelgaas@google.com \
    --cc=helgaas@kernel.org \
    --cc=jenniferchan@meta.com \
    --cc=jgg@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.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®