[PATCH V2 3/4] PCI: Save and restore the Device 3 Control register
From: Vidya Sagar
Date: Tue Aug 11 2026 - 13:34:26 EST
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@xxxxxxxxxx>
---
V2:
* New patch as a result of splitting the V1 monolithic patch
drivers/pci/pci.c | 81 +++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/probe.c | 12 +++++++
2 files changed, 93 insertions(+)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ff6d5d059b21..3bbeed1ba20c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1703,6 +1703,82 @@ 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.
+ */
+ 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;
+ cap[0] = val;
+ 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 +1835,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 +1906,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