Re: [PATCH v2 07/10] PCI/FLIT: Add support for Flit Logging Extended Capability
From: Ilpo Järvinen
Date: Fri Sep 18 2026 - 12:49:44 EST
On Fri, 18 Sep 2026, Yazen Ghannam wrote:
> 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
But you lack the actual include for printing??
> +#include <linux/bitfield.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
Add empty line.
> +#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 */
> +};
Move before functions.
> +
> +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);
I suggest adding the generic clear+set accessor into access.c, there's
already one for dword but not for config word.
> + 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);
Success path should be silent.
--
i.
> +
> + 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 */
>