From: Terry Bowman <terry.bowman@amd.com>
To: Bjorn Helgaas <bhelgaas@google.com>,
Dan Williams <djbw@kernel.org>,
"Dave Jiang" <dave.jiang@intel.com>,
Ira Weiny <iweiny@kernel.org>,
Jonathan Cameron <jic23@kernel.org>, Len Brown <lenb@kernel.org>,
"Rafael J . Wysocki" <rafael@kernel.org>,
Robert Richter <rrichter@amd.com>
Cc: <linux-acpi@vger.kernel.org>, <linux-cxl@vger.kernel.org>,
<linux-doc@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<linux-pci@vger.kernel.org>, <linuxppc-dev@lists.ozlabs.org>,
"Alejandro Lucero" <alucerop@amd.com>,
Alison Schofield <alison.schofield@intel.com>,
Ankit Agrawal <ankita@nvidia.com>,
Ard Biesheuvel <ardb@kernel.org>,
"Ben Cheatham" <Benjamin.Cheatham@amd.com>,
Borislav Petkov <bp@alien8.de>,
"Breno Leitao" <leitao@debian.org>,
Davidlohr Bueso <dave@stgolabs.net>,
"Fabio M . De Francesco" <fabio.m.de.francesco@linux.intel.com>,
Gregory Price <gourry@gourry.net>,
Hanjun Guo <guohanjun@huawei.com>,
Jonathan Corbet <corbet@lwn.net>, Kees Cook <kees@kernel.org>,
Kuppuswamy Sathyanarayanan
<sathyanarayanan.kuppuswamy@linux.intel.com>,
Li Ming <ming.li@zohomail.com>,
Mahesh J Salgaonkar <mahesh@linux.ibm.com>,
Mauro Carvalho Chehab <mchehab@kernel.org>,
Oliver O'Halloran <oohall@gmail.com>,
Shiju Jose <shiju.jose@huawei.com>,
Shuah Khan <skhan@linuxfoundation.org>,
Shuai Xue <xueshuai@linux.alibaba.com>,
Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com>,
Terry Bowman <terry.bowman@amd.com>,
Tony Luck <tony.luck@intel.com>,
Vishal Verma <vishal.l.verma@intel.com>
Subject: [PATCH v18 06/13] PCI: Establish common CXL Port protocol error flow
Date: Fri, 17 Jul 2026 17:26:59 -0500 [thread overview]
Message-ID: <20260717222706.3540281-7-terry.bowman@amd.com> (raw)
In-Reply-To: <20260717222706.3540281-1-terry.bowman@amd.com>
Add CXL protocol error dispatch in handle_error_source() using
is_cxl_error() and cxl_forward_error() to route errors through the
AER-CXL kfifo. Expand is_cxl_error() from Endpoint-only to include
Root Port, Upstream Port, and Downstream Port device types. The
producer and consumer go live in the same commit to avoid silently
dropping CXL errors during bisect.
For uncorrectable events, call cxl_proto_err_flush() to ensure CXL RAS
registers are read, panic policy is applied, and CXL state is cleared
before pci_aer_handle_error() drives PCIe recovery. Without the flush,
AER recovery can tear down drivers and unmap the CXL RAS iomaps while
the kfifo consumer is still reading them. Correctable events do not
need the flush and run asynchronously. RCH kfifo support is added in
the following patch ("PCI/CXL: Add RCH support to CXL handlers").
Add cxl_handle_proto_error() to dispatch correctable and uncorrectable
errors through the CXL RAS helpers. Add cxl_do_recovery() to coordinate
uncorrectable recovery. Panic when a UCE is confirmed by a successful
CXL RAS status register read. If the RAS registers cannot be read the
UCE cannot be confirmed and panic is not triggered. Gate error handling
on the port driver being bound to avoid processing errors on disabled
devices.
The kfifo consumer holds guard(device)(&port->dev) and checks
port->dev.driver before accessing RAS registers, serializing against
driver unbind and devm iomap teardown. For UCE, cxl_proto_err_flush()
runs the worker synchronously before AER recovery, ensuring the device
is present during RAS register access.
Add to_ras_base() to centralize RAS base lookup: dport->regs.ras for
Root/Downstream Ports, port->regs.ras for Upstream Ports and Endpoints.
Use to_ras_base() to access the CXL devices' RAS registers as it will
provide an avenue to inject status simulation during testing.
Add CXL RAS logging in cxl_handle_cor_ras() and cxl_handle_ras(). The
existing cxl_cor_error_detected() and cxl_error_detected() AER
callbacks remain for all Endpoints and are reworked to use
find_cxl_port_by_uport() and to_ras_base(), with UCE now triggering
panic unconditionally. These callbacks are further updated in the
following patch ("PCI/CXL: Add RCH support to CXL handlers").
Fix a pre-existing race for cxlds between cxl_handle_rdport_errors() and
cxl_memdev_shutdown() by holding a cxlmd device scoped_guard() around
the rdport call. Release the lock before taking the Port lock to avoid
the lock inversion.
Co-developed-by: Dan Williams <djbw@kernel.org>
Signed-off-by: Dan Williams <djbw@kernel.org>
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
Changes in v17->v18:
- Fix pre-existing race: hold memdev device lock around
cxl_handle_rdport_errors(), release before port lock
- Fix handle_error_source() to call pci_aer_handle_error() unconditionally
so AER handling always runs after cxl_forward_error()
- Add cxl_proto_err_flush() call for CXL UCE to drain kfifo before AER
recovery tears down the device
- Fix NULL dereference of dport->dport_dev in cxl_handle_cor_ras() and
cxl_handle_ras() for UPSTREAM/ENDPOINT port types: use dport->dport_dev
when dport is non-NULL, else fall back to port->uport_dev
- Remove duplicate pcie_clear_device_status() call from
cxl_handle_proto_error() CE path; pci_aer_handle_error() already clears it
- Clarify panic policy: panic only on confirmed UCE via RAS status read
- Document kfifo consumer serialization against driver unbind via
guard(device)(&port->dev) and port->dev.driver check
Changes in v16->v17:
- get_cxl_port() -> find_cxl_port_by_dev()
- Simplified find_cxl_port_by_dev()
- Replace and remove cxl_serial_number() w/ pci_get_dsn()
- cxl_get_ras_base() -> to_ras_base()
- Drop dependency on PCI_ERS_RESULT_PANIC; cxl_do_recovery() panics
directly. (PANIC enum patch dropped from series.)
- Clarify panic semantics: panic on any uncorrectable CXL RAS error, not
only AER-FATAL severities.
- Add is_cxl_error() switch in handle_error_source() here, paired with the
kfifo consumer registration, to keep each commit bisect-safe.
- Drop pcie_aer_is_native() guard in cxl_do_recovery() (always native).
- Swap order with the "Limit" patch for bisectability w/ cxl_ras_exit()
- Reword for "any uncorrectable" CXL RAS error panics.
- Restore log messages for port-not-found and port-unbound cases.
- Whitespace cleanup (Jonathan)
- Update to get_cxl_port() documentation (Terry)
- Fix __cxl_proto_err_work_fn() to return 0 for transient errors.
- Drop !port check in cxl_do_recovery(), caller already validated
- Fix kerneldoc @pdev -> @dev in find_cxl_port_by_dev()
- Fix missing space in pr_err_ratelimited()
- Made pcie_clear_device_status() and pci_aer_clear_fatal_status()
EXPORT_SYMBOL_FOR_MODULES("cxl_core") (Dan)
- Move find_cxl_port_by_dport() and find_cxl_port_by_uport()
de-staticisation and core.h declarations from the rename patch to
here, where the first cross-file callers in find_cxl_port_by_dev()
land.
Changes in v15->v16:
- get_ras_base(), initialize dport to NULL (Jonathan)
- Remove guard(device)(&cxlmd->dev) (Jonathan)
- Fix dev_warns() (Jonathan)
- Remove comment in cxl_port_error_detected() (Dan)
- Update switch-case brackets to follow clang-format (Dan)
- Add PCI_EXP_TYPE_RC_END for cxl_get_ras_base() (Terry)
- Add NULL port check in cxl_serial_number() (Terry)
Changes in v14->v15:
- Update commit message and title. Added Bjorn's ack.
- Move CE and UCE handling logic here
Changes in v13->v14:
- Add Dave Jiang's review-by
- Update commit message & headline (Bjorn)
- Refactor cxl_port_error_detected()/cxl_port_cor_error_detected() to
one line (Jonathan)
- Remove cxl_walk_port() (Dan)
- Remove cxl_pci_drv_bound(). Check for 'is_cxl' parent port is
sufficient (Dan)
- Remove device_lock_if()
- Combined CE and UCE here (Terry)
Changes in v12->v13:
- Move get_pci_cxl_host_dev() and cxl_handle_proto_error() to Dequeue
patch (Terry)
- Remove EP case in cxl_get_ras_base(), not used. (Terry)
- Remove check for dport->dport_dev (Dave)
- Remove whitespace (Terry)
Changes in v11->v12:
- Add call to cxl_pci_drv_bound() in cxl_handle_proto_error() and
pci_to_cxl_dev()
- Change cxl_error_detected() -> cxl_cor_error_detected()
- Remove NULL variable assignments
- Replace bus_find_device() with find_cxl_port_by_uport() for upstream
port searches.
Changes in v10->v11:
- None
---
drivers/cxl/core/core.h | 7 ++
drivers/cxl/core/port.c | 6 +-
drivers/cxl/core/ras.c | 223 +++++++++++++++++++++++++++-------
drivers/pci/pci.h | 1 -
drivers/pci/pcie/aer.c | 13 ++
drivers/pci/pcie/aer_cxl_vh.c | 16 ++-
6 files changed, 220 insertions(+), 46 deletions(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 23fe40ddf4c6b..7c70bea06c2db 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -186,6 +186,8 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)
void cxl_ras_init(void);
void cxl_ras_exit(void);
bool cxl_handle_ras(struct device *dev, void __iomem *ras_base);
+void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port,
+ struct cxl_dport *dport);
void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base);
void cxl_dport_map_rch_aer(struct cxl_dport *dport);
void cxl_disable_rch_root_ints(struct cxl_dport *dport);
@@ -198,6 +200,8 @@ static inline bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
{
return false;
}
+static inline void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port,
+ struct cxl_dport *dport) { }
static inline void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base) { }
static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
@@ -206,6 +210,9 @@ static inline void devm_cxl_dport_ras_setup(struct cxl_dport *dport) { }
#endif /* CONFIG_CXL_RAS */
int cxl_gpf_port_setup(struct cxl_dport *dport);
+struct cxl_port *find_cxl_port_by_dport(struct device *dport_dev,
+ struct cxl_dport **dport);
+struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev);
struct cxl_hdm;
int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index cadb51f70f854..a76f3ee05cba8 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1400,8 +1400,8 @@ static struct cxl_port *__find_cxl_port_by_dport(struct cxl_find_port_ctx *ctx)
* Return a 'struct cxl_port' with an elevated reference if found. Use
* __free(put_cxl_port) to release.
*/
-static struct cxl_port *find_cxl_port_by_dport(struct device *dport_dev,
- struct cxl_dport **dport)
+struct cxl_port *find_cxl_port_by_dport(struct device *dport_dev,
+ struct cxl_dport **dport)
{
struct cxl_find_port_ctx ctx = {
.dport_dev = dport_dev,
@@ -1596,7 +1596,7 @@ static int match_port_by_uport(struct device *dev, const void *data)
* Function takes a device reference on the port device. Caller should do a
* put_device() when done.
*/
-static struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
+struct cxl_port *find_cxl_port_by_uport(struct device *uport_dev)
{
struct device *dev;
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 135f1997e6f4f..b190e69c2d415 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -77,6 +77,36 @@ static int match_memdev_by_parent(struct device *dev, const void *uport)
return 0;
}
+
+/**
+ * find_cxl_port_by_dev - Use @dev as hint to do a _by_dport or _by_uport lookup
+ * @dev: generic device that may either be a companion of port or target dport
+ * @dport: output parameter; set to the matched dport for dport-class
+ * lookups (Root Port, Downstream Port), NULL otherwise.
+ *
+ * Return a 'struct cxl_port' with an elevated reference if found. Use
+ * __free(put_cxl_port) to release.
+ */
+static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dport **dport)
+{
+ if (dport)
+ *dport = NULL;
+ if (!dev_is_pci(dev))
+ return NULL;
+
+ switch (pci_pcie_type(to_pci_dev(dev))) {
+ case PCI_EXP_TYPE_ROOT_PORT:
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ return find_cxl_port_by_dport(dev, dport);
+ case PCI_EXP_TYPE_UPSTREAM:
+ case PCI_EXP_TYPE_ENDPOINT:
+ case PCI_EXP_TYPE_RC_END:
+ return find_cxl_port_by_uport(dev);
+ }
+
+ return NULL;
+}
+
void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
{
unsigned int devfn = PCI_DEVFN(data->prot_err.agent_addr.device,
@@ -132,16 +162,6 @@ static void cxl_cper_prot_err_work_fn(struct work_struct *work)
}
static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
-void cxl_ras_init(void)
-{
- cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
-}
-
-void cxl_ras_exit(void)
-{
- cxl_cper_unregister_prot_err_work();
-}
-
static void cxl_dport_map_ras(struct cxl_dport *dport)
{
struct cxl_register_map *map = &dport->reg_map;
@@ -198,10 +218,39 @@ void devm_cxl_port_ras_setup(struct cxl_port *port)
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_port_ras_setup, "CXL");
+static void __iomem *to_ras_base(struct cxl_port *port, struct cxl_dport *dport)
+{
+ if (!port)
+ return NULL;
+
+ if (dport)
+ return dport->regs.ras;
+
+ return port->regs.ras;
+}
+
+void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dport *dport)
+{
+ struct device *dev = dport ? dport->dport_dev : port->uport_dev;
+ void __iomem *ras_base = to_ras_base(port, dport);
+
+ if (!ras_base) {
+ dev_err(&pdev->dev,
+ "CXL UCE signaled but RAS registers not mapped\n");
+ return;
+ }
+
+ if (cxl_handle_ras(dev, ras_base))
+ panic("CXL cachemem error");
+
+ dev_dbg(&pdev->dev,
+ "CXL UCE signaled but no CXL RAS status bits set\n");
+}
+
void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base)
{
- void __iomem *addr;
u32 status;
+ void __iomem *addr;
if (!ras_base)
return;
@@ -210,7 +259,10 @@ void cxl_handle_cor_ras(struct device *dev, void __iomem *ras_base)
status = readl(addr);
if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
- trace_cxl_aer_correctable_error(to_cxl_memdev(dev), status);
+ if (is_cxl_memdev(dev))
+ trace_cxl_aer_correctable_error(to_cxl_memdev(dev), status);
+ else
+ trace_cxl_port_aer_correctable_error(dev, status);
}
}
@@ -262,7 +314,11 @@ bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
}
header_log_copy(ras_base, hl);
- trace_cxl_aer_uncorrectable_error(to_cxl_memdev(dev), status, fe, hl);
+ if (is_cxl_memdev(dev))
+ trace_cxl_aer_uncorrectable_error(to_cxl_memdev(dev), status, fe, hl);
+ else
+ trace_cxl_port_aer_uncorrectable_error(dev, status, fe, hl);
+
writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
return true;
@@ -270,22 +326,32 @@ bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)
void cxl_cor_error_detected(struct pci_dev *pdev)
{
- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct cxl_memdev *cxlmd = cxlds->cxlmd;
- struct device *dev = &cxlds->cxlmd->dev;
+ guard(device)(&pdev->dev);
+ if (!pdev->dev.driver)
+ return;
+
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
+ if (!port)
+ return;
+
+ if (is_cxl_restricted(pdev)) {
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
- scoped_guard(device, dev) {
- if (!dev->driver) {
+ scoped_guard(device, &cxlmd->dev) {
+ cxl_handle_rdport_errors(cxlds);
+ }
+ }
+
+ scoped_guard(device, &port->dev) {
+ if (!port->dev.driver) {
dev_warn(&pdev->dev,
- "%s: memdev disabled, abort error handling\n",
- dev_name(dev));
+ "%s: port disabled, abort error handling\n",
+ dev_name(&port->dev));
return;
}
- if (cxlds->rcd)
- cxl_handle_rdport_errors(cxlds);
-
- cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlmd->endpoint->regs.ras);
+ cxl_handle_cor_ras(port->uport_dev, to_ras_base(port, NULL));
}
}
EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
@@ -293,42 +359,53 @@ EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
- struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
- struct cxl_memdev *cxlmd = cxlds->cxlmd;
- struct device *dev = &cxlmd->dev;
- bool ue;
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);
+ bool ue = false;
- scoped_guard(device, dev) {
- if (!dev->driver) {
+ if (!port)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ if (is_cxl_restricted(pdev)) {
+ struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+ struct cxl_memdev *cxlmd = cxlds->cxlmd;
+
+ scoped_guard(device, &cxlmd->dev) {
+ cxl_handle_rdport_errors(cxlds);
+ }
+ }
+
+ scoped_guard(device, &port->dev) {
+ if (!port->dev.driver) {
dev_warn(&pdev->dev,
- "%s: memdev disabled, abort error handling\n",
- dev_name(dev));
+ "%s: port disabled, abort error handling\n",
+ dev_name(&port->dev));
return PCI_ERS_RESULT_DISCONNECT;
}
- if (cxlds->rcd)
- cxl_handle_rdport_errors(cxlds);
/*
* A frozen channel indicates an impending reset which is fatal to
* CXL.mem operation, and will likely crash the system. On the off
* chance the situation is recoverable dump the status of the RAS
* capability registers and bounce the active state of the memdev.
*/
- ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlmd->endpoint->regs.ras);
+ ue = cxl_handle_ras(port->uport_dev, to_ras_base(port, NULL));
}
+ /*
+ * CXL.mem UCE means cache coherency is lost. Continuing risks
+ * silent data corruption across interleaved HDM regions.
+ */
+ if (ue)
+ panic("CXL cachemem error");
+
switch (state) {
case pci_channel_io_normal:
- if (ue) {
- device_release_driver(dev);
- return PCI_ERS_RESULT_NEED_RESET;
- }
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_frozen:
dev_warn(&pdev->dev,
"%s: frozen state error detected, disable CXL.mem\n",
- dev_name(dev));
- device_release_driver(dev);
+ dev_name(port->uport_dev));
+ device_release_driver(port->uport_dev);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
dev_warn(&pdev->dev,
@@ -338,3 +415,67 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
return PCI_ERS_RESULT_NEED_RESET;
}
EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
+
+static void cxl_handle_proto_error(struct pci_dev *pdev, struct cxl_port *port,
+ struct cxl_dport *dport, int severity)
+{
+ struct device *dev = dport ? dport->dport_dev : port->uport_dev;
+
+ if (severity == AER_CORRECTABLE)
+ cxl_handle_cor_ras(dev, to_ras_base(port, dport));
+ else
+ cxl_do_recovery(pdev, port, dport);
+}
+
+static void __cxl_proto_err_work_fn(struct cxl_proto_err_work_data *wd)
+{
+ struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_dev(&wd->pdev->dev, NULL);
+ if (!port) {
+ dev_err_ratelimited(&wd->pdev->dev,
+ "Failed to find parent port device in CXL topology\n");
+ return;
+ }
+ guard(device)(&port->dev);
+ if (!port->dev.driver) {
+ dev_err_ratelimited(&port->dev,
+ "Port device is unbound, abort error handling\n");
+ return;
+ }
+
+ struct cxl_dport *dport = cxl_find_dport_by_dev(port, &wd->pdev->dev);
+ if (!dport && (pci_pcie_type(wd->pdev) == PCI_EXP_TYPE_ROOT_PORT ||
+ pci_pcie_type(wd->pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
+ dev_err_ratelimited(&wd->pdev->dev,
+ "Failed to find dport device in CXL topology\n");
+ return;
+ }
+
+ cxl_handle_proto_error(wd->pdev, port, dport, wd->severity);
+}
+
+static void cxl_proto_err_work_fn(struct work_struct *work)
+{
+ struct cxl_proto_err_work_data wd;
+
+ for_each_cxl_proto_err(&wd, __cxl_proto_err_work_fn);
+}
+
+static DECLARE_WORK(cxl_proto_err_work, cxl_proto_err_work_fn);
+
+static void cxl_proto_err_do_flush(void)
+{
+ flush_work(&cxl_proto_err_work);
+}
+
+void cxl_ras_init(void)
+{
+ cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
+ cxl_register_proto_err_work(&cxl_proto_err_work,
+ cxl_proto_err_do_flush);
+}
+
+void cxl_ras_exit(void)
+{
+ cxl_unregister_proto_err_work();
+ cxl_cper_unregister_prot_err_work();
+}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4469e1a77f3c1..a83e2aef75912 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1296,7 +1296,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
static inline void pci_no_aer(void) { }
static inline void pci_aer_init(struct pci_dev *d) { }
static inline void pci_aer_exit(struct pci_dev *d) { }
-static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
static inline void pci_save_aer_state(struct pci_dev *dev) { }
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index c5bce25df51cb..2d9d40528e709 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1185,7 +1185,20 @@ static void pci_aer_handle_error(struct pci_dev *dev, struct aer_err_info *info)
static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
{
+ bool cxl_pending = false;
+
cxl_rch_handle_error(dev, info);
+
+ if (is_cxl_error(dev, info))
+ cxl_pending |= cxl_forward_error(dev, info);
+
+ /*
+ * Wait for UCE CXL work to complete before AER recovery
+ * tears down the device. CE can run asynchronously.
+ */
+ if (cxl_pending && info->severity != AER_CORRECTABLE)
+ cxl_proto_err_flush();
+
pci_aer_handle_error(dev, info);
pci_dev_put(dev);
}
diff --git a/drivers/pci/pcie/aer_cxl_vh.c b/drivers/pci/pcie/aer_cxl_vh.c
index 93bed07936100..ecf47bba0c9d4 100644
--- a/drivers/pci/pcie/aer_cxl_vh.c
+++ b/drivers/pci/pcie/aer_cxl_vh.c
@@ -49,8 +49,22 @@ bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
if (!info || !info->is_cxl)
return false;
- if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT)
+ /*
+ * RC_END (Restricted CXL Device) is not included here because RC_END
+ * reports errors on behalf of upstream RCH Downstream Port and thus
+ * requires a unique discovery detailed in CXL4.0 spec (12.2.1.1).
+ * The RCH device error discovery and RC_END forwarding flow begins
+ * in cxl_rch_handle_error().
+ */
+ switch (pci_pcie_type(pdev)) {
+ case PCI_EXP_TYPE_ENDPOINT:
+ case PCI_EXP_TYPE_ROOT_PORT:
+ case PCI_EXP_TYPE_UPSTREAM:
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ break;
+ default:
return false;
+ }
return is_aer_internal_error(info);
}
--
2.34.1
next prev parent reply other threads:[~2026-07-17 22:28 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-17 22:26 [PATCH v18 00/13] Enable CXL PCIe Port Protocol Error handling and logging Terry Bowman
2026-07-17 22:26 ` [PATCH v18 01/13] cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register Terry Bowman
2026-07-17 22:43 ` sashiko-bot
2026-07-17 22:26 ` [PATCH v18 02/13] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks Terry Bowman
2026-07-17 22:49 ` sashiko-bot
2026-07-17 22:26 ` [PATCH v18 03/13] cxl: Tighten CPER kfifo registration API and symbol visibility Terry Bowman
2026-07-17 22:37 ` sashiko-bot
2026-07-17 22:26 ` [PATCH v18 04/13] cxl: Rename find_cxl_port() to find_cxl_port_by_dport() Terry Bowman
2026-07-17 22:34 ` sashiko-bot
2026-07-17 22:26 ` [PATCH v18 05/13] PCI/AER: Introduce AER-CXL protocol error kfifo Terry Bowman
2026-07-17 22:35 ` sashiko-bot
2026-07-17 22:26 ` Terry Bowman [this message]
2026-07-17 22:43 ` [PATCH v18 06/13] PCI: Establish common CXL Port protocol error flow sashiko-bot
2026-07-17 22:27 ` [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers Terry Bowman
2026-07-17 22:43 ` sashiko-bot
2026-07-17 22:27 ` [PATCH v18 08/13] cxl/pci: Thread port and dport through RAS handling helpers Terry Bowman
2026-07-17 22:40 ` sashiko-bot
2026-07-17 22:27 ` [PATCH v18 09/13] cxl: Update CXL Endpoint AER handler Terry Bowman
2026-07-17 22:53 ` sashiko-bot
2026-07-17 22:27 ` [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events Terry Bowman
2026-07-17 22:53 ` sashiko-bot
2026-07-17 22:27 ` [PATCH v18 11/13] PCI: Cache PCI DSN into pci_dev->dsn during probe Terry Bowman
2026-07-17 22:44 ` sashiko-bot
2026-07-17 22:27 ` [PATCH v18 12/13] PCI/CXL: Mask/Unmask CXL protocol errors Terry Bowman
2026-07-17 22:58 ` sashiko-bot
2026-07-17 22:27 ` [PATCH v18 13/13] Documentation: cxl: Document CXL protocol error handling Terry Bowman
2026-07-17 22:43 ` 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=20260717222706.3540281-7-terry.bowman@amd.com \
--to=terry.bowman@amd.com \
--cc=Benjamin.Cheatham@amd.com \
--cc=Smita.KoralahalliChannabasappa@amd.com \
--cc=alison.schofield@intel.com \
--cc=alucerop@amd.com \
--cc=ankita@nvidia.com \
--cc=ardb@kernel.org \
--cc=bhelgaas@google.com \
--cc=bp@alien8.de \
--cc=corbet@lwn.net \
--cc=dave.jiang@intel.com \
--cc=dave@stgolabs.net \
--cc=djbw@kernel.org \
--cc=fabio.m.de.francesco@linux.intel.com \
--cc=gourry@gourry.net \
--cc=guohanjun@huawei.com \
--cc=iweiny@kernel.org \
--cc=jic23@kernel.org \
--cc=kees@kernel.org \
--cc=leitao@debian.org \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=mahesh@linux.ibm.com \
--cc=mchehab@kernel.org \
--cc=ming.li@zohomail.com \
--cc=oohall@gmail.com \
--cc=rafael@kernel.org \
--cc=rrichter@amd.com \
--cc=sathyanarayanan.kuppuswamy@linux.intel.com \
--cc=shiju.jose@huawei.com \
--cc=skhan@linuxfoundation.org \
--cc=tony.luck@intel.com \
--cc=vishal.l.verma@intel.com \
--cc=xueshuai@linux.alibaba.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.