From: Vidya Sagar <vidyas@nvidia.com>
To: <bhelgaas@google.com>
Cc: <vsethi@nvidia.com>, <sdonthineni@nvidia.com>,
<kthota@nvidia.com>, <mmaddireddy@nvidia.com>,
<kumarahul@nvidia.com>, <sagar.tv@gmail.com>,
<linux-pci@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
Vidya Sagar <vidyas@nvidia.com>
Subject: [PATCH V3 3/5] PCI: Save and restore the Device 3 Control register
Date: Sat, 15 Aug 2026 01:46:19 +0530 [thread overview]
Message-ID: <20260814201621.2281245-4-vidyas@nvidia.com> (raw)
In-Reply-To: <20260814201621.2281245-1-vidyas@nvidia.com>
The Device 3 Extended Capability carries the 14-Bit Tag Requester Enable
bit, which platform firmware may have programmed before the PCI core takes
over. The core neither saves nor restores DEV3_CTL, so its contents are
lost on every path that goes through pci_save_state() and
pci_restore_state(), e.g. a Secondary Bus Reset, a slot reset or a D3cold
resume.
Restoring the saved value verbatim is not correct either. 14-Bit Tag
Requester Enable is only meaningful while the link operates in Flit Mode;
in Non-Flit Mode the upper tag bits are not transmitted on the wire, so a
requester that still has it set emits TLPs whose completions it can no
longer match. That shows up as a Completion Timeout together with an
Unexpected Completion on the very first transaction after the reset. A
link that comes back in Non-Flit Mode must therefore come back with
14-Bit Tag Requester Enable cleared. The completer side needs no such
handling: a completer reflects the Tag field of the request it answers, so
the spec defines no completer enable to fix up.
Allocate a save buffer in pci_dev3_init() for every device that exposes
the Device 3 Extended Capability and save DEV3_CTL from pci_save_state().
DEV3_STA needs no save buffer of its own because all of its fields
(Initial Link Width, Segment Captured and Remote L0p Supported) are
read-only status reported by hardware.
On restore, sanitize the saved value first: if the device advertises
14-Bit Tag Requester support but Flit Mode is no longer active, as
determined from the live LNKSTA2.Flit_Mode and DEV3_STA.Segment Captured,
drop PCI_DEV3_CTL_14BIT_TAG_REQ_EN before writing DEV3_CTL back and
refresh dev->fm_enabled and bus->flit_mode to match what the hardware now
reports. Devices without 14-Bit Tag Requester support, and every other
DEV3_CTL bit, are restored unchanged.
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
---
V3:
* Modified to preserve the original DEV3_CTL value
V2:
* New patch as a result of splitting the V1 monolithic patch
drivers/pci/pci.c | 84 +++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/probe.c | 12 +++++++
2 files changed, 96 insertions(+)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ff6d5d059b21..c59329365ad6 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1703,6 +1703,85 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
}
+static int pci_save_dev3_state(struct pci_dev *dev)
+{
+ struct pci_cap_saved_state *save_state;
+ u32 *cap;
+ int pos;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DEV3);
+ if (!pos)
+ return 0;
+
+ save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DEV3);
+ if (!save_state)
+ return -ENOMEM;
+
+ cap = (u32 *)&save_state->cap.data[0];
+ pci_read_config_dword(dev, pos + PCI_DEV3_CTL, &cap[0]);
+
+ return 0;
+}
+
+static void pci_restore_dev3_state(struct pci_dev *dev)
+{
+ struct pci_cap_saved_state *save_state;
+ u32 *cap, val, dev3_cap, dev3_sta;
+ u16 lnksta2 = 0;
+ bool flit_now;
+ int pos;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DEV3);
+ if (!pos)
+ return;
+
+ save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_DEV3);
+ if (!save_state)
+ return;
+
+ cap = (u32 *)&save_state->cap.data[0];
+ val = cap[0];
+
+ /*
+ * DEV3_CTL.14-Bit Tag Requester Enable is only meaningful in flit
+ * mode. On devices that advertise 14-Bit Tag Requester support,
+ * sanitize the saved value before writing it back, so that callers
+ * that issue further TLPs through this device after restore see a
+ * coherent enable state. Every other bit of DEV3_CTL (DMWr
+ * Requester Enable, DMWr Egress Blocking, L0p Enable, Target Link
+ * Width and any future addition) is written back unchanged.
+ *
+ * Only the value written to hardware is adjusted. The save buffer
+ * keeps what was saved, so the decision is taken afresh on every
+ * restore and the originally programmed value is not lost.
+ */
+ pci_read_config_dword(dev, pos + PCI_DEV3_CAP, &dev3_cap);
+ if (dev3_cap & PCI_DEV3_CAP_14BIT_TAG_REQ) {
+ /*
+ * Check both LNKSTA2.Flit_Mode (link-level) and
+ * DEV3_STA.Segment Captured (end-to-end); both must be
+ * active for 14-bit tags. Refresh bus->flit_mode and
+ * dev->fm_enabled in lock-step.
+ */
+ pci_read_config_dword(dev, pos + PCI_DEV3_STA, &dev3_sta);
+ dev->fm_enabled = !!(dev3_sta & PCI_DEV3_STA_SEGMENT);
+
+ pcie_capability_read_word(dev, PCI_EXP_LNKSTA2, &lnksta2);
+ flit_now = !!(lnksta2 & PCI_EXP_LNKSTA2_FLIT);
+ if (dev->bus)
+ dev->bus->flit_mode = flit_now;
+
+ if ((!dev->fm_enabled || !flit_now) &&
+ (val & PCI_DEV3_CTL_14BIT_TAG_REQ_EN)) {
+ val &= ~PCI_DEV3_CTL_14BIT_TAG_REQ_EN;
+ pci_info(dev, "clearing 14-Bit Tag Requester Enable: flit mode no longer active (LNKSTA2=%#06x, DEV3_STA=%#010x)\n",
+ lnksta2, dev3_sta);
+ }
+ }
+
+ pci_write_config_dword(dev, pos + PCI_DEV3_CTL, val);
+}
+
static int pci_save_pcix_state(struct pci_dev *dev)
{
int pos;
@@ -1759,6 +1838,10 @@ int pci_save_state(struct pci_dev *dev)
if (i != 0)
return i;
+ i = pci_save_dev3_state(dev);
+ if (i != 0)
+ return i;
+
i = pci_save_pcix_state(dev);
if (i != 0)
return i;
@@ -1826,6 +1909,7 @@ static void pci_restore_config_space(struct pci_dev *pdev)
void pci_restore_state(struct pci_dev *dev)
{
pci_restore_pcie_state(dev);
+ pci_restore_dev3_state(dev);
pci_restore_pasid_state(dev);
pci_restore_pri_state(dev);
pci_restore_ats_state(dev);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 60dd1efe9abb..810114029ee0 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2334,11 +2334,23 @@ static void pci_dev3_init(struct pci_dev *pdev)
{
u16 cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DEV3);
u32 val = 0;
+ int err;
if (!cap)
return;
pci_read_config_dword(pdev, cap + PCI_DEV3_STA, &val);
pdev->fm_enabled = !!(val & PCI_DEV3_STA_SEGMENT);
+
+ /*
+ * Save buffer for DEV3_CTL only. Every field in DEV3_STA is
+ * read-only status reported by hardware, so there is nothing there
+ * to restore.
+ */
+ err = pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_DEV3,
+ sizeof(u32));
+ if (err)
+ pci_warn(pdev,
+ "unable to preallocate Device 3 save buffer\n");
}
/**
--
2.43.0
next prev parent reply other threads:[~2026-08-14 20:17 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 20:16 [PATCH V3 0/5] PCI: Re-evaluate DEV3 14-Bit Tag Requester Enable on link mode changes Vidya Sagar
2026-08-14 20:16 ` [PATCH V3 1/5] PCI: Add DEV3 14-Bit Tag Requester register definitions Vidya Sagar
2026-08-14 20:19 ` sashiko-bot
2026-08-14 20:16 ` [PATCH V3 2/5] PCI: Move __pcie_update_link_speed() out of line Vidya Sagar
2026-08-14 20:31 ` sashiko-bot
2026-08-14 20:16 ` Vidya Sagar [this message]
2026-08-14 20:28 ` [PATCH V3 3/5] PCI: Save and restore the Device 3 Control register sashiko-bot
2026-08-14 20:16 ` [PATCH V3 4/5] PCI: Clear stale 14-Bit Tag Requester Enable when a link leaves Flit Mode Vidya Sagar
2026-08-14 20:34 ` sashiko-bot
2026-08-14 20:16 ` [PATCH V3 5/5] PCI: pciehp: Clear stale 14-Bit Tag Requester Enable on hot add Vidya Sagar
2026-08-14 20:34 ` sashiko-bot
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=20260814201621.2281245-4-vidyas@nvidia.com \
--to=vidyas@nvidia.com \
--cc=bhelgaas@google.com \
--cc=kthota@nvidia.com \
--cc=kumarahul@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=mmaddireddy@nvidia.com \
--cc=sagar.tv@gmail.com \
--cc=sdonthineni@nvidia.com \
--cc=vsethi@nvidia.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.