mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: Yazen Ghannam <yazen.ghannam@amd.com>
Cc: linux-pci@vger.kernel.org, LKML <linux-kernel@vger.kernel.org>,
	 linux-acpi@vger.kernel.org, linux-edac@vger.kernel.org,
	 bhelgaas@google.com
Subject: Re: [PATCH v2 07/10] PCI/FLIT: Add support for Flit Logging Extended Capability
Date: Fri, 18 Sep 2026 19:38:16 +0300 (EEST)	[thread overview]
Message-ID: <3d907699-9f79-0740-2b84-7990f1e9eac1@linux.intel.com> (raw)
In-Reply-To: <20260918145619.3016889-8-yazen.ghannam@amd.com>

[-- Attachment #1: Type: text/plain, Size: 23907 bytes --]

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@amd.com>
> Assisted-by: LLM
> Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
> ---
>  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@amd.com>
> + *		Yazen Ghannam <Yazen.Ghannam@amd.com>
> + */
> +
> +#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, &reg);
> +	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, &reg);
> +
> +	/* 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 */
> 

  reply	other threads:[~2026-09-18 16:38 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-18 14:56 [PATCH v2 00/10] PCIe Flit Logging Ext Capability Support Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 01/10] MAINTAINERS: Add the AER sysfs ABI file to PCI SUBSYSTEM Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 02/10] PCI/AER: Clamp negative ratelimit burst to zero Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 03/10] PCI/AER: Report the ratelimit interval in milliseconds Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 04/10] PCI/AER: Hide the "aer" sysfs directory when AER is unavailable Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 05/10] PCI: Share the AER ratelimit sysfs accessors Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 06/10] PCI/portdrv: Group PCI Exp Cap services into a single mask Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 07/10] PCI/FLIT: Add support for Flit Logging Extended Capability Yazen Ghannam
2026-09-18 16:38   ` Ilpo Järvinen [this message]
2026-09-18 14:56 ` [PATCH v2 08/10] PCI/FLIT: Add trace event for flit errors Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 09/10] PCI/FLIT: Ratelimit flit error logging Yazen Ghannam
2026-09-18 14:56 ` [PATCH v2 10/10] PCI/FLIT: Expose the error counter controls through sysfs Yazen Ghannam

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=3d907699-9f79-0740-2b84-7990f1e9eac1@linux.intel.com \
    --to=ilpo.jarvinen@linux.intel.com \
    --cc=bhelgaas@google.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-edac@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=yazen.ghannam@amd.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 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®