[PATCH v2 07/10] PCI/FLIT: Add support for Flit Logging Extended Capability
From: Yazen Ghannam
Date: Fri Sep 18 2026 - 11:05:49 EST
PCIe r6.4 defines the Flit Logging Extended Capability for logging
erroneous flits, and requires it on ports and RCRBs that support PCIe
Flit Mode.[1]
Add a port service driver for it. Include _OSC negotiation for control
of the capability.
The driver claims only the port types the PCIe port bus driver binds to.
An Endpoint implements the capability on its Upstream Port too, and _OSC
is negotiated per host bridge, so accepting control leaves those
instances with neither firmware nor the OS managing them. Covering them
needs a home outside the port bus driver.
[1] PCI Express® Base Specification Revision 6.4, section 7.7.8
Link: https://pcisig.com/specification/extend-osc-negotiate-control-pcie-flit-logging-extended-capability
Originally-by: Avadhut Naik <avadhut.naik@xxxxxxx>
Assisted-by: LLM
Signed-off-by: Yazen Ghannam <yazen.ghannam@xxxxxxx>
---
drivers/acpi/pci_root.c | 11 ++
drivers/pci/pci.c | 2 +
drivers/pci/pci.h | 12 ++
drivers/pci/pcie/Kconfig | 9 +
drivers/pci/pcie/Makefile | 1 +
drivers/pci/pcie/flit.c | 324 ++++++++++++++++++++++++++++++++++
drivers/pci/pcie/portdrv.c | 7 +
drivers/pci/pcie/portdrv.h | 13 +-
drivers/pci/probe.c | 3 +
include/linux/acpi.h | 1 +
include/linux/pci.h | 6 +
include/uapi/linux/pci_regs.h | 19 +-
12 files changed, 405 insertions(+), 3 deletions(-)
create mode 100644 drivers/pci/pcie/flit.c
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 88c65f34e305..402686a9ca4c 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -137,6 +137,7 @@ static struct pci_osc_bit_struct pci_osc_control_bit[] = {
{ OSC_PCI_EXPRESS_CAPABILITY_CONTROL, "PCIeCapability" },
{ OSC_PCI_EXPRESS_LTR_CONTROL, "LTR" },
{ OSC_PCI_EXPRESS_DPC_CONTROL, "DPC" },
+ { OSC_PCI_EXPRESS_FLIT_CONTROL, "FlitLogging" },
};
static struct pci_osc_bit_struct cxl_osc_support_bit[] = {
@@ -520,6 +521,14 @@ static u32 calculate_control(void)
if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR))
control |= OSC_PCI_EXPRESS_DPC_CONTROL;
+ /*
+ * An OS that requests Flit Logging control must request AER control
+ * as well, so pair it with the bit that was actually requested above.
+ */
+ if (IS_ENABLED(CONFIG_PCIE_FLIT) &&
+ (control & OSC_PCI_EXPRESS_AER_CONTROL))
+ control |= OSC_PCI_EXPRESS_FLIT_CONTROL;
+
return control;
}
@@ -1040,6 +1049,8 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
host_bridge->native_ltr = 0;
if (!(root->osc_control_set & OSC_PCI_EXPRESS_DPC_CONTROL))
host_bridge->native_dpc = 0;
+ if (!(root->osc_control_set & OSC_PCI_EXPRESS_FLIT_CONTROL))
+ host_bridge->native_flit = 0;
if (!(root->osc_ext_control_set & OSC_CXL_ERROR_REPORTING_CONTROL))
host_bridge->native_cxl_error = 0;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b2879a6be5f8..c1cfa0e3d75c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1798,6 +1798,7 @@ int pci_save_state(struct pci_dev *dev)
pci_save_dpc_state(dev);
pci_save_aer_state(dev);
+ pci_save_flit_state(dev);
pci_save_ptm_state(dev);
pci_save_tph_state(dev);
return pci_save_vc_state(dev);
@@ -1870,6 +1871,7 @@ void pci_restore_state(struct pci_dev *dev)
pci_aer_clear_status(dev);
pci_restore_aer_state(dev);
+ pci_restore_flit_state(dev);
pci_restore_config_space(dev);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f43c5330fca3..53a90f75cd76 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1000,6 +1000,18 @@ static inline void pci_dpc_init(struct pci_dev *pdev) { }
static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
#endif
+#ifdef CONFIG_PCIE_FLIT
+void pci_flit_init(struct pci_dev *pdev);
+void pci_flit_exit(struct pci_dev *pdev);
+void pci_save_flit_state(struct pci_dev *pdev);
+void pci_restore_flit_state(struct pci_dev *pdev);
+#else
+static inline void pci_flit_init(struct pci_dev *pdev) { }
+static inline void pci_flit_exit(struct pci_dev *pdev) { }
+static inline void pci_save_flit_state(struct pci_dev *pdev) { }
+static inline void pci_restore_flit_state(struct pci_dev *pdev) { }
+#endif
+
#ifdef CONFIG_PCIEPORTBUS
void pci_rcec_init(struct pci_dev *dev);
void pci_rcec_exit(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 207c2deae35f..7ddadad57d3f 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -146,3 +146,12 @@ config PCIE_EDR
the PCI Firmware Specification r3.2. Enable this if you want to
support hybrid DPC model which uses both firmware and OS to
implement DPC.
+
+config PCIE_FLIT
+ bool "PCI Express Flit Logging support"
+ depends on PCIEPORTBUS && PCIEAER
+ help
+ This enables support for the PCI Express Flit Logging Extended
+ Capability, which logs errors encountered by a port operating
+ in PCIe Flit Mode. If your system doesn't have this capability
+ or you do not want to use this feature, it is safe to answer N.
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index b0b43a18c304..14a5222920b9 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_PCIE_PME) += pme.o
obj-$(CONFIG_PCIE_DPC) += dpc.o
obj-$(CONFIG_PCIE_PTM) += ptm.o
obj-$(CONFIG_PCIE_EDR) += edr.o
+obj-$(CONFIG_PCIE_FLIT) += flit.o
diff --git a/drivers/pci/pcie/flit.c b/drivers/pci/pcie/flit.c
new file mode 100644
index 000000000000..7c0b9c8dd481
--- /dev/null
+++ b/drivers/pci/pcie/flit.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Service driver for PCIe Flit Logging Extended Capability
+ *
+ * Copyright (c) 2026, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Authors: Avadhut Naik <Avadhut.Naik@xxxxxxx>
+ * Yazen Ghannam <Yazen.Ghannam@xxxxxxx>
+ */
+
+#define pr_fmt(fmt) "Flit: " fmt
+#define dev_fmt pr_fmt
+
+#include <linux/bitfield.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "portdrv.h"
+#include "../pci.h"
+
+/*
+ * Report only a link accumulating errors far faster than the counter drains.
+ * 0xff never fires, since an event needs the counter to exceed the trigger.
+ */
+#define FLIT_DEFAULT_TRIGGER 0xfe
+
+/*
+ * Per PCIe r6.4, sec 7.7.8.2, table 7-93, More Entries can be set again
+ * mid-drain, so bound the loop.
+ */
+#define FLIT_MAX_LOG_ENTRIES 0xff
+
+/*
+ * Per PCIe r6.4, sec 7.7.8.2, table 7-92, an entry with none of these set
+ * and Flit Error Log 2 zero is Reserved.
+ */
+#define FLIT_ERR_LOG1_ERROR (PCI_FLIT_ERR_LOG1_UNRECOG | \
+ PCI_FLIT_ERR_LOG1_FEC_UNCOR | \
+ PCI_FLIT_ERR_LOG1_SYND_PARITY0 | \
+ PCI_FLIT_ERR_LOG1_SYND_CHECK0)
+
+/* Only the port types pcie_portdrv_probe() claims get a Flit service. */
+static bool flit_is_port(struct pci_dev *pdev)
+{
+ if (!pci_is_pcie(pdev))
+ return false;
+
+ switch (pci_pcie_type(pdev)) {
+ case PCI_EXP_TYPE_ROOT_PORT:
+ case PCI_EXP_TYPE_UPSTREAM:
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ case PCI_EXP_TYPE_RC_EC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * Without _OSC control the OS must not touch the capability. Flit Logging
+ * control is only meaningful alongside AER control, so require both.
+ */
+static bool flit_is_native(struct pci_dev *pdev)
+{
+ struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
+
+ if (pcie_ports_native)
+ return true;
+
+ return host->native_flit && host->native_aer;
+}
+
+struct flit_info {
+ spinlock_t lock; /* serializes Counter Control read-modify-write */
+ bool cntr_enabled; /* Counter Enable as the driver intends it */
+};
+
+void pci_flit_init(struct pci_dev *pdev)
+{
+ if (!flit_is_port(pdev) || !flit_is_native(pdev))
+ return;
+
+ pdev->flit_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_FLIT);
+ if (!pdev->flit_cap)
+ return;
+
+ pdev->flit_info = kzalloc_obj(*pdev->flit_info);
+ if (!pdev->flit_info) {
+ pdev->flit_cap = 0;
+ return;
+ }
+
+ spin_lock_init(&pdev->flit_info->lock);
+
+ pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_FLIT, sizeof(u16));
+
+ pci_dbg(pdev, "Flit Logging Extended Capability present.\n");
+}
+
+void pci_flit_exit(struct pci_dev *pdev)
+{
+ kfree(pdev->flit_info);
+ pdev->flit_info = NULL;
+ pdev->flit_cap = 0;
+}
+
+void pci_save_flit_state(struct pci_dev *pdev)
+{
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ if (!pdev->flit_cap)
+ return;
+
+ save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_FLIT);
+ if (!save_state)
+ return;
+
+ /*
+ * Take Counter Enable from the driver rather than the register.
+ * flit_isr() clears it and only flit_ist() sets it again once the log
+ * is drained, and a save landing in between would capture a zero that
+ * the next restore writes back for good.
+ */
+ cap = (u16 *)&save_state->cap.data[0];
+ pci_read_config_word(pdev, pdev->flit_cap + PCI_FLIT_ERR_CNTR_CTRL, cap);
+ if (pdev->flit_info->cntr_enabled)
+ *cap |= PCI_FLIT_ERR_CNTR_CTRL_EN;
+ else
+ *cap &= ~PCI_FLIT_ERR_CNTR_CTRL_EN;
+}
+
+void pci_restore_flit_state(struct pci_dev *pdev)
+{
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ if (!pdev->flit_cap)
+ return;
+
+ save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_FLIT);
+ if (!save_state)
+ return;
+
+ cap = (u16 *)&save_state->cap.data[0];
+ pci_write_config_word(pdev, pdev->flit_cap + PCI_FLIT_ERR_CNTR_CTRL, *cap);
+}
+
+/*
+ * Serializes the Counter Control read-modify-write against flit_isr(), which
+ * runs in hard irq context on the vector this port shares with PME, hotplug
+ * and bandwidth notification. A lost update here leaves Trigger Event on Error
+ * Count at zero, and per PCIe r6.4, sec 7.7.8.4, table 7-95, a zero trigger
+ * never generates an event.
+ */
+static void flit_cntr_ctrl_update(struct pci_dev *pdev, u16 clear, u16 set)
+{
+ unsigned long flags;
+ u16 ctrl;
+
+ spin_lock_irqsave(&pdev->flit_info->lock, flags);
+ pci_read_config_word(pdev, pdev->flit_cap + PCI_FLIT_ERR_CNTR_CTRL, &ctrl);
+ ctrl &= ~clear;
+ ctrl |= set;
+ pci_write_config_word(pdev, pdev->flit_cap + PCI_FLIT_ERR_CNTR_CTRL, ctrl);
+ spin_unlock_irqrestore(&pdev->flit_info->lock, flags);
+}
+
+static void flit_cntr_enable(struct pci_dev *pdev)
+{
+ u16 flit = pdev->flit_cap;
+ unsigned long flags;
+ u16 reg;
+
+ pci_read_config_word(pdev, flit + PCI_FLIT_ERR_CNTR_STA, ®);
+ pci_write_config_word(pdev, flit + PCI_FLIT_ERR_CNTR_STA, reg);
+
+ pdev->flit_info->cntr_enabled = true;
+
+ spin_lock_irqsave(&pdev->flit_info->lock, flags);
+ pci_read_config_word(pdev, flit + PCI_FLIT_ERR_CNTR_CTRL, ®);
+
+ /* Set default trigger count if not set by platform, since zero never fires */
+ if (!(reg & PCI_FLIT_ERR_CNTR_CTRL_TRIGGER))
+ reg |= FIELD_PREP(PCI_FLIT_ERR_CNTR_CTRL_TRIGGER, FLIT_DEFAULT_TRIGGER);
+
+ reg |= PCI_FLIT_ERR_CNTR_CTRL_EN | PCI_FLIT_ERR_CNTR_CTRL_INTR_EN;
+ pci_write_config_word(pdev, flit + PCI_FLIT_ERR_CNTR_CTRL, reg);
+ spin_unlock_irqrestore(&pdev->flit_info->lock, flags);
+}
+
+static void flit_cntr_disable(struct pci_dev *pdev)
+{
+ pdev->flit_info->cntr_enabled = false;
+ flit_cntr_ctrl_update(pdev, PCI_FLIT_ERR_CNTR_CTRL_EN | PCI_FLIT_ERR_CNTR_CTRL_INTR_EN, 0);
+}
+
+static void flit_report(struct pci_dev *pdev, u32 err_log1, u32 err_log2)
+{
+ /* Software should silently discard a Reserved entry */
+ if (!(err_log1 & FLIT_ERR_LOG1_ERROR) && !err_log2)
+ return;
+
+ pci_warn(pdev, "ErrLog1: 0x%08x ErrLog2: 0x%08x\n", err_log1, err_log2);
+}
+
+static irqreturn_t flit_ist(int irq, void *context)
+{
+ struct pcie_device *dev = (struct pcie_device *)context;
+ struct pci_dev *pdev = dev->port;
+ u16 flit = pdev->flit_cap;
+ u32 err_log1, err_log2;
+ unsigned int i;
+
+ for (i = 0; i < FLIT_MAX_LOG_ENTRIES; i++) {
+ pci_read_config_dword(pdev, flit + PCI_FLIT_ERR_LOG1, &err_log1);
+
+ if (PCI_POSSIBLE_ERROR(err_log1) || !(err_log1 & PCI_FLIT_ERR_LOG1_VALID))
+ break;
+
+ pci_read_config_dword(pdev, flit + PCI_FLIT_ERR_LOG2, &err_log2);
+
+ flit_report(pdev, err_log1, err_log2);
+
+ pci_write_config_dword(pdev, flit + PCI_FLIT_ERR_LOG1, err_log1);
+
+ if (!(err_log1 & PCI_FLIT_ERR_LOG1_MORE))
+ break;
+ }
+
+ /*
+ * Re-enable the counter. Per PCIe r6.4, sec 7.7.8.5, table 7-96, the
+ * status bit is "Cleared on 0b to 1b transition of Flit Error Counter
+ * Enable", which also clears the counter and re-arms interrupt
+ * generation.
+ */
+ flit_cntr_ctrl_update(pdev, 0, PCI_FLIT_ERR_CNTR_CTRL_EN);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t flit_isr(int irq, void *context)
+{
+ struct pcie_device *dev = (struct pcie_device *)context;
+ struct pci_dev *pdev = dev->port;
+ u16 flit = pdev->flit_cap;
+ u16 cntr_sta;
+
+ pci_read_config_word(pdev, flit + PCI_FLIT_ERR_CNTR_STA, &cntr_sta);
+ if (PCI_POSSIBLE_ERROR(cntr_sta) || !(cntr_sta & PCI_FLIT_ERR_CNTR_STA_INTR_GEN))
+ return IRQ_NONE;
+
+ /*
+ * Clear Flit Error Counter Enable first, so the counter cannot reach
+ * the trigger again while the thread runs, then clear the status bit.
+ * A message-signaled vector needs no more than that, but this service
+ * can land on INTx, where the line stays asserted until the status is
+ * cleared. flit_ist() transitions Counter Enable back 0->1.
+ */
+ flit_cntr_ctrl_update(pdev, PCI_FLIT_ERR_CNTR_CTRL_EN, 0);
+ pci_write_config_word(pdev, flit + PCI_FLIT_ERR_CNTR_STA,
+ PCI_FLIT_ERR_CNTR_STA_INTR_GEN);
+ return IRQ_WAKE_THREAD;
+}
+
+static int flit_probe(struct pcie_device *dev)
+{
+ struct pci_dev *pdev = dev->port;
+ int status;
+
+ /*
+ * Not devm_request_threaded_irq(): devres would free the IRQ only
+ * after .remove() runs, too late to stop flit_ist() re-enabling the
+ * counter.
+ */
+ status = request_threaded_irq(dev->irq, flit_isr, flit_ist,
+ IRQF_SHARED, "pcie-flit", dev);
+ if (status) {
+ pci_warn(pdev, "request Flit IRQ %d failed: %d\n", dev->irq, status);
+ return status;
+ }
+
+ flit_cntr_enable(pdev);
+ pci_info(pdev, "enabled with IRQ %d\n", dev->irq);
+
+ return 0;
+}
+
+/*
+ * No .suspend or .runtime_suspend counterpart. pci_save_state() runs after
+ * both, so disabling the counter there would put a transient value in the
+ * save buffer, and pcie_portdrv_slot_reset() restores that buffer after
+ * calling .slot_reset.
+ */
+static int flit_cntr_restore(struct pcie_device *dev)
+{
+ flit_cntr_enable(dev->port);
+ return 0;
+}
+
+static void flit_cntr_remove(struct pcie_device *dev)
+{
+ /* Drop the IRQ first: free_irq() waits for the threaded handler. */
+ free_irq(dev->irq, dev);
+ flit_cntr_disable(dev->port);
+}
+
+static struct pcie_port_service_driver flitdriver = {
+ .name = "flit",
+ .port_type = PCIE_ANY_PORT,
+ .service = PCIE_PORT_SERVICE_FLIT,
+ .probe = flit_probe,
+ .resume = flit_cntr_restore,
+ .runtime_resume = flit_cntr_restore,
+ .slot_reset = flit_cntr_restore,
+ .remove = flit_cntr_remove,
+};
+
+int __init pcie_flit_init(void)
+{
+ return pcie_port_service_register(&flitdriver);
+}
diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c
index ca1b9dbb8b08..6328233c75d7 100644
--- a/drivers/pci/pcie/portdrv.c
+++ b/drivers/pci/pcie/portdrv.c
@@ -278,6 +278,12 @@ static int get_port_device_capability(struct pci_dev *dev)
services |= PCIE_PORT_SERVICE_BWCTRL;
}
+#ifdef CONFIG_PCIE_FLIT
+ /* flit_cap is set only when the capability is OS-managed */
+ if (dev->flit_cap)
+ services |= PCIE_PORT_SERVICE_FLIT;
+#endif
+
return services;
}
@@ -834,6 +840,7 @@ static void __init pcie_init_services(void)
pcie_dpc_init();
pcie_bwctrl_init();
pcie_hp_init();
+ pcie_flit_init();
}
static int __init pcie_portdrv_init(void)
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index bf18ca415990..975f83134a5b 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -22,13 +22,16 @@
#define PCIE_PORT_SERVICE_DPC (1 << PCIE_PORT_SERVICE_DPC_SHIFT)
#define PCIE_PORT_SERVICE_BWCTRL_SHIFT 4 /* Bandwidth Controller (notifications) */
#define PCIE_PORT_SERVICE_BWCTRL (1 << PCIE_PORT_SERVICE_BWCTRL_SHIFT)
+#define PCIE_PORT_SERVICE_FLIT_SHIFT 5 /* Flit Logging */
+#define PCIE_PORT_SERVICE_FLIT (1 << PCIE_PORT_SERVICE_FLIT_SHIFT)
/* Services sharing the PCI Express Capability Interrupt Message Number */
#define PCIE_PORT_SERVICES_EXPCAP (PCIE_PORT_SERVICE_PME | \
PCIE_PORT_SERVICE_HP | \
- PCIE_PORT_SERVICE_BWCTRL)
+ PCIE_PORT_SERVICE_BWCTRL | \
+ PCIE_PORT_SERVICE_FLIT)
-#define PCIE_PORT_DEVICE_MAXSERVICES 5
+#define PCIE_PORT_DEVICE_MAXSERVICES 6
extern bool pcie_ports_dpc_native;
@@ -56,6 +59,12 @@ int pcie_dpc_init(void);
static inline int pcie_dpc_init(void) { return 0; }
#endif
+#ifdef CONFIG_PCIE_FLIT
+int pcie_flit_init(void);
+#else
+static inline int pcie_flit_init(void) { return 0; }
+#endif
+
int pcie_bwctrl_init(void);
/* Port Type */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 27008e2ea5af..6bf62bdadc8d 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -674,6 +674,7 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge)
bridge->native_pme = 1;
bridge->native_ltr = 1;
bridge->native_dpc = 1;
+ bridge->native_flit = 1;
bridge->domain_nr = PCI_DOMAIN_NR_NOT_SET;
bridge->native_cxl_error = 1;
bridge->dev.type = &pci_host_bridge_type;
@@ -2465,6 +2466,7 @@ static void pci_configure_device(struct pci_dev *dev)
static void pci_release_capabilities(struct pci_dev *dev)
{
+ pci_flit_exit(dev);
pci_aer_exit(dev);
pci_rcec_exit(dev);
pci_iov_release(dev);
@@ -2666,6 +2668,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_pasid_init(dev); /* Process Address Space ID */
pci_acs_init(dev); /* Access Control Services */
pci_ptm_init(dev); /* Precision Time Measurement */
+ pci_flit_init(dev); /* Flit Logging */
pci_aer_init(dev); /* Advanced Error Reporting */
pci_dpc_init(dev); /* Downstream Port Containment */
pci_rcec_init(dev); /* Root Complex Event Collector */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index ddacac812094..b3d8a5bb79e9 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -667,6 +667,7 @@ extern u32 osc_sb_native_usb4_control;
#define OSC_PCI_EXPRESS_CAPABILITY_CONTROL 0x00000010
#define OSC_PCI_EXPRESS_LTR_CONTROL 0x00000020
#define OSC_PCI_EXPRESS_DPC_CONTROL 0x00000080
+#define OSC_PCI_EXPRESS_FLIT_CONTROL 0x00000800
/* CXL _OSC: Capabilities DWORD 4: Support Field */
#define OSC_CXL_1_1_PORT_REG_ACCESS_SUPPORT 0x00000001
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8650c627bebb..37d01fab50bb 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -598,6 +598,11 @@ struct pci_dev {
u8 tph_mode; /* TPH mode */
u8 tph_req_type; /* TPH requester type */
#endif
+
+#ifdef CONFIG_PCIE_FLIT
+ u16 flit_cap; /* Flit Logging Capability offset */
+ struct flit_info *flit_info; /* Flit Logging state */
+#endif
};
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
@@ -663,6 +668,7 @@ struct pci_host_bridge {
unsigned int native_pme:1; /* OS may use PCIe PME */
unsigned int native_ltr:1; /* OS may use PCIe LTR */
unsigned int native_dpc:1; /* OS may use PCIe DPC */
+ unsigned int native_flit:1; /* OS may use PCIe Flit logging */
unsigned int native_cxl_error:1; /* OS may use CXL RAS/Events */
unsigned int preserve_config:1; /* Preserve FW resource setup */
unsigned int size_windows:1; /* Enable root bus sizing */
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index facaa324bd86..73482024359b 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -763,7 +763,8 @@
#define PCI_EXT_CAP_ID_DEV3 0x2F /* Device 3 Capability/Control/Status */
#define PCI_EXT_CAP_ID_IDE 0x30 /* Integrity and Data Encryption */
#define PCI_EXT_CAP_ID_PL_64GT 0x31 /* Physical Layer 64.0 GT/s */
-#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_64GT
+#define PCI_EXT_CAP_ID_FLIT 0x32 /* Flit Logging */
+#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_FLIT
#define PCI_EXT_CAP_DSN_SIZEOF 12
#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
@@ -1187,6 +1188,22 @@
/* Physical Layer 64.0 GT/s */
#define PCI_PL_64GT_LE_CTRL 0x20 /* Lane Equalization Control Register */
+/* Flit Logging Extended Capability */
+#define PCI_FLIT_ERR_LOG1 0x04 /* Flit Error Log 1 Register */
+#define PCI_FLIT_ERR_LOG1_VALID 0x00000001 /* Flit Error Log Valid */
+#define PCI_FLIT_ERR_LOG1_MORE 0x00002000 /* More Entries Valid */
+#define PCI_FLIT_ERR_LOG1_UNRECOG 0x00004000 /* Unrecognized Flit */
+#define PCI_FLIT_ERR_LOG1_FEC_UNCOR 0x00008000 /* FEC Uncorrectable Error in Flit */
+#define PCI_FLIT_ERR_LOG1_SYND_PARITY0 0x00ff0000 /* Syndrome Parity for ECC Group 0 */
+#define PCI_FLIT_ERR_LOG1_SYND_CHECK0 0xff000000 /* Syndrome Check for ECC Group 0 */
+#define PCI_FLIT_ERR_LOG2 0x08 /* Flit Error Log 2 Register */
+#define PCI_FLIT_ERR_CNTR_CTRL 0x0c /* Flit Error Counter Control Register */
+#define PCI_FLIT_ERR_CNTR_CTRL_EN 0x0001 /* Flit Error Counter Enable */
+#define PCI_FLIT_ERR_CNTR_CTRL_INTR_EN 0x0002 /* Flit Error Counter Interrupt Enable */
+#define PCI_FLIT_ERR_CNTR_CTRL_TRIGGER 0x0ff0 /* Trigger Event on Error Count */
+#define PCI_FLIT_ERR_CNTR_STA 0x0e /* Flit Error Counter Status Register */
+#define PCI_FLIT_ERR_CNTR_STA_INTR_GEN 0x0008 /* Interrupt Generated based on Trigger */
+
/* Native PCIe Enclosure Management */
#define PCI_NPEM_CAP 0x04 /* NPEM capability register */
#define PCI_NPEM_CAP_CAPABLE 0x00000001 /* NPEM Capable */
--
2.43.0