Enable CXL PCIe Port Protocol Error handling and logging
Subsystems (6)
v18 cover Enable CXL PCIe Port Protocol Error handling and logging
This patch series enables CXL protocol error handling for both CXL Ports and CXL Endpoints (EP). The previous revision is available at:
https://lore.kernel.org/linux-cxl/[email protected]/
Today the kernel handles native CXL.cachemem RAS only for Endpoints and Restricted CXL Host (RCH) Downstream Ports. Root Ports, Upstream Switch Ports, and Downstream Switch Ports are uncovered. This series introduces a unified CXL protocol error path for all CXL device types, in both VH and RCH topologies.
CXL protocol errors are layered as a distinct error plane on top of PCIe AER. CXL RAS conditions are signaled as PCIe correctable (CE) and uncorrectable (UCE) Internal AER Errors. The AER driver classifies these events using pcie_is_cxl() and hands them off to cxl_core through the AER-CXL kfifo.
The cxl_core driver dequeues each event, resolves the cxl_port topology, and dispatches to the CE or UCE handler. RCD Endpoints are handled slightly differently: the RCH Downstream Port's RAS state is processed first, then the Endpoint's own RAS follows the common path.
PCIe AER errors remain a separate plane and are handled independently. This series updates the CXL Endpoint AER UCE handler and removes the Endpoint AER CE handler, which is now redundant since the AER driver clears and logs CE status itself.
PCI_ERS_RESULT_PANIC, introduced in earlier revisions, has been dropped. The panic decision is made directly in cxl_do_recovery(): the kernel panics on any uncorrectable CXL RAS error reported by cxl_handle_ras(), or earlier on link disconnect.
A fatal UCE on an Upstream Switch Port or Endpoint surfaces through the AER path rather than the CXL RAS path. USP devices are bound to the PCIe portdrv driver, so when a USP reports a fatal UCE, the PCIe error handler provided by portdrv is invoked. PCI config reads to the source device are expected to fail in this scenario, so the AER core never retrieves UNCOR_STATUS, and the event cannot be classified as CXL. See the fatal and non-fatal log excerpts for USP and EP below.
== Patch Details ==
Patch 1 - cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register Fix RCH Downstream Port severity classification. Was using PCI_ERR_ROOT_FATAL_RCV (a Root Error Status bit) instead of uncor_severity to classify fatal vs non-fatal.
Patch 2 - acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks Convert cxl_cper_work_lock and cxl_cper_prot_err_work_lock from spinlock_t to raw_spinlock_t to avoid sleeping-in-hardirq deadlock on PREEMPT_RT kernels.
Patch 3 - cxl: Tighten CPER kfifo registration API and symbol visibility Replace EXPORT_SYMBOL_NS_GPL() with EXPORT_SYMBOL_FOR_MODULES() for CPER kfifo helpers. Simplify register/unregister return types to void.
Patch 4 - cxl: Rename find_cxl_port() to find_cxl_port_by_dport() Renames find_cxl_port() to find_cxl_port_by_dport() to make the lookup method explicit and consistent with the existing find_cxl_port_by_uport().
Patch 5 - PCI/AER: Introduce AER-CXL protocol error kfifo Adds the AER-CXL kfifo in drivers/pci/pcie/aer_cxl_vh.c along with the producer helper cxl_forward_error() and the consumer registration helpers cxl_register_proto_err_work() and cxl_unregister_proto_err_work(). The kfifo delivers CXL VH protocol errors from the AER driver to cxl_core.
Patch 6 - PCI: Establish common CXL Port protocol error flow Dequeues work from the AER-CXL kfifo and establishes a common flow for all CXL Port protocol error handling. Panics on any uncorrectable CXL RAS error. The producer dispatch and consumer go live atomically.
Patch 7 - PCI/CXL: Add RCH support to CXL handlers
Folds Restricted CXL Host (RCH) error handling into the common Port flow. An RCD uncorrectable CXL RAS error now panics, matching the policy applied to all other CXL devices.
Patch 8 - cxl/pci: Thread port and dport through RAS handling helpers Refactors cxl_handle_ras() and cxl_handle_cor_ras() to accept struct cxl_port * and struct cxl_dport * directly, eliminating redundant bus walks on the error path.
Patch 9 - cxl: Update CXL Endpoint AER handler
Replaces cxl_error_detected() with cxl_pci_error_detected(). Reads CXL RAS unconditionally; panics on UCE regardless of channel state.
Patch 10 - cxl: Add port and dport identifiers to CXL AER trace events Passes struct cxl_port * and struct cxl_dport * to trace events. Adds new "port" and "dport" string fields for all CXL device classes.
Patch 11 - PCI: Cache PCI DSN into pci_dev->dsn during probe Caches the PCI Device Serial Number at probe time so error handlers and panic paths avoid live config-space reads.
Patch 12 - PCI/CXL: Mask/Unmask CXL protocol errors
Enables CXL Internal Error reporting on CXL Ports and Endpoints. The unmask is paired with RAS register block mapping; the mask is registered as a devres action.
Patch 13 - Documentation: cxl: Document CXL protocol error handling Adds protocol-error-handling.rst describing the end-to-end CXL protocol error path.
== Notes ==
- @Bjorn, I kindly request your review for the following patches. Many of the changes are to CXL-specific files in the PCI tree:
Patch 5 - PCI/AER: Introduce AER-CXL protocol error kfifo
Patch 6 - PCI: Establish common CXL Port protocol error flow
Patch 7 - PCI/CXL: Add RCH support to CXL handlers Patch 11 - PCI: Cache PCI DSN into pci_dev->dsn during probe Patch 12 - PCI/CXL: Mask/Unmask CXL protocol errors
- USP/EP fatal UCE follows the AER path because of how the AER core collects status. aer_get_device_error_info() only reads PCI_ERR_UNCOR_STATUS for Root Ports/RCECs/Downstream Ports or non-fatal severities, where config reads to the source are still expected to succeed. For a fatal UCE signaled by an upstream component, config reads to that device are expected to fail, so UNCOR_STATUS is never retrieved. Without the status word, is_cxl_error() cannot classify the event as CXL and the AER path handles it.
- Dan's related series addressing RAS setup has more details:
https://lore.kernel.org/linux-cxl/[email protected]/
- TODOs for future series:
- Move aer_cxl_rch.c to cxl/core/ras_rch.c
- Move RCH traversing for handling from AER driver into CXL driver
- Support user-defined status masks
- Add CXL Port traversing in cxl_do_recovery()
== Testing ==
Testing included the following:
- cxl-test
- RCH/RCD AER error injection
- CPER GHES (firmware first)
- VH AER error injection
** The AER error injection is not included in this series but will be posted as an RFC for review and for others to use. The error injection using AER will be posted separately as ("cxl: Device protocol AER injection").
Below are the testing results.
=== cxl_test ===
The cxl_test CXL testsuite passed on QEMU with no issues.
This required changes in patch 12 ("PCI/CXL: Mask/Unmask CXL protocol errors"). __wrap_devm_cxl_dport_rch_ras_setup() is introduced to prevent cxl_test from trying to map the RCH AER/RAS registers.
=== CPER Tests ===
CPER/firmware first error injection was run and passed on real HW using AMD RAS tool for protocol error injection at the CXL Root Port.
==== Restricted CXL Host (RCH) ====
Error injection tests for RCH devices were run using CXL2.0 Endpoint that enumerate as a RCiEP.
echo "0000:7f:00.0 CE 00000000 00000002 RCH" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:40:00.3: aer_inject: Injecting errors 00004000/00000000 into device 0000:40:00.3 pcieport 0000:40:00.3: AER: Correctable error message received from 0000:40:00.3
pcieport 0000:40:00.3: PCIe Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:40:00.3: device [1022:14a6] error status/mask=00004000/00002000
pcieport 0000:40:00.3: [14] CorrIntErrcxl_aer_correctable_error: memdev= port=root0 dport=pci0000:7f host=ACPI0017:00 serial=0: status: 'Memory Data ECC Error'
echo "0000:7f:00.0 UCE 00000000 00000002 RCH" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:40:00.3: aer_inject: Injecting errors 00000000/00400000 into device 0000:40:00.3
pcieport 0000:40:00.3: AER: Uncorrectable (Non-Fatal) error message received from 0000:40:00.3
pcieport 0000:40:00.3: PCIe Bus Error: severity=Uncorrectable (Non-Fatal), type=Transaction Layer, (Receiver ID)
pcieport 0000:40:00.3: device [1022:14a6] error status/mask=00400000/00000000
pcieport 0000:40:00.3: [22] UncorrIntErrcxl_aer_uncorrectable_error: memdev= port=root0 dport=pci0000:7f host=ACPI0017:00 serial=0: status: 'Cache Address Parity Error' first_error: 'Cache Address Parity Error'
Kernel panic - not syncing: CXL cachemem error CPU: 26 UID: 0 PID: 396 Comm: kworker/26:1 Kdump: loaded Not tainted 7.2.0-rc3-tb-00014-g6346be30306a #1363 PREEMPT(lazy) Hardware name: AMD Corporation ONYX/ONYX, BIOS TOX100HB 12/03/2025 Workqueue: events cxl_proto_err_work_fn [cxl_core] Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_do_recovery+0x66/0x70 [cxl_core] cxl_handle_rdport_errors+0x176/0x190 [cxl_core] ? srso_alias_return_thunk+0x5/0xfbef5 ? update_load_avg+0x5c/0x2b0 ? srso_alias_return_thunk+0x5/0xfbef5 ? dequeue_entities+0x160/0xb40 ? srso_alias_return_thunk+0x5/0xfbef5 ? pick_task_fair+0x164/0x670 ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] __cxl_proto_err_work_fn+0xea/0x1b0 [cxl_core] ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] for_each_cxl_proto_err+0x5a/0x80 cxl_proto_err_work_fn+0x26/0x50 [cxl_core] process_one_work+0x16e/0x3a0 worker_thread+0x172/0x2e0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK>
==== Restricted CXL Device (RCD) ====
Error injection tests for RCD devices were run using CXL2.0 Endpoint that enumerate as a RCiEP.
echo "0000:7f:00.0 CE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:40:00.3: aer_inject: Injecting errors 00004000/00000000 into device 0000:40:00.3 pcieport 0000:40:00.3: AER: Correctable error message received from 0000:40:00.3
pcieport 0000:40:00.3: PCIe Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:40:00.3: device [1022:14a6] error status/mask=00004000/00002000
pcieport 0000:40:00.3: [14] CorrIntErrcxl_aer_correctable_error: memdev=mem0 port=endpoint1 dport= host=0000:7f:00.0 serial=0: status: 'Memory Data ECC Error'
echo "0000:7f:00.0 UCE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:40:00.3: aer_inject: Injecting errors 00000000/00400000 into device 0000:40:00.3
pcieport 0000:40:00.3: AER: Uncorrectable (Non-Fatal) error message received from 0000:40:00.3
pcieport 0000:40:00.3: PCIe Bus Error: severity=Uncorrectable (Non-Fatal), type=Transaction Layer, (Receiver ID)
pcieport 0000:40:00.3: device [1022:14a6] error status/mask=00400000/00000000
pcieport 0000:40:00.3: [22] UncorrIntErrcxl_aer_uncorrectable_error: memdev=mem0 port=endpoint1 dport= host=0000:7f:00.0 serial=0: status: 'Cache Address Parity Error' first_error: 'Cache Address Parity Error'
Kernel panic - not syncing: CXL cachemem error CPU: 26 UID: 0 PID: 394 Comm: kworker/26:1 Kdump: loaded Not tainted 7.2.0-rc3-tb-00014-g6346be30306a #1363 PREEMPT(lazy) Hardware name: AMD Corporation ONYX/ONYX, BIOS TOX100HB 12/03/2025 Workqueue: events cxl_proto_err_work_fn [cxl_core] Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_do_recovery+0x66/0x70 [cxl_core] __cxl_proto_err_work_fn+0xa0/0x1b0 [cxl_core] ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] for_each_cxl_proto_err+0x5a/0x80 cxl_proto_err_work_fn+0x26/0x50 [cxl_core] process_one_work+0x16e/0x3a0 worker_thread+0x172/0x2e0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK>
=== Virtual Hierarchy ===
Below are the VH error injection test results using QEMU with CXL AER error injection via /sys/kernel/debug/cxl/aer_einj_inject on kernel 7.2.0-rc3 based kernel.
The below QEMU testing uses a CXL Root Port, a CXL Upstream Switch Port, a CXL Downstream Switch Port, and a CXL Type3 Endpoint as given below.
The sub-topology for the QEMU testing is:
---------------------
| CXL RP - 0C:00.0 |
---------------------
|
---------------------
| CXL USP - 0D:00.0 |
---------------------
|
--------------------
| CXL DSP - 0E:00.0 |
--------------------
|
---------------------
| CXL EP - 0F:00.0 |
---------------------Error Injection Test Results Summary:
| # | Device Type | BDF | Test | Result | AER | RAS | Verdict | |---|------------------|---------|------|-----------|-----|-----|------------------| | 1 | Root Port | 0c:00.0 | CE | Recovered | OK | OK | PASS | | 2 | Root Port | 0c:00.0 | UCE | Panic | OK | OK | PASS | | 3 | Upstream Port | 0d:00.0 | CE | Recovered | OK | OK | PASS | | 4 | Upstream Port | 0d:00.0 | UCE | Recovered | OK | -- | PASS (Known Lim) | | 5 | Downstream Port | 0e:00.0 | CE | Recovered | OK | OK | PASS | | 6 | Downstream Port | 0e:00.0 | UCE | Panic | OK | OK | PASS | | 7 | Endpoint | 0f:00.0 | CE | Recovered | OK | OK | PASS | | 8 | Endpoint | 0f:00.0 | UCE | Panic | OK | OK | PASS |
Overall: 8/8 PASS
=== Root Port - CE ===
echo "0000:0c:00.0 CE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:0c:00.0: aer_inject: Injecting errors 00004000/00000000 into device 0000:0c:00.0 pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0c:00.0
pcieport 0000:0c:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:0c:00.0: device [8086:7075] error status/mask=00004000/0000a000
pcieport 0000:0c:00.0: [14] CorrIntErrcxl_aer_correctable_error: memdev= port=port1 dport=0000:0c:00.0 host=pci0000:0c serial=0: status: 'Memory Data ECC Error'
=== Root Port - UCE ===
echo "0000:0c:00.0 UCE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:0c:00.0: aer_inject: Injecting errors 00000000/00400000 into device 0000:0c:00.0
pcieport 0000:0c:00.0: AER: Uncorrectable (Fatal) error message received from 0000:0c:00.0
pcieport 0000:0c:00.0: CXL Bus Error: severity=Uncorrectable (Fatal), type=Transaction Layer, (Receiver ID)
pcieport 0000:0c:00.0: device [8086:7075] error status/mask=00400000/02000000
pcieport 0000:0c:00.0: [22] UncorrIntErrcxl_aer_uncorrectable_error: memdev= port=port1 dport=0000:0c:00.0 host=pci0000:0c serial=0: status: 'Cache Address Parity Error' first_error: 'Cache Address Parity Error'
Kernel panic - not syncing: CXL cachemem error CPU: 58 UID: 0 PID: 409 Comm: kworker/58:1 Not tainted 7.2.0-rc3-tb-00014-g23418142f421 #1291 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 Workqueue: events cxl_proto_err_work_fn [cxl_core] Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_do_recovery+0x66/0x70 [cxl_core] __cxl_proto_err_work_fn+0x9e/0x1b0 [cxl_core] ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] for_each_cxl_proto_err+0x5a/0x80 cxl_proto_err_work_fn+0x26/0x50 [cxl_core] process_one_work+0x16e/0x3a0 worker_thread+0x172/0x2e0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Kernel Offset: disabled ---[ end Kernel panic - not syncing: CXL cachemem error ]---
=== Upstream Switch Port - CE ===
echo "0000:0d:00.0 CE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:0c:00.0: aer_inject: Injecting errors 00004000/00000000 into device 0000:0d:00.0 pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0d:00.0
pcieport 0000:0d:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:0d:00.0: device [19e5:a128] error status/mask=00004000/0000a000
pcieport 0000:0d:00.0: [14] CorrIntErrcxl_aer_correctable_error: memdev= port=port2 dport= host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'
=== Upstream Switch Port - UCE (fatal - AER recovery, known limitation) ===
echo "0000:0d:00.0 UCE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:0c:00.0: aer_inject: Injecting errors 00000000/00400000 into device 0000:0d:00.0 pcieport 0000:0c:00.0: AER: Uncorrectable (Fatal) error message received from 0000:0d:00.0 pcieport 0000:0d:00.0: AER: CXL Bus Error: severity=Uncorrectable (Fatal), type=Inaccessible, (Unregistered Agent ID) cxl_pci 0000:0f:00.0: mem0: frozen state error detected, disable CXL.mem
pcieport 0000:0c:00.0: AER: Root Port link has been reset (0)cxl_pci 0000:0f:00.0: mem0: restart CXL.mem after slot resetcxl_pci 0000:0f:00.0: mem0: error resume successful
pcieport 0000:0c:00.0: AER: device recovery successful
=== Downstream Port - CE ===
echo "0000:0e:00.0 CE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:0c:00.0: aer_inject: Injecting errors 00004000/00000000 into device 0000:0e:00.0
pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0e:00.0
pcieport 0000:0e:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:0e:00.0: device [19e5:a129] error status/mask=00004000/0000a000
pcieport 0000:0e:00.0: [14] CorrIntErrcxl_aer_correctable_error: memdev= port=port2 dport=0000:0e:00.0 host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'
=== Downstream Port - UCE ===
echo "0000:0e:00.0 UCE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:0c:00.0: aer_inject: Injecting errors 00000000/00400000 into device 0000:0e:00.0
pcieport 0000:0c:00.0: AER: Uncorrectable (Fatal) error message received from 0000:0e:00.0
pcieport 0000:0e:00.0: CXL Bus Error: severity=Uncorrectable (Fatal), type=Transaction Layer, (Receiver ID)
pcieport 0000:0e:00.0: device [19e5:a129] error status/mask=00400000/02000000
pcieport 0000:0e:00.0: [22] UncorrIntErrcxl_aer_uncorrectable_error: memdev= port=port2 dport=0000:0e:00.0 host=0000:0d:00.0 serial=0: status: 'Cache Address Parity Error' first_error: 'Cache Address Parity Error'
Kernel panic - not syncing: CXL cachemem error CPU: 7 UID: 0 PID: 299 Comm: kworker/7:1 Not tainted 7.2.0-rc3-tb-00014-g832c50e87f10 #1364 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 Workqueue: events cxl_proto_err_work_fn [cxl_core] Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_do_recovery+0x66/0x70 [cxl_core] __cxl_proto_err_work_fn+0xa0/0x1b0 [cxl_core] ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] for_each_cxl_proto_err+0x5a/0x80 cxl_proto_err_work_fn+0x26/0x50 [cxl_core] process_one_work+0x16e/0x3a0 worker_thread+0x172/0x2e0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Kernel Offset: disabled ---[ end Kernel panic - not syncing: CXL cachemem error ]---
=== Endpoint - CE ===
echo "0000:0f:00.0 CE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:0c:00.0: aer_inject: Injecting errors 00004000/00000000 into device 0000:0f:00.0 pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0f:00.0cxl_pci 0000:0f:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)cxl_pci 0000:0f:00.0: device [8086:0d93] error status/mask=00004000/0000a000cxl_pci 0000:0f:00.0: [14] CorrIntErrcxl_aer_correctable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 serial=0: status: 'Memory Data ECC Error'
=== Endpoint - UCE ===
echo "0000:0f:00.0 UCE 00000000 00000002" > /sys/kernel/debug/cxl/aer_einj_inject
pcieport 0000:0c:00.0: aer_inject: Injecting errors 00000000/00400000 into device 0000:0f:00.0
pcieport 0000:0c:00.0: AER: Uncorrectable (Fatal) error message received from 0000:0f:00.0cxl_pci 0000:0f:00.0: AER: CXL Bus Error: severity=Uncorrectable (Fatal), type=Inaccessible, (Unregistered Agent ID) cxl_aer_uncorrectable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 serial=0: status: 'Cache Address Parity Error' first_error: 'Cache Address Parity Error'
Kernel panic - not syncing: CXL cachemem error CPU: 58 UID: 0 PID: 430 Comm: irq/24-aerdrv Not tainted 7.2.0-rc3-tb-00014-g23418142f421 #1291 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_pci_error_detected+0x15c/0x160 [cxl_core] report_error_detected+0xc7/0x1c0 ? __pfx_report_frozen_detected+0x10/0x10 __pci_walk_bus+0x47/0x70 ? __pfx_report_frozen_detected+0x10/0x10 pci_walk_bus+0x2c/0x40 ? __pfx_aer_root_reset+0x10/0x10 pcie_do_recovery+0x234/0x330 ? __pfx_irq_thread_fn+0x10/0x10 aer_isr_one_error_type+0x333/0x340 aer_isr_one_error+0x112/0x140 aer_isr+0x47/0x80 irq_thread_fn+0x1f/0x60 irq_thread+0x123/0x220 ? __pfx_irq_thread_dtor+0x10/0x10 ? __pfx_irq_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Kernel Offset: disabled ---[ end Kernel panic - not syncing: CXL cachemem error ]---
== Changes ==
Changes in v17->v18:
acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
- New commit
- Convert cxl_cper_work_lock and cxl_cper_prot_err_work_lock from spinlock_t to raw_spinlock_t; use guard(raw_spinlock_irqsave) at
all call sites to avoid sleeping-in-hardirq on PREEMPT_RT.
- Add kfifo_reset(&cxl_cper_fifo) to cxl_cper_unregister_work()
- Add WARN_ONCE to cxl_cper_register_work() for double-registration consistency
- Fix cxl_cper_unregister_work() to clear global pointer before cancel_work_sync()
- Remove redundant cancel_work_sync() from cxl_ras_exit()
cxl: Tighten CPER kfifo registration API and symbol visibility
- New commit (split/rework of v17 "Limit CXL-CPER kfifo registration functions scope")
cxl: Rename find_cxl_port() to find_cxl_port_by_dport()
- None
PCI/AER: Introduce AER-CXL protocol error kfifo
- Remove correctable status clear from cxl_forward_error(); the AER core clears all status bits via pci_aer_handle_error() info->status writeback
- Schedule consumer on kfifo overflow so existing entries can be drained
PCI: Establish common CXL Port protocol error flow
- 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
PCI/CXL: Add RCH support to CXL handlers
- Pass &pdev->dev instead of dport->port->uport_dev in cxl_handle_rdport_errors() to avoid dropping RCH trace events.
- Document trace event attribution change.
- Document removal of cxl_cor_error_detected() and cxlds->rcd branches.
- Capitalize Endpoint per PCI spec convention.
- Use to_ras_base() in cxl_handle_rdport_errors() to centralize RAS base address lookup in preparation for error injection testing.
cxl/pci: Thread port and dport through RAS handling helpers
- New commit
cxl: Update CXL Endpoint AER handler
- Fix cxl_pci_error_detected() to use find_cxl_port_by_uport() and port->uport_dev
- Read CXL RAS unconditionally; panic on UCE regardless of channel state
- Document unconditional read policy and 0xFFFFFFFF behavior in comment
cxl: Add port and dport identifiers to CXL AER trace events
- Consolidate double find_cxl_port_by_dev() in cxl_cper_handle_prot_err()
- Add comment noting dport is NULL for endpoint and upstream port devices
PCI: Cache PCI DSN into pci_dev->dsn during probe
- New commit
PCI/CXL: Mask/Unmask CXL protocol errors
- Make cxl_unmask_proto_interrupts() and cxl_mask_proto_interrupts() static
- Remove dev_is_pci() guard from devm_cxl_dport_rch_ras_setup(); the guard blocked real RCH hardware because pci_host_bridge is not on pci_bus_type
Documentation: cxl: Document CXL protocol error handling
- Simplify document for readability (Jonathan)
- Drop historical context that goes stale (Jonathan)
- Shorten ASCII flow diagram (Jonathan)
- Drop manual backtick markup, use automarkup (Jonathan)
- Clarify USP/DSP as single switch component (Dave)
- Fix line wrapping to 80 chars (Jonathan)
Changes in v16->v17:
PCI/AER: Introduce AER-CXL Kfifo
- Reword "kfifo semaphore" to "kfifo spinlock" to match fifo_lock.
- Defer the handle_error_source() is_cxl_error() switch to the patch that registers the kfifo consumer to keep each commit bisect-safe.
- Rename rwsema to rwsem
- Change CPER exports to use EXPORT_SYMBOL_FOR_MODULES.
- Add work cancel function.
- Replace kfifo_put() with kfifo_in_spinlocked() for multiple producers
- Add fifo_lock spinlock for concurrent producer serialisation
- Initialize the embedded kfifo with INIT_KFIFO() in a subsys_initcall so kfifo->mask, ->esize and ->data are set before first use.
- Clear PCI_ERR_COR_STATUS in cxl_forward_error() before enqueue so the device is acked for correctable events even when the consumer drops the event. Uncorrectable status is left for cxl_do_recovery() to clear after recovery completes, mirroring the AER core convention.
- WARN on double-registration in cxl_register_proto_err_work() to make an unintended second consumer visible at runtime.
- Add direct rwsem.h, cleanup.h and workqueue.h includes for symbols used in aer_cxl_vh.c
- Add MAINTAINERS entries for drivers/pci/pcie/aer_cxl_*.c
- Update message
cxl/ras: Unify Endpoint and Port AER trace events
- Replace cxlds->serial with pci_get_dsn()
- Change 'memdev' to 'device' (Dan)
- Updated Commit message
cxl: Use common CPER handling for all CXL devices
- New commit
cxl: Rename find_cxl_port() to find_cxl_port_by_dport()
- New commit
- Drop the de-staticisation of find_cxl_port_by_uport() and the core.h declarations from this prep patch; both move to the patch that introduces the first cross-file caller.
cxl: Limit CXL-CPER kfifo registration functions scope
- Split from v16 02/10 ("Update unregistration for AER-CXL and CPER-CXL kfifos"); AER-CXL half folded into v17 01/10.
- Convert exports to EXPORT_SYMBOL_FOR_MODULES("cxl_core").
- Change register/unregister return type from int to void.
- Drop work_struct argument from cxl_cper_unregister_prot_err_work(); it now cancels its own work.
- Remove now-redundant cancel_work_sync() from cxl_ras_exit().
- Add WARN_ONCE() in cxl_cper_register_prot_err_work() for double-registration.
PCI: Establish common CXL Port protocol error flow
- 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.
- Drop the redundant PCI_ERR_COR_STATUS RMW in cxl_handle_proto_error(); cxl_forward_error() already acks the correctable AER status.
- 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()
- Add disconnect check before access
- 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.
PCI/CXL: Add RCH support to CXL handlers
- Drop now-dead cxlds->rcd branches from cxl_{cor_,}error_detected().
- Drop duplicate subject line from commit body.
- Document panic-on-uncorrectable behavior change for RCD path.
- Document trace event device-name change (memN -> PCI BDF) for RCH path.
- Rewrite cxl_handle_proto_error() RC_END comment to clarify RCD/RCH shared interrupt relationship
- Rewrite commit message
cxl: Remove Endpoint AER correctable handler
- Update commit message
- Add Reviewed-by from Jonathan and DaveJ
cxl: Update Endpoint AER uncorrectable handler
- Rename pci_error_handlers struct instance to cxl_pci_error_handlers to avoid shadowing the struct type tag.
- Restore scoped_guard(device) and dev->driver check around AER read.
- NULL-check find_cxl_port_by_dev() before deref of port->uport_dev.
- Updated commit message. (Terry)
- Add scope cleanup for port variable in cxl_pci_error_detected() (Terry)
- Drop cxl_uncor_aer_present(), rely on AER state
PCI/CXL: Mask/Unmask CXL protocol errors
- Drop redundant cxl_mask_proto_interrupts() calls from unregister_port() and cxl_dport_remove(); the devres action registered alongside the unmask is the sole mask path.
- Update title
- Remove unnecessary check for aer_capabilities
- Gate cxl_unmask_proto_interrupts() on pcie_aer_is_native()
- Add pci_aer_mask_internal_errors() and cxl_mask_proto_interrupts()
- Only unmask on successful cxl_map_component_regs()
- NULL-check @dev in cxl_{un,}mask_proto_interrupts()
- Drop static and declare in core/core.h
Documentation: cxl: Document CXL protocol error handling
- New commit
Changes in v15->v16:
PCI/AER: Introduce AER-CXL Kfifo
- Add pci_dev_put() and comment at pci_dev_get() (Dan)
- /rw_sema/rwsema/ (Dan)
- Split validation checks in cxl_forward_error() to allow for meaningful reason in log (Terry)
- Shortened commit title to remove wordiness (Terry) PCI/CXL: Update unregistration for AER-CXL and CPER-CXL kfifos
- New commit
cxl: Update CXL Endpoint tracing
- Add Dan's review-by
- Incorporate Dan's comment into commit message:
"Add the serial number at the end to preserve compatibility with libtraceevent parsing of the parameters."
PCI/ERR: Introduce PCI_ERS_RESULT_PANIC
- None
PCI: Establish common CXL Port protocol error flow
- 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)
- Made pcie_clear_device_status() and pci_aer_clear_fatal_status() "CXL" Export namespace (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) PCI/CXL: Add RCH support to CXL handlers
- New commit
cxl: Update error handlers to support CXL Port devices
- None
cxl: Update Endpoint AER uncorrectable handler
- Update commit message (DaveJ)
- s/cxl_handle_aer()/cxl_uncor_aer_present()/g (Jonathan)
- cxl_uncor_aer_present(): Leave original result calculation based on if a UCE is present and the provided state (Terry)
- Add call to pci_print_aer(). AER fails to log because is upstream link (Terry)
cxl: Remove Endpoint AER correctable handler
- None
cxl: Enable CXL protocol error reporting
- None
Changes in v14->v15:
PCI/AER: Introduce AER-CXL Kfifo in new file, pcie/aer_cxl_vh.c
- Move pci_dev_get() call to this patch (Dave)
cxl: Update CXL Endpoint tracing
- Update commit message
- Moved cxl_handle_ras/cxl_handle_cor_ras() changes to future patch (Terry) PCI/ERR: Introduce PCI_ERS_RESULT_PANIC
- None
PCI/AER: Dequeue forwarded CXL error
- Move pci_dev_get() to cxl_forward_error() (Dave)
- Move in is_cxl_error() change from later patch (Terry)
PCI: Establish common CXL Port protocol error flow
- Update commit message and title. Added Bjorn's ack.
- Move CE and UCE handling logic here (Terry)
cxl: Update error handlers to support CXL Port protocol errors
- New commit (Terry)
cxl: Update Endpoint AER uncorrectable handler
- Title update (Terry)
- Change cxl_pci_error-detected() to handle & log AER (Terry)
- Update commit message (Terry)
- Moved cxl_handle_ras()/cxl_handle_cor_ras() to earlier patch (Terry)
cxl: Remove Endpoint AER correctable handler
- Remove cxl_pci_cor_error_detected(). Is not needed. AER is logged in the AER driver. (Dan)
- Update commit message
Changes in v13->v14:
PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
- Add Jonathan's and Dan's review-by
- Update commit title prefix (Bjorn)
- Revert format fix for cxl_sbr_masked() (Jonathan)
- Update 'Compute Express Link' comment block (Jonathan)
- Move PCI_DVSEC_CXL_FLEXBUS definitions to later patch where
used (Jonathan)
- Removed stray change (Bjorn)
PCI: Update CXL DVSEC definitions
- New patch. Split from previous patch such that there is now a separate move patch and a format fix patch.
- Formatting update requested (Bjorn)
- Remove PCI_DVSEC_HEADER1_LENGTH_MASK because it duplicates PCI_DVSEC_HEADER1_LEN() (Bjorn)
- Add Dan's review-by
PCI: Introduce pcie_is_cxl()
- Move FLEXBUS_STATUS DVSEC here (Jonathan)
- Remove check for EP and USP (Dan)
- Update commit message (Bjorn)
- Fix writing past 80 columns (Bjorn)
- Add pci_is_pcie() parent bridge check at beginning of function (Bjorn)
PCI: Replace cxl_error_is_native() with pcie_aer_is_native()
- New commit
cxl/pci: Move CXL driver's RCH error handling into core/ras_rch.c
- Add sign-off for Dan and Jonathan
- Revert inadvertent formatting of cxl_dport_map_rch_aer() (Jonathan)
- Remove default value for CXL_RCH_RAS (Dan)
- Remove unnecessary pci.h include in core.h & ras_rch.c (Jonathan)
- Add linux/types.h include in ras_rch.c (Jonathan)
- Change CONFIG_CXL_RCH_RAS -> CONFIG_CXL_RAS (Dan)
PCI/AER: Export pci_aer_unmask_internal_errors
- New commit. Bjorn requested separating out and adding immediatetly before being used. This is called from cxl_rch_enable_rcec() in following patch.
PCI/AER: Update is_internal_error() to be non-static is_aer_internal_error()
- New commit
PCI/AER: Move CXL RCH error handling to aer_cxl_rch.c
- Add review-by and signed-off for Dan
- Commit message fixup (Dan)
- Update commit message with use-case description (Dan, Lukas)
- Make cxl_error_is_native() static (Dan)
- Make is_internal_error() non-static, non-export (Terry)
PCI/AER: Use guard() in cxl_rch_handle_error_iter()
- Add review-by for Jonathan, Dave Jiang, Dan WIlliams, and Bjorn
- Remove cleanup.h (Jonathan)
- Reverted comment removal (Bjorn)
- Move this patch after pci/pcie/aer_cxl_rch.c creation (Bjorn) PCI/AER: Replace PCIEAER_CXL symbol with CXL_RAS
- New commit
PCI/AER: Report CXL or PCIe bus type in AER trace logging
- Merged with Dan's commit. Changes are moving bus_type the last parameter in function calls (Dan)
- Removed all DCOs because of changes (Terry)
- Update commit message (Bjorn)
- Add Bjorn's ack-by
PCI/AER: Update struct aer_err_info with kernel-doc formatting
- New commit
cxl/mem: Clarify @host for devm_cxl_add_nvdimm()
- New commit
cxl/port: Remove "enumerate dports" helpers
- New commit
cxl/port: Fix devm resource leaks around with dport management
- New commit
cxl/port: Move dport operations to a driver event
- New commit
cxl/port: Move dport RAS reporting to a port resource
- New commit
cxl: Map CXL Endpoint Port and CXL Switch Port RAS registers
- Correct message spelling (Terry)
cxl/port: Move endpoint component register management to cxl_port
- Correct message spelling (Terry)
cxl/port: Map Port component registers before switchport init
- Updates to use cxl_port_setup_regs() (Dan)
cxl: Change CXL handlers to use guard() instead of scoped_guard()
- Add reviewed-by for Jonathan and Dave Jiang
PCI/ERR: Introduce PCI_ERS_RESULT_PANIC
- Add review-by for Dan
- Update Title prefix (Bjorn)
- Removed merge_result. Only logging error for device reporting the error (Dan)
- Remove PCI_ERS_RESULT_PANIC paragraph in pci-error-recovery.rst (Bjorn) PCI/AER: Move AER driver's CXL VH handling to pcie/aer_cxl_vh.c
- Replaced workqueue_types.h include with 'struct work_struct' predeclaration (Bjorn)
- Update error message (Bjorn)
- Reordered 'struct cxl_proto_err_work_data' (Bjorn)
- Remove export of cxl_error_is_native() here (Bjorn)
cxl/port: Unify endpoint and switch port lookup
- New patch
PCI/AER: Dequeue forwarded CXL error
- Update commit title's prefix (Bjorn)
- Add pdev ref get in AER driver before enqueue and add pdev ref put in CXL driver after dequeue and handling (Dan)
- Removed handling to simplify patch context (Terry)
PCI: Introduce CXL Port protocol error handlers
- 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(). Only log the erroring device. No port walking. (Dan)
- Remove cxl_pci_drv_bound(). Check for 'is_cxl' parent port is sufficient (Dan)
- Remove device_lock_if()
- Combine CE and UCE here (Terry)
cxl: Update Endpoint uncorrectable protocol error handling
- Update commit headline (Bjorn)
- Rename pci_error_detected()/pci_cor_error_detected() -> cxl_pci_error_detected/cxl_pci_cor_error_detected() (Jonathan)
- Remove now-invalid comment in cxl_error_detected() (Jonathan)
- Split into separate patches for UCE and CE (Terry)
cxl: Update Endpoint correctable protocol error handling
- New commit
- Change cxl_cor_error_detected() parameter to &pdev->dev device from memdev device. (Terry)
cxl: Enable CXL protocol errors during CXL Port probe
- Update commit title's prefix (Bjorn)
Changes in v12->v13:
CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
- Add Dave Jiang's reviewed-by
- Remove changes to existing PCI_DVSEC_CXL_PORT* defines. Update commit message. (Jonathan)
PCI/CXL: Introduce pcie_is_cxl()
- Add Ben's "reviewed-by"
cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
- None
cxl/pci: Remove unnecessary CXL RCH handling helper functions
- None
cxl: Remove CXL VH handling in CONFIG_PCIEAER_CXL conditional blocks from core
- None
cxl: Move CXL driver's RCH error handling into core/ras_rch.c
- None
CXL/AER: Replace device_lock() in cxl_rch_handle_error_iter() with guard() lock
- New patch
CXL/AER: Move AER drivers RCH error handling into pcie/aer_cxl_rch.c
- Add forward declararation of 'struct aer_err_info' in pci/pci.h (Terry)
- Changed copyright date from 2025 to 2023 (Jonathan)
- Add David Jiang's, Jonathan's, and Ben's review-by
- Readd 'struct aer_err_info' (Bot)
PCI/AER: Report CXL or PCIe bus error type in trace logging
- Remove duplicated aer_err_info inline comments. Is already in the kernel-doc header (Ben)
cxl/pci: Update RAS handler interfaces to also support CXL Ports
- None
cxl/pci: Log message if RAS registers are unmapped
- Added Bens review-by
cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
- Added Dave Jiang's review-by
cxl/pci: Update cxl_handle_cor_ras() to return early if no RAS errors
- Add Ben's review-by
cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
- Change as result of dport delay fix. No longer need switchport and endport approach. Refactor. (Terry)
CXL/PCI: Introduce PCI_ERS_RESULT_PANIC
- Add Dave Jiang's, Jonathan's, Ben's review-by
- Typo fix (Ben)
CXL/AER: Introduce pcie/aer_cxl_vh.c in AER driver for forwarding CXL errors
- Add Dave Jiang's review-by
- Update error message (Ben)
cxl: Introduce cxl_pci_drv_bound() to check for bound driver
- Add Dave Jiang's review-by.
cxl: Change CXL handlers to use guard() instead of scoped_guard()
- New patch
cxl/pci: Introduce CXL protocol error handlers for endpoints
- Updated all the implemetnation and commit message. (Terry)
- Refactored cxl_cor_error_detected()/cxl_error_detected() to remove pdev (Dave Jiang)
CXL/PCI: Introduce CXL Port protocol error handlers
- 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)
PCI/AER: Dequeue forwarded CXL error
- Rewrite cxl_handle_proto_error() and cxl_proto_err_work_fn() (Terry)
- Rename get_cxl_host dev() to be get_cxl_port() (Terry)
- Remove exporting of unused function, pci_aer_clear_fatal_status() (Dave Jiang)
- Change pr_err() calls to ratelimited. (Terry)
- Update commit message. (Terry)
- Remove namespace qualifier from pcie_clear_device_status()
export (Dave Jiang)
- Move locks into cxl_proto_err_work_fn() (Dave)
- Update log messages in cxl_forward_error() (Ben)
CXL/PCI: Export and rename merge_result() to pci_ers_merge_result()
- Renamed pci_ers_merge_result() to pcie_ers_merge_result(). pci_ers_merge_result() is already used in eeh driver. (Bot)
CXL/PCI: Introduce CXL uncorrectable protocol error recovery
- Rewrite report_error_detected() and cxl_walk_port (Terry)
- Add guard() before calling cxl_pci_drv_bound() (Dave Jiang)
- Add guard() calls for EP (cxlds->cxlmd->dev & pdev->dev) and ports (pdev->dev & parent cxl_port) in cxl_report_error_detected() and cxl_handle_proto_error() (Terry)
- Remove unnecessary check for endpoint port. (Dave Jiang)
- Remove check for RCIEP EP in cxl_report_error_detected() (Terry)
CXL/PCI: Enable CXL protocol errors during CXL Port probe
- Add dev and dev_is_pci() NULL checks in cxl_unmask_proto_interrupts() (Terry)
- Add Dave Jiang's and Ben's review-by
CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
- Added dev and dev_is_pci() checks in cxl_mask_proto_interrupts() (Terry)
Changes in v11 -> v12:
cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
- Added Dave Jiang's review by
- Moved to front of series
cxl/pci: Remove unnecessary CXL RCH handling helper functions
- Add reviewed-by for Alejandro & Dave Jiang
- Moved to front of series
cxl: Remove ifdef blocks of CONFIG_PCIEAER_CXL from core/pci.c
- Update CONFIG_CXL_RAS in CXL Kconfig to have CXL_PCI dependency (Terry)
CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS
- Added review-by for Sathyanarayanan
- Changed Kconfig dependency from PCIEAER_CXL to PCIEAER. Moved
this backwards into this patch.
cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditio
- Moved CXL_RCH_RAS Kconfig definition here from following commit
CXL/AER: Introduce aer_cxl_rch.c into AER driver for handling CXL RCH errors
- Rename drivers/pci/pcie/cxl_rch.c to drivers/pci/pcie/aer_cxl_rch.c (Lukas)
- Removed forward declararation of 'struct aer_err_info' in pci/pci.h (Terry)
CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
- Change formatting to be same as existing definitions
- Change GENMASK() -> __GENMASK() and BIT() to _BITUL()
PCI/CXL: Introduce pcie_is_cxl()
- Add review-by for Alejandro
- Add comment in set_pcie_cxl() explaining why updating parent status.
PCI/AER: Report CXL or PCIe bus error type in trace logging
- Change aer_err_info::is_cxl to be bool a bitfield. Update structure padding. (Lukas)
- Add kernel-doc for 'struct aer_err_info' (Lukas)
cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
- Correct parameters to call trace_cxl_aer_correctable_error() (Shiju)
- Add reviewed-by for Jonathan and Shiju
cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
- Add check for dport_parent->rch before calling cxl_dport_init_ras_reporting().
- RCH dports are initialized from cxl_dport_init_ras_reporting cxl_mem_probe().
CXL/PCI: Introduce PCI_ERS_RESULT_PANIC
- Documentation requested by (Lukas)
CXL/AER: Introduce aer_cxl_vh.c in AER driver for forwarding CXL errors
- Rename drivers/pci/pcie/cxl_aer.c to drivers/pci/pcie/aer_cxl_vh.c (Lukas)
cxl: Introduce cxl_pci_drv_bound() to check for bound driver
- New patch
PCI/AER: Dequeue forwarded CXL error
- Add guard for CE case in cxl_handle_proto_error() (Dave)
- Updated commit message (Terry)
CXL/PCI: Introduce CXL Port protocol error handlers
- Add call to cxl_pci_drv_bound() in cxl_handle_proto_error() and
pci_to_cxl_dev() (Lukas)
- Change cxl_error_detected() -> cxl_cor_error_detected() (Terry)
- Remove NULL variable assignments (Jonathan)
- Replace bus_find_device() with find_cxl_port_by_uport() for upstream port searches. (Dave)
CXL/PCI: Export and rename merge_result() to pci_ers_merge_result()
- Remove static inline pci_ers_merge_result() definition for !CONFIG_PCIEAER. Is not needed. (Lukas)
CXL/PCI: Introduce CXL uncorrectable protocol error recovery
- Clean up port discovery in cxl_do_recovery() (Dave)
- Add PCI_EXP_TYPE_RC_END to type check in cxl_report_error_detected()
Changes in v10 -> v11:
cxl: Remove ifdef blocks of CONFIG_PCIEAER_CXL from core/pci.c
- New patch
CXL/AER: Remove CONFIG_PCIEAER_CXL and replace with CONFIG_CXL_RAS
- New patch
cxl/pci: Remove unnecessary CXL RCH handling helper functions
- New patch
cxl: Move CXL driver RCH error handling into CONFIG_CXL_RCH_RAS conditional block
- New patch
CXL/AER: Introduce rch_aer.c into AER driver for handling CXL RCH errors
- Remove changes in code-split and move to earlier, new patch
- Add #include <linux/bitfield.h> to cxl_ras.c
- Move cxl_rch_handle_error() & cxl_rch_enable_rcec() declarations from pci.h to aer.h, more localized.
- Introduce CONFIG_CXL_RCH_RAS, includes Makefile changes, ras.c ifdef changes CXL/PCI: Move CXL DVSEC definitions into uapi/linux/pci_regs.h
- New patch
PCI/CXL: Introduce pcie_is_cxl()
- Amended set_pcie_cxl() to check for Upstream Port's and EP's parent downstream port by calling set_pcie_cxl(). (Dan)
- Retitle patch: 'Add' -> 'Introduce'
- Add check for CXL.mem and CXL.cache (Alejandro, Dan)
PCI/AER: Report CXL or PCIe bus error type in trace logging
- Remove duplicate call to trace_aer_event() (Shiju)
- Added Dan William's and Dave Jiang's reviewed-by
CXL/AER: Update PCI class code check to use FIELD_GET()
- Add #include <linux/bitfield.h> to cxl_ras.c (Terry)
- Removed line wrapping at "(CXL 3.2, 8.1.12.1)". (Jonathan)
cxl/pci: Log message if RAS registers are unmapped
- Added Dave Jiang's review-by (Terry)
cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
- Updated CE and UCE trace routines to maintian consistent TP_Struct ABI and unchanged TP_printk() logging. (Shiju, Alison)
cxl/pci: Update cxl_handle_cor_ras() to return early if no RAS errors
- Added Dave Jiang and Jonathan Cameron's review-by
- Changes moved to core/ras.c
cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
- Use local pointer for readability in cxl_switch_port_init_ras() (Jonathan Cameron)
- Rename port to be ep in cxl_endpoint_port_init_ras() (Dave Jiang)
- Rename dport to be parent_dport in cxl_endpoint_port_init_ras()
and cxl_switch_port_init_ras() (Dave Jiang)
- Port helper changes were in cxl/port.c, now in core/ras.c (Dave Jiang) cxl/pci: Introduce CXL Endpoint protocol error handlers
- cxl_error_detected() - Change handlers' scoped_guard() to guard() (Jonathan)
- cxl_error_detected() - Remove extra line (Shiju)
- Changes moved to core/ras.c (Terry)
- cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
- Remove extra space in documentation for PCI_ERS_RESULT_PANIC definition
- Move #include "pci.h from cxl.h to core.h (Terry)
- Remove unnecessary includes of cxl.h and core.h in mem.c (Terry) CXL/AER: Introduce cxl_aer.c into AER driver for forwarding CXL errors
- Move RCH implementation to cxl_rch.c and RCH declarations to pci/pci.h. (Terry)
- Introduce 'struct cxl_proto_err_kfifo' containing semaphore, fifo, and work struct. (Dan)
- Remove embedded struct from cxl_proto_err_work (Dan)
- Make 'struct work_struct *cxl_proto_err_work' definition static (Jonathan)
- Add check for NULL cxl_proto_err_kfifo to determine if CXL driver is not registered for workqueue. (Dan)
PCI/AER: Dequeue forwarded CXL error
- Reword patch commit message to remove RCiEP details (Jonathan)
- Add #include <linux/bitfield.h> (Terry)
- is_cxl_rcd() - Fix short comment message wrap (Jonathan)
- is_cxl_rcd() - Combine return calls into 1 (Jonathan)
- cxl_handle_proto_error() - Move comment earlier (Jonathan)
- Usse FIELD_GET() in discovering class code (Jonathan)
- Remove BDF from cxl_proto_err_work_data. Use 'struct pci_dev *' (Dan) CXL/PCI: Introduce CXL Port protocol error handlers
- Removed check for PCI_EXP_TYPE_RC_END in cxl_report_error_detected() (Terry)
- Update is_cxl_error() to check for acceptable PCI EP and port types CXL/PCI: Export and rename merge_result() to pci_ers_merge_result()
- pci_ers_merge_result() - Change export to non-namespace and rename to be pci_ers_merge_result() (Jonathan)
- Move pci_ers_merge_result() definition to pci.h. Needs pci_ers_result (Terry) CXL/PCI: Introduce CXL uncorrectable protocol error recovery
- pci_ers_merge_results() - Move to earlier patch
CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
- Remove guard() in cxl_mask_proto_interrupts(). Observed device lockup/block during testing. (Terry)
Changes in v9 -> v10:
- Add drivers/pci/pcie/cxl_aer.c
- Add drivers/cxl/core/native_ras.c
- Change cxl_register_prot_err_work()/cxl_unregister_prot_err_work to return void
- Check for pcie_ports_native in cxl_do_recovery()
- Remove debug logging in cxl_do_recovery()
- Update PCI_ERS_RESULT_PANIC definition to indicate is CXL specific
- Revert trace logging changes: name,parent -> memdev,host.
- Use FIELD_GET() to check for EP class code (cxl_aer.c & native_ras.c).
- Change _prot_ to _proto_ everywhere
- cxl_rch_handle_error_iter(), check if driver is cxl_pci_driver
- Remove cxl_create_prot_error_info(). Move logic into forward_cxl_error()
- Remove sbdf_to_pci() and move logic into cxl_handle_proto_error()
- Simplify/refactor get_pci_cxl_host_dev()
- Simplify/refactor cxl_get_ras_base()
- Move patch 'Remove unnecessary CXL Endpoint handling helper functions' to front
- Update description for 'CXL/PCI: Introduce CXL Port protocol error handlers' with why state is not used to determine handling
- Introduce cxl_pci_drv_bound() and call from cxl_rch_handle_error_iter() Changes in v8 -> v9:
- Updated reference counting to use pci_get_device()/pci_put_device() in cxl_disable_prot_errors()/cxl_enable_prot_errors
- Refactored cxl_create_prot_err_info() to fix reference counting
- Removed 'struct cxl_port' driver changes for error handler. Instead check for CXL device type (EP or Port device) and call handler
- Make pcie_is_cxl() static inline in include/linux/linux.h
- Remove NULL check in create_prot_err_info()
- Change success return in cxl_ras_init() to use hardcoded 0
- Changed 'struct work_struct cxl_prot_err_work' declaration to static
- Change to use rate limited log with dev anchor in forward_cxl_error()
- Refactored forward-cxl_error() to remove severity auto variable
- Changed pci_aer_clear_nonfatal_status() to be static inline for !(CONFIG_PCIEAER)
- Renamed merge_result() to be cxl_merge_result()
- Removed 'ue' condition in cxl_error_detected()
- Updated 2nd parameter in call to __cxl_handle_cor_ras()/__cxl_handle_ras() in unify patch
- Added log message for failure while assigning interrupt disable callback
- Updated pci_aer_mask_internal_errors() to use pci_clear_and_set_config_dword()
- Simplified patch titles for clarity
- Moved CXL error interrupt disabling into cxl/core/port.c with CXL Port teardown
- Updated 'struct cxl_port_err_info' to only contain sbdf and severity Removed everything else.
- Added pdev and CXL device get_device()/put_device() before calling handlers
Changes in v7 -> v8:
[Dan] Use kfifo. Move handling to CXL driver. AER forwards error to CXL driver
[Dan] Add device reference incrementors where needed throughout [Dan] Initiate CXL Port RAS init from Switch Port and Endpoint Port init [Dan] Combine CXL Port and CXL Endpoint trace routine
[Dan] Introduce aer_info::is_cxl. Use to indicate CXL or PCI errors [Jonathan] Add serial number for all devices in trace [DaveJ] Move find_cxl_port() change into patch using it [Terry] Move CXL Port RAS init into cxl/port.c
[Terry] Moved kfifo functions into cxl/core/ras.c
Changes in v6 -> v7:
[Terry] Move updated trace routine call to later patch. Was causing build error.
Changes in v5 -> v6:
[Ira] Move pcie_is_cxl(dev) define to a inline function
[Ira] Update returning value from pcie_is_cxl_port() to bool w/o cast
[Ira] Change cxl_report_error_detected() cleanup to return correct bool
[Ira] Introduce and use PCI_ERS_RESULT_PANIC
[Ira] Reuse comment for PCIe and CXL recovery paths
[Jonathan] Add type check in for cxl_handle_cor_ras() and cxl_handle_ras() [Jonathan] cxl_uport/dport_init_ras_reporting(), added a mutex.
[Jonathan] Add logging example to patches updating trace output
[Jonathan] Make parameter 'const' to eliminate for cast in match_uport() [Jonathan] Use __free() in cxl_pci_port_ras()
[Terry] Add patch to log the PCIe SBDF along with CXL device name
[Terry] Add patch to handle CXL endpoint and RCH DP errors as CXL errors [Terry] Remove patch w USP UCE fatal support @ aer_get_device_error_info() [Terry] Rebase to cxl/next commit 5585e342e8d3 ("cxl/memdev: Remove unused partition values") [Gregory] Pre-initialize pointer to NULL in cxl_pci_port_ras()
[Gregory] Move AER driver bus name detection to a static function
Changes in v4 -> v5:
[Alejandro] Refactor cxl_walk_bridge to simplify 'status' variable usage [Alejandro] Add WARN_ONCE() in __cxl_handle_ras() and cxl_handle_cor_ras() [Ming] Remove unnecessary NULL check in cxl_pci_port_ras() [Terry] Add failure check for call to to_cxl_port() in cxl_pci_port_ras() [Ming] Use port->dev for call to devm_add_action_or_reset() in cxl_dport_init_ras_reporting() and cxl_uport_init_ras_reporting() [Jonathan] Use get_device()/put_device() to prevent race condition in cxl_clear_port_error_handlers() and cxl_clear_port_error_handlers() [Terry] Commit message cleanup. Capitalize keywords from CXL and PCI specifications
Changes in v3 -> v4:
[Lukas] Capitalize PCIe and CXL device names as in specifications [Lukas] Move call to pcie_is_cxl() into cxl_port_devsec()
[Lukas] Correct namespace spelling
[Lukas] Removed export from pcie_is_cxl_port()
[Lukas] Simplify 'if' blocks in cxl_handle_error()
[Lukas] Change panic message to remove redundant 'panic' text
[Ming] Update to call cxl_dport_init_ras_reporting() in RCH case [lkp@intel] 'host' parameter is already removed. Remove parameter description too. [Terry] Added field description for cxl_err_handlers in pci.h comment block
Changes in v1 -> v2:
[Jonathan] Remove extra NULL check and cleanup in cxl_pci_port_ras() [Jonathan] Update description to DSP map patch description
[Jonathan] Update cxl_pci_port_ras() to check for NULL port [Jonathan] Dont call handler before handler port changes are present (patch order) [Bjorn] Fix linebreak in cover sheet URL
[Bjorn] Remove timestamps from test logs in cover sheet
[Bjorn] Retitle AER commits to use "PCI/AER:"
[Bjorn] Retitle patch#3 to use renaming instead of refactoring [Bjorn] Fix base commit-id on cover sheet
[Bjorn] Add VH spec reference/citation
[Terry] Removed last 2 patches to enable internal errors. Is not needed because internal errors are enabled in AER driver.
[Dan] Create cxl_do_recovery() and pci_driver::cxl_err_handlers. [Dan] Use kernel panic in CXL recovery
[Dan] cxl_port_hndlrs -> cxl_port_error_handlers
Dan Williams (4):
cxl: Tighten CPER kfifo registration API and symbol visibility
cxl: Rename find_cxl_port() to find_cxl_port_by_dport() cxl/pci: Thread port and dport through RAS handling helpers
cxl: Add port and dport identifiers to CXL AER trace events
Terry Bowman (9):
cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks PCI/AER: Introduce AER-CXL protocol error kfifo
PCI: Establish common CXL Port protocol error flow PCI/CXL: Add RCH support to CXL handlers
cxl: Update CXL Endpoint AER handler
PCI: Cache PCI DSN into pci_dev->dsn during probe PCI/CXL: Mask/Unmask CXL protocol errors
Documentation: cxl: Document CXL protocol error handling
Documentation/driver-api/cxl/index.rst | 1 + .../cxl/linux/protocol-error-handling.rst | 222 ++++++++++ MAINTAINERS | 2 + drivers/acpi/apei/ghes.c | 66 +-- drivers/cxl/core/core.h | 36 +- drivers/cxl/core/port.c | 28 +- drivers/cxl/core/ras.c | 395 ++++++++++++------ drivers/cxl/core/ras_rch.c | 20 +- drivers/cxl/core/trace.c | 35 ++ drivers/cxl/core/trace.h | 91 ++-- drivers/cxl/cxlmem.h | 7 + drivers/cxl/cxlpci.h | 11 +- drivers/cxl/pci.c | 16 +- drivers/pci/pci.h | 1 - drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer.c | 45 +- drivers/pci/pcie/aer_cxl_rch.c | 39 +- drivers/pci/pcie/aer_cxl_vh.c | 235 +++++++++++ drivers/pci/pcie/portdrv.h | 10 +- drivers/pci/probe.c | 14 + include/cxl/event.h | 17 +- include/linux/aer.h | 26 ++ include/linux/pci.h | 1 + tools/testing/cxl/Kbuild | 1 + tools/testing/cxl/test/mock.c | 12 + 25 files changed, 1013 insertions(+), 319 deletions(-) create mode 100644 Documentation/driver-api/cxl/linux/protocol-error-handling.rst create mode 100644 drivers/pci/pcie/aer_cxl_vh.c
base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
Signature · 1 line
2.34.1
PATCH v18 1/13 cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register
cxl_rch_get_aer_severity() classifies RCH Downstream Port uncorrectable errors as fatal or non-fatal by ANDing uncorrectable status with PCI_ERR_ROOT_FATAL_RCV. This is wrong because PCI_ERR_ROOT_FATAL_RCV is a Root Error Status register bit (bit 6), not a severity bit. ANDing it against uncorrectable status tests a reserved bit and produces incorrect severity classification.
Fix by ANDing the unmasked uncor_status against uncor_severity. Per PCIe Base Spec r6.0 Section 7.8.4.4, each bit in the Uncorrectable Error Severity register indicates whether the corresponding error is fatal (1) or non-fatal (0).
---
Changes in v17 -> v18:
- New patch.
--- drivers/cxl/core/ras_rch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/cxl/core/ras_rch.c +2 -1
@@ -80,7 +80,8 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, int *severity) {if (aer_regs->uncor_status & ~aer_regs->uncor_mask) { -if (aer_regs->uncor_status &PCI_ERR_ROOT_FATAL_RCV ) +if ((aer_regs->uncor_status & ~aer_regs->uncor_mask) & + aer_regs->uncor_severity) *severity =AER_FATAL ;else *severity =AER_NONFATAL ;
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 01/13] cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] cxl_rch_get_aer_info() uses sizeof(struct aer_capability_regs) to perform a linear MMIO read block copy, but the struct contains software-defined fields that break physical hardware layout parity, causing out-of-bounds MMIO reads and a stack data leak.
- [Medium] Correctable errors are silently dropped and permanently lost if uncorrectable errors are simultaneously present.
--
--- Patch [1]: [PATCH v18 01/13] cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register --- commit 900d8b615c2219573e44e775aca2f70550afbe9a
Author: Terry Bowman <[email protected]>
cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register
This commit fixes the AER severity classification for RCH Downstream Port uncorrectable errors by correctly checking the unmasked uncor_status against uncor_severity.
Quoted 5 lines
drivers/cxl/core/ras_rch.c +0
-0
drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 87
Quoted 9 lines
drivers/cxl/core/ras_rch.c +2
-1@@ -80,7 +80,8 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, int *severity) {if (aer_regs->uncor_status & ~aer_regs->uncor_mask) { -if (aer_regs->uncor_status &PCI_ERR_ROOT_FATAL_RCV ) +if ((aer_regs->uncor_status & ~aer_regs->uncor_mask) & + aer_regs->uncor_severity) *severity =AER_FATAL ;else *severity =AER_NONFATAL ;
[Severity: Medium]
This isn't a bug introduced by this patch, but does this logic permanently lose correctable errors if both types are logged simultaneously?
Looking at cxl_rch_get_aer_info(), it reads the entire AER capability and clears both error types in hardware:
drivers/cxl/core/ras_rch.c:cxl_rch_get_aer_info() {
...
writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS);
writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS);
...
}Then here in cxl_rch_get_aer_severity(), it evaluates the uncorrectable error, assigns the severity, and returns early without checking for correctable errors:
drivers/cxl/core/ras_rch.c:cxl_rch_get_aer_severity() {
if (aer_regs->uncor_status & ~aer_regs->uncor_mask) {
...
return true;
}
...
}Returning true immediately bypasses the correctable error check, preventing cxl_handle_cor_ras() from being called on the same pass.
[Severity: High]
This is a pre-existing issue, but do the MMIO reads in the related cxl_rch_get_aer_info() perform out-of-bounds hardware access?
drivers/cxl/core/ras_rch.c:cxl_rch_get_aer_info() {
int read_cnt = sizeof(struct aer_capability_regs) / sizeof(u32);
...
for (n = 0; n < read_cnt; n++)
aer_regs_buf[n] = readl(aer_base + n * sizeof(u32));
}Since struct aer_capability_regs includes struct pcie_tlp_log, recent additions to struct pcie_tlp_log (such as header_len and flit) increase the size of the software struct well beyond the standard physical AER capability size.
Would this loop copy unmapped PCIe config space (typically returning 0xFFFFFFFF) into software fields like header_len, leading pcie_print_tlp_log() to later loop over an inflated log->header_len value and trigger an out-of-bounds read on the kernel stack?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH v18 01/13] cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register
In reply to Terry BowmanQuoted 7 lines · Terry Bowman
cxl_rch_get_aer_severity()classifies RCH Downstream Port uncorrectable errors as fatal or non-fatal by ANDing uncorrectable status withPCI_ERR_ROOT_FATAL_RCV. This is wrong becausePCI_ERR_ROOT_FATAL_RCVis a Root Error Status register bit (bit 6), not a severity bit. ANDing it against uncorrectable status tests a reserved bit and produces incorrect severity classification.
Quoted 8 lines
Fix by ANDing the unmasked
uncor_statusagainstuncor_severity. Per PCIe Base Spec r6.0 Section 7.8.4.4, each bit in the Uncorrectable Error Severity register indicates whether the corresponding error is fatal (1) or non-fatal (0).Fixes 6ac07883dbb5 ("cxl/pci: Add RCH downstream port error logging")Signed-off-by Terry Bowman <[email protected]>
This can be picked up ahead looks like?
Quoted 23 lines
---
Changes in v17 -> v18:
- New patch.--- drivers/cxl/core/ras_rch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)drivers/cxl/core/ras_rch.c +2
-1@@ -80,7 +80,8 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, int *severity) {if (aer_regs->uncor_status & ~aer_regs->uncor_mask) { -if (aer_regs->uncor_status &PCI_ERR_ROOT_FATAL_RCV ) +if ((aer_regs->uncor_status & ~aer_regs->uncor_mask) & + aer_regs->uncor_severity) *severity =AER_FATAL ;else *severity =AER_NONFATAL ;
Re: [PATCH v18 01/13] cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register
Quoted 15 lines · Dave Jiang
Quoted 12 lines · Terry Bowman
cxl_rch_get_aer_severity()classifies RCH Downstream Port uncorrectable errors as fatal or non-fatal by ANDing uncorrectable status withPCI_ERR_ROOT_FATAL_RCV. This is wrong becausePCI_ERR_ROOT_FATAL_RCVis a Root Error Status register bit (bit 6), not a severity bit. ANDing it against uncorrectable status tests a reserved bit and produces incorrect severity classification.Fix by ANDing the unmasked
uncor_statusagainstuncor_severity. Per PCIe Base Spec r6.0 Section 7.8.4.4, each bit in the Uncorrectable Error Severity register indicates whether the corresponding error is fatal (1) or non-fatal (0).
Quoted 8 lines
Quoted 3 lines
Fixes 6ac07883dbb5 ("cxl/pci: Add RCH downstream port error logging")Signed-off-by Terry Bowman <[email protected]>Reviewed-by Dave Jiang <[email protected]>This can be picked up ahead looks like?
Yes.
-Terry
Quoted 24 lines
Quoted 23 lines
---
Changes in v17 -> v18:
- New patch.--- drivers/cxl/core/ras_rch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)drivers/cxl/core/ras_rch.c +2
-1@@ -80,7 +80,8 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, int *severity) {if (aer_regs->uncor_status & ~aer_regs->uncor_mask) { -if (aer_regs->uncor_status &PCI_ERR_ROOT_FATAL_RCV ) +if ((aer_regs->uncor_status & ~aer_regs->uncor_mask) & + aer_regs->uncor_severity) *severity =AER_FATAL ;else *severity =AER_NONFATAL ;
Re: [PATCH v18 01/13] cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register
In reply to Terry BowmanQuoted 7 lines · On Fri, 17 Jul 2026 17:26:54 -0500 Terry Bowman <[email protected]> wrote:
cxl_rch_get_aer_severity()classifies RCH Downstream Port uncorrectable errors as fatal or non-fatal by ANDing uncorrectable status withPCI_ERR_ROOT_FATAL_RCV. This is wrong becausePCI_ERR_ROOT_FATAL_RCVis a Root Error Status register bit (bit 6), not a severity bit. ANDing it against uncorrectable status tests a reserved bit and produces incorrect severity classification.
Quoted 9 lines
Fix by ANDing the unmasked
uncor_statusagainstuncor_severity. Per PCIe Base Spec r6.0 Section 7.8.4.4, each bit in the Uncorrectable Error Severity register indicates whether the corresponding error is fatal (1) or non-fatal (0).Fixes 6ac07883dbb5 ("cxl/pci: Add RCH downstream port error logging")Signed-off-by Terry Bowman <[email protected]>
One trivial thing below, otherwise LGTM
Either way
Quoted 13 lines
---
Changes in v17 -> v18:
- New patch.--- drivers/cxl/core/ras_rch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)drivers/cxl/core/ras_rch.c +0
-0
drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 83
Quoted 5 lines
drivers/cxl/core/ras_rch.c +1
-1@@ -80,7 +80,8 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, int *severity) {if (aer_regs->uncor_status & ~aer_regs->uncor_mask) { -if (aer_regs->uncor_status &PCI_ERR_ROOT_FATAL_RCV ) + if ((aer_regs->uncor_status & ~aer_regs->uncor_mask) &
This bit looks familiar (see line above!) Worth a local variable maybe?
Quoted 4 lines
drivers/cxl/core/ras_rch.c +1
-0+ aer_regs->uncor_severity) *severity =AER_FATAL ; else *severity =AER_NONFATAL ;
Re: [PATCH v18 01/13] cxl/ras: Fix cxl_rch_get_aer_severity() wrong severity register
In reply to Terry BowmanQuoted 29 lines · Terry Bowman
cxl_rch_get_aer_severity()classifies RCH Downstream Port uncorrectable errors as fatal or non-fatal by ANDing uncorrectable status withPCI_ERR_ROOT_FATAL_RCV. This is wrong becausePCI_ERR_ROOT_FATAL_RCVis a Root Error Status register bit (bit 6), not a severity bit. ANDing it against uncorrectable status tests a reserved bit and produces incorrect severity classification.Fix by ANDing the unmasked
uncor_statusagainstuncor_severity. Per PCIe Base Spec r6.0 Section 7.8.4.4, each bit in the Uncorrectable Error Severity register indicates whether the corresponding error is fatal (1) or non-fatal (0).Fixes 6ac07883dbb5 ("cxl/pci: Add RCH downstream port error logging")Signed-off-by Terry Bowman <[email protected]>---
Changes in v17 -> v18:
- New patch.--- drivers/cxl/core/ras_rch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)drivers/cxl/core/ras_rch.c +0
-0
drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 87
Quoted 9 lines
drivers/cxl/core/ras_rch.c +2
-1@@ -80,7 +80,8 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, int *severity) {if (aer_regs->uncor_status & ~aer_regs->uncor_mask) { -if (aer_regs->uncor_status &PCI_ERR_ROOT_FATAL_RCV ) +if ((aer_regs->uncor_status & ~aer_regs->uncor_mask) & + aer_regs->uncor_severity) *severity =AER_FATAL ;else *severity =AER_NONFATAL ;
The logic looks correct to me, maybe the small tweak would be cleaner ?
"""
u32 status = aer_regs->uncor_status & ~aer_regs->uncor_mask;
if (status) {
*severity = (status & aer_regs->uncor_severity) ? AER_FATAL : AER_NONFATAL;
}"""
Quoted 4 lines
Signature · 1 line
2.34.1
PATCH v18 2/13 acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
In reply to Terry BowmanThe CXL CPER work registration and unregistration helpers in drivers/acpi/apei/ghes.c acquire cxl_cper_work_lock and cxl_cper_prot_err_work_lock with guard(spinlock), which leaves local interrupts enabled. The corresponding post paths (cxl_cper_post_event(), cxl_cper_post_prot_err()) execute in hard IRQ context (they are called from the GHES error notification path) and acquire the same locks via guard(spinlock_irqsave).
If a CPU is holding one of these locks via guard(spinlock) when a GHES interrupt arrives on the same CPU, the IRQ handler spins on the held lock waiting for it to release, while the lock holder is preempted by the IRQ. The result is a deadlock.
Convert both locks from spinlock_t to raw_spinlock_t and use guard(raw_spinlock_irqsave) at all call sites. On PREEMPT_RT kernels spinlock_t is backed by rt_mutex and sleeping from hard IRQ context is not permitted; raw_spinlock_t is safe in both contexts.
Add WARN_ONCE to both register functions to surface double-registration bugs at runtime.
Restructure both unregister functions to clear the global work pointer under the lock before calling cancel_work_sync(), closing the window where a CPER interrupt could schedule work on a pointer about to be freed. Add kfifo_reset() after cancel_work_sync() so stale entries are not replayed on next module load.
Both kfifos are single-consumer: only one work_struct is registered at a time, enforced by the WARN_ONCE guard in the register functions. kfifo_reset() is safe outside the lock because cancel_work_sync() has already quiesced the consumer, and no new consumer can register until the current module exit completes and a fresh module init runs.
Remove the now-redundant cancel_work_sync() call from cxl_pci_driver_exit() - cxl_cper_unregister_work() handles quiescing internally.
---
Changes in v17 -> v18:
- New patch.
--- drivers/acpi/apei/ghes.c | 50 ++++++++++++++++++++++++++-------------- drivers/cxl/pci.c | 1 - 2 files changed, 33 insertions(+), 18 deletions(-)
drivers/acpi/apei/ghes.c +33 -17
@@ -749,7 +749,7 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data, CXL_CPER_PROT_ERR_FIFO_DEPTH);/* Synchronize schedule_work() with cxl_cper_prot_err_work changes */ -static DEFINE_SPINLOCK (cxl_cper_prot_err_work_lock); +static DEFINE_RAW_SPINLOCK (cxl_cper_prot_err_work_lock);struct work_struct *cxl_cper_prot_err_work; static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,
@@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,if (cxl_cper_sec_prot_err_valid (prot_err))return ; -guard (spinlock_irqsave)(&cxl_cper_prot_err_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (!cxl_cper_prot_err_work)return ;
@@ -780,10 +780,11 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,int cxl_cper_register_prot_err_work (struct work_struct *work) { -if (cxl_cper_prot_err_work) -return -EINVAL ; +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock); -guard (spinlock)(&cxl_cper_prot_err_work_lock); +if (WARN_ONCE (cxl_cper_prot_err_work, +"CPER-CXL kfifo consumer already registered\n" )) +return -EINVAL ; cxl_cper_prot_err_work = work;return 0 ; }
@@ -791,11 +792,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL");int cxl_cper_unregister_prot_err_work (struct work_struct *work) { -if (cxl_cper_prot_err_work != work) -return -EINVAL ; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) { +if (WARN_ONCE (cxl_cper_prot_err_work != work, +"CPER-CXL kfifo consumer mismatch on unregister\n" )) +return -EINVAL ; + cxl_cper_prot_err_work =NULL ; + } + +cancel_work_sync (work); + +/* Discard stale entries so they are not replayed on next module load */ +kfifo_reset (&cxl_cper_prot_err_fifo); -guard (spinlock)(&cxl_cper_prot_err_work_lock); - cxl_cper_prot_err_work =NULL ;return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_prot_err_work,"CXL" );
@@ -811,7 +819,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL"); DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH);/* Synchronize schedule_work() with cxl_cper_work changes */ -static DEFINE_SPINLOCK (cxl_cper_work_lock); +static DEFINE_RAW_SPINLOCK (cxl_cper_work_lock);struct work_struct *cxl_cper_work; static void cxl_cper_post_event(enum cxl_event_type event_type,
@@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,return ; } -guard (spinlock_irqsave)(&cxl_cper_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock);if (!cxl_cper_work)return ;
@@ -849,10 +857,11 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,int cxl_cper_register_work (struct work_struct *work) { -if (cxl_cper_work) +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock); +if (WARN_ONCE (cxl_cper_work, +"CXL CPER kfifo consumer already registered\n" ))return -EINVAL ; -guard (spinlock)(&cxl_cper_work_lock); cxl_cper_work = work;return 0 ; }
@@ -860,11 +869,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL");int cxl_cper_unregister_work (struct work_struct *work) { -if (cxl_cper_work != work) -return -EINVAL ; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) { +if (WARN_ONCE (cxl_cper_work != work, +"CXL CPER kfifo consumer mismatch on unregister\n" )) +return -EINVAL ; + cxl_cper_work =NULL ; + } + +cancel_work_sync (work); + +/* Discard stale entries so they are not replayed on next module load */ +kfifo_reset (&cxl_cper_fifo); -guard (spinlock)(&cxl_cper_work_lock); - cxl_cper_work =NULL ;return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_work,"CXL" );
drivers/cxl/pci.c +0 -1
@@ -1083,7 +1083,6 @@ static int __init cxl_pci_driver_init(void) static void __exit cxl_pci_driver_exit(void) {cxl_cper_unregister_work (&cxl_cper_work); -cancel_work_sync (&cxl_cper_work);pci_unregister_driver (&cxl_pci_driver); }
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 02/13] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Low] The patch adds internal cancellation to both unregister functions but misses removing the redundant cancel_work_sync() for the protocol error work in cxl_ras_exit().
Pre-existing issues:
- [High] Fixed-size memcpy in cxl_cper_post_event causes an out-of-bounds read if the provided GHES CPER payload is smaller than sizeof(*rec).
- [High] Missing bounds check on untrusted dvsec_len in cxl_cper_setup_prot_err_work_data leads to an out-of-bounds read. --
--- Patch [2]: [PATCH v18 02/13] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks --- commit 70fa064ce36bd35723148aab9a91c80d0fbef760
Author: Terry Bowman <[email protected]>
acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
This commit converts cxl_cper_work_lock and cxl_cper_prot_err_work_lock from spinlock_t to raw_spinlock_t to prevent a deadlock between IRQ and process contexts. It also restructures registration functions to warn on double registration and clear work pointers before cancelling them. Redundant cancel_work_sync() calls are removed since quiescing is handled internally.
Quoted 4 lines
drivers/acpi/apei/ghes.c +0
-0
[ ... ]
drivers/acpi/apei/ghes.c static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, · line 767
Quoted 9 lines
drivers/acpi/apei/ghes.c +1
-1@@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,if (cxl_cper_sec_prot_err_valid (prot_err))return ; -guard (spinlock_irqsave)(&cxl_cper_prot_err_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (!cxl_cper_prot_err_work)return ;
[Severity: High]
This is a pre-existing issue, but does cxl_cper_setup_prot_err_work_data() lack bounds checking on the untrusted dvsec_len?
If firmware provides a CXL protocol error record with a maliciously large dvsec_len, could this lead to an out-of-bounds read when calculating cap_start?
drivers/acpi/apei/ghes_helpers.c:cxl_cper_setup_prot_err_work_data() {
...
dvsec_start = (u8 *)(prot_err + 1);
cap_start = dvsec_start + prot_err->dvsec_len;
memcpy(&wd->ras_cap, cap_start, sizeof(wd->ras_cap));
...
}[ ... ]
drivers/acpi/apei/ghes.c static void cxl_cper_post_event(enum cxl_event_type event_type, · line 845
Quoted 9 lines
drivers/acpi/apei/ghes.c +1
-1@@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,return ; } -guard (spinlock_irqsave)(&cxl_cper_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock);if (!cxl_cper_work)return ;
[Severity: High]
This is a pre-existing issue, but does cxl_cper_post_event() have an out-of-bounds read if the provided GHES CPER payload is smaller than sizeof(*rec)?
If firmware provides a CXL event record where gdata->error_data_length is smaller than sizeof(struct cxl_cper_event_rec), this fixed-size memcpy could exceed the bounds of the error status block:
drivers/acpi/apei/ghes.c:cxl_cper_post_event() {
...
wd.event_type = event_type;
memcpy(&wd.rec, rec, sizeof(wd.rec));
...
}[ ... ]
drivers/cxl/pci.c static int __init cxl_pci_driver_init(void) · line 1087
Quoted 11 lines
drivers/cxl/pci.c +0
-1@@ -1083,7 +1083,6 @@ static int __init cxl_pci_driver_init(void) static void __exit cxl_pci_driver_exit(void) {cxl_cper_unregister_work (&cxl_cper_work); -cancel_work_sync (&cxl_cper_work);pci_unregister_driver (&cxl_pci_driver); }
[Severity: Low]
Is there a missed redundant cancel_work_sync() call in cxl_ras_exit() that should also be removed?
Since internal cancellation was added to the unregister functions, cxl_ras_exit() now has redundant synchronization:
drivers/cxl/core/ras.c:cxl_ras_exit() {
...
cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work);
cancel_work_sync(&cxl_cper_prot_err_work);
...
}Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH v18 02/13] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
The LOW issue is valid and the extra cancel_work_sync() needs to be removed. I propose we fix if a series respin is necessary or otherwise fix in future.
The preexisting HIGH issues are GHES area and to be fixed by owners.
Terry
Quoted 108 lines · On 7/17/2026 5:49 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Low] The patch adds internal cancellation to both unregister functions but misses removing the redundantcancel_work_sync()for the protocol error work incxl_ras_exit().Pre-existing issues:
- [High] Fixed-size memcpy incxl_cper_post_eventcauses an out-of-bounds read if the provided GHES CPER payload is smaller thansizeof(*rec).
- [High] Missing bounds check on untrusteddvsec_lenincxl_cper_setup_prot_err_work_dataleads to an out-of-bounds read. ----- Patch [2]: [PATCH v18 02/13] acpi/apei/ghes: Use
raw_spinlock_tfor CXL CPER work locks --- commit70fa064ce36bd35723148aab9a91c80d0fbef760
Author: Terry Bowman <[email protected]>acpi/apei/ghes: Use
raw_spinlock_tfor CXL CPER work locksThis commit converts
cxl_cper_work_lockandcxl_cper_prot_err_work_lockfromspinlock_ttoraw_spinlock_tto prevent a deadlock between IRQ and process contexts. It also restructures registration functions to warn on double registration and clear work pointers before cancelling them. Redundantcancel_work_sync()calls are removed since quiescing is handled internally.Quoted 4 lines
drivers/acpi/apei/ghes.c +0
-0[ ... ]
drivers/acpi/apei/ghes.c static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, · line 767
Quoted 9 lines
drivers/acpi/apei/ghes.c +1
-1@@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,if (cxl_cper_sec_prot_err_valid (prot_err))return ; -guard (spinlock_irqsave)(&cxl_cper_prot_err_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (!cxl_cper_prot_err_work)return ;[Severity: High]
This is a pre-existing issue, but doescxl_cper_setup_prot_err_work_data()lack bounds checking on the untrusteddvsec_len?If firmware provides a CXL protocol error record with a maliciously large
dvsec_len, could this lead to an out-of-bounds read when calculatingcap_start?drivers/acpi/apei/ghes_helpers.c:cxl_cper_setup_prot_err_work_data() { ... dvsec_start = (u8 *)(prot_err + 1); cap_start = dvsec_start + prot_err->dvsec_len; memcpy(&wd->ras_cap, cap_start, sizeof(wd->ras_cap)); ... }[ ... ]
drivers/acpi/apei/ghes.c static void cxl_cper_post_event(enum cxl_event_type event_type, · line 845
Quoted 9 lines
drivers/acpi/apei/ghes.c +1
-1@@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,return ; } -guard (spinlock_irqsave)(&cxl_cper_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock);if (!cxl_cper_work)return ;[Severity: High]
This is a pre-existing issue, but doescxl_cper_post_event()have an out-of-bounds read if the provided GHES CPER payload is smaller thansizeof(*rec)?If firmware provides a CXL event record where
gdata->error_data_lengthis smaller thansizeof(struct cxl_cper_event_rec), this fixed-size memcpy could exceed the bounds of the error status block:drivers/acpi/apei/ghes.c:cxl_cper_post_event() { ... wd.event_type = event_type; memcpy(&wd.rec, rec, sizeof(wd.rec)); ... }[ ... ]
drivers/cxl/pci.c static int __init cxl_pci_driver_init(void) · line 1087
Quoted 11 lines
drivers/cxl/pci.c +0
-1@@ -1083,7 +1083,6 @@ static int __init cxl_pci_driver_init(void) static void __exit cxl_pci_driver_exit(void) {cxl_cper_unregister_work (&cxl_cper_work); -cancel_work_sync (&cxl_cper_work);pci_unregister_driver (&cxl_pci_driver); }[Severity: Low]
Is there a missed redundantcancel_work_sync()call incxl_ras_exit()that should also be removed?Since internal cancellation was added to the unregister functions,
cxl_ras_exit()now has redundant synchronization:drivers/cxl/core/ras.c:cxl_ras_exit() { ... cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work); cancel_work_sync(&cxl_cper_prot_err_work); ... }
Jonathan Cameron
maintainerRe: [PATCH v18 02/13] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
Quoted 5 lines · Terry
The LOW issue is valid and the extra
cancel_work_sync()needs to be removed. I propose we fix if a series respin is necessary or otherwise fix in future.The preexisting HIGH issues are GHES area and to be fixed by owners.
Mauro, this smells like one that your nice QEMU + scripts could detect. Fancy it as a test case? (he says hoping you'll also fix it :)
Also, I just flagged on discord that we should discuss what we do about these sort of issues and tracking them at the CXL sync call tomorrow. (Tracking somewhat discussion here:
https://lore.kernel.org/ksummit/[email protected]/T/#t
Jonathan
Quoted 113 lines
Terry
Quoted 108 lines · On 7/17/2026 5:49 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [Low] The patch adds internal cancellation to both unregister functions but misses removing the redundantcancel_work_sync()for the protocol error work incxl_ras_exit().Pre-existing issues:
- [High] Fixed-size memcpy incxl_cper_post_eventcauses an out-of-bounds read if the provided GHES CPER payload is smaller thansizeof(*rec).
- [High] Missing bounds check on untrusteddvsec_lenincxl_cper_setup_prot_err_work_dataleads to an out-of-bounds read. ----- Patch [2]: [PATCH v18 02/13] acpi/apei/ghes: Use
raw_spinlock_tfor CXL CPER work locks --- commit70fa064ce36bd35723148aab9a91c80d0fbef760
Author: Terry Bowman <[email protected]>acpi/apei/ghes: Use
raw_spinlock_tfor CXL CPER work locksThis commit converts
cxl_cper_work_lockandcxl_cper_prot_err_work_lockfromspinlock_ttoraw_spinlock_tto prevent a deadlock between IRQ and process contexts. It also restructures registration functions to warn on double registration and clear work pointers before cancelling them. Redundantcancel_work_sync()calls are removed since quiescing is handled internally.Quoted 4 lines
drivers/acpi/apei/ghes.c +0
-0[ ... ]
drivers/acpi/apei/ghes.c static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err, · line 767
Quoted 9 lines
drivers/acpi/apei/ghes.c +1
-1@@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,if (cxl_cper_sec_prot_err_valid (prot_err))return ; -guard (spinlock_irqsave)(&cxl_cper_prot_err_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (!cxl_cper_prot_err_work)return ;[Severity: High]
This is a pre-existing issue, but doescxl_cper_setup_prot_err_work_data()lack bounds checking on the untrusteddvsec_len?If firmware provides a CXL protocol error record with a maliciously large
dvsec_len, could this lead to an out-of-bounds read when calculatingcap_start?drivers/acpi/apei/ghes_helpers.c:cxl_cper_setup_prot_err_work_data() { ... dvsec_start = (u8 *)(prot_err + 1); cap_start = dvsec_start + prot_err->dvsec_len; memcpy(&wd->ras_cap, cap_start, sizeof(wd->ras_cap)); ... }[ ... ]
drivers/acpi/apei/ghes.c static void cxl_cper_post_event(enum cxl_event_type event_type, · line 845
Quoted 9 lines
drivers/acpi/apei/ghes.c +1
-1@@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,return ; } -guard (spinlock_irqsave)(&cxl_cper_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock);if (!cxl_cper_work)return ;[Severity: High]
This is a pre-existing issue, but doescxl_cper_post_event()have an out-of-bounds read if the provided GHES CPER payload is smaller thansizeof(*rec)?If firmware provides a CXL event record where
gdata->error_data_lengthis smaller thansizeof(struct cxl_cper_event_rec), this fixed-size memcpy could exceed the bounds of the error status block:drivers/acpi/apei/ghes.c:cxl_cper_post_event() { ... wd.event_type = event_type; memcpy(&wd.rec, rec, sizeof(wd.rec)); ... }[ ... ]
drivers/cxl/pci.c static int __init cxl_pci_driver_init(void) · line 1087
Quoted 11 lines
drivers/cxl/pci.c +0
-1@@ -1083,7 +1083,6 @@ static int __init cxl_pci_driver_init(void) static void __exit cxl_pci_driver_exit(void) {cxl_cper_unregister_work (&cxl_cper_work); -cancel_work_sync (&cxl_cper_work);pci_unregister_driver (&cxl_pci_driver); }[Severity: Low]
Is there a missed redundantcancel_work_sync()call incxl_ras_exit()that should also be removed?Since internal cancellation was added to the unregister functions,
cxl_ras_exit()now has redundant synchronization:drivers/cxl/core/ras.c:cxl_ras_exit() { ... cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work); cancel_work_sync(&cxl_cper_prot_err_work); ... }
Re: [PATCH v18 02/13] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
In reply to Terry BowmanQuoted 37 lines · Terry Bowman
The CXL CPER work registration and unregistration helpers in
drivers/acpi/apei/ghes.cacquirecxl_cper_work_lockandcxl_cper_prot_err_work_lockwith guard(spinlock), which leaves local interrupts enabled. The corresponding post paths (cxl_cper_post_event(),cxl_cper_post_prot_err()) execute in hard IRQ context (they are called from the GHES error notification path) and acquire the same locks viaguard(spinlock_irqsave).If a CPU is holding one of these locks via guard(spinlock) when a GHES interrupt arrives on the same CPU, the IRQ handler spins on the held lock waiting for it to release, while the lock holder is preempted by the IRQ. The result is a deadlock.
Convert both locks from
spinlock_ttoraw_spinlock_tand useguard(raw_spinlock_irqsave)at all call sites. OnPREEMPT_RTkernelsspinlock_tis backed byrt_mutexand sleeping from hard IRQ context is not permitted;raw_spinlock_tis safe in both contexts.Add
WARN_ONCEto both register functions to surface double-registration bugs at runtime.Restructure both unregister functions to clear the global work pointer under the lock before calling
cancel_work_sync(), closing the window where a CPER interrupt could schedule work on a pointer about to be freed. Addkfifo_reset()aftercancel_work_sync()so stale entries are not replayed on next module load.Both kfifos are single-consumer: only one
work_structis registered at a time, enforced by theWARN_ONCEguard in the register functions.kfifo_reset()is safe outside the lock becausecancel_work_sync()has already quiesced the consumer, and no new consumer can register until the current module exit completes and a fresh module init runs.Remove the now-redundant
cancel_work_sync()call fromcxl_pci_driver_exit()-cxl_cper_unregister_work()handles quiescing internally.
Quoted 5 lines
Reported-by Sashiko <[email protected]>Signed-off-by Terry Bowman <[email protected]>Fixes 5e4a264bf8b5 ("acpi/ghes: Process CXL Component Events")Fixes 36f257e3b0ba ("acpi/ghes, cxl/pci: Process CXL CPER Protocol Errors")
With the minor sashiko issue addressed,
This can probably be picked up ahead of the series.
Quoted 137 lines
---
Changes in v17 -> v18:
- New patch.--- drivers/acpi/apei/ghes.c | 50 ++++++++++++++++++++++++++-------------- drivers/cxl/pci.c | 1 - 2 files changed, 33 insertions(+), 18 deletions(-)drivers/acpi/apei/ghes.c +33
-17@@ -749,7 +749,7 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data, CXL_CPER_PROT_ERR_FIFO_DEPTH);/* Synchronize schedule_work() with cxl_cper_prot_err_work changes */ -static DEFINE_SPINLOCK (cxl_cper_prot_err_work_lock); +static DEFINE_RAW_SPINLOCK (cxl_cper_prot_err_work_lock);struct work_struct *cxl_cper_prot_err_work; static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,@@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,if (cxl_cper_sec_prot_err_valid (prot_err))return ; -guard (spinlock_irqsave)(&cxl_cper_prot_err_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (!cxl_cper_prot_err_work)return ;@@ -780,10 +780,11 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,int cxl_cper_register_prot_err_work (struct work_struct *work) { -if (cxl_cper_prot_err_work) -return -EINVAL ; +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock); -guard (spinlock)(&cxl_cper_prot_err_work_lock); +if (WARN_ONCE (cxl_cper_prot_err_work, +"CPER-CXL kfifo consumer already registered\n" )) +return -EINVAL ; cxl_cper_prot_err_work = work;return 0 ; }@@ -791,11 +792,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL");int cxl_cper_unregister_prot_err_work (struct work_struct *work) { -if (cxl_cper_prot_err_work != work) -return -EINVAL ; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) { +if (WARN_ONCE (cxl_cper_prot_err_work != work, +"CPER-CXL kfifo consumer mismatch on unregister\n" )) +return -EINVAL ; + cxl_cper_prot_err_work =NULL ; + } + +cancel_work_sync (work); + +/* Discard stale entries so they are not replayed on next module load */ +kfifo_reset (&cxl_cper_prot_err_fifo); -guard (spinlock)(&cxl_cper_prot_err_work_lock); - cxl_cper_prot_err_work =NULL ;return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_prot_err_work,"CXL" );@@ -811,7 +819,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL"); DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH);/* Synchronize schedule_work() with cxl_cper_work changes */ -static DEFINE_SPINLOCK (cxl_cper_work_lock); +static DEFINE_RAW_SPINLOCK (cxl_cper_work_lock);struct work_struct *cxl_cper_work; static void cxl_cper_post_event(enum cxl_event_type event_type,@@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,return ; } -guard (spinlock_irqsave)(&cxl_cper_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock);if (!cxl_cper_work)return ;@@ -849,10 +857,11 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,int cxl_cper_register_work (struct work_struct *work) { -if (cxl_cper_work) +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock); +if (WARN_ONCE (cxl_cper_work, +"CXL CPER kfifo consumer already registered\n" ))return -EINVAL ; -guard (spinlock)(&cxl_cper_work_lock); cxl_cper_work = work;return 0 ; }@@ -860,11 +869,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL");int cxl_cper_unregister_work (struct work_struct *work) { -if (cxl_cper_work != work) -return -EINVAL ; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) { +if (WARN_ONCE (cxl_cper_work != work, +"CXL CPER kfifo consumer mismatch on unregister\n" )) +return -EINVAL ; + cxl_cper_work =NULL ; + } + +cancel_work_sync (work); + +/* Discard stale entries so they are not replayed on next module load */ +kfifo_reset (&cxl_cper_fifo); -guard (spinlock)(&cxl_cper_work_lock); - cxl_cper_work =NULL ;return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_work,"CXL" );drivers/cxl/pci.c +0
-1@@ -1083,7 +1083,6 @@ static int __init cxl_pci_driver_init(void) static void __exit cxl_pci_driver_exit(void) {cxl_cper_unregister_work (&cxl_cper_work); -cancel_work_sync (&cxl_cper_work);pci_unregister_driver (&cxl_pci_driver); }
Re: [PATCH v18 02/13] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
Quoted 46 lines · Dave Jiang
Quoted 37 lines · Terry Bowman
The CXL CPER work registration and unregistration helpers in
drivers/acpi/apei/ghes.cacquirecxl_cper_work_lockandcxl_cper_prot_err_work_lockwith guard(spinlock), which leaves local interrupts enabled. The corresponding post paths (cxl_cper_post_event(),cxl_cper_post_prot_err()) execute in hard IRQ context (they are called from the GHES error notification path) and acquire the same locks viaguard(spinlock_irqsave).If a CPU is holding one of these locks via guard(spinlock) when a GHES interrupt arrives on the same CPU, the IRQ handler spins on the held lock waiting for it to release, while the lock holder is preempted by the IRQ. The result is a deadlock.
Convert both locks from
spinlock_ttoraw_spinlock_tand useguard(raw_spinlock_irqsave)at all call sites. OnPREEMPT_RTkernelsspinlock_tis backed byrt_mutexand sleeping from hard IRQ context is not permitted;raw_spinlock_tis safe in both contexts.Add
WARN_ONCEto both register functions to surface double-registration bugs at runtime.Restructure both unregister functions to clear the global work pointer under the lock before calling
cancel_work_sync(), closing the window where a CPER interrupt could schedule work on a pointer about to be freed. Addkfifo_reset()aftercancel_work_sync()so stale entries are not replayed on next module load.Both kfifos are single-consumer: only one
work_structis registered at a time, enforced by theWARN_ONCEguard in the register functions.kfifo_reset()is safe outside the lock becausecancel_work_sync()has already quiesced the consumer, and no new consumer can register until the current module exit completes and a fresh module init runs.Remove the now-redundant
cancel_work_sync()call fromcxl_pci_driver_exit()-cxl_cper_unregister_work()handles quiescing internally.Quoted 5 lines
Reported-by Sashiko <[email protected]>Signed-off-by Terry Bowman <[email protected]>Fixes 5e4a264bf8b5 ("acpi/ghes: Process CXL Component Events")Fixes 36f257e3b0ba ("acpi/ghes, cxl/pci: Process CXL CPER Protocol Errors")
Quoted 6 lines
With the minor sashiko issue addressed,
Reviewed-by Dave Jiang <[email protected]>This can probably be picked up ahead of the series.
Yes.
-Terry
Quoted 138 lines
Quoted 137 lines
---
Changes in v17 -> v18:
- New patch.--- drivers/acpi/apei/ghes.c | 50 ++++++++++++++++++++++++++-------------- drivers/cxl/pci.c | 1 - 2 files changed, 33 insertions(+), 18 deletions(-)drivers/acpi/apei/ghes.c +33
-17@@ -749,7 +749,7 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data, CXL_CPER_PROT_ERR_FIFO_DEPTH);/* Synchronize schedule_work() with cxl_cper_prot_err_work changes */ -static DEFINE_SPINLOCK (cxl_cper_prot_err_work_lock); +static DEFINE_RAW_SPINLOCK (cxl_cper_prot_err_work_lock);struct work_struct *cxl_cper_prot_err_work; static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,@@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,if (cxl_cper_sec_prot_err_valid (prot_err))return ; -guard (spinlock_irqsave)(&cxl_cper_prot_err_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (!cxl_cper_prot_err_work)return ;@@ -780,10 +780,11 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,int cxl_cper_register_prot_err_work (struct work_struct *work) { -if (cxl_cper_prot_err_work) -return -EINVAL ; +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock); -guard (spinlock)(&cxl_cper_prot_err_work_lock); +if (WARN_ONCE (cxl_cper_prot_err_work, +"CPER-CXL kfifo consumer already registered\n" )) +return -EINVAL ; cxl_cper_prot_err_work = work;return 0 ; }@@ -791,11 +792,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL");int cxl_cper_unregister_prot_err_work (struct work_struct *work) { -if (cxl_cper_prot_err_work != work) -return -EINVAL ; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) { +if (WARN_ONCE (cxl_cper_prot_err_work != work, +"CPER-CXL kfifo consumer mismatch on unregister\n" )) +return -EINVAL ; + cxl_cper_prot_err_work =NULL ; + } + +cancel_work_sync (work); + +/* Discard stale entries so they are not replayed on next module load */ +kfifo_reset (&cxl_cper_prot_err_fifo); -guard (spinlock)(&cxl_cper_prot_err_work_lock); - cxl_cper_prot_err_work =NULL ;return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_prot_err_work,"CXL" );@@ -811,7 +819,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL"); DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH);/* Synchronize schedule_work() with cxl_cper_work changes */ -static DEFINE_SPINLOCK (cxl_cper_work_lock); +static DEFINE_RAW_SPINLOCK (cxl_cper_work_lock);struct work_struct *cxl_cper_work; static void cxl_cper_post_event(enum cxl_event_type event_type,@@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,return ; } -guard (spinlock_irqsave)(&cxl_cper_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock);if (!cxl_cper_work)return ;@@ -849,10 +857,11 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,int cxl_cper_register_work (struct work_struct *work) { -if (cxl_cper_work) +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock); +if (WARN_ONCE (cxl_cper_work, +"CXL CPER kfifo consumer already registered\n" ))return -EINVAL ; -guard (spinlock)(&cxl_cper_work_lock); cxl_cper_work = work;return 0 ; }@@ -860,11 +869,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL");int cxl_cper_unregister_work (struct work_struct *work) { -if (cxl_cper_work != work) -return -EINVAL ; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) { +if (WARN_ONCE (cxl_cper_work != work, +"CXL CPER kfifo consumer mismatch on unregister\n" )) +return -EINVAL ; + cxl_cper_work =NULL ; + } + +cancel_work_sync (work); + +/* Discard stale entries so they are not replayed on next module load */ +kfifo_reset (&cxl_cper_fifo); -guard (spinlock)(&cxl_cper_work_lock); - cxl_cper_work =NULL ;return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_work,"CXL" );drivers/cxl/pci.c +0
-1@@ -1083,7 +1083,6 @@ static int __init cxl_pci_driver_init(void) static void __exit cxl_pci_driver_exit(void) {cxl_cper_unregister_work (&cxl_cper_work); -cancel_work_sync (&cxl_cper_work);pci_unregister_driver (&cxl_pci_driver); }
Re: [PATCH v18 02/13] acpi/apei/ghes: Use raw_spinlock_t for CXL CPER work locks
In reply to Terry BowmanQuoted 37 lines · On Fri, 17 Jul 2026 17:26:55 -0500 Terry Bowman <[email protected]> wrote:
The CXL CPER work registration and unregistration helpers in
drivers/acpi/apei/ghes.cacquirecxl_cper_work_lockandcxl_cper_prot_err_work_lockwith guard(spinlock), which leaves local interrupts enabled. The corresponding post paths (cxl_cper_post_event(),cxl_cper_post_prot_err()) execute in hard IRQ context (they are called from the GHES error notification path) and acquire the same locks viaguard(spinlock_irqsave).If a CPU is holding one of these locks via guard(spinlock) when a GHES interrupt arrives on the same CPU, the IRQ handler spins on the held lock waiting for it to release, while the lock holder is preempted by the IRQ. The result is a deadlock.
Convert both locks from
spinlock_ttoraw_spinlock_tand useguard(raw_spinlock_irqsave)at all call sites. OnPREEMPT_RTkernelsspinlock_tis backed byrt_mutexand sleeping from hard IRQ context is not permitted;raw_spinlock_tis safe in both contexts.Add
WARN_ONCEto both register functions to surface double-registration bugs at runtime.Restructure both unregister functions to clear the global work pointer under the lock before calling
cancel_work_sync(), closing the window where a CPER interrupt could schedule work on a pointer about to be freed. Addkfifo_reset()aftercancel_work_sync()so stale entries are not replayed on next module load.Both kfifos are single-consumer: only one
work_structis registered at a time, enforced by theWARN_ONCEguard in the register functions.kfifo_reset()is safe outside the lock becausecancel_work_sync()has already quiesced the consumer, and no new consumer can register until the current module exit completes and a fresh module init runs.Remove the now-redundant
cancel_work_sync()call fromcxl_pci_driver_exit()-cxl_cper_unregister_work()handles quiescing internally.
Quoted 5 lines
Reported-by Sashiko <[email protected]>Signed-off-by Terry Bowman <[email protected]>Fixes 5e4a264bf8b5 ("acpi/ghes: Process CXL Component Events")Fixes 36f257e3b0ba ("acpi/ghes, cxl/pci: Process CXL CPER Protocol Errors")
Quoted 137 lines
---
Changes in v17 -> v18:
- New patch.--- drivers/acpi/apei/ghes.c | 50 ++++++++++++++++++++++++++-------------- drivers/cxl/pci.c | 1 - 2 files changed, 33 insertions(+), 18 deletions(-)drivers/acpi/apei/ghes.c +33
-17@@ -749,7 +749,7 @@ static DEFINE_KFIFO(cxl_cper_prot_err_fifo, struct cxl_cper_prot_err_work_data, CXL_CPER_PROT_ERR_FIFO_DEPTH);/* Synchronize schedule_work() with cxl_cper_prot_err_work changes */ -static DEFINE_SPINLOCK (cxl_cper_prot_err_work_lock); +static DEFINE_RAW_SPINLOCK (cxl_cper_prot_err_work_lock);struct work_struct *cxl_cper_prot_err_work; static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,@@ -761,7 +761,7 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,if (cxl_cper_sec_prot_err_valid (prot_err))return ; -guard (spinlock_irqsave)(&cxl_cper_prot_err_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (!cxl_cper_prot_err_work)return ;@@ -780,10 +780,11 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,int cxl_cper_register_prot_err_work (struct work_struct *work) { -if (cxl_cper_prot_err_work) -return -EINVAL ; +guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock); -guard (spinlock)(&cxl_cper_prot_err_work_lock); +if (WARN_ONCE (cxl_cper_prot_err_work, +"CPER-CXL kfifo consumer already registered\n" )) +return -EINVAL ; cxl_cper_prot_err_work = work;return 0 ; }@@ -791,11 +792,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_prot_err_work, "CXL");int cxl_cper_unregister_prot_err_work (struct work_struct *work) { -if (cxl_cper_prot_err_work != work) -return -EINVAL ; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) { +if (WARN_ONCE (cxl_cper_prot_err_work != work, +"CPER-CXL kfifo consumer mismatch on unregister\n" )) +return -EINVAL ; + cxl_cper_prot_err_work =NULL ; + } + +cancel_work_sync (work); + +/* Discard stale entries so they are not replayed on next module load */ +kfifo_reset (&cxl_cper_prot_err_fifo); -guard (spinlock)(&cxl_cper_prot_err_work_lock); - cxl_cper_prot_err_work =NULL ;return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_prot_err_work,"CXL" );@@ -811,7 +819,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_prot_err_kfifo_get, "CXL"); DEFINE_KFIFO(cxl_cper_fifo, struct cxl_cper_work_data, CXL_CPER_FIFO_DEPTH);/* Synchronize schedule_work() with cxl_cper_work changes */ -static DEFINE_SPINLOCK (cxl_cper_work_lock); +static DEFINE_RAW_SPINLOCK (cxl_cper_work_lock);struct work_struct *cxl_cper_work; static void cxl_cper_post_event(enum cxl_event_type event_type,@@ -831,7 +839,7 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,return ; } -guard (spinlock_irqsave)(&cxl_cper_work_lock); +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock);if (!cxl_cper_work)return ;@@ -849,10 +857,11 @@ static void cxl_cper_post_event(enum cxl_event_type event_type,int cxl_cper_register_work (struct work_struct *work) { -if (cxl_cper_work) +guard (raw_spinlock_irqsave)(&cxl_cper_work_lock); +if (WARN_ONCE (cxl_cper_work, +"CXL CPER kfifo consumer already registered\n" ))return -EINVAL ; -guard (spinlock)(&cxl_cper_work_lock); cxl_cper_work = work;return 0 ; }@@ -860,11 +869,18 @@ EXPORT_SYMBOL_NS_GPL(cxl_cper_register_work, "CXL");int cxl_cper_unregister_work (struct work_struct *work) { -if (cxl_cper_work != work) -return -EINVAL ; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) { +if (WARN_ONCE (cxl_cper_work != work, +"CXL CPER kfifo consumer mismatch on unregister\n" )) +return -EINVAL ; + cxl_cper_work =NULL ; + } + +cancel_work_sync (work); + +/* Discard stale entries so they are not replayed on next module load */ +kfifo_reset (&cxl_cper_fifo); -guard (spinlock)(&cxl_cper_work_lock); - cxl_cper_work =NULL ;return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_work,"CXL" );drivers/cxl/pci.c +0
-1@@ -1083,7 +1083,6 @@ static int __init cxl_pci_driver_init(void) static void __exit cxl_pci_driver_exit(void) {cxl_cper_unregister_work (&cxl_cper_work); -cancel_work_sync (&cxl_cper_work);pci_unregister_driver (&cxl_pci_driver); }
PATCH v18 3/13 cxl: Tighten CPER kfifo registration API and symbol visibility
In reply to Terry BowmanFrom: Dan Williams <[email protected]>
Tighten the CPER protocol error kfifo registration API and symbol visibility.
Use EXPORT_SYMBOL_FOR_MODULES() instead of EXPORT_SYMBOL_NS_GPL() for the CPER kfifo registration symbols. This names the consuming module explicitly and gives compile-time enforcement.
Drop the work_struct argument from the unregister path. Change the WARN_ONCE condition to a NULL check since there is no caller pointer to compare against anymore.
Change register/unregister return types to void. Flag double registration with WARN_ONCE() inside the lock instead of returning an error.
Change cxl_ras_init() to void because there is one consumer and one producer so the error return was unnecessary. Remove the now-dead error check in cxl_core_init().
Add a diagnostic log when the driver is not bound in cxl_cper_handle_prot_err().
---
Changes in v17 -> v18:
- New patch.
--- drivers/acpi/apei/ghes.c | 32 +++++++++++++++----------------- drivers/cxl/core/core.h | 7 ++----- drivers/cxl/core/port.c | 6 +----- drivers/cxl/core/ras.c | 12 +++++++----- include/cxl/event.h | 17 ++++++----------- 5 files changed, 31 insertions(+), 43 deletions(-)
drivers/acpi/apei/ghes.c +15 -17
@@ -778,41 +778,41 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,#endif } -int cxl_cper_register_prot_err_work (struct work_struct *work) +void cxl_cper_register_prot_err_work (struct work_struct *work) {guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (WARN_ONCE (cxl_cper_prot_err_work,"CPER-CXL kfifo consumer already registered\n" )) -return -EINVAL ; +return ; cxl_cper_prot_err_work = work; -return 0 ; } -EXPORT_SYMBOL_NS_GPL (cxl_cper_register_prot_err_work,"CXL" ); +EXPORT_SYMBOL_FOR_MODULES (cxl_cper_register_prot_err_work,"cxl_core" ); -int cxl_cper_unregister_prot_err_work (struct work_struct *work) +void cxl_cper_unregister_prot_err_work (void ) { +struct work_struct *old; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) { -if (WARN_ONCE (cxl_cper_prot_err_work != work, -"CPER-CXL kfifo consumer mismatch on unregister\n" )) -return -EINVAL ; +WARN_ONCE (!cxl_cper_prot_err_work, +"CPER-CXL kfifo consumer not registered on unregister\n" ); + old = cxl_cper_prot_err_work; cxl_cper_prot_err_work =NULL ; } -cancel_work_sync (work); +if (old) +cancel_work_sync (old);/* Discard stale entries so they are not replayed on next module load */ kfifo_reset (&cxl_cper_prot_err_fifo); - -return 0 ; } -EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_prot_err_work,"CXL" ); +EXPORT_SYMBOL_FOR_MODULES (cxl_cper_unregister_prot_err_work,"cxl_core" );int cxl_cper_prot_err_kfifo_get (struct cxl_cper_prot_err_work_data *wd) {return kfifo_get (&cxl_cper_prot_err_fifo, wd); } -EXPORT_SYMBOL_NS_GPL (cxl_cper_prot_err_kfifo_get,"CXL" ); +EXPORT_SYMBOL_FOR_MODULES (cxl_cper_prot_err_kfifo_get,"cxl_core" );/* Room for 8 entries for each of the 4 event log queues */ #define CXL_CPER_FIFO_DEPTH 32
@@ -867,12 +867,12 @@ int cxl_cper_register_work(struct work_struct *work) }EXPORT_SYMBOL_NS_GPL (cxl_cper_register_work,"CXL" ); -int cxl_cper_unregister_work (struct work_struct *work) +void cxl_cper_unregister_work (struct work_struct *work) { scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) {if (WARN_ONCE (cxl_cper_work != work,"CXL CPER kfifo consumer mismatch on unregister\n" )) -return -EINVAL ; +return ; cxl_cper_work =NULL ; }
@@ -880,8 +880,6 @@ int cxl_cper_unregister_work(struct work_struct *work)/* Discard stale entries so they are not replayed on next module load */ kfifo_reset (&cxl_cper_fifo); - -return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_work,"CXL" );
drivers/cxl/core/core.h +2 -5
@@ -183,7 +183,7 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)return &port->dev; }#ifdef CONFIG_CXL_RAS -int cxl_ras_init (void ); +void cxl_ras_init (void );void cxl_ras_exit (void );bool cxl_handle_ras (struct device *dev,void __iomem *ras_base);void cxl_handle_cor_ras (struct device *dev,void __iomem *ras_base);
@@ -192,10 +192,7 @@ void cxl_disable_rch_root_ints(struct cxl_dport *dport);void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds);void devm_cxl_dport_ras_setup (struct cxl_dport *dport);#else -static inline int cxl_ras_init (void ) -{ -return 0 ; -} +static inline void cxl_ras_init (void ) { }static inline void cxl_ras_exit (void ) { }static inline bool cxl_handle_ras (struct device *dev,void __iomem *ras_base) {
drivers/cxl/core/port.c +1 -5
@@ -2531,14 +2531,10 @@ static __init int cxl_core_init(void)if (rc) goto err_region; - rc =cxl_ras_init (); -if (rc) - goto err_ras; +cxl_ras_init ();return 0 ; -err_ras: -cxl_region_exit (); err_region:bus_unregister (&cxl_bus_type); err_bus:
drivers/cxl/core/ras.c +7 -5
@@ -104,8 +104,11 @@ void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data) }guard (device)(&pdev->dev); -if (!pdev->dev.driver) +if (!pdev->dev.driver) { +dev_warn_ratelimited (&pdev->dev, +"Device is unbound, abort CPER error handling\n" );return ; + } struct device *mem_dev __free(put_device) = bus_find_device( &cxl_bus_type,NULL , pdev, match_memdev_by_parent);
@@ -129,15 +132,14 @@ 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); -int cxl_ras_init (void ) +void cxl_ras_init (void ) { -return cxl_cper_register_prot_err_work (&cxl_cper_prot_err_work); +cxl_cper_register_prot_err_work (&cxl_cper_prot_err_work); }void cxl_ras_exit (void ) { -cxl_cper_unregister_prot_err_work (&cxl_cper_prot_err_work); -cancel_work_sync (&cxl_cper_prot_err_work); +cxl_cper_unregister_prot_err_work (); }static void cxl_dport_map_ras (struct cxl_dport *dport)
include/cxl/event.h +6 -11
@@ -287,10 +287,10 @@ struct cxl_cper_prot_err_work_data {#ifdef CONFIG_ACPI_APEI_GHES int cxl_cper_register_work (struct work_struct *work); -int cxl_cper_unregister_work (struct work_struct *work); +void cxl_cper_unregister_work (struct work_struct *work);int cxl_cper_kfifo_get (struct cxl_cper_work_data *wd); -int cxl_cper_register_prot_err_work (struct work_struct *work); -int cxl_cper_unregister_prot_err_work (struct work_struct *work); +void cxl_cper_register_prot_err_work (struct work_struct *work); +void cxl_cper_unregister_prot_err_work (void );int cxl_cper_prot_err_kfifo_get (struct cxl_cper_prot_err_work_data *wd);#else static inline int cxl_cper_register_work (struct work_struct *work)
@@ -298,21 +298,16 @@ static inline int cxl_cper_register_work(struct work_struct *work)return 0 ; } -static inline int cxl_cper_unregister_work (struct work_struct *work) -{ -return 0 ; -} +static inline void cxl_cper_unregister_work (struct work_struct *work) { }static inline int cxl_cper_kfifo_get (struct cxl_cper_work_data *wd) {return 0 ; } -static inline int cxl_cper_register_prot_err_work (struct work_struct *work) +static inline void cxl_cper_register_prot_err_work (struct work_struct *work) { -return 0 ; } -static inline int cxl_cper_unregister_prot_err_work (struct work_struct *work) +static inline void cxl_cper_unregister_prot_err_work (void ) { -return 0 ; }static inline int cxl_cper_prot_err_kfifo_get (struct cxl_cper_prot_err_work_data *wd) {
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 03/13] cxl: Tighten CPER kfifo registration API and symbol visibility
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 20 lines
From: Dan Williams <[email protected]>
Tighten the CPER protocol error kfifo registration API and symbol visibility.
Use
EXPORT_SYMBOL_FOR_MODULES()instead ofEXPORT_SYMBOL_NS_GPL()for the CPER kfifo registration symbols. This names the consuming module explicitly and gives compile-time enforcement.Drop the
work_structargument from the unregister path. Change theWARN_ONCEcondition to a NULL check since there is no caller pointer to compare against anymore.Change register/unregister return types to void. Flag double registration with
WARN_ONCE()inside the lock instead of returning an error.Change
cxl_ras_init()to void because there is one consumer and one producer so the error return was unnecessary. Remove the now-dead error check incxl_core_init().
Quoted 6 lines
Add a diagnostic log when the driver is not bound in
cxl_cper_handle_prot_err().Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH v18 03/13] cxl: Tighten CPER kfifo registration API and symbol visibility
In reply to Terry BowmanQuoted 20 lines · Terry Bowman
From: Dan Williams <[email protected]>
Tighten the CPER protocol error kfifo registration API and symbol visibility.
Use
EXPORT_SYMBOL_FOR_MODULES()instead ofEXPORT_SYMBOL_NS_GPL()for the CPER kfifo registration symbols. This names the consuming module explicitly and gives compile-time enforcement.Drop the
work_structargument from the unregister path. Change theWARN_ONCEcondition to a NULL check since there is no caller pointer to compare against anymore.Change register/unregister return types to void. Flag double registration with
WARN_ONCE()inside the lock instead of returning an error.Change
cxl_ras_init()to void because there is one consumer and one producer so the error return was unnecessary. Remove the now-dead error check incxl_core_init().
Quoted 6 lines
Add a diagnostic log when the driver is not bound in
cxl_cper_handle_prot_err().Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>
Quoted 220 lines
---
Changes in v17 -> v18:
- New patch.--- drivers/acpi/apei/ghes.c | 32 +++++++++++++++----------------- drivers/cxl/core/core.h | 7 ++----- drivers/cxl/core/port.c | 6 +----- drivers/cxl/core/ras.c | 12 +++++++----- include/cxl/event.h | 17 ++++++----------- 5 files changed, 31 insertions(+), 43 deletions(-)drivers/acpi/apei/ghes.c +15
-17@@ -778,41 +778,41 @@ static void cxl_cper_post_prot_err(struct cxl_cper_sec_prot_err *prot_err,#endif } -int cxl_cper_register_prot_err_work (struct work_struct *work) +void cxl_cper_register_prot_err_work (struct work_struct *work) {guard (raw_spinlock_irqsave)(&cxl_cper_prot_err_work_lock);if (WARN_ONCE (cxl_cper_prot_err_work,"CPER-CXL kfifo consumer already registered\n" )) -return -EINVAL ; +return ; cxl_cper_prot_err_work = work; -return 0 ; } -EXPORT_SYMBOL_NS_GPL (cxl_cper_register_prot_err_work,"CXL" ); +EXPORT_SYMBOL_FOR_MODULES (cxl_cper_register_prot_err_work,"cxl_core" ); -int cxl_cper_unregister_prot_err_work (struct work_struct *work) +void cxl_cper_unregister_prot_err_work (void ) { +struct work_struct *old; + scoped_guard(raw_spinlock_irqsave, &cxl_cper_prot_err_work_lock) { -if (WARN_ONCE (cxl_cper_prot_err_work != work, -"CPER-CXL kfifo consumer mismatch on unregister\n" )) -return -EINVAL ; +WARN_ONCE (!cxl_cper_prot_err_work, +"CPER-CXL kfifo consumer not registered on unregister\n" ); + old = cxl_cper_prot_err_work; cxl_cper_prot_err_work =NULL ; } -cancel_work_sync (work); +if (old) +cancel_work_sync (old);/* Discard stale entries so they are not replayed on next module load */ kfifo_reset (&cxl_cper_prot_err_fifo); - -return 0 ; } -EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_prot_err_work,"CXL" ); +EXPORT_SYMBOL_FOR_MODULES (cxl_cper_unregister_prot_err_work,"cxl_core" );int cxl_cper_prot_err_kfifo_get (struct cxl_cper_prot_err_work_data *wd) {return kfifo_get (&cxl_cper_prot_err_fifo, wd); } -EXPORT_SYMBOL_NS_GPL (cxl_cper_prot_err_kfifo_get,"CXL" ); +EXPORT_SYMBOL_FOR_MODULES (cxl_cper_prot_err_kfifo_get,"cxl_core" );/* Room for 8 entries for each of the 4 event log queues */ #define CXL_CPER_FIFO_DEPTH 32@@ -867,12 +867,12 @@ int cxl_cper_register_work(struct work_struct *work) }EXPORT_SYMBOL_NS_GPL (cxl_cper_register_work,"CXL" ); -int cxl_cper_unregister_work (struct work_struct *work) +void cxl_cper_unregister_work (struct work_struct *work) { scoped_guard(raw_spinlock_irqsave, &cxl_cper_work_lock) {if (WARN_ONCE (cxl_cper_work != work,"CXL CPER kfifo consumer mismatch on unregister\n" )) -return -EINVAL ; +return ; cxl_cper_work =NULL ; }@@ -880,8 +880,6 @@ int cxl_cper_unregister_work(struct work_struct *work)/* Discard stale entries so they are not replayed on next module load */ kfifo_reset (&cxl_cper_fifo); - -return 0 ; }EXPORT_SYMBOL_NS_GPL (cxl_cper_unregister_work,"CXL" );drivers/cxl/core/core.h +2
-5@@ -183,7 +183,7 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)return &port->dev; }#ifdef CONFIG_CXL_RAS -int cxl_ras_init (void ); +void cxl_ras_init (void );void cxl_ras_exit (void );bool cxl_handle_ras (struct device *dev,void __iomem *ras_base);void cxl_handle_cor_ras (struct device *dev,void __iomem *ras_base);@@ -192,10 +192,7 @@ void cxl_disable_rch_root_ints(struct cxl_dport *dport);void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds);void devm_cxl_dport_ras_setup (struct cxl_dport *dport);#else -static inline int cxl_ras_init (void ) -{ -return 0 ; -} +static inline void cxl_ras_init (void ) { }static inline void cxl_ras_exit (void ) { }static inline bool cxl_handle_ras (struct device *dev,void __iomem *ras_base) {drivers/cxl/core/port.c +1
-5@@ -2531,14 +2531,10 @@ static __init int cxl_core_init(void)if (rc) goto err_region; - rc =cxl_ras_init (); -if (rc) - goto err_ras; +cxl_ras_init ();return 0 ; -err_ras: -cxl_region_exit (); err_region:bus_unregister (&cxl_bus_type); err_bus:drivers/cxl/core/ras.c +7
-5@@ -104,8 +104,11 @@ void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data) }guard (device)(&pdev->dev); -if (!pdev->dev.driver) +if (!pdev->dev.driver) { +dev_warn_ratelimited (&pdev->dev, +"Device is unbound, abort CPER error handling\n" );return ; + } struct device *mem_dev __free(put_device) = bus_find_device( &cxl_bus_type,NULL , pdev, match_memdev_by_parent);@@ -129,15 +132,14 @@ 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); -int cxl_ras_init (void ) +void cxl_ras_init (void ) { -return cxl_cper_register_prot_err_work (&cxl_cper_prot_err_work); +cxl_cper_register_prot_err_work (&cxl_cper_prot_err_work); }void cxl_ras_exit (void ) { -cxl_cper_unregister_prot_err_work (&cxl_cper_prot_err_work); -cancel_work_sync (&cxl_cper_prot_err_work); +cxl_cper_unregister_prot_err_work (); }static void cxl_dport_map_ras (struct cxl_dport *dport)include/cxl/event.h +6
-11@@ -287,10 +287,10 @@ struct cxl_cper_prot_err_work_data {#ifdef CONFIG_ACPI_APEI_GHES int cxl_cper_register_work (struct work_struct *work); -int cxl_cper_unregister_work (struct work_struct *work); +void cxl_cper_unregister_work (struct work_struct *work);int cxl_cper_kfifo_get (struct cxl_cper_work_data *wd); -int cxl_cper_register_prot_err_work (struct work_struct *work); -int cxl_cper_unregister_prot_err_work (struct work_struct *work); +void cxl_cper_register_prot_err_work (struct work_struct *work); +void cxl_cper_unregister_prot_err_work (void );int cxl_cper_prot_err_kfifo_get (struct cxl_cper_prot_err_work_data *wd);#else static inline int cxl_cper_register_work (struct work_struct *work)@@ -298,21 +298,16 @@ static inline int cxl_cper_register_work(struct work_struct *work)return 0 ; } -static inline int cxl_cper_unregister_work (struct work_struct *work) -{ -return 0 ; -} +static inline void cxl_cper_unregister_work (struct work_struct *work) { }static inline int cxl_cper_kfifo_get (struct cxl_cper_work_data *wd) {return 0 ; } -static inline int cxl_cper_register_prot_err_work (struct work_struct *work) +static inline void cxl_cper_register_prot_err_work (struct work_struct *work) { -return 0 ; } -static inline int cxl_cper_unregister_prot_err_work (struct work_struct *work) +static inline void cxl_cper_unregister_prot_err_work (void ) { -return 0 ; }static inline int cxl_cper_prot_err_kfifo_get (struct cxl_cper_prot_err_work_data *wd) {
Jonathan Cameron
maintainerRe: [PATCH v18 03/13] cxl: Tighten CPER kfifo registration API and symbol visibility
In reply to Terry BowmanQuoted 2 lines · On Fri, 17 Jul 2026 17:26:56 -0500 Terry Bowman <[email protected]> wrote:
From: Dan Williams <[email protected]>
Hi Terry, Dan,
There are a few different things in here. Having them all together may make it a little harder to keep track of the different changes.
Quoted 6 lines
Tighten the CPER protocol error kfifo registration API and symbol visibility.
Use
EXPORT_SYMBOL_FOR_MODULES()instead ofEXPORT_SYMBOL_NS_GPL()for the CPER kfifo registration symbols. This names the consuming module explicitly and gives compile-time enforcement.
To me this is one patch.
Quoted 4 lines
Drop the
work_structargument from the unregister path. Change theWARN_ONCEcondition to a NULL check since there is no caller pointer to compare against anymore.
This is one.
Quoted 3 lines
Change register/unregister return types to void. Flag double registration with
WARN_ONCE()inside the lock instead of returning an error.
Another change.
That covers why for the register, for unregister maybe mention it was unchecked anyway.
Quoted 4 lines
Change
cxl_ras_init()to void because there is one consumer and one producer so the error return was unnecessary. Remove the now-dead error check incxl_core_init().
This is change
Quoted 3 lines
Add a diagnostic log when the driver is not bound in
cxl_cper_handle_prot_err().
Unrelated really to all the rest.
All nice changes and maybe a few of them can be combined but to me this is too many in one. Anyhow I might be letting perfect be enemy of good and all that so if others think it should go in as one then I'm fine with that.
Trivial thing inline todo with formatting consistency.
Quoted 22 lines
Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>---
Changes in v17 -> v18:
- New patch.--- drivers/acpi/apei/ghes.c | 32 +++++++++++++++----------------- drivers/cxl/core/core.h | 7 ++----- drivers/cxl/core/port.c | 6 +----- drivers/cxl/core/ras.c | 12 +++++++----- include/cxl/event.h | 17 ++++++----------- 5 files changed, 31 insertions(+), 43 deletions(-)include/cxl/event.h +0
-0
include/cxl/event.h struct cxl_cper_prot_err_work_data { · line 290
Quoted 6 lines
include/cxl/event.h +1
-2@@ -287,10 +287,10 @@ struct cxl_cper_prot_err_work_data { -static inline int cxl_cper_register_prot_err_work (struct work_struct *work) +static inline void cxl_cper_register_prot_err_work (struct work_struct *work) { -return 0 ; }
I'd go a bit long and move { } up. Compact stubs are always nice!
include/cxl/event.h static inline int cxl_cper_register_work(struct work_struct *work) · line 309
Quoted 2 lines
include/cxl/event.h +1
-1-static inline int cxl_cper_unregister_prot_err_work (struct work_struct *work) +static inline void cxl_cper_unregister_prot_err_work (void )
This one is shorter than the one you did it for above!
Quoted 5 lines
include/cxl/event.h +0
-1{ -return 0 ; }static inline int cxl_cper_prot_err_kfifo_get (struct cxl_cper_prot_err_work_data *wd) {
PATCH v18 4/13 cxl: Rename find_cxl_port() to find_cxl_port_by_dport()
In reply to Terry BowmanFrom: Dan Williams <[email protected]>
find_cxl_port() and find_cxl_port_by_uport() are internal port lookup functions that search the CXL bus by dport and uport respectively, but their names do not make the lookup method clear.
Rename find_cxl_port() to find_cxl_port_by_dport() to make the lookup method explicit and consistent with find_cxl_port_by_uport(). Both functions remain static to port.c; the upcoming patch that adds the first cross-file caller will widen their scope.
---
Changes in v17 -> v18:
- New commit
--- drivers/cxl/core/port.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
drivers/cxl/core/port.c +14 -6
@@ -1379,7 +1379,7 @@ static int match_port_by_dport(struct device *dev, const void *data)return dport !=NULL ; } -static struct cxl_port *__find_cxl_port (struct cxl_find_port_ctx *ctx) +static struct cxl_port *__find_cxl_port_by_dport (struct cxl_find_port_ctx *ctx) {struct device *dev;
@@ -1392,8 +1392,16 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)return NULL ; } -static struct cxl_port *find_cxl_port (struct device *dport_dev, -struct cxl_dport **dport) +/** +* find_cxl_port_by_dport - find a cxl_port by one of its targets +* @dport_dev: device representing the dport target +* @dport: optional output of the 'struct cxl_dport' companion of the @dport_dev +* +* 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_find_port_ctx ctx = { .dport_dev = dport_dev,
@@ -1401,7 +1409,7 @@ static struct cxl_port *find_cxl_port(struct device *dport_dev, };struct cxl_port *port; - port =__find_cxl_port (&ctx); + port =__find_cxl_port_by_dport (&ctx);return port; }
@@ -1895,14 +1903,14 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, "CXL");struct cxl_port *cxl_pci_find_port (struct pci_dev *pdev,struct cxl_dport **dport) { -return find_cxl_port (pdev->dev.parent, dport); +return find_cxl_port_by_dport (pdev->dev.parent, dport); }EXPORT_SYMBOL_NS_GPL (cxl_pci_find_port,"CXL" );struct cxl_port *cxl_mem_find_port (struct cxl_memdev *cxlmd,struct cxl_dport **dport) { -return find_cxl_port (grandparent (&cxlmd->dev), dport); +return find_cxl_port_by_dport (grandparent (&cxlmd->dev), dport); }EXPORT_SYMBOL_NS_GPL (cxl_mem_find_port,"CXL" );
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 04/13] cxl: Rename find_cxl_port() to find_cxl_port_by_dport()
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 6 lines
From: Dan Williams <[email protected]>
find_cxl_port()andfind_cxl_port_by_uport()are internal port lookup functions that search the CXL bus by dport and uport respectively, but their names do not make the lookup method clear.
Quoted 8 lines
Rename
find_cxl_port()tofind_cxl_port_by_dport()to make the lookup method explicit and consistent withfind_cxl_port_by_uport(). Both functions remain static toport.c; the upcoming patch that adds the first cross-file caller will widen their scope.Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Re: [PATCH v18 04/13] cxl: Rename find_cxl_port() to find_cxl_port_by_dport()
In reply to Terry BowmanQuoted 6 lines · Terry Bowman
From: Dan Williams <[email protected]>
find_cxl_port()andfind_cxl_port_by_uport()are internal port lookup functions that search the CXL bus by dport and uport respectively, but their names do not make the lookup method clear.
Quoted 8 lines
Rename
find_cxl_port()tofind_cxl_port_by_dport()to make the lookup method explicit and consistent withfind_cxl_port_by_uport(). Both functions remain static toport.c; the upcoming patch that adds the first cross-file caller will widen their scope.Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>
Quoted 67 lines
---
Changes in v17 -> v18:
- New commit--- drivers/cxl/core/port.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)drivers/cxl/core/port.c +14
-6@@ -1379,7 +1379,7 @@ static int match_port_by_dport(struct device *dev, const void *data)return dport !=NULL ; } -static struct cxl_port *__find_cxl_port (struct cxl_find_port_ctx *ctx) +static struct cxl_port *__find_cxl_port_by_dport (struct cxl_find_port_ctx *ctx) {struct device *dev;@@ -1392,8 +1392,16 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)return NULL ; } -static struct cxl_port *find_cxl_port (struct device *dport_dev, -struct cxl_dport **dport) +/** +* find_cxl_port_by_dport - find a cxl_port by one of its targets +* @dport_dev: device representing the dport target +* @dport: optional output of the 'struct cxl_dport' companion of the @dport_dev +* +* 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_find_port_ctx ctx = { .dport_dev = dport_dev,@@ -1401,7 +1409,7 @@ static struct cxl_port *find_cxl_port(struct device *dport_dev, };struct cxl_port *port; - port =__find_cxl_port (&ctx); + port =__find_cxl_port_by_dport (&ctx);return port; }@@ -1895,14 +1903,14 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, "CXL");struct cxl_port *cxl_pci_find_port (struct pci_dev *pdev,struct cxl_dport **dport) { -return find_cxl_port (pdev->dev.parent, dport); +return find_cxl_port_by_dport (pdev->dev.parent, dport); }EXPORT_SYMBOL_NS_GPL (cxl_pci_find_port,"CXL" );struct cxl_port *cxl_mem_find_port (struct cxl_memdev *cxlmd,struct cxl_dport **dport) { -return find_cxl_port (grandparent (&cxlmd->dev), dport); +return find_cxl_port_by_dport (grandparent (&cxlmd->dev), dport); }EXPORT_SYMBOL_NS_GPL (cxl_mem_find_port,"CXL" );
Re: [PATCH v18 04/13] cxl: Rename find_cxl_port() to find_cxl_port_by_dport()
In reply to Terry BowmanQuoted 10 lines · On Fri, 17 Jul 2026 17:26:57 -0500 Terry Bowman <[email protected]> wrote:
From: Dan Williams <[email protected]>
find_cxl_port()andfind_cxl_port_by_uport()are internal port lookup functions that search the CXL bus by dport and uport respectively, but their names do not make the lookup method clear.Rename
find_cxl_port()tofind_cxl_port_by_dport()to make the lookup method explicit and consistent withfind_cxl_port_by_uport(). Both functions remain static toport.c; the upcoming patch that adds the first cross-file caller will widen their scope.
Could have mentioned the __ one, but it is fairly obvious why you did that even without saying it.
Nice improvement
Quoted 71 lines
Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>---
Changes in v17 -> v18:
- New commit--- drivers/cxl/core/port.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)drivers/cxl/core/port.c +14
-6@@ -1379,7 +1379,7 @@ static int match_port_by_dport(struct device *dev, const void *data)return dport !=NULL ; } -static struct cxl_port *__find_cxl_port (struct cxl_find_port_ctx *ctx) +static struct cxl_port *__find_cxl_port_by_dport (struct cxl_find_port_ctx *ctx) {struct device *dev;@@ -1392,8 +1392,16 @@ static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx)return NULL ; } -static struct cxl_port *find_cxl_port (struct device *dport_dev, -struct cxl_dport **dport) +/** +* find_cxl_port_by_dport - find a cxl_port by one of its targets +* @dport_dev: device representing the dport target +* @dport: optional output of the 'struct cxl_dport' companion of the @dport_dev +* +* 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_find_port_ctx ctx = { .dport_dev = dport_dev,@@ -1401,7 +1409,7 @@ static struct cxl_port *find_cxl_port(struct device *dport_dev, };struct cxl_port *port; - port =__find_cxl_port (&ctx); + port =__find_cxl_port_by_dport (&ctx);return port; }@@ -1895,14 +1903,14 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, "CXL");struct cxl_port *cxl_pci_find_port (struct pci_dev *pdev,struct cxl_dport **dport) { -return find_cxl_port (pdev->dev.parent, dport); +return find_cxl_port_by_dport (pdev->dev.parent, dport); }EXPORT_SYMBOL_NS_GPL (cxl_pci_find_port,"CXL" );struct cxl_port *cxl_mem_find_port (struct cxl_memdev *cxlmd,struct cxl_dport **dport) { -return find_cxl_port (grandparent (&cxlmd->dev), dport); +return find_cxl_port_by_dport (grandparent (&cxlmd->dev), dport); }EXPORT_SYMBOL_NS_GPL (cxl_mem_find_port,"CXL" );
PATCH v18 5/13 PCI/AER: Introduce AER-CXL protocol error kfifo
In reply to Terry BowmanCXL VH RAS handling requires a path for the AER driver to hand off CXL protocol errors to cxl_core for logging and recovery before PCIe AER recovery tears down the device. Add drivers/pci/pcie/aer_cxl_vh.c to implement this handoff via a kfifo-backed work item.
Introduce is_aer_internal_error() to identify CXL protocol errors from AER internal error status bits across both correctable and uncorrectable severities.
Introduce is_cxl_error() to gate the VH kfifo path.
Introduce struct cxl_proto_err_work_data to carry the error source PCI device and severity through the kfifo. Encapsulate the kfifo, per-producer spinlock, registration rwsem, and work pointer in struct cxl_proto_err_kfifo. Initialize the embedded kfifo via INIT_KFIFO() from a subsys_initcall so its metadata is populated before any producer or consumer runs.
Introduce cxl_forward_error() to enqueue a CXL protocol error. A reference is taken on the PCI device; the consumer releases it via for_each_cxl_proto_err(). On enqueue failure the reference is released immediately, the error is dropped, and the consumer is scheduled to drain existing entries. A subsequent patch wires cxl_forward_error() into handle_error_source() where correctable and uncorrectable status clearing is left to pci_aer_handle_error().
Introduce cxl_proto_err_flush() to synchronously wait for the consumer worker to drain the kfifo. A subsequent patch wires this into handle_error_source() for UCE events so the CXL plane completes error handling and panic policy before pci_aer_handle_error() drives PCIe recovery.
Introduce cxl_register_proto_err_work() and cxl_unregister_proto_err_work() for cxl_core to register and deregister its work handler. On unregistration, pending kfifo entries are drained and their pdev references released before cancel_work_sync() runs. Export these and for_each_cxl_proto_err() via EXPORT_SYMBOL_FOR_MODULES restricted to cxl_core.
Protect the work pointer with a rwsem to correctly serialize registration, deregistration, enqueue, and dequeue against concurrent AER IRQ threads. Serialize concurrent kfifo writers with a spinlock.
Add MAINTAINERS entries for aer_cxl_vh.c and aer_cxl_rch.c under the CXL entry so CXL maintainers are CC'd on changes to the AER-CXL bridging code.
---
Changes in v17->v18:
- Remove correctable status clear from cxl_forward_error(); the AER core clears all status bits via pci_aer_handle_error() info->status writeback
- Schedule consumer on kfifo overflow so existing entries can be drained
Changes in v16->v17:
- Reword "kfifo semaphore" to "kfifo spinlock" to match fifo_lock.
- Defer the handle_error_source() is_cxl_error() switch to the patch that registers the kfifo consumer to keep each commit bisect-safe.
- Rename rwsema to rwsem
- Change CPER exports to use EXPORT_SYMBOL_FOR_MODULES.
- Add work cancel function.
- Replace kfifo_put() with kfifo_in_spinlocked() for multiple producers
- Add fifo_lock spinlock for concurrent producer serialisation
- Initialize the embedded kfifo with INIT_KFIFO() in a subsys_initcall so kfifo->mask, ->esize and ->data are set before first use.
- Clear PCI_ERR_COR_STATUS in cxl_forward_error() after enqueue so the device is acked for correctable events even when the consumer drops the event. Uncorrectable status is left for cxl_do_recovery() to clear after recovery completes, mirroring the AER core convention.
- WARN on double-registration in cxl_register_proto_err_work() to make an unintended second consumer visible at runtime.
- Add direct rwsem.h, cleanup.h and workqueue.h includes for symbols used in aer_cxl_vh.c
- Add MAINTAINERS entries for drivers/pci/pcie/aer_cxl_*.c
- Update message
--- MAINTAINERS | 2 + drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer.c | 10 -- drivers/pci/pcie/aer_cxl_vh.c | 221 ++++++++++++++++++++++++++++++++++ drivers/pci/pcie/portdrv.h | 6 + include/linux/aer.h | 24 ++++ 6 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 drivers/pci/pcie/aer_cxl_vh.c
MAINTAINERS +2 -0
@@ -6526,6 +6526,8 @@ S: Maintained F: Documentation/driver-api/cxl F: Documentation/userspace-api/fwctl/fwctl-cxl.rst F: drivers/cxl/ +F: drivers/pci/pcie/aer_cxl_rch.c +F: drivers/pci/pcie/aer_cxl_vh.c F: include/cxl/ F: include/uapi/linux/cxl_mem.h F: tools/testing/cxl/
drivers/pci/pcie/Makefile +1 -0
@@ -9,6 +9,7 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o bwctrl.o obj-y += aspm.o obj-$(CONFIG_PCIEAER) += aer.o err.o tlp.o obj-$(CONFIG_CXL_RAS) += aer_cxl_rch.o +obj-$(CONFIG_CXL_RAS) += aer_cxl_vh.o obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o obj-$(CONFIG_PCIE_PME) += pme.o obj-$(CONFIG_PCIE_DPC) += dpc.o
drivers/pci/pcie/aer.c +0 -10
@@ -1150,16 +1150,6 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)*/ EXPORT_SYMBOL_FOR_MODULES (pci_aer_unmask_internal_errors,"cxl_core" ); -#ifdef CONFIG_CXL_RAS -bool is_aer_internal_error (struct aer_err_info *info) -{ -if (info->severity ==AER_CORRECTABLE ) -return info->status &PCI_ERR_COR_INTERNAL ; - -return info->status &PCI_ERR_UNC_INTN ; -} -#endif -/** * pci_aer_handle_error - handle logging error into an event log * @dev: pointer to pci_dev data structure of error source device
drivers/pci/pcie/aer_cxl_vh.c new file +221 -0
221 lines not on this page · raw message
drivers/pci/pcie/portdrv.h +6 -0
@@ -130,9 +130,15 @@ struct aer_err_info;bool is_aer_internal_error (struct aer_err_info *info);void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info);void cxl_rch_enable_rcec (struct pci_dev *rcec); +bool is_cxl_error (struct pci_dev *pdev,struct aer_err_info *info); +bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info); +void cxl_proto_err_flush (void );#else static inline bool is_aer_internal_error (struct aer_err_info *info) {return false; }static inline void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) { }static inline void cxl_rch_enable_rcec (struct pci_dev *rcec) { } +static inline bool is_cxl_error (struct pci_dev *pdev,struct aer_err_info *info) {return false; } +static inline bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info) {return false; } +static inline void cxl_proto_err_flush (void ) { }#endif /* CONFIG_CXL_RAS */ #endif /* _PORTDRV_H_ */
include/linux/aer.h +24 -0
@@ -25,6 +25,7 @@#define PCIE_STD_MAX_TLP_HEADERLOG (PCIE_STD_NUM_TLP_HEADERLOG + 10)struct pci_dev ; +struct work_struct ; struct pcie_tlp_log { union {
@@ -66,6 +67,29 @@ static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }static inline void pci_aer_unmask_internal_errors (struct pci_dev *dev) { }#endif +#ifdef CONFIG_CXL_RAS +/** +* struct cxl_proto_err_work_data - Error information used in CXL error handling +* @pdev: PCI device detecting the error +* @severity: AER severity +*/ +struct cxl_proto_err_work_data { +struct pci_dev *pdev; +int severity; +}; + +/** +* Callback for processing a CXL protocol error from the AER-CXL kfifo. +*/ +typedef void (*cxl_proto_err_fn_t )(struct cxl_proto_err_work_data *wd); + +void cxl_register_proto_err_work (struct work_struct *work, +void (*flush)(void )); +void for_each_cxl_proto_err (struct cxl_proto_err_work_data *wd, +cxl_proto_err_fn_t fn); +void cxl_unregister_proto_err_work (void ); +#endif +void pci_print_aer (struct pci_dev *dev,int aer_severity,struct aer_capability_regs *aer);int cper_severity_to_aer (int cper_severity);
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 05/13] PCI/AER: Introduce AER-CXL protocol error kfifo
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 18 lines
CXL VH RAS handling requires a path for the AER driver to hand off CXL protocol errors to
cxl_corefor logging and recovery before PCIe AER recovery tears down the device. Adddrivers/pci/pcie/aer_cxl_vh.cto implement this handoff via a kfifo-backed work item.Introduce
is_aer_internal_error()to identify CXL protocol errors from AER internal error status bits across both correctable and uncorrectable severities.Introduce
is_cxl_error()to gate the VH kfifo path.Introduce struct
cxl_proto_err_work_datato carry the error source PCI device and severity through the kfifo. Encapsulate the kfifo, per-producer spinlock, registration rwsem, and work pointer in struct [ ... ]
bridging code.
Quoted 3 lines
Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
Re: [PATCH v18 05/13] PCI/AER: Introduce AER-CXL protocol error kfifo
In reply to Terry BowmanQuoted 44 lines · Terry Bowman
CXL VH RAS handling requires a path for the AER driver to hand off CXL protocol errors to
cxl_corefor logging and recovery before PCIe AER recovery tears down the device. Adddrivers/pci/pcie/aer_cxl_vh.cto implement this handoff via a kfifo-backed work item.Introduce
is_aer_internal_error()to identify CXL protocol errors from AER internal error status bits across both correctable and uncorrectable severities.Introduce
is_cxl_error()to gate the VH kfifo path.Introduce struct
cxl_proto_err_work_datato carry the error source PCI device and severity through the kfifo. Encapsulate the kfifo, per-producer spinlock, registration rwsem, and work pointer in structcxl_proto_err_kfifo. Initialize the embedded kfifo viaINIT_KFIFO()from asubsys_initcallso its metadata is populated before any producer or consumer runs.Introduce
cxl_forward_error()to enqueue a CXL protocol error. A reference is taken on the PCI device; the consumer releases it viafor_each_cxl_proto_err(). On enqueue failure the reference is released immediately, the error is dropped, and the consumer is scheduled to drain existing entries. A subsequent patch wirescxl_forward_error()intohandle_error_source()where correctable and uncorrectable status clearing is left topci_aer_handle_error().Introduce
cxl_proto_err_flush()to synchronously wait for the consumer worker to drain the kfifo. A subsequent patch wires this intohandle_error_source()for UCE events so the CXL plane completes error handling and panic policy beforepci_aer_handle_error()drives PCIe recovery.Introduce
cxl_register_proto_err_work()andcxl_unregister_proto_err_work()forcxl_coreto register and deregister its work handler. On unregistration, pending kfifo entries are drained and their pdev references released beforecancel_work_sync()runs. Export these andfor_each_cxl_proto_err()viaEXPORT_SYMBOL_FOR_MODULESrestricted tocxl_core.Protect the work pointer with a rwsem to correctly serialize registration, deregistration, enqueue, and dequeue against concurrent AER IRQ threads. Serialize concurrent kfifo writers with a spinlock.
Quoted 7 lines
Add
MAINTAINERSentries foraer_cxl_vh.candaer_cxl_rch.cunder the CXL entry so CXL maintainers are CC'd on changes to the AER-CXL bridging code.Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>
Quoted 374 lines
---
Changes in
v17->v18:
- Remove correctable status clear fromcxl_forward_error(); the AER core clears all status bits viapci_aer_handle_error()info->statuswriteback
- Schedule consumer on kfifo overflow so existing entries can be drainedChanges in
v16->v17:
- Reword "kfifo semaphore" to "kfifo spinlock" to matchfifo_lock.
- Defer thehandle_error_source()is_cxl_error()switch to the patch that registers the kfifo consumer to keep each commit bisect-safe.
- Rename rwsema to rwsem
- Change CPER exports to useEXPORT_SYMBOL_FOR_MODULES.
- Add work cancel function.
- Replacekfifo_put()withkfifo_in_spinlocked()for multiple producers
- Addfifo_lockspinlock for concurrent producer serialisation
- Initialize the embedded kfifo withINIT_KFIFO()in asubsys_initcallsokfifo->mask, ->esize and ->data are set before first use.
- ClearPCI_ERR_COR_STATUSincxl_forward_error()after enqueue so the device is acked for correctable events even when the consumer drops the event. Uncorrectable status is left forcxl_do_recovery()to clear after recovery completes, mirroring the AER core convention.
- WARN on double-registration incxl_register_proto_err_work()to make an unintended second consumer visible at runtime.
- Add directrwsem.h,cleanup.handworkqueue.hincludes for symbols used inaer_cxl_vh.c
- AddMAINTAINERSentries fordrivers/pci/pcie/aer_cxl_*.c
- Update message--- MAINTAINERS | 2 + drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer.c | 10 -- drivers/pci/pcie/aer_cxl_vh.c | 221 ++++++++++++++++++++++++++++++++++ drivers/pci/pcie/portdrv.h | 6 + include/linux/aer.h | 24 ++++ 6 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 drivers/pci/pcie/aer_cxl_vh.cMAINTAINERS +2
-0@@ -6526,6 +6526,8 @@ S: Maintained F: Documentation/driver-api/cxl F: Documentation/userspace-api/fwctl/fwctl-cxl.rst F: drivers/cxl/ +F: drivers/pci/pcie/aer_cxl_rch.c +F: drivers/pci/pcie/aer_cxl_vh.c F: include/cxl/ F: include/uapi/linux/cxl_mem.h F: tools/testing/cxl/drivers/pci/pcie/Makefile +1
-0@@ -9,6 +9,7 @@ obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o bwctrl.o obj-y += aspm.o obj-$(CONFIG_PCIEAER) += aer.o err.o tlp.o obj-$(CONFIG_CXL_RAS) += aer_cxl_rch.o +obj-$(CONFIG_CXL_RAS) += aer_cxl_vh.o obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o obj-$(CONFIG_PCIE_PME) += pme.o obj-$(CONFIG_PCIE_DPC) += dpc.odrivers/pci/pcie/aer.c +0
-10@@ -1150,16 +1150,6 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)*/ EXPORT_SYMBOL_FOR_MODULES (pci_aer_unmask_internal_errors,"cxl_core" ); -#ifdef CONFIG_CXL_RAS -bool is_aer_internal_error (struct aer_err_info *info) -{ -if (info->severity ==AER_CORRECTABLE ) -return info->status &PCI_ERR_COR_INTERNAL ; - -return info->status &PCI_ERR_UNC_INTN ; -} -#endif -/** * pci_aer_handle_error - handle logging error into an event log * @dev: pointer to pci_dev data structure of error source device drivers/pci/pcie/aer_cxl_vh.c new file +221
-0@@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2026 AMD Corporation. All rights reserved. */ + +#include <linux/aer.h> +#include <linux/atomic.h> +#include <linux/cleanup.h> +#include <linux/init.h> +#include <linux/kfifo.h> +#include <linux/rwsem.h> +#include <linux/wait_bit.h> +#include <linux/workqueue.h> +#include "../pci.h" +#include "portdrv.h" + +#define CXL_ERROR_SOURCES_MAX 128 + +struct cxl_proto_err_kfifo { +struct work_struct *work; +void (*flush)(void ); +struct rw_semaphore rwsem; +spinlock_t fifo_lock; +atomic_t flush_inflight; + DECLARE_KFIFO(fifo, struct cxl_proto_err_work_data, + CXL_ERROR_SOURCES_MAX); +}; + +static struct cxl_proto_err_kfifo cxl_proto_err_kfifo = { + .rwsem =__RWSEM_INITIALIZER (cxl_proto_err_kfifo.rwsem), + .fifo_lock =__SPIN_LOCK_UNLOCKED (cxl_proto_err_kfifo.fifo_lock), +}; + +static int __init cxl_proto_err_kfifo_init (void ) +{ +INIT_KFIFO (cxl_proto_err_kfifo.fifo); +return 0 ; +} +subsys_initcall (cxl_proto_err_kfifo_init); + +bool is_aer_internal_error (struct aer_err_info *info) +{ +if (info->severity ==AER_CORRECTABLE ) +return info->status &PCI_ERR_COR_INTERNAL ; + +return info->status &PCI_ERR_UNC_INTN ; +} + +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 ) +return false; + +return is_aer_internal_error (info); +} + +/** +* cxl_forward_error - Forward a CXL protocol error to the CXL subsystem via kfifo +* @pdev: PCI device that reported the AER error +* @info: AER error info containing severity and status +* +* Producer side of the AER-CXL kfifo. Enqueues a CXL protocol error work +* item and schedules the consumer workqueue. Takes a reference on @pdev +* that the consumer releases after handling. +* +* Return: true if the caller must flush the kfifo before AER recovery, +* false if no CXL error handling was initiated due to early return on +* error. +*/ +bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info) +{ +struct cxl_proto_err_work_data wd = { + .severity = info->severity, + .pdev = pdev, + }; + +guard (rwsem_read)(&cxl_proto_err_kfifo.rwsem); + +if (!cxl_proto_err_kfifo.work) { +dev_err_ratelimited (&pdev->dev,"AER-CXL kfifo reader not registered\n" ); +return false; + } + +/* +* Reference discipline: the AER caller (handle_error_source()) +* holds a ref on @pdev for the duration of this call and releases +* it on return. Take a fresh ref here so the pdev stays live while +* queued in the kfifo; the consumer (for_each_cxl_proto_err()) +* drops that ref after handling. On enqueue failure below, drop +* the ref we just took to avoid a leak. +*/ +pci_dev_get (pdev); + +/* Serialize concurrent kfifo writers: multiple AER threaded IRQs */ +if (!kfifo_in_spinlocked (&cxl_proto_err_kfifo.fifo, &wd,1 , + &cxl_proto_err_kfifo.fifo_lock)) { +/* Dropped; no panic - UCE unconfirmed without RAS read */ +dev_err_ratelimited (&pdev->dev,"AER-CXL kfifo add failed\n" ); +pci_dev_put (pdev); +schedule_work (cxl_proto_err_kfifo.work); +return true; + } + +schedule_work (cxl_proto_err_kfifo.work); +return true; +} + +void cxl_register_proto_err_work (struct work_struct *work, +void (*flush)(void )) +{ +guard (rwsem_write)(&cxl_proto_err_kfifo.rwsem); + +/* +* Warn on double-registration to surface driver bugs (e.g. missing +* cxl_unregister_proto_err_work() on module exit) +*/ +if (WARN (cxl_proto_err_kfifo.work, +"AER-CXL kfifo consumer already registered\n" )) +return ; + cxl_proto_err_kfifo.work = work; + cxl_proto_err_kfifo.flush = flush; +} +EXPORT_SYMBOL_FOR_MODULES (cxl_register_proto_err_work,"cxl_core" ); + +static struct work_struct *cancel_cxl_proto_err (void ) +{ +struct work_struct *work; +struct cxl_proto_err_work_data wd; + +guard (rwsem_write)(&cxl_proto_err_kfifo.rwsem); + work = cxl_proto_err_kfifo.work; + cxl_proto_err_kfifo.work =NULL ; + cxl_proto_err_kfifo.flush =NULL ; + +/* rwsem_write excludes all producers; fifo_lock not needed */ +while (kfifo_get (&cxl_proto_err_kfifo.fifo, &wd)) { +dev_err_ratelimited (&wd.pdev->dev, +"AER-CXL error report canceled\n" ); +pci_dev_put (wd.pdev); + } +return work; +} + +void cxl_unregister_proto_err_work (void ) +{ +struct work_struct *work; + +lockdep_assert_not_held (&cxl_proto_err_kfifo.rwsem); + + work =cancel_cxl_proto_err (); + +/* Wait for any in-flight cxl_proto_err_flush() calls to complete */ +wait_var_event (&cxl_proto_err_kfifo.flush_inflight, +atomic_read (&cxl_proto_err_kfifo.flush_inflight) ==0 ); + +if (work) +cancel_work_sync (work); +} +EXPORT_SYMBOL_FOR_MODULES (cxl_unregister_proto_err_work,"cxl_core" ); + +/** +* for_each_cxl_proto_err - Call a function for each kfifo work item +* +* Single-consumer invariant: this function is only called from +* cxl_proto_err_work_fn() via a single DECLARE_WORK. +* +* Holds rwsem_read internally; fn() must not call cxl_register_proto_err_work() +* or cxl_unregister_proto_err_work(). +*/ +void for_each_cxl_proto_err (struct cxl_proto_err_work_data *wd, +cxl_proto_err_fn_t fn) +{ +guard (rwsem_read)(&cxl_proto_err_kfifo.rwsem); +while (kfifo_get (&cxl_proto_err_kfifo.fifo, wd)) { +fn (wd); +pci_dev_put (wd->pdev); + } +} +EXPORT_SYMBOL_FOR_MODULES (for_each_cxl_proto_err,"cxl_core" ); + +/** +* cxl_proto_err_flush - drain pending AER-CXL kfifo work synchronously +* +* Wait for the consumer worker to finish processing all entries +* currently in the kfifo. Used by handle_error_source() for UCE so +* the CXL plane can read CXL RAS, apply panic policy, and clear CXL +* state before pci_aer_handle_error() drives PCIe recovery. +* +* Snapshots the flush callback under rwsem_read and releases the rwsem +* before calling it. This avoids holding rwsem_read across flush_work(), +* which would deadlock via the rwsem HANDOFF mechanism when a concurrent +* rwsem_write waiter (cxl_unregister_proto_err_work) blocks new readers +* including the worker's for_each_cxl_proto_err() rwsem_read acquisition. +* +* The flush_inflight counter prevents cxl_core module unload while a +* flush is in progress outside the rwsem. The counter is incremented +* under rwsem_read (mutually exclusive with the rwsem_write in +* cancel_cxl_proto_err() that NULLs the flush pointer) and decremented +* after the flush completes. cxl_unregister_proto_err_work() waits for +* the counter to reach zero before proceeding with cancel_work_sync(). +* +* For correctable events the consumer can run asynchronously; AER +* does not need to call this helper for AER_CORRECTABLE. +*/ +void cxl_proto_err_flush (void ) +{ +void (*flush)(void ); + + scoped_guard(rwsem_read, &cxl_proto_err_kfifo.rwsem) { + flush = cxl_proto_err_kfifo.flush; +if (flush) +atomic_inc (&cxl_proto_err_kfifo.flush_inflight); + } + +if (flush) { +flush (); +if (atomic_dec_and_test (&cxl_proto_err_kfifo.flush_inflight)) +wake_up_var (&cxl_proto_err_kfifo.flush_inflight); + } +}drivers/pci/pcie/portdrv.h +6
-0@@ -130,9 +130,15 @@ struct aer_err_info;bool is_aer_internal_error (struct aer_err_info *info);void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info);void cxl_rch_enable_rcec (struct pci_dev *rcec); +bool is_cxl_error (struct pci_dev *pdev,struct aer_err_info *info); +bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info); +void cxl_proto_err_flush (void );#else static inline bool is_aer_internal_error (struct aer_err_info *info) {return false; }static inline void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) { }static inline void cxl_rch_enable_rcec (struct pci_dev *rcec) { } +static inline bool is_cxl_error (struct pci_dev *pdev,struct aer_err_info *info) {return false; } +static inline bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info) {return false; } +static inline void cxl_proto_err_flush (void ) { }#endif /* CONFIG_CXL_RAS */ #endif /* _PORTDRV_H_ */ include/linux/aer.h +24
-0@@ -25,6 +25,7 @@#define PCIE_STD_MAX_TLP_HEADERLOG (PCIE_STD_NUM_TLP_HEADERLOG + 10)struct pci_dev ; +struct work_struct ; struct pcie_tlp_log { union {@@ -66,6 +67,29 @@ static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }static inline void pci_aer_unmask_internal_errors (struct pci_dev *dev) { }#endif +#ifdef CONFIG_CXL_RAS +/** +* struct cxl_proto_err_work_data - Error information used in CXL error handling +* @pdev: PCI device detecting the error +* @severity: AER severity +*/ +struct cxl_proto_err_work_data { +struct pci_dev *pdev; +int severity; +}; + +/** +* Callback for processing a CXL protocol error from the AER-CXL kfifo. +*/ +typedef void (*cxl_proto_err_fn_t )(struct cxl_proto_err_work_data *wd); + +void cxl_register_proto_err_work (struct work_struct *work, +void (*flush)(void )); +void for_each_cxl_proto_err (struct cxl_proto_err_work_data *wd, +cxl_proto_err_fn_t fn); +void cxl_unregister_proto_err_work (void ); +#endif +void pci_print_aer (struct pci_dev *dev,int aer_severity,struct aer_capability_regs *aer);int cper_severity_to_aer (int cper_severity);
Jonathan Cameron
maintainerRe: [PATCH v18 05/13] PCI/AER: Introduce AER-CXL protocol error kfifo
In reply to Terry BowmanOn Fri, 17 Jul 2026 17:26:58 -0500
Terry Bowman <[email protected]> wrote:
Hi Terry.
This is a rather length patch description. Might be worth a parse to see if key details can be covered in something that folk are more likely to read!
Quoted 9 lines
CXL VH RAS handling requires a path for the AER driver to hand off CXL protocol errors to
cxl_corefor logging and recovery before PCIe AER recovery tears down the device. Adddrivers/pci/pcie/aer_cxl_vh.cto implement this handoff via a kfifo-backed work item.Introduce
is_aer_internal_error()to identify CXL protocol errors from AER internal error status bits across both correctable and uncorrectable severities.
Already existed. Just in a different location.
Quoted 2 lines
Introduce
is_cxl_error()to gate the VH kfifo path.
Feels like to much detail to me given not really anything to say about it other than the obvious.
Quoted 5 lines
Introduce struct
cxl_proto_err_work_datato carry the error source PCI device and severity through the kfifo. Encapsulate the kfifo, per-producer spinlock, registration rwsem, and work pointer in structcxl_proto_err_kfifo. Initialize the embedded kfifo viaINIT_KFIFO()
Can we cut this down a little where we don't use useful info. e.g. "Initialize the kfifo from a subsys_initcall() to it is ready before any producer or consumer runs."
Quoted 9 lines
from a
subsys_initcallso its metadata is populated before any producer or consumer runs.Introduce
cxl_forward_error()to enqueue a CXL protocol error. A reference is taken on the PCI device; the consumer releases it viafor_each_cxl_proto_err(). On enqueue failure the reference is released immediately, the error is dropped, and the consumer is scheduled to drain existing entries.
We don't need to cover error paths in the patch description unless they are really complex and need explanation. Even then probably belongs more in comments.
Anyhow you get the idea..
Quoted 17 lines
A subsequent patch wires
cxl_forward_error()intohandle_error_source()where correctable and uncorrectable status clearing is left topci_aer_handle_error().Introduce
cxl_proto_err_flush()to synchronously wait for the consumer worker to drain the kfifo. A subsequent patch wires this intohandle_error_source()for UCE events so the CXL plane completes error handling and panic policy beforepci_aer_handle_error()drives PCIe recovery.Introduce
cxl_register_proto_err_work()andcxl_unregister_proto_err_work()forcxl_coreto register and deregister its work handler. On unregistration, pending kfifo entries are drained and their pdev references released beforecancel_work_sync()runs. Export these andfor_each_cxl_proto_err()viaEXPORT_SYMBOL_FOR_MODULESrestricted tocxl_core.
Quoted 7 lines
Protect the work pointer with a rwsem to correctly serialize registration, deregistration, enqueue, and dequeue against concurrent AER IRQ threads. Serialize concurrent kfifo writers with a spinlock.
Add
MAINTAINERSentries foraer_cxl_vh.candaer_cxl_rch.cunder the CXL entry so CXL maintainers are CC'd on changes to the AER-CXL bridging code.
Various things inline. The one potential thing I'd like to highlight is the loss of tracking assume panic isn't appropriate. My paranoid hat says always go the other way. If we don't know we didn't lose an uncorrectable error panic. Maybe it's worth us considering when this might happen in a real system?
Quoted 51 lines
Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>---
Changes in
v17->v18:
- Remove correctable status clear fromcxl_forward_error(); the AER core clears all status bits viapci_aer_handle_error()info->statuswriteback
- Schedule consumer on kfifo overflow so existing entries can be drainedChanges in
v16->v17:
- Reword "kfifo semaphore" to "kfifo spinlock" to matchfifo_lock.
- Defer thehandle_error_source()is_cxl_error()switch to the patch that registers the kfifo consumer to keep each commit bisect-safe.
- Rename rwsema to rwsem
- Change CPER exports to useEXPORT_SYMBOL_FOR_MODULES.
- Add work cancel function.
- Replacekfifo_put()withkfifo_in_spinlocked()for multiple producers
- Addfifo_lockspinlock for concurrent producer serialisation
- Initialize the embedded kfifo withINIT_KFIFO()in asubsys_initcallsokfifo->mask, ->esize and ->data are set before first use.
- ClearPCI_ERR_COR_STATUSincxl_forward_error()after enqueue so the device is acked for correctable events even when the consumer drops the event. Uncorrectable status is left forcxl_do_recovery()to clear after recovery completes, mirroring the AER core convention.
- WARN on double-registration incxl_register_proto_err_work()to make an unintended second consumer visible at runtime.
- Add directrwsem.h,cleanup.handworkqueue.hincludes for symbols used inaer_cxl_vh.c
- AddMAINTAINERSentries fordrivers/pci/pcie/aer_cxl_*.c
- Update message--- MAINTAINERS | 2 + drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer.c | 10 -- drivers/pci/pcie/aer_cxl_vh.c | 221 ++++++++++++++++++++++++++++++++++ drivers/pci/pcie/portdrv.h | 6 + include/linux/aer.h | 24 ++++ 6 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 drivers/pci/pcie/aer_cxl_vh.cdrivers/pci/pcie/aer_cxl_vh.c new file +0
-0
drivers/pci/pcie/aer_cxl_vh.c line 9
Quoted 9 lines
drivers/pci/pcie/aer_cxl_vh.c new file +9
-0@@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2026 AMD Corporation. All rights reserved. */ + +#include <linux/aer.h> +#include <linux/atomic.h> +#include <linux/cleanup.h> +#include <linux/init.h> +#include <linux/kfifo.h> +#include <linux/rwsem.h>
Check these. I'd expect at least spinlock.h to meet the rough include what you use aim.
drivers/pci/pcie/aer_cxl_vh.c line 21
Quoted 12 lines
drivers/pci/pcie/aer_cxl_vh.c new file +12
-0+#include <linux/wait_bit.h> +#include <linux/workqueue.h> +#include "../pci.h" +#include "portdrv.h" + +#define CXL_ERROR_SOURCES_MAX 128 + +struct cxl_proto_err_kfifo { +struct work_struct *work; +void (*flush)(void ); +struct rw_semaphore rwsem; +spinlock_t fifo_lock;
Ideally add a quick comment to every lock to say what data it covers. Kind of obvious for this one but in general it is good practice and reduces chance of later scope confusion.
Quoted 29 lines
drivers/pci/pcie/aer_cxl_vh.c new file +28
-0+atomic_t flush_inflight; + DECLARE_KFIFO(fifo, struct cxl_proto_err_work_data, +CXL_ERROR_SOURCES_MAX ); +}; +/** +* cxl_forward_error - Forward a CXL protocol error to the CXL subsystem via kfifo +* @pdev: PCI device that reported the AER error +* @info: AER error info containing severity and status +* +* Producer side of the AER-CXL kfifo. Enqueues a CXL protocol error work +* item and schedules the consumer workqueue. Takes a reference on @pdev +* that the consumer releases after handling. +* +* Return: true if the caller must flush the kfifo before AER recovery, +* false if no CXL error handling was initiated due to early return on +* error. +*/ +bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info) +{ +struct cxl_proto_err_work_data wd = { + .severity = info->severity, + .pdev = pdev, + }; + +guard (rwsem_read)(&cxl_proto_err_kfifo.rwsem); + +if (!cxl_proto_err_kfifo.work) { +dev_err_ratelimited (&pdev->dev,"AER-CXL kfifo reader not registered\n" );
drivers/pci/pcie/aer_cxl_vh.c line 91
Quoted 10 lines
drivers/pci/pcie/aer_cxl_vh.c new file +10
-0+return false; + } + +/* +* Reference discipline: the AER caller (handle_error_source()) +* holds a ref on @pdev for the duration of this call and releases +* it on return. Take a fresh ref here so the pdev stays live while +* queued in the kfifo; the consumer (for_each_cxl_proto_err()) +* drops that ref after handling. On enqueue failure below, drop +* the ref we just took to avoid a leak.
Most of this is useful. The what we do in error handling (given so local) probably not.
drivers/pci/pcie/aer_cxl_vh.c line 98
Quoted 7 lines
drivers/pci/pcie/aer_cxl_vh.c new file +7
-0+*/ +pci_dev_get (pdev); + +/* Serialize concurrent kfifo writers: multiple AER threaded IRQs */ +if (!kfifo_in_spinlocked (&cxl_proto_err_kfifo.fifo, &wd,1 , + &cxl_proto_err_kfifo.fifo_lock)) { +/* Dropped; no panic - UCE unconfirmed without RAS read */
Hmm. That's interesting. To me it fails the normal ras thing of assume the worst if we lost track. I'd panic. But I'm open to other views on this!
drivers/pci/pcie/aer_cxl_vh.c line 101
Quoted 3 lines
drivers/pci/pcie/aer_cxl_vh.c new file +3
-0+dev_err_ratelimited (&pdev->dev,"AER-CXL kfifo add failed\n" ); +pci_dev_put (pdev); +schedule_work (cxl_proto_err_kfifo.work);
Shared with below. Maybe just drop out of the if unless this gets more complex in later patches.
Quoted 13 lines
drivers/pci/pcie/aer_cxl_vh.c new file +11
-0+return true; + } + +schedule_work (cxl_proto_err_kfifo.work); +return true; +} +/** +* for_each_cxl_proto_err - Call a function for each kfifo work item +* +* Single-consumer invariant: this function is only called from +* cxl_proto_err_work_fn() via a single DECLARE_WORK.
drivers/pci/pcie/aer_cxl_vh.c line 176
Quoted 10 lines
drivers/pci/pcie/aer_cxl_vh.c new file +10
-0+* +* Holds rwsem_read internally; fn() must not call cxl_register_proto_err_work() +* or cxl_unregister_proto_err_work(). +*/ +void for_each_cxl_proto_err (struct cxl_proto_err_work_data *wd, +cxl_proto_err_fn_t fn) +{ +guard (rwsem_read)(&cxl_proto_err_kfifo.rwsem); +while (kfifo_get (&cxl_proto_err_kfifo.fifo, wd)) { +fn (wd);
Like the earlier case I razed, I'd like a comment here to say where the reference we re releasing was taken.
Quoted 15 lines
drivers/pci/pcie/aer_cxl_vh.c new file +15
-0+pci_dev_put (wd->pdev); + } +} +EXPORT_SYMBOL_FOR_MODULES (for_each_cxl_proto_err,"cxl_core" ); + +/** +* cxl_proto_err_flush - drain pending AER-CXL kfifo work synchronously +* +* Wait for the consumer worker to finish processing all entries +* currently in the kfifo. Used by handle_error_source() for UCE so +* the CXL plane can read CXL RAS, apply panic policy, and clear CXL +* state before pci_aer_handle_error() drives PCIe recovery. +* +* Snapshots the flush callback under rwsem_read and releases the rwsem +* before calling it. This avoids holding rwsem_read across flush_work(),
drivers/pci/pcie/aer_cxl_vh.c line 201
Quoted 10 lines
drivers/pci/pcie/aer_cxl_vh.c new file +10
-0+* which would deadlock via the rwsem HANDOFF mechanism when a concurrent +* rwsem_write waiter (cxl_unregister_proto_err_work) blocks new readers +* including the worker's for_each_cxl_proto_err() rwsem_read acquisition. +* +* The flush_inflight counter prevents cxl_core module unload while a +* flush is in progress outside the rwsem. The counter is incremented +* under rwsem_read (mutually exclusive with the rwsem_write in +* cancel_cxl_proto_err() that NULLs the flush pointer) and decremented +* after the flush completes. cxl_unregister_proto_err_work() waits for +* the counter to reach zero before proceeding with cancel_work_sync().
I can't see it from just this patch so it might be useful to say if the counter is ever not equal to 1 or 0. If it isn't can we make that explicit in the code?
Quoted 3 lines
+ *
+ * For correctable events the consumer can run asynchronously; AER
+ * does not need to call this helper forAER_CORRECTABLE.
For me this is both too much and likely to rot over time. Some stuff feels like it belongs with the flags it is talking about rather than here.
Quoted 17 lines
+ */
drivers/pci/pcie/aer_cxl_vh.c new file +16
-0+void cxl_proto_err_flush (void ) +{ +void (*flush)(void ); + + scoped_guard(rwsem_read, &cxl_proto_err_kfifo.rwsem) { + flush = cxl_proto_err_kfifo.flush; +if (flush) +atomic_inc (&cxl_proto_err_kfifo.flush_inflight); + } + +if (flush) { +flush (); +if (atomic_dec_and_test (&cxl_proto_err_kfifo.flush_inflight)) +wake_up_var (&cxl_proto_err_kfifo.flush_inflight); + } +}
Re: [PATCH v18 05/13] PCI/AER: Introduce AER-CXL protocol error kfifo
Quoted 208 lines · Jonathan Cameron
On Fri, 17 Jul 2026 17:26:58 -0500
Terry Bowman <[email protected]> wrote:Hi Terry.
This is a rather length patch description. Might be worth a parse to see if key details can be covered in something that folk are more likely to read!
Quoted 9 lines
CXL VH RAS handling requires a path for the AER driver to hand off CXL protocol errors to
cxl_corefor logging and recovery before PCIe AER recovery tears down the device. Adddrivers/pci/pcie/aer_cxl_vh.cto implement this handoff via a kfifo-backed work item.Introduce
is_aer_internal_error()to identify CXL protocol errors from AER internal error status bits across both correctable and uncorrectable severities.Already existed. Just in a different location.
Quoted 2 lines
Introduce
is_cxl_error()to gate the VH kfifo path.Feels like to much detail to me given not really anything to say about it other than the obvious.
Quoted 5 lines
Introduce struct
cxl_proto_err_work_datato carry the error source PCI device and severity through the kfifo. Encapsulate the kfifo, per-producer spinlock, registration rwsem, and work pointer in structcxl_proto_err_kfifo. Initialize the embedded kfifo viaINIT_KFIFO()Can we cut this down a little where we don't use useful info. e.g. "Initialize the kfifo from a
subsys_initcall()to it is ready before any producer or consumer runs."Quoted 9 lines
from a
subsys_initcallso its metadata is populated before any producer or consumer runs.Introduce
cxl_forward_error()to enqueue a CXL protocol error. A reference is taken on the PCI device; the consumer releases it viafor_each_cxl_proto_err(). On enqueue failure the reference is released immediately, the error is dropped, and the consumer is scheduled to drain existing entries.We don't need to cover error paths in the patch description unless they are really complex and need explanation. Even then probably belongs more in comments.
Anyhow you get the idea..
Quoted 17 lines
A subsequent patch wires
cxl_forward_error()intohandle_error_source()where correctable and uncorrectable status clearing is left topci_aer_handle_error().Introduce
cxl_proto_err_flush()to synchronously wait for the consumer worker to drain the kfifo. A subsequent patch wires this intohandle_error_source()for UCE events so the CXL plane completes error handling and panic policy beforepci_aer_handle_error()drives PCIe recovery.Introduce
cxl_register_proto_err_work()andcxl_unregister_proto_err_work()forcxl_coreto register and deregister its work handler. On unregistration, pending kfifo entries are drained and their pdev references released beforecancel_work_sync()runs. Export these andfor_each_cxl_proto_err()viaEXPORT_SYMBOL_FOR_MODULESrestricted tocxl_core.Quoted 7 lines
Protect the work pointer with a rwsem to correctly serialize registration, deregistration, enqueue, and dequeue against concurrent AER IRQ threads. Serialize concurrent kfifo writers with a spinlock.
Add
MAINTAINERSentries foraer_cxl_vh.candaer_cxl_rch.cunder the CXL entry so CXL maintainers are CC'd on changes to the AER-CXL bridging code.Various things inline. The one potential thing I'd like to highlight is the loss of tracking assume panic isn't appropriate. My paranoid hat says always go the other way. If we don't know we didn't lose an uncorrectable error panic. Maybe it's worth us considering when this might happen in a real system?
Quoted 51 lines
Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>---
Changes in
v17->v18:
- Remove correctable status clear fromcxl_forward_error(); the AER core clears all status bits viapci_aer_handle_error()info->statuswriteback
- Schedule consumer on kfifo overflow so existing entries can be drainedChanges in
v16->v17:
- Reword "kfifo semaphore" to "kfifo spinlock" to matchfifo_lock.
- Defer thehandle_error_source()is_cxl_error()switch to the patch that registers the kfifo consumer to keep each commit bisect-safe.
- Rename rwsema to rwsem
- Change CPER exports to useEXPORT_SYMBOL_FOR_MODULES.
- Add work cancel function.
- Replacekfifo_put()withkfifo_in_spinlocked()for multiple producers
- Addfifo_lockspinlock for concurrent producer serialisation
- Initialize the embedded kfifo withINIT_KFIFO()in asubsys_initcallsokfifo->mask, ->esize and ->data are set before first use.
- ClearPCI_ERR_COR_STATUSincxl_forward_error()after enqueue so the device is acked for correctable events even when the consumer drops the event. Uncorrectable status is left forcxl_do_recovery()to clear after recovery completes, mirroring the AER core convention.
- WARN on double-registration incxl_register_proto_err_work()to make an unintended second consumer visible at runtime.
- Add directrwsem.h,cleanup.handworkqueue.hincludes for symbols used inaer_cxl_vh.c
- AddMAINTAINERSentries fordrivers/pci/pcie/aer_cxl_*.c
- Update message--- MAINTAINERS | 2 + drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer.c | 10 -- drivers/pci/pcie/aer_cxl_vh.c | 221 ++++++++++++++++++++++++++++++++++ drivers/pci/pcie/portdrv.h | 6 + include/linux/aer.h | 24 ++++ 6 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 drivers/pci/pcie/aer_cxl_vh.cdrivers/pci/pcie/aer_cxl_vh.c new file +0
-0drivers/pci/pcie/aer_cxl_vh.c line 9
Quoted 9 lines
drivers/pci/pcie/aer_cxl_vh.c new file +9
-0@@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2026 AMD Corporation. All rights reserved. */ + +#include <linux/aer.h> +#include <linux/atomic.h> +#include <linux/cleanup.h> +#include <linux/init.h> +#include <linux/kfifo.h> +#include <linux/rwsem.h> Check these. I'd expect at least
spinlock.hto meet the rough include what you use aim.drivers/pci/pcie/aer_cxl_vh.c line 21
Quoted 12 lines
drivers/pci/pcie/aer_cxl_vh.c new file +12
-0+#include <linux/wait_bit.h> +#include <linux/workqueue.h> +#include "../pci.h" +#include "portdrv.h" + +#define CXL_ERROR_SOURCES_MAX 128 + +struct cxl_proto_err_kfifo { +struct work_struct *work; +void (*flush)(void ); +struct rw_semaphore rwsem; +spinlock_t fifo_lock;Ideally add a quick comment to every lock to say what data it covers. Kind of obvious for this one but in general it is good practice and reduces chance of later scope confusion.
Quoted 29 lines
drivers/pci/pcie/aer_cxl_vh.c new file +28
-0+atomic_t flush_inflight; + DECLARE_KFIFO(fifo, struct cxl_proto_err_work_data, +CXL_ERROR_SOURCES_MAX ); +}; +/** +* cxl_forward_error - Forward a CXL protocol error to the CXL subsystem via kfifo +* @pdev: PCI device that reported the AER error +* @info: AER error info containing severity and status +* +* Producer side of the AER-CXL kfifo. Enqueues a CXL protocol error work +* item and schedules the consumer workqueue. Takes a reference on @pdev +* that the consumer releases after handling. +* +* Return: true if the caller must flush the kfifo before AER recovery, +* false if no CXL error handling was initiated due to early return on +* error. +*/ +bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info) +{ +struct cxl_proto_err_work_data wd = { + .severity = info->severity, + .pdev = pdev, + }; + +guard (rwsem_read)(&cxl_proto_err_kfifo.rwsem); + +if (!cxl_proto_err_kfifo.work) { +dev_err_ratelimited (&pdev->dev,"AER-CXL kfifo reader not registered\n" );drivers/pci/pcie/aer_cxl_vh.c line 91
Quoted 10 lines
drivers/pci/pcie/aer_cxl_vh.c new file +10
-0+return false; + } + +/* +* Reference discipline: the AER caller (handle_error_source()) +* holds a ref on @pdev for the duration of this call and releases +* it on return. Take a fresh ref here so the pdev stays live while +* queued in the kfifo; the consumer (for_each_cxl_proto_err()) +* drops that ref after handling. On enqueue failure below, drop +* the ref we just took to avoid a leak. Most of this is useful. The what we do in error handling (given so local) probably not.
Quoted 11 lines
drivers/pci/pcie/aer_cxl_vh.c line 98
Quoted 7 lines
drivers/pci/pcie/aer_cxl_vh.c new file +7
-0+*/ +pci_dev_get (pdev); + +/* Serialize concurrent kfifo writers: multiple AER threaded IRQs */ +if (!kfifo_in_spinlocked (&cxl_proto_err_kfifo.fifo, &wd,1 , + &cxl_proto_err_kfifo.fifo_lock)) { +/* Dropped; no panic - UCE unconfirmed without RAS read */ Hmm. That's interesting. To me it fails the normal ras thing of assume the worst if we lost track. I'd panic. But I'm open to other views on this!
Hi Terry, Jonathan,
I aggree with this concern.
When FIFO is full, cxl_forward_error() drops the new entry regardless of severity and returns true. For an UCE, the caller then flushes the worker, but the worker can only process the older entries that are still in the FIFO.
The disgarded one is never read.
Coud the overflow path be made severity-aware so an UCE is never dropped ? For example by processing it synchronously, or reserving space for UCEs ?
Dropping CE may be acceptable, but that's not the case for UCE.
--Richard
Quoted 91 lines
drivers/pci/pcie/aer_cxl_vh.c line 101
Quoted 3 lines
drivers/pci/pcie/aer_cxl_vh.c new file +3
-0+dev_err_ratelimited (&pdev->dev,"AER-CXL kfifo add failed\n" ); +pci_dev_put (pdev); +schedule_work (cxl_proto_err_kfifo.work);Shared with below. Maybe just drop out of the if unless this gets more complex in later patches.
Quoted 13 lines
drivers/pci/pcie/aer_cxl_vh.c new file +11
-0+return true; + } + +schedule_work (cxl_proto_err_kfifo.work); +return true; +} +/** +* for_each_cxl_proto_err - Call a function for each kfifo work item +* +* Single-consumer invariant: this function is only called from +* cxl_proto_err_work_fn() via a single DECLARE_WORK. drivers/pci/pcie/aer_cxl_vh.c line 176
Quoted 10 lines
drivers/pci/pcie/aer_cxl_vh.c new file +10
-0+* +* Holds rwsem_read internally; fn() must not call cxl_register_proto_err_work() +* or cxl_unregister_proto_err_work(). +*/ +void for_each_cxl_proto_err (struct cxl_proto_err_work_data *wd, +cxl_proto_err_fn_t fn) +{ +guard (rwsem_read)(&cxl_proto_err_kfifo.rwsem); +while (kfifo_get (&cxl_proto_err_kfifo.fifo, wd)) { +fn (wd);Like the earlier case I razed, I'd like a comment here to say where the reference we re releasing was taken.
Quoted 15 lines
drivers/pci/pcie/aer_cxl_vh.c new file +15
-0+pci_dev_put (wd->pdev); + } +} +EXPORT_SYMBOL_FOR_MODULES (for_each_cxl_proto_err,"cxl_core" ); + +/** +* cxl_proto_err_flush - drain pending AER-CXL kfifo work synchronously +* +* Wait for the consumer worker to finish processing all entries +* currently in the kfifo. Used by handle_error_source() for UCE so +* the CXL plane can read CXL RAS, apply panic policy, and clear CXL +* state before pci_aer_handle_error() drives PCIe recovery. +* +* Snapshots the flush callback under rwsem_read and releases the rwsem +* before calling it. This avoids holding rwsem_read across flush_work(), drivers/pci/pcie/aer_cxl_vh.c line 201
Quoted 10 lines
drivers/pci/pcie/aer_cxl_vh.c new file +10
-0+* which would deadlock via the rwsem HANDOFF mechanism when a concurrent +* rwsem_write waiter (cxl_unregister_proto_err_work) blocks new readers +* including the worker's for_each_cxl_proto_err() rwsem_read acquisition. +* +* The flush_inflight counter prevents cxl_core module unload while a +* flush is in progress outside the rwsem. The counter is incremented +* under rwsem_read (mutually exclusive with the rwsem_write in +* cancel_cxl_proto_err() that NULLs the flush pointer) and decremented +* after the flush completes. cxl_unregister_proto_err_work() waits for +* the counter to reach zero before proceeding with cancel_work_sync(). I can't see it from just this patch so it might be useful to say if the counter is ever not equal to 1 or 0. If it isn't can we make that explicit in the code?
Quoted 3 lines
+ *
+ * For correctable events the consumer can run asynchronously; AER
+ * does not need to call this helper forAER_CORRECTABLE.For me this is both too much and likely to rot over time. Some stuff feels like it belongs with the flags it is talking about rather than here.
Quoted 17 lines
+ */
drivers/pci/pcie/aer_cxl_vh.c new file +16
-0+void cxl_proto_err_flush (void ) +{ +void (*flush)(void ); + + scoped_guard(rwsem_read, &cxl_proto_err_kfifo.rwsem) { + flush = cxl_proto_err_kfifo.flush; +if (flush) +atomic_inc (&cxl_proto_err_kfifo.flush_inflight); + } + +if (flush) { +flush (); +if (atomic_dec_and_test (&cxl_proto_err_kfifo.flush_inflight)) +wake_up_var (&cxl_proto_err_kfifo.flush_inflight); + } +}
Re: [PATCH v18 05/13] PCI/AER: Introduce AER-CXL protocol error kfifo
Quoted 230 lines · Richard Cheng
Quoted 208 lines · Jonathan Cameron
On Fri, 17 Jul 2026 17:26:58 -0500
Terry Bowman <[email protected]> wrote:Hi Terry.
This is a rather length patch description. Might be worth a parse to see if key details can be covered in something that folk are more likely to read!
Quoted 9 lines
CXL VH RAS handling requires a path for the AER driver to hand off CXL protocol errors to
cxl_corefor logging and recovery before PCIe AER recovery tears down the device. Adddrivers/pci/pcie/aer_cxl_vh.cto implement this handoff via a kfifo-backed work item.Introduce
is_aer_internal_error()to identify CXL protocol errors from AER internal error status bits across both correctable and uncorrectable severities.Already existed. Just in a different location.
Quoted 2 lines
Introduce
is_cxl_error()to gate the VH kfifo path.Feels like to much detail to me given not really anything to say about it other than the obvious.
Quoted 5 lines
Introduce struct
cxl_proto_err_work_datato carry the error source PCI device and severity through the kfifo. Encapsulate the kfifo, per-producer spinlock, registration rwsem, and work pointer in structcxl_proto_err_kfifo. Initialize the embedded kfifo viaINIT_KFIFO()Can we cut this down a little where we don't use useful info. e.g. "Initialize the kfifo from a
subsys_initcall()to it is ready before any producer or consumer runs."Quoted 9 lines
from a
subsys_initcallso its metadata is populated before any producer or consumer runs.Introduce
cxl_forward_error()to enqueue a CXL protocol error. A reference is taken on the PCI device; the consumer releases it viafor_each_cxl_proto_err(). On enqueue failure the reference is released immediately, the error is dropped, and the consumer is scheduled to drain existing entries.We don't need to cover error paths in the patch description unless they are really complex and need explanation. Even then probably belongs more in comments.
Anyhow you get the idea..
Quoted 17 lines
A subsequent patch wires
cxl_forward_error()intohandle_error_source()where correctable and uncorrectable status clearing is left topci_aer_handle_error().Introduce
cxl_proto_err_flush()to synchronously wait for the consumer worker to drain the kfifo. A subsequent patch wires this intohandle_error_source()for UCE events so the CXL plane completes error handling and panic policy beforepci_aer_handle_error()drives PCIe recovery.Introduce
cxl_register_proto_err_work()andcxl_unregister_proto_err_work()forcxl_coreto register and deregister its work handler. On unregistration, pending kfifo entries are drained and their pdev references released beforecancel_work_sync()runs. Export these andfor_each_cxl_proto_err()viaEXPORT_SYMBOL_FOR_MODULESrestricted tocxl_core.Quoted 7 lines
Protect the work pointer with a rwsem to correctly serialize registration, deregistration, enqueue, and dequeue against concurrent AER IRQ threads. Serialize concurrent kfifo writers with a spinlock.
Add
MAINTAINERSentries foraer_cxl_vh.candaer_cxl_rch.cunder the CXL entry so CXL maintainers are CC'd on changes to the AER-CXL bridging code.Various things inline. The one potential thing I'd like to highlight is the loss of tracking assume panic isn't appropriate. My paranoid hat says always go the other way. If we don't know we didn't lose an uncorrectable error panic. Maybe it's worth us considering when this might happen in a real system?
Quoted 51 lines
Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>---
Changes in
v17->v18:
- Remove correctable status clear fromcxl_forward_error(); the AER core clears all status bits viapci_aer_handle_error()info->statuswriteback
- Schedule consumer on kfifo overflow so existing entries can be drainedChanges in
v16->v17:
- Reword "kfifo semaphore" to "kfifo spinlock" to matchfifo_lock.
- Defer thehandle_error_source()is_cxl_error()switch to the patch that registers the kfifo consumer to keep each commit bisect-safe.
- Rename rwsema to rwsem
- Change CPER exports to useEXPORT_SYMBOL_FOR_MODULES.
- Add work cancel function.
- Replacekfifo_put()withkfifo_in_spinlocked()for multiple producers
- Addfifo_lockspinlock for concurrent producer serialisation
- Initialize the embedded kfifo withINIT_KFIFO()in asubsys_initcallsokfifo->mask, ->esize and ->data are set before first use.
- ClearPCI_ERR_COR_STATUSincxl_forward_error()after enqueue so the device is acked for correctable events even when the consumer drops the event. Uncorrectable status is left forcxl_do_recovery()to clear after recovery completes, mirroring the AER core convention.
- WARN on double-registration incxl_register_proto_err_work()to make an unintended second consumer visible at runtime.
- Add directrwsem.h,cleanup.handworkqueue.hincludes for symbols used inaer_cxl_vh.c
- AddMAINTAINERSentries fordrivers/pci/pcie/aer_cxl_*.c
- Update message--- MAINTAINERS | 2 + drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer.c | 10 -- drivers/pci/pcie/aer_cxl_vh.c | 221 ++++++++++++++++++++++++++++++++++ drivers/pci/pcie/portdrv.h | 6 + include/linux/aer.h | 24 ++++ 6 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 drivers/pci/pcie/aer_cxl_vh.cdrivers/pci/pcie/aer_cxl_vh.c new file +0
-0drivers/pci/pcie/aer_cxl_vh.c line 9
Quoted 9 lines
drivers/pci/pcie/aer_cxl_vh.c new file +9
-0@@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2026 AMD Corporation. All rights reserved. */ + +#include <linux/aer.h> +#include <linux/atomic.h> +#include <linux/cleanup.h> +#include <linux/init.h> +#include <linux/kfifo.h> +#include <linux/rwsem.h> Check these. I'd expect at least
spinlock.hto meet the rough include what you use aim.drivers/pci/pcie/aer_cxl_vh.c line 21
Quoted 12 lines
drivers/pci/pcie/aer_cxl_vh.c new file +12
-0+#include <linux/wait_bit.h> +#include <linux/workqueue.h> +#include "../pci.h" +#include "portdrv.h" + +#define CXL_ERROR_SOURCES_MAX 128 + +struct cxl_proto_err_kfifo { +struct work_struct *work; +void (*flush)(void ); +struct rw_semaphore rwsem; +spinlock_t fifo_lock;Ideally add a quick comment to every lock to say what data it covers. Kind of obvious for this one but in general it is good practice and reduces chance of later scope confusion.
Quoted 29 lines
drivers/pci/pcie/aer_cxl_vh.c new file +28
-0+atomic_t flush_inflight; + DECLARE_KFIFO(fifo, struct cxl_proto_err_work_data, +CXL_ERROR_SOURCES_MAX ); +}; +/** +* cxl_forward_error - Forward a CXL protocol error to the CXL subsystem via kfifo +* @pdev: PCI device that reported the AER error +* @info: AER error info containing severity and status +* +* Producer side of the AER-CXL kfifo. Enqueues a CXL protocol error work +* item and schedules the consumer workqueue. Takes a reference on @pdev +* that the consumer releases after handling. +* +* Return: true if the caller must flush the kfifo before AER recovery, +* false if no CXL error handling was initiated due to early return on +* error. +*/ +bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info) +{ +struct cxl_proto_err_work_data wd = { + .severity = info->severity, + .pdev = pdev, + }; + +guard (rwsem_read)(&cxl_proto_err_kfifo.rwsem); + +if (!cxl_proto_err_kfifo.work) { +dev_err_ratelimited (&pdev->dev,"AER-CXL kfifo reader not registered\n" );drivers/pci/pcie/aer_cxl_vh.c line 91
Quoted 10 lines
drivers/pci/pcie/aer_cxl_vh.c new file +10
-0+return false; + } + +/* +* Reference discipline: the AER caller (handle_error_source()) +* holds a ref on @pdev for the duration of this call and releases +* it on return. Take a fresh ref here so the pdev stays live while +* queued in the kfifo; the consumer (for_each_cxl_proto_err()) +* drops that ref after handling. On enqueue failure below, drop +* the ref we just took to avoid a leak. Most of this is useful. The what we do in error handling (given so local) probably not.
Quoted 11 lines
drivers/pci/pcie/aer_cxl_vh.c line 98
Quoted 7 lines
drivers/pci/pcie/aer_cxl_vh.c new file +7
-0+*/ +pci_dev_get (pdev); + +/* Serialize concurrent kfifo writers: multiple AER threaded IRQs */ +if (!kfifo_in_spinlocked (&cxl_proto_err_kfifo.fifo, &wd,1 , + &cxl_proto_err_kfifo.fifo_lock)) { +/* Dropped; no panic - UCE unconfirmed without RAS read */ Hmm. That's interesting. To me it fails the normal ras thing of assume the worst if we lost track. I'd panic. But I'm open to other views on this!
Hi Terry, Jonathan,
I aggree with this concern.
When FIFO is full,
cxl_forward_error()drops the new entry regardless of severity and returns true. For an UCE, the caller then flushes the worker, but the worker can only process the older entries that are still in the FIFO.
The disgarded one is never read.
Quoted 7 lines
Coud the overflow path be made severity-aware so an UCE is never dropped ? For example by processing it synchronously, or reserving space for UCEs ?
Dropping CE may be acceptable, but that's not the case for UCE.
--Richard
Hi Richard,
Thanks for reviewing.
The implementation chosen here intentionally follows the same pattern as the AER core: both aer_recover_queue() and aer_irq() only log (or silently drop) on kfifo overflow rather than escalating. Diverging to panic here would be inconsistent with the AER behaviour this code largely mirrors.
An overflow requires a sustained error rate that outpaces the consumer draining. Hardware errors are being produced faster than they can be processed. If the host cannot maintain free space through the kfifo work handler processing, the system already has severe problems well beyond a single dropped entry. The system is busted.
You and Jonathan have convinced me to make the overflow path severity aware. CXL has system-wide implications, unlike PCI device errors that are typically more localized. Given the coherency requirements, changing the kfifo overflow behaviour for UCE errors makes sense. I'll add a panic for UCE errors that fail to enqueue due to kfifo overflow.
Terry
PATCH v18 6/13 PCI: Establish common CXL Port protocol error flow
In reply to Terry BowmanAdd 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.
---
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(-)
drivers/cxl/core/core.h +7 -0
@@ -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,
drivers/cxl/core/port.c +3 -3
@@ -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;
drivers/cxl/core/ras.c +182 -41
295 lines not on this page · raw message
drivers/pci/pci.h +0 -1
@@ -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) { }
drivers/pci/pcie/aer.c +13 -0
@@ -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); }
drivers/pci/pcie/aer_cxl_vh.c +15 -1
@@ -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); }
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 06/13] PCI: Establish common CXL Port protocol error flow
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 15 lines
Add CXL protocol error dispatch in
handle_error_source()usingis_cxl_error()andcxl_forward_error()to route errors through the AER-CXL kfifo. Expandis_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 beforepci_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").
Quoted 6 lines
[ ... ]
the lock inversion.Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
Re: [PATCH v18 06/13] PCI: Establish common CXL Port protocol error flow
In reply to Terry BowmanQuoted 41 lines · Terry Bowman
Add CXL protocol error dispatch in
handle_error_source()usingis_cxl_error()andcxl_forward_error()to route errors through the AER-CXL kfifo. Expandis_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 beforepci_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. Addcxl_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.driverbefore 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.rasfor Root/Downstream Ports,port->regs.rasfor Upstream Ports and Endpoints. Useto_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()andcxl_handle_ras(). The existingcxl_cor_error_detected()andcxl_error_detected()AER callbacks remain for all Endpoints and are reworked to usefind_cxl_port_by_uport()andto_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").
Quoted 8 lines
Fix a pre-existing race for cxlds between
cxl_handle_rdport_errors()andcxl_memdev_shutdown()by holding a cxlmd devicescoped_guard()around the rdport call. Release the lock before taking the Port lock to avoid the lock inversion.Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>
Quoted 525 lines
---
Changes in
v17->v18:
- Fix pre-existing race: hold memdev device lock aroundcxl_handle_rdport_errors(), release before port lock
- Fixhandle_error_source()to callpci_aer_handle_error()unconditionally so AER handling always runs aftercxl_forward_error()
- Addcxl_proto_err_flush()call for CXL UCE to drain kfifo before AER recovery tears down the device
- Fix NULL dereference ofdport->dport_devincxl_handle_cor_ras()andcxl_handle_ras()for UPSTREAM/ENDPOINT port types: usedport->dport_devwhen dport is non-NULL, else fall back toport->uport_dev
- Remove duplicatepcie_clear_device_status()call fromcxl_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) andport->dev.drivercheckChanges in
v16->v17:
-get_cxl_port()->find_cxl_port_by_dev()
- Simplifiedfind_cxl_port_by_dev()
- Replace and removecxl_serial_number()w/pci_get_dsn()
-cxl_get_ras_base()->to_ras_base()
- Drop dependency onPCI_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.
- Addis_cxl_error()switch inhandle_error_source()here, paired with the kfifo consumer registration, to keep each commit bisect-safe.
- Droppcie_aer_is_native()guard incxl_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 toget_cxl_port()documentation (Terry)
- Fix__cxl_proto_err_work_fn()to return 0 for transient errors.
- Drop !port check incxl_do_recovery(), caller already validated
- Fix kerneldoc @pdev -> @dev infind_cxl_port_by_dev()
- Fix missing space inpr_err_ratelimited()
- Madepcie_clear_device_status()andpci_aer_clear_fatal_status()EXPORT_SYMBOL_FOR_MODULES("cxl_core")(Dan)
- Movefind_cxl_port_by_dport()andfind_cxl_port_by_uport()de-staticisation andcore.hdeclarations from the rename patch to here, where the first cross-file callers infind_cxl_port_by_dev()land.Changes in
v15->v16:
-get_ras_base(), initialize dport to NULL (Jonathan)
- Remove guard(device)(&cxlmd->dev) (Jonathan)
- Fixdev_warns()(Jonathan)
- Remove comment incxl_port_error_detected()(Dan)
- Update switch-case brackets to follow clang-format (Dan)
- AddPCI_EXP_TYPE_RC_ENDforcxl_get_ras_base()(Terry)
- Add NULL port check incxl_serial_number()(Terry)Changes in
v14->v15:
- Update commit message and title. Added Bjorn's ack.
- Move CE and UCE handling logic hereChanges 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)
- Removecxl_walk_port()(Dan)
- Removecxl_pci_drv_bound(). Check for 'is_cxl' parent port is sufficient (Dan)
- Removedevice_lock_if()
- Combined CE and UCE here (Terry)Changes in
v12->v13:
- Moveget_pci_cxl_host_dev()andcxl_handle_proto_error()to Dequeue patch (Terry)
- Remove EP case incxl_get_ras_base(), not used. (Terry)
- Remove check fordport->dport_dev(Dave)
- Remove whitespace (Terry)Changes in
v11->v12:
- Add call tocxl_pci_drv_bound()incxl_handle_proto_error()andpci_to_cxl_dev()
- Changecxl_error_detected()->cxl_cor_error_detected()
- Remove NULL variable assignments
- Replacebus_find_device()withfind_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(-)drivers/cxl/core/core.h +7
-0@@ -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,drivers/cxl/core/port.c +3
-3@@ -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;drivers/cxl/core/ras.c +182
-41@@ -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 (); +}drivers/pci/pci.h +0
-1@@ -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) { }drivers/pci/pcie/aer.c +13
-0@@ -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); }drivers/pci/pcie/aer_cxl_vh.c +15
-1@@ -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); }
Jonathan Cameron
maintainerRe: [PATCH v18 06/13] PCI: Establish common CXL Port protocol error flow
In reply to Terry BowmanQuoted 6 lines · On Fri, 17 Jul 2026 17:26:59 -0500 Terry Bowman <[email protected]> wrote:
Add CXL protocol error dispatch in
handle_error_source()usingis_cxl_error()andcxl_forward_error()to route errors through the AER-CXL kfifo. Expandis_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.
Take a stab at making this description a lot more concise. I'd like to just be seeing a very brief summary of flow + clearly highlighting of potentially controversial choices.
Quoted 35 lines
For uncorrectable events, call
cxl_proto_err_flush()to ensure CXL RAS registers are read, panic policy is applied, and CXL state is cleared beforepci_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. Addcxl_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.driverbefore 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.rasfor Root/Downstream Ports,port->regs.rasfor Upstream Ports and Endpoints. Useto_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()andcxl_handle_ras(). The existingcxl_cor_error_detected()andcxl_error_detected()AER callbacks remain for all Endpoints and are reworked to usefind_cxl_port_by_uport()andto_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").
Quoted 9 lines
Fix a pre-existing race for cxlds between
cxl_handle_rdport_errors()andcxl_memdev_shutdown()by holding a cxlmd devicescoped_guard()around the rdport call. Release the lock before taking the Port lock to avoid the lock inversion.Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>
A few minor things about the code inline.
Thanks,
Jonathan
drivers/cxl/core/ras.c static int match_memdev_by_parent(struct device *dev, const void *uport) · line 84
Quoted 13 lines
drivers/cxl/core/ras.c +5
-0@@ -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
I'd state this is optional.
Quoted 24 lines
drivers/cxl/core/ras.c +24
-0+* 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 ; +}
...
Quoted 14 lines
drivers/cxl/core/ras.c +7
-3@@ -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 ;
drivers/cxl/core/ras.c bool cxl_handle_ras(struct device *dev, void __iomem *ras_base) · line 343
Quoted 10 lines
drivers/cxl/core/ras.c +7
-2+ +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); + }
Unless this gets more complex later you can just use a guard() as exits scope here anyway.
drivers/cxl/core/ras.c bool cxl_handle_ras(struct device *dev, void __iomem *ras_base) · line 346
Quoted 3 lines
drivers/cxl/core/ras.c +3
-0+ } + + scoped_guard(device, &port->dev) {
Similar here. I haven't read on though for this one so if it's needed later just ignore me.
Quoted 22 lines
drivers/cxl/core/ras.c +4
-7+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);
...
drivers/cxl/core/ras.c EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL"); · line 396
Quoted 4 lines
drivers/cxl/core/ras.c +3
-0+/* +* CXL.mem UCE means cache coherency is lost. Continuing risks +* silent data corruption across interleaved HDM regions.
It is a problem whether interleave or not. So maybe just stop at corruption.
Quoted 3 lines
drivers/cxl/core/ras.c +3
-0+*/ +if (ue) +panic ("CXL cachemem error" );
...
Quoted 1 line
drivers/cxl/core/ras.c +0
-0@@ -338,3 +415,67 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
...
drivers/cxl/core/ras.c pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, · line 437
Quoted 8 lines
drivers/cxl/core/ras.c +8
-0+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 ; + }
I'd put a blank line here.
Quoted 30 lines
drivers/cxl/core/ras.c +17
-0+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); +}drivers/pci/pcie/aer.c +3
-0@@ -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); +
drivers/pci/pcie/aer.c static void pci_aer_handle_error(struct pci_dev *dev, struct aer_err_info *info) · line 1201
Quoted 10 lines
drivers/pci/pcie/aer.c +9
-0+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 ();
This kind of makes me wonder if the naming of _flush() is clear. Normally I'd kind of expect that to be dumping any queued up errors.
Perhaps cxl_proto_err_wait_for_empty() or something like that?
I guess flush_work() set the precedent so I'm too later on this one!
Jonathan
PATCH v18 7/13 PCI/CXL: Add RCH support to CXL handlers
In reply to Terry BowmanRestricted CXL Host (RCH) error handling is a separate path from the new CXL Port error handling flow. Fold RCH error handling into the Port flow so both share a common entry point.
Update cxl_rch_handle_error_iter() to forward RCH protocol errors through the AER-CXL kfifo. Change cxl_rch_handle_error() return type from void to bool so handle_error_source() can determine whether work was enqueued and call cxl_proto_err_flush() before AER recovery proceeds.
For RC_END devices, __cxl_proto_err_work_fn() calls cxl_handle_rdport_errors() to process RCH Downstream Port errors, then falls through to the VH path for RC_END Endpoint handling.
An RCD uncorrectable CXL RAS error now panics via cxl_do_recovery(). Before this patch the RCH Downstream Port UCE path called cxl_handle_ras() but ignored its return value - no panic. After this patch the same condition calls cxl_do_recovery() which panics on confirmed UCE. The Endpoint UCE path already panicked at the parent commit. This matches the panic policy added in the common CXL Port protocol error flow.
Remove cxl_cor_error_detected() and its .cor_error_detected registration in cxl_error_handlers. Correctable Endpoint errors are now routed through the AER-CXL kfifo like all other CXL protocol errors.
Drop the cxlds->rcd / cxl_handle_rdport_errors(cxlds) branches from cxl_error_detected(). RCH downstream port error handling is now performed by __cxl_proto_err_work_fn() via the kfifo path, which calls cxl_handle_rdport_errors(pdev) before the common dispatch.
Change cxl_handle_rdport_errors() to take a struct pci_dev * instead of a struct cxl_dev_state *, matching the new caller context. Re-fetch dport under guard() to close the TOCTOU window between cxl_pci_find_port()'s lockless xa_load() and the first dereference of the returned pointer.
Change find_cxl_port_by_dev() RC_END lookup from find_cxl_port_by_dport(dev->parent) to find_cxl_port_by_uport(dev), matching the Endpoint lookup path. RC_END Endpoint port resolution uses the uport (the RC_END device itself), while the separate RCH Downstream Port lookup is handled by cxl_handle_rdport_errors().
The RCH Downstream Port and the RCD Endpoint (RC_END) are separate devices with independent RAS register blocks. cxl_handle_rdport_errors() handles the RCH Downstream Port RAS. RCD Endpoint (RC_END) is handled in cxl_handle_proto_error().
Use to_ras_base() in cxl_handle_rdport_errors() instead of referencing dport->regs.ras directly. Make to_ras_base() non-static in ras.c and declare it in core.h so ras_rch.c can access it. Route all RAS base address lookups through a single helper to prepare for CXL RAS error injection testing that follows this series.
---
Changes in v17->v18:
- Pass &pdev->dev instead of dport->port->uport_dev in cxl_handle_rdport_errors() to avoid dropping RCH trace events.
- Document trace event attribution change.
- Document removal of cxl_cor_error_detected() and cxlds->rcd branches.
- Capitalize Endpoint per PCI spec convention.
- Use to_ras_base() in cxl_handle_rdport_errors() to centralize RAS base address lookup in preparation for error injection testing.
Changes in v16->v17:
- Drop now-dead cxlds->rcd branches from cxl_{cor_,}error_detected().
- Drop duplicate subject line from commit body.
- Document panic-on-uncorrectable behavior change for RCD path.
- Document trace event device-name change (memN -> PCI BDF) for RCH path.
- Rewrite cxl_handle_proto_error() RC_END comment to clarify RCD/RCH shared interrupt relationship
- Rewrite commit message
Changes in v16:
- New commit
--- drivers/cxl/core/core.h | 10 +++++-- drivers/cxl/core/ras.c | 50 ++++++++-------------------------- drivers/cxl/core/ras_rch.c | 16 ++++++----- drivers/cxl/cxlpci.h | 3 -- drivers/cxl/pci.c | 1 - drivers/pci/pcie/aer.c | 4 +-- drivers/pci/pcie/aer_cxl_rch.c | 39 ++++++++++++-------------- drivers/pci/pcie/portdrv.h | 4 +-- 8 files changed, 48 insertions(+), 79 deletions(-)
drivers/cxl/core/core.h +8 -2
@@ -191,7 +191,8 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port,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); -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds); +void cxl_handle_rdport_errors (struct pci_dev *pdev); +void __iomem *to_ras_base (struct cxl_port *port,struct cxl_dport *dport);void devm_cxl_dport_ras_setup (struct cxl_dport *dport);#else static inline void cxl_ras_init (void ) { }
@@ -205,7 +206,12 @@ static inline void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port,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) { } -static inline void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) { } +static inline void cxl_handle_rdport_errors (struct pci_dev *pdev) { } +static inline void __iomem *to_ras_base (struct cxl_port *port, +struct cxl_dport *dport) +{ +return NULL ; +}static inline void devm_cxl_dport_ras_setup (struct cxl_dport *dport) { }#endif /* CONFIG_CXL_RAS */
drivers/cxl/core/ras.c +11 -39
75 lines not on this page · raw message
drivers/cxl/core/ras_rch.c +9 -7
@@ -1,7 +1,6 @@// SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2025 AMD Corporation. All rights reserved. */ -#include <linux/types.h> #include <linux/aer.h> #include "cxl.h" #include "core.h"
@@ -96,18 +95,21 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,return false; } -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) +void cxl_handle_rdport_errors (struct pci_dev *pdev) { -struct pci_dev *pdev =to_pci_dev (cxlds->dev);struct aer_capability_regs aer_regs;struct cxl_dport *dport;int severity; - struct cxl_port *port __free(put_cxl_port) = -cxl_pci_find_port (pdev, &dport); + struct cxl_port *port __free(put_cxl_port) = cxl_pci_find_port(pdev, NULL);if (!port)return ; +guard (device)(&port->dev); + dport =cxl_find_dport_by_dev (port, pdev->dev.parent); +if (!dport) +return ; +if (!cxl_rch_get_aer_info (dport->regs.dport_aer, &aer_regs))return ;
@@ -116,7 +118,7 @@ void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)pci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (&cxlds->cxlmd->dev, dport->regs.ras); +cxl_handle_cor_ras (&pdev->dev,to_ras_base (port, dport));else -cxl_handle_ras (&cxlds->cxlmd->dev, dport->regs.ras); +cxl_do_recovery (pdev, dport->port, dport); }
drivers/cxl/cxlpci.h +0 -3
@@ -89,14 +89,11 @@ struct cxl_dev_state;void read_cdat_data (struct cxl_port *port);#ifdef CONFIG_CXL_RAS -void cxl_cor_error_detected (struct pci_dev *pdev);pci_ers_result_t cxl_error_detected (struct pci_dev *pdev,pci_channel_state_t state);void devm_cxl_dport_rch_ras_setup (struct cxl_dport *dport);void devm_cxl_port_ras_setup (struct cxl_port *port);#else -static inline void cxl_cor_error_detected (struct pci_dev *pdev) { } -static inline pci_ers_result_t cxl_error_detected (struct pci_dev *pdev,pci_channel_state_t state) {
drivers/cxl/pci.c +0 -1
@@ -1004,7 +1004,6 @@ static const struct pci_error_handlers cxl_error_handlers = { .error_detected = cxl_error_detected, .slot_reset = cxl_slot_reset, .resume = cxl_error_resume, - .cor_error_detected = cxl_cor_error_detected, .reset_done = cxl_reset_done, };
drivers/pci/pcie/aer.c +1 -3
@@ -1185,9 +1185,7 @@ 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); +bool cxl_pending =cxl_rch_handle_error (dev, info);if (is_cxl_error (dev, info)) cxl_pending |=cxl_forward_error (dev, info);
drivers/pci/pcie/aer_cxl_rch.c +17 -22
@@ -34,42 +34,37 @@ static bool cxl_error_is_native(struct pci_dev *dev)return (pcie_ports_native || host->native_aer); } +struct cxl_rch_error_ctx { +struct aer_err_info *info; +bool enqueued; +}; +static int cxl_rch_handle_error_iter (struct pci_dev *dev,void *data) { -struct aer_err_info *info = (struct aer_err_info *)data; -const struct pci_error_handlers *err_handler; +struct cxl_rch_error_ctx *ctx = data;if (!is_cxl_mem_dev (dev) || !cxl_error_is_native (dev))return 0 ; -guard (device)(&dev->dev); - - err_handler = dev->driver ? dev->driver->err_handler :NULL ; -if (!err_handler) -return 0 ; - -if (info->severity ==AER_CORRECTABLE ) { -if (err_handler->cor_error_detected) - err_handler->cor_error_detected (dev); - }else if (err_handler->error_detected) { -if (info->severity ==AER_NONFATAL ) - err_handler->error_detected (dev, pci_channel_io_normal); -else if (info->severity ==AER_FATAL ) - err_handler->error_detected (dev, pci_channel_io_frozen); - } +if (cxl_forward_error (dev, ctx->info)) + ctx->enqueued = true;return 0 ; } -void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) +bool cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) { +struct cxl_rch_error_ctx ctx = { .info = info }; +/* -* Internal errors of an RCEC indicate an AER error in an -* RCH's downstream port. Check and handle them in the CXL.mem -* device driver. +* An RCEC AER internal error indicates an error in an +* associated RCH Downstream Port or RC_END device or both. +* Forward to the cxl_core module for handling. */ if (pci_pcie_type (dev) ==PCI_EXP_TYPE_RC_EC &&is_aer_internal_error (info)) -pcie_walk_rcec (dev, cxl_rch_handle_error_iter, info); +pcie_walk_rcec (dev, cxl_rch_handle_error_iter, &ctx); + +return ctx.enqueued; }static int handles_cxl_error_iter (struct pci_dev *dev,void *data)
drivers/pci/pcie/portdrv.h +2 -2
@@ -128,14 +128,14 @@ struct aer_err_info;#ifdef CONFIG_CXL_RAS bool is_aer_internal_error (struct aer_err_info *info); -void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info); +bool cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info);void cxl_rch_enable_rcec (struct pci_dev *rcec);bool is_cxl_error (struct pci_dev *pdev,struct aer_err_info *info);bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info);void cxl_proto_err_flush (void );#else static inline bool is_aer_internal_error (struct aer_err_info *info) {return false; } -static inline void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) { } +static inline bool cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) {return false; }static inline void cxl_rch_enable_rcec (struct pci_dev *rcec) { }static inline bool is_cxl_error (struct pci_dev *pdev,struct aer_err_info *info) {return false; }static inline bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info) {return false; }
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Removal of explicit PCI error handler forwarding for RCH devices leaves RCDs bound after a fatal PCI error.
Pre-existing issues:
- [High] Preexisting lockless dereference of dport returned by cxl_pci_find_port() and cxl_mem_find_port() leading to Use-After-Free. --
--- Patch [7]: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers --- commit 6a99c70b18865d01d350aa367342e701ebe6dde2
Author: Terry Bowman <[email protected]>
PCI/CXL: Add RCH support to CXL handlers
Restricted CXL Host (RCH) error handling is folded into the new CXL Port error handling flow. RCH protocol errors are forwarded through the AER-CXL kfifo, and the manual CXL.mem error handler invocation is removed.
Quoted 13 lines
drivers/cxl/core/ras_rch.c +1
-2@@ -96,18 +95,21 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,return false; } -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) +void cxl_handle_rdport_errors (struct pci_dev *pdev) { -struct pci_dev *pdev =to_pci_dev (cxlds->dev);struct aer_capability_regs aer_regs;struct cxl_dport *dport;
drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 109
Quoted 10 lines
drivers/cxl/core/ras_rch.c +3
-2int severity; - struct cxl_port *port __free(put_cxl_port) = -cxl_pci_find_port (pdev, &dport); + struct cxl_port *port __free(put_cxl_port) = cxl_pci_find_port(pdev, NULL);if (!port)return ; +guard (device)(&port->dev); + dport =cxl_find_dport_by_dev (port, pdev->dev.parent);
[Severity: High]
This is a pre-existing issue, but while this change correctly closes a lockless Use-After-Free window for dport here, does the same vulnerability still exist in cxl_pci_setup_regs() and rcd_pcie_cap_emit()?
In cxl_pci_setup_regs(), cxl_rcrb_get_comp_regs() dereferences the dport returned by cxl_pci_find_port() before any lock is taken.
Similarly, in rcd_pcie_cap_emit(), dport->regs.rcd_pcie_cap is dereferenced entirely locklessly, and then the function takes guard(device)(root_dev) instead of the required &root->dev lock.
Since rcd_pcie_cap_emit() is reachable via sysfs attributes, could an unprivileged local user trigger a Use-After-Free by reading sysfs during a concurrent device hot-unplug?
[ ... ]
Quoted 28 lines
drivers/pci/pcie/aer_cxl_rch.c +6
-9@@ -34,42 +34,37 @@ static bool cxl_error_is_native(struct pci_dev *dev)return (pcie_ports_native || host->native_aer); } +struct cxl_rch_error_ctx { +struct aer_err_info *info; +bool enqueued; +}; +static int cxl_rch_handle_error_iter (struct pci_dev *dev,void *data) { -struct aer_err_info *info = (struct aer_err_info *)data; -const struct pci_error_handlers *err_handler; +struct cxl_rch_error_ctx *ctx = data;if (!is_cxl_mem_dev (dev) || !cxl_error_is_native (dev))return 0 ; -guard (device)(&dev->dev); - - err_handler = dev->driver ? dev->driver->err_handler :NULL ; -if (!err_handler) -return 0 ; - -if (info->severity ==AER_CORRECTABLE ) {
drivers/pci/pcie/aer_cxl_rch.c static bool cxl_error_is_native(struct pci_dev *dev) · line 50
Quoted 10 lines
drivers/pci/pcie/aer_cxl_rch.c +2
-8-if (err_handler->cor_error_detected) - err_handler->cor_error_detected (dev); - }else if (err_handler->error_detected) { -if (info->severity ==AER_NONFATAL ) - err_handler->error_detected (dev, pci_channel_io_normal); -else if (info->severity ==AER_FATAL ) - err_handler->error_detected (dev, pci_channel_io_frozen); - } +if (cxl_forward_error (dev, ctx->info)) + ctx->enqueued = true;
[Severity: High]
Does removing the explicit invocation of the err_handler leave RCDs bound after a fatal PCI error?
The standard pcie_do_recovery() on an RCEC does not iterate over its associated RC_END (RCD) devices, so this manual invocation used to handle the CXL.mem driver fallback. Now that errors are routed solely through the CXL protocol error work queue (__cxl_proto_err_work_fn()), the work queue only panics on uncorrectable cachemem errors.
Does the work queue replicate the PCI recovery state machine's fallback behavior, such as calling device_release_driver() to unbind the CXL.mem driver on frozen channel states?
Quoted 2 lines
drivers/pci/pcie/aer_cxl_rch.c +0
-0return 0 ; }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
Re: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers
Quoted 4 lines · On 7/17/2026 5:43 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Removal of explicit PCI error handler forwarding for RCH devices leaves RCDs bound after a fatal PCI error.
This is a false positive. device_release_driver() is called in cxl_pci_error_detected()
Quoted 3 lines
Pre-existing issues:
- [High] Preexisting lockless dereference ofdportreturned bycxl_pci_find_port()andcxl_mem_find_port()leading to Use-After-Free.
This is existing issue and is not planned to be fixed in this series.
Quoted 48 lines
--
--- Patch [7]: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers --- commit
6a99c70b18865d01d350aa367342e701ebe6dde2
Author: Terry Bowman <[email protected]>PCI/CXL: Add RCH support to CXL handlers
Restricted CXL Host (RCH) error handling is folded into the new CXL Port error handling flow. RCH protocol errors are forwarded through the AER-CXL kfifo, and the manual CXL.mem error handler invocation is removed.
Quoted 13 lines
drivers/cxl/core/ras_rch.c +1
-2@@ -96,18 +95,21 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,return false; } -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) +void cxl_handle_rdport_errors (struct pci_dev *pdev) { -struct pci_dev *pdev =to_pci_dev (cxlds->dev);struct aer_capability_regs aer_regs;struct cxl_dport *dport;drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 109
Quoted 10 lines
drivers/cxl/core/ras_rch.c +3
-2int severity; - struct cxl_port *port __free(put_cxl_port) = -cxl_pci_find_port (pdev, &dport); + struct cxl_port *port __free(put_cxl_port) = cxl_pci_find_port(pdev, NULL);if (!port)return ; +guard (device)(&port->dev); + dport =cxl_find_dport_by_dev (port, pdev->dev.parent);[Severity: High]
This is a pre-existing issue, but while this change correctly closes a lockless Use-After-Free window for dport here, does the same vulnerability still exist incxl_pci_setup_regs()andrcd_pcie_cap_emit()?In
cxl_pci_setup_regs(),cxl_rcrb_get_comp_regs()dereferences the dport returned bycxl_pci_find_port()before any lock is taken.Similarly, in
rcd_pcie_cap_emit(),dport->regs.rcd_pcie_capis dereferenced entirely locklessly, and then the function takes guard(device)(root_dev) instead of the required&root->devlock.
Quoted 6 lines
Since
rcd_pcie_cap_emit()is reachable via sysfs attributes, could an unprivileged local user trigger a Use-After-Free by reading sysfs during a concurrent device hot-unplug?[ ... ]
This is existing issue and is not planned to be fixed in this series.
Quoted 49 lines
Quoted 28 lines
drivers/pci/pcie/aer_cxl_rch.c +6
-9@@ -34,42 +34,37 @@ static bool cxl_error_is_native(struct pci_dev *dev)return (pcie_ports_native || host->native_aer); } +struct cxl_rch_error_ctx { +struct aer_err_info *info; +bool enqueued; +}; +static int cxl_rch_handle_error_iter (struct pci_dev *dev,void *data) { -struct aer_err_info *info = (struct aer_err_info *)data; -const struct pci_error_handlers *err_handler; +struct cxl_rch_error_ctx *ctx = data;if (!is_cxl_mem_dev (dev) || !cxl_error_is_native (dev))return 0 ; -guard (device)(&dev->dev); - - err_handler = dev->driver ? dev->driver->err_handler :NULL ; -if (!err_handler) -return 0 ; - -if (info->severity ==AER_CORRECTABLE ) {drivers/pci/pcie/aer_cxl_rch.c static bool cxl_error_is_native(struct pci_dev *dev) · line 50
Quoted 10 lines
drivers/pci/pcie/aer_cxl_rch.c +2
-8-if (err_handler->cor_error_detected) - err_handler->cor_error_detected (dev); - }else if (err_handler->error_detected) { -if (info->severity ==AER_NONFATAL ) - err_handler->error_detected (dev, pci_channel_io_normal); -else if (info->severity ==AER_FATAL ) - err_handler->error_detected (dev, pci_channel_io_frozen); - } +if (cxl_forward_error (dev, ctx->info)) + ctx->enqueued = true;[Severity: High]
Does removing the explicit invocation of theerr_handlerleave RCDs bound after a fatal PCI error?The standard
pcie_do_recovery()on an RCEC does not iterate over its associatedRC_END(RCD) devices, so this manual invocation used to handle the CXL.mem driver fallback. Now that errors are routed solely through the CXL protocol error work queue (__cxl_proto_err_work_fn()), the work queue only panics on uncorrectable cachemem errors.
Quoted 7 lines
Does the work queue replicate the PCI recovery state machine's fallback behavior, such as calling
device_release_driver()to unbind the CXL.mem driver on frozen channel states?Quoted 2 lines
drivers/pci/pcie/aer_cxl_rch.c +0
-0return 0 ; }
The change to forward CXL errors through Kfifo using schedulable work is intentional. This series does not exactly *replicate* the PCI handling.
The device_release_driver() is called in cxl_pci_error_detected() for pci_channel_io_frozen. cxl_pci_error_detected() serves as the PCIe error handler for Endpoints, including RCDs.
Terry
Re: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers
Quoted 126 lines · Terry
Quoted 4 lines · On 7/17/2026 5:43 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Removal of explicit PCI error handler forwarding for RCH devices leaves RCDs bound after a fatal PCI error.This is a false positive.
device_release_driver()is called incxl_pci_error_detected()Quoted 3 lines
Pre-existing issues:
- [High] Preexisting lockless dereference ofdportreturned bycxl_pci_find_port()andcxl_mem_find_port()leading to Use-After-Free.This is existing issue and is not planned to be fixed in this series.
Quoted 48 lines
--
--- Patch [7]: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers --- commit
6a99c70b18865d01d350aa367342e701ebe6dde2
Author: Terry Bowman <[email protected]>PCI/CXL: Add RCH support to CXL handlers
Restricted CXL Host (RCH) error handling is folded into the new CXL Port error handling flow. RCH protocol errors are forwarded through the AER-CXL kfifo, and the manual CXL.mem error handler invocation is removed.
Quoted 13 lines
drivers/cxl/core/ras_rch.c +1
-2@@ -96,18 +95,21 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,return false; } -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) +void cxl_handle_rdport_errors (struct pci_dev *pdev) { -struct pci_dev *pdev =to_pci_dev (cxlds->dev);struct aer_capability_regs aer_regs;struct cxl_dport *dport;drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 109
Quoted 10 lines
drivers/cxl/core/ras_rch.c +3
-2int severity; - struct cxl_port *port __free(put_cxl_port) = -cxl_pci_find_port (pdev, &dport); + struct cxl_port *port __free(put_cxl_port) = cxl_pci_find_port(pdev, NULL);if (!port)return ; +guard (device)(&port->dev); + dport =cxl_find_dport_by_dev (port, pdev->dev.parent);[Severity: High]
This is a pre-existing issue, but while this change correctly closes a lockless Use-After-Free window for dport here, does the same vulnerability still exist incxl_pci_setup_regs()andrcd_pcie_cap_emit()?In
cxl_pci_setup_regs(),cxl_rcrb_get_comp_regs()dereferences the dport returned bycxl_pci_find_port()before any lock is taken.Similarly, in
rcd_pcie_cap_emit(),dport->regs.rcd_pcie_capis dereferenced entirely locklessly, and then the function takes guard(device)(root_dev) instead of the required&root->devlock.Quoted 6 lines
Since
rcd_pcie_cap_emit()is reachable via sysfs attributes, could an unprivileged local user trigger a Use-After-Free by reading sysfs during a concurrent device hot-unplug?[ ... ]
This is existing issue and is not planned to be fixed in this series.
Quoted 49 lines
Quoted 28 lines
drivers/pci/pcie/aer_cxl_rch.c +6
-9@@ -34,42 +34,37 @@ static bool cxl_error_is_native(struct pci_dev *dev)return (pcie_ports_native || host->native_aer); } +struct cxl_rch_error_ctx { +struct aer_err_info *info; +bool enqueued; +}; +static int cxl_rch_handle_error_iter (struct pci_dev *dev,void *data) { -struct aer_err_info *info = (struct aer_err_info *)data; -const struct pci_error_handlers *err_handler; +struct cxl_rch_error_ctx *ctx = data;if (!is_cxl_mem_dev (dev) || !cxl_error_is_native (dev))return 0 ; -guard (device)(&dev->dev); - - err_handler = dev->driver ? dev->driver->err_handler :NULL ; -if (!err_handler) -return 0 ; - -if (info->severity ==AER_CORRECTABLE ) {drivers/pci/pcie/aer_cxl_rch.c static bool cxl_error_is_native(struct pci_dev *dev) · line 50
Quoted 10 lines
drivers/pci/pcie/aer_cxl_rch.c +2
-8-if (err_handler->cor_error_detected) - err_handler->cor_error_detected (dev); - }else if (err_handler->error_detected) { -if (info->severity ==AER_NONFATAL ) - err_handler->error_detected (dev, pci_channel_io_normal); -else if (info->severity ==AER_FATAL ) - err_handler->error_detected (dev, pci_channel_io_frozen); - } +if (cxl_forward_error (dev, ctx->info)) + ctx->enqueued = true;[Severity: High]
Does removing the explicit invocation of theerr_handlerleave RCDs bound after a fatal PCI error?The standard
pcie_do_recovery()on an RCEC does not iterate over its associatedRC_END(RCD) devices, so this manual invocation used to handle the CXL.mem driver fallback. Now that errors are routed solely through the CXL protocol error work queue (__cxl_proto_err_work_fn()), the work queue only panics on uncorrectable cachemem errors.Quoted 7 lines
Does the work queue replicate the PCI recovery state machine's fallback behavior, such as calling
device_release_driver()to unbind the CXL.mem driver on frozen channel states?Quoted 2 lines
drivers/pci/pcie/aer_cxl_rch.c +0
-0return 0 ; }
Quoted 9 lines
The change to forward CXL errors through Kfifo using schedulable work is intentional. This series does not exactly *replicate* the PCI handling.
The
device_release_driver()is called incxl_pci_error_detected()forpci_channel_io_frozen.cxl_pci_error_detected()serves as the PCIe error handler for Endpoints, including RCDs.Terry
Hi Terry,
I agree with you on this part, but what I can't find after this patch is the path that invokees it for an associated RCD.
you replace all error_detected() for associated RCD with cxl_forward_error() and queue CXL RAS work, what if a fatal case where it finds no RAS UCE?
It'll return normal and RCD driver will remain bound won't it ?
--Richard
Re: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers
Quoted 149 lines · Richard Cheng
Quoted 126 lines · Terry
Quoted 4 lines · On 7/17/2026 5:43 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Removal of explicit PCI error handler forwarding for RCH devices leaves RCDs bound after a fatal PCI error.This is a false positive.
device_release_driver()is called incxl_pci_error_detected()Quoted 3 lines
Pre-existing issues:
- [High] Preexisting lockless dereference ofdportreturned bycxl_pci_find_port()andcxl_mem_find_port()leading to Use-After-Free.This is existing issue and is not planned to be fixed in this series.
Quoted 48 lines
--
--- Patch [7]: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers --- commit
6a99c70b18865d01d350aa367342e701ebe6dde2
Author: Terry Bowman <[email protected]>PCI/CXL: Add RCH support to CXL handlers
Restricted CXL Host (RCH) error handling is folded into the new CXL Port error handling flow. RCH protocol errors are forwarded through the AER-CXL kfifo, and the manual CXL.mem error handler invocation is removed.
Quoted 13 lines
drivers/cxl/core/ras_rch.c +1
-2@@ -96,18 +95,21 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,return false; } -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) +void cxl_handle_rdport_errors (struct pci_dev *pdev) { -struct pci_dev *pdev =to_pci_dev (cxlds->dev);struct aer_capability_regs aer_regs;struct cxl_dport *dport;drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 109
Quoted 10 lines
drivers/cxl/core/ras_rch.c +3
-2int severity; - struct cxl_port *port __free(put_cxl_port) = -cxl_pci_find_port (pdev, &dport); + struct cxl_port *port __free(put_cxl_port) = cxl_pci_find_port(pdev, NULL);if (!port)return ; +guard (device)(&port->dev); + dport =cxl_find_dport_by_dev (port, pdev->dev.parent);[Severity: High]
This is a pre-existing issue, but while this change correctly closes a lockless Use-After-Free window for dport here, does the same vulnerability still exist incxl_pci_setup_regs()andrcd_pcie_cap_emit()?In
cxl_pci_setup_regs(),cxl_rcrb_get_comp_regs()dereferences the dport returned bycxl_pci_find_port()before any lock is taken.Similarly, in
rcd_pcie_cap_emit(),dport->regs.rcd_pcie_capis dereferenced entirely locklessly, and then the function takes guard(device)(root_dev) instead of the required&root->devlock.Quoted 6 lines
Since
rcd_pcie_cap_emit()is reachable via sysfs attributes, could an unprivileged local user trigger a Use-After-Free by reading sysfs during a concurrent device hot-unplug?[ ... ]
This is existing issue and is not planned to be fixed in this series.
Quoted 49 lines
Quoted 28 lines
drivers/pci/pcie/aer_cxl_rch.c +6
-9@@ -34,42 +34,37 @@ static bool cxl_error_is_native(struct pci_dev *dev)return (pcie_ports_native || host->native_aer); } +struct cxl_rch_error_ctx { +struct aer_err_info *info; +bool enqueued; +}; +static int cxl_rch_handle_error_iter (struct pci_dev *dev,void *data) { -struct aer_err_info *info = (struct aer_err_info *)data; -const struct pci_error_handlers *err_handler; +struct cxl_rch_error_ctx *ctx = data;if (!is_cxl_mem_dev (dev) || !cxl_error_is_native (dev))return 0 ; -guard (device)(&dev->dev); - - err_handler = dev->driver ? dev->driver->err_handler :NULL ; -if (!err_handler) -return 0 ; - -if (info->severity ==AER_CORRECTABLE ) {drivers/pci/pcie/aer_cxl_rch.c static bool cxl_error_is_native(struct pci_dev *dev) · line 50
Quoted 10 lines
drivers/pci/pcie/aer_cxl_rch.c +2
-8-if (err_handler->cor_error_detected) - err_handler->cor_error_detected (dev); - }else if (err_handler->error_detected) { -if (info->severity ==AER_NONFATAL ) - err_handler->error_detected (dev, pci_channel_io_normal); -else if (info->severity ==AER_FATAL ) - err_handler->error_detected (dev, pci_channel_io_frozen); - } +if (cxl_forward_error (dev, ctx->info)) + ctx->enqueued = true;[Severity: High]
Does removing the explicit invocation of theerr_handlerleave RCDs bound after a fatal PCI error?The standard
pcie_do_recovery()on an RCEC does not iterate over its associatedRC_END(RCD) devices, so this manual invocation used to handle the CXL.mem driver fallback. Now that errors are routed solely through the CXL protocol error work queue (__cxl_proto_err_work_fn()), the work queue only panics on uncorrectable cachemem errors.Quoted 7 lines
Does the work queue replicate the PCI recovery state machine's fallback behavior, such as calling
device_release_driver()to unbind the CXL.mem driver on frozen channel states?Quoted 2 lines
drivers/pci/pcie/aer_cxl_rch.c +0
-0return 0 ; }Quoted 9 lines
The change to forward CXL errors through Kfifo using schedulable work is intentional. This series does not exactly *replicate* the PCI handling.
The
device_release_driver()is called incxl_pci_error_detected()forpci_channel_io_frozen.cxl_pci_error_detected()serves as the PCIe error handler for Endpoints, including RCDs.Terry
Hi Terry,
I agree with you on this part, but what I can't find after this patch is the path that invokees it for an associated RCD.
you replace all
error_detected()for associated RCD withcxl_forward_error()and queue CXL RAS work, what if a fatal case where it finds no RAS UCE?It'll return normal and RCD driver will remain bound won't it ?
--Richard
Re: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers
In reply to Richard ChengQuoted 142 lines · Richard Cheng
Quoted 126 lines · Terry
Quoted 4 lines · On 7/17/2026 5:43 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Removal of explicit PCI error handler forwarding for RCH devices leaves RCDs bound after a fatal PCI error.This is a false positive.
device_release_driver()is called incxl_pci_error_detected()Quoted 3 lines
Pre-existing issues:
- [High] Preexisting lockless dereference ofdportreturned bycxl_pci_find_port()andcxl_mem_find_port()leading to Use-After-Free.This is existing issue and is not planned to be fixed in this series.
Quoted 48 lines
--
--- Patch [7]: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers --- commit
6a99c70b18865d01d350aa367342e701ebe6dde2
Author: Terry Bowman <[email protected]>PCI/CXL: Add RCH support to CXL handlers
Restricted CXL Host (RCH) error handling is folded into the new CXL Port error handling flow. RCH protocol errors are forwarded through the AER-CXL kfifo, and the manual CXL.mem error handler invocation is removed.
Quoted 13 lines
drivers/cxl/core/ras_rch.c +1
-2@@ -96,18 +95,21 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,return false; } -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) +void cxl_handle_rdport_errors (struct pci_dev *pdev) { -struct pci_dev *pdev =to_pci_dev (cxlds->dev);struct aer_capability_regs aer_regs;struct cxl_dport *dport;drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 109
Quoted 10 lines
drivers/cxl/core/ras_rch.c +3
-2int severity; - struct cxl_port *port __free(put_cxl_port) = -cxl_pci_find_port (pdev, &dport); + struct cxl_port *port __free(put_cxl_port) = cxl_pci_find_port(pdev, NULL);if (!port)return ; +guard (device)(&port->dev); + dport =cxl_find_dport_by_dev (port, pdev->dev.parent);[Severity: High]
This is a pre-existing issue, but while this change correctly closes a lockless Use-After-Free window for dport here, does the same vulnerability still exist incxl_pci_setup_regs()andrcd_pcie_cap_emit()?In
cxl_pci_setup_regs(),cxl_rcrb_get_comp_regs()dereferences the dport returned bycxl_pci_find_port()before any lock is taken.Similarly, in
rcd_pcie_cap_emit(),dport->regs.rcd_pcie_capis dereferenced entirely locklessly, and then the function takes guard(device)(root_dev) instead of the required&root->devlock.Quoted 6 lines
Since
rcd_pcie_cap_emit()is reachable via sysfs attributes, could an unprivileged local user trigger a Use-After-Free by reading sysfs during a concurrent device hot-unplug?[ ... ]
This is existing issue and is not planned to be fixed in this series.
Quoted 49 lines
Quoted 28 lines
drivers/pci/pcie/aer_cxl_rch.c +6
-9@@ -34,42 +34,37 @@ static bool cxl_error_is_native(struct pci_dev *dev)return (pcie_ports_native || host->native_aer); } +struct cxl_rch_error_ctx { +struct aer_err_info *info; +bool enqueued; +}; +static int cxl_rch_handle_error_iter (struct pci_dev *dev,void *data) { -struct aer_err_info *info = (struct aer_err_info *)data; -const struct pci_error_handlers *err_handler; +struct cxl_rch_error_ctx *ctx = data;if (!is_cxl_mem_dev (dev) || !cxl_error_is_native (dev))return 0 ; -guard (device)(&dev->dev); - - err_handler = dev->driver ? dev->driver->err_handler :NULL ; -if (!err_handler) -return 0 ; - -if (info->severity ==AER_CORRECTABLE ) {drivers/pci/pcie/aer_cxl_rch.c static bool cxl_error_is_native(struct pci_dev *dev) · line 50
Quoted 10 lines
drivers/pci/pcie/aer_cxl_rch.c +2
-8-if (err_handler->cor_error_detected) - err_handler->cor_error_detected (dev); - }else if (err_handler->error_detected) { -if (info->severity ==AER_NONFATAL ) - err_handler->error_detected (dev, pci_channel_io_normal); -else if (info->severity ==AER_FATAL ) - err_handler->error_detected (dev, pci_channel_io_frozen); - } +if (cxl_forward_error (dev, ctx->info)) + ctx->enqueued = true;[Severity: High]
Does removing the explicit invocation of theerr_handlerleave RCDs bound after a fatal PCI error?The standard
pcie_do_recovery()on an RCEC does not iterate over its associatedRC_END(RCD) devices, so this manual invocation used to handle the CXL.mem driver fallback. Now that errors are routed solely through the CXL protocol error work queue (__cxl_proto_err_work_fn()), the work queue only panics on uncorrectable cachemem errors.Quoted 7 lines
Does the work queue replicate the PCI recovery state machine's fallback behavior, such as calling
device_release_driver()to unbind the CXL.mem driver on frozen channel states?Quoted 2 lines
drivers/pci/pcie/aer_cxl_rch.c +0
-0return 0 ; }Quoted 9 lines
The change to forward CXL errors through Kfifo using schedulable work is intentional. This series does not exactly *replicate* the PCI handling.
The
device_release_driver()is called incxl_pci_error_detected()forpci_channel_io_frozen.cxl_pci_error_detected()serves as the PCIe error handler for Endpoints, including RCDs.Terry
Hi Terry,
I agree with you on this part, but what I can't find after this patch is the path that invokees it for an associated RCD.
Quoted 7 lines
you replace all
error_detected()for associated RCD withcxl_forward_error()and queue CXL RAS work, what if a fatal case where it finds no RAS UCE?It'll return normal and RCD driver will remain bound won't it ?
--Richard
Hi Richard,
An RCD with a fatal UCE will call cxl_pci_error_detected(). This is because the AER core doesn't read the AER registers for an EP or USP with a fatal UCE. As a result it fails the is_aer_internal_error() check in cxl_rch_handle_error() due to the missing internal error status bit.
In your example the RAS isn't mapped, so cxl_handle_ras() is not called and the subsequent handling is based on device state. Do you feel there should be a panic regardless of whether the registers can be read? The policy so far was to panic only on confirmed UCEs. I erred on the side of caution with the thought that it could be made stricter if needed, and because an AER non-fatal UCE can potentially recover without a CXL.mem error. I'm inclined to make the unmapped-RAS case panic as well — the Port/cxl_do_recovery() path has no channel state to drive graceful recovery the way the Endpoint path does, and a Port can have live coherent CXL.mem downstream, so an unconfirmable UCE there risks silent corruption. Interested in your view.
You've also pointed out a real gap: I need to add back the RCH error handler call in cxl_pci_error_detected() for the RCD fatal UCE case. Thanks for catching that.
Note: the RCD and VH EP non-fatal UCE does get passed through the kfifo and calls cxl_do_recovery(). You were asking about the fatal case, but it's worth rounding out the non-fatal path too since it's separate. The plan has been to treat fatal and non-fatal UCEs alike with panic once confirmed.
Terry
Re: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers
In reply to Richard ChengQuoted 142 lines · Richard Cheng
Quoted 126 lines · Terry
Quoted 4 lines · On 7/17/2026 5:43 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Removal of explicit PCI error handler forwarding for RCH devices leaves RCDs bound after a fatal PCI error.This is a false positive.
device_release_driver()is called incxl_pci_error_detected()Quoted 3 lines
Pre-existing issues:
- [High] Preexisting lockless dereference ofdportreturned bycxl_pci_find_port()andcxl_mem_find_port()leading to Use-After-Free.This is existing issue and is not planned to be fixed in this series.
Quoted 48 lines
--
--- Patch [7]: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers --- commit
6a99c70b18865d01d350aa367342e701ebe6dde2
Author: Terry Bowman <[email protected]>PCI/CXL: Add RCH support to CXL handlers
Restricted CXL Host (RCH) error handling is folded into the new CXL Port error handling flow. RCH protocol errors are forwarded through the AER-CXL kfifo, and the manual CXL.mem error handler invocation is removed.
Quoted 13 lines
drivers/cxl/core/ras_rch.c +1
-2@@ -96,18 +95,21 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,return false; } -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) +void cxl_handle_rdport_errors (struct pci_dev *pdev) { -struct pci_dev *pdev =to_pci_dev (cxlds->dev);struct aer_capability_regs aer_regs;struct cxl_dport *dport;drivers/cxl/core/ras_rch.c static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs, · line 109
Quoted 10 lines
drivers/cxl/core/ras_rch.c +3
-2int severity; - struct cxl_port *port __free(put_cxl_port) = -cxl_pci_find_port (pdev, &dport); + struct cxl_port *port __free(put_cxl_port) = cxl_pci_find_port(pdev, NULL);if (!port)return ; +guard (device)(&port->dev); + dport =cxl_find_dport_by_dev (port, pdev->dev.parent);[Severity: High]
This is a pre-existing issue, but while this change correctly closes a lockless Use-After-Free window for dport here, does the same vulnerability still exist incxl_pci_setup_regs()andrcd_pcie_cap_emit()?In
cxl_pci_setup_regs(),cxl_rcrb_get_comp_regs()dereferences the dport returned bycxl_pci_find_port()before any lock is taken.Similarly, in
rcd_pcie_cap_emit(),dport->regs.rcd_pcie_capis dereferenced entirely locklessly, and then the function takes guard(device)(root_dev) instead of the required&root->devlock.Quoted 6 lines
Since
rcd_pcie_cap_emit()is reachable via sysfs attributes, could an unprivileged local user trigger a Use-After-Free by reading sysfs during a concurrent device hot-unplug?[ ... ]
This is existing issue and is not planned to be fixed in this series.
Quoted 49 lines
Quoted 28 lines
drivers/pci/pcie/aer_cxl_rch.c +6
-9@@ -34,42 +34,37 @@ static bool cxl_error_is_native(struct pci_dev *dev)return (pcie_ports_native || host->native_aer); } +struct cxl_rch_error_ctx { +struct aer_err_info *info; +bool enqueued; +}; +static int cxl_rch_handle_error_iter (struct pci_dev *dev,void *data) { -struct aer_err_info *info = (struct aer_err_info *)data; -const struct pci_error_handlers *err_handler; +struct cxl_rch_error_ctx *ctx = data;if (!is_cxl_mem_dev (dev) || !cxl_error_is_native (dev))return 0 ; -guard (device)(&dev->dev); - - err_handler = dev->driver ? dev->driver->err_handler :NULL ; -if (!err_handler) -return 0 ; - -if (info->severity ==AER_CORRECTABLE ) {drivers/pci/pcie/aer_cxl_rch.c static bool cxl_error_is_native(struct pci_dev *dev) · line 50
Quoted 10 lines
drivers/pci/pcie/aer_cxl_rch.c +2
-8-if (err_handler->cor_error_detected) - err_handler->cor_error_detected (dev); - }else if (err_handler->error_detected) { -if (info->severity ==AER_NONFATAL ) - err_handler->error_detected (dev, pci_channel_io_normal); -else if (info->severity ==AER_FATAL ) - err_handler->error_detected (dev, pci_channel_io_frozen); - } +if (cxl_forward_error (dev, ctx->info)) + ctx->enqueued = true;[Severity: High]
Does removing the explicit invocation of theerr_handlerleave RCDs bound after a fatal PCI error?The standard
pcie_do_recovery()on an RCEC does not iterate over its associatedRC_END(RCD) devices, so this manual invocation used to handle the CXL.mem driver fallback. Now that errors are routed solely through the CXL protocol error work queue (__cxl_proto_err_work_fn()), the work queue only panics on uncorrectable cachemem errors.Quoted 7 lines
Does the work queue replicate the PCI recovery state machine's fallback behavior, such as calling
device_release_driver()to unbind the CXL.mem driver on frozen channel states?Quoted 2 lines
drivers/pci/pcie/aer_cxl_rch.c +0
-0return 0 ; }Quoted 9 lines
The change to forward CXL errors through Kfifo using schedulable work is intentional. This series does not exactly *replicate* the PCI handling.
The
device_release_driver()is called incxl_pci_error_detected()forpci_channel_io_frozen.cxl_pci_error_detected()serves as the PCIe error handler for Endpoints, including RCDs.Terry
Hi Terry,
I agree with you on this part, but what I can't find after this patch is the path that invokees it for an associated RCD.
Quoted 7 lines
you replace all
error_detected()for associated RCD withcxl_forward_error()and queue CXL RAS work, what if a fatal case where it finds no RAS UCE?It'll return normal and RCD driver will remain bound won't it ?
--Richard
Hi Richard,
Rereading your question, let me give a fuller explanation of the Endpoint UCE paths.
CXL Endpoint UCEs (both VH and RCD) are handled by the AER handlers, including pcie_do_recovery() calling cxl_pci_error_detected(), for both severities - so the Endpoint is not left bound. The two severities take different call paths:
UCE non-fatal
=============
The AER status is readable, so the event is classified as CXL and forwarded to the kfifo. Below is the UCE fatal AER path:
handle_error_source()
cxl_forward_error() [enqueue kfifo]
cxl_proto_err_wait_for_empty() [drain]
cxl_do_recovery() -> cxl_handle_ras()
pci_aer_handle_error()
pcie_do_recovery(io_normal)
cxl_pci_error_detected() -> cxl_handle_ras()
return CAN_RECOVER [normal -> recoverable, driver stays bound]UCE fatal
=========
The uplink is unstable, so the AER core cannot read the source's AER status. is_cxl_error() cannot classify the event as CXL, so it is handled as a PCIe error (not forwarded to the kfifo). It still reaches cxl_pci_error_detected() via pcie_do_recovery(), which releases the CXL.mem driver on the frozen channel. Below is the UCE non-fatal path:
handle_error_source()
pci_aer_handle_error()
pcie_do_recovery(io_frozen)
cxl_pci_error_detected() -> cxl_handle_ras()
device_release_driver() [frozen -> unbind CXL.mem]So the Endpoint is not left bound after a fatal (frozen) error.
The non-fatal case does call the RAS handler twice (kfifo + AER path), but this is benign since the CXL RAS status is W1C.
Thanks for the careful review.
Terry
Re: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers
In reply to Terry BowmanQuoted 49 lines · Terry Bowman
Restricted CXL Host (RCH) error handling is a separate path from the new CXL Port error handling flow. Fold RCH error handling into the Port flow so both share a common entry point.
Update
cxl_rch_handle_error_iter()to forward RCH protocol errors through the AER-CXL kfifo. Changecxl_rch_handle_error()return type from void to bool sohandle_error_source()can determine whether work was enqueued and callcxl_proto_err_flush()before AER recovery proceeds.For
RC_ENDdevices,__cxl_proto_err_work_fn()callscxl_handle_rdport_errors()to process RCH Downstream Port errors, then falls through to the VH path forRC_ENDEndpoint handling.An RCD uncorrectable CXL RAS error now panics via
cxl_do_recovery(). Before this patch the RCH Downstream Port UCE path calledcxl_handle_ras()but ignored its return value - no panic. After this patch the same condition callscxl_do_recovery()which panics on confirmed UCE. The Endpoint UCE path already panicked at the parent commit. This matches the panic policy added in the common CXL Port protocol error flow.Remove
cxl_cor_error_detected()and its .cor_error_detected registration incxl_error_handlers. Correctable Endpoint errors are now routed through the AER-CXL kfifo like all other CXL protocol errors.Drop the
cxlds->rcd/cxl_handle_rdport_errors(cxlds)branches fromcxl_error_detected(). RCH downstream port error handling is now performed by__cxl_proto_err_work_fn()via the kfifo path, which callscxl_handle_rdport_errors(pdev)before the common dispatch.Change
cxl_handle_rdport_errors()to take a structpci_dev* instead of a structcxl_dev_state*, matching the new caller context. Re-fetch dport underguard()to close the TOCTOU window between cxl_pci_find_port()'s locklessxa_load()and the first dereference of the returned pointer.Change
find_cxl_port_by_dev()RC_ENDlookup fromfind_cxl_port_by_dport(dev->parent)tofind_cxl_port_by_uport(dev), matching the Endpoint lookup path.RC_ENDEndpoint port resolution uses the uport (theRC_ENDdevice itself), while the separate RCH Downstream Port lookup is handled bycxl_handle_rdport_errors().The RCH Downstream Port and the RCD Endpoint (
RC_END) are separate devices with independent RAS register blocks.cxl_handle_rdport_errors()handles the RCH Downstream Port RAS. RCD Endpoint (RC_END) is handled incxl_handle_proto_error().
Quoted 7 lines
Use
to_ras_base()incxl_handle_rdport_errors()instead of referencingdport->regs.rasdirectly. Maketo_ras_base()non-static inras.cand declare it incore.hsoras_rch.ccan access it. Route all RAS base address lookups through a single helper to prepare for CXL RAS error injection testing that follows this series.Signed-off-by Terry Bowman <[email protected]>
Quoted 324 lines
---
Changes in
v17->v18:
- Pass&pdev->devinstead ofdport->port->uport_devincxl_handle_rdport_errors()to avoid dropping RCH trace events.
- Document trace event attribution change.
- Document removal ofcxl_cor_error_detected()andcxlds->rcdbranches.
- Capitalize Endpoint per PCI spec convention.
- Useto_ras_base()incxl_handle_rdport_errors()to centralize RAS base address lookup in preparation for error injection testing.Changes in
v16->v17:
- Drop now-deadcxlds->rcdbranches from cxl_{cor_,}error_detected().
- Drop duplicate subject line from commit body.
- Document panic-on-uncorrectable behavior change for RCD path.
- Document trace event device-name change (memN -> PCI BDF) for RCH path.
- Rewritecxl_handle_proto_error()RC_ENDcomment to clarify RCD/RCH shared interrupt relationship
- Rewrite commit messageChanges in v16:
- New commit--- drivers/cxl/core/core.h | 10 +++++-- drivers/cxl/core/ras.c | 50 ++++++++-------------------------- drivers/cxl/core/ras_rch.c | 16 ++++++----- drivers/cxl/cxlpci.h | 3 -- drivers/cxl/pci.c | 1 - drivers/pci/pcie/aer.c | 4 +-- drivers/pci/pcie/aer_cxl_rch.c | 39 ++++++++++++-------------- drivers/pci/pcie/portdrv.h | 4 +-- 8 files changed, 48 insertions(+), 79 deletions(-)drivers/cxl/core/core.h +8
-2@@ -191,7 +191,8 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port,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); -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds); +void cxl_handle_rdport_errors (struct pci_dev *pdev); +void __iomem *to_ras_base (struct cxl_port *port,struct cxl_dport *dport);void devm_cxl_dport_ras_setup (struct cxl_dport *dport);#else static inline void cxl_ras_init (void ) { }@@ -205,7 +206,12 @@ static inline void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port,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) { } -static inline void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) { } +static inline void cxl_handle_rdport_errors (struct pci_dev *pdev) { } +static inline void __iomem *to_ras_base (struct cxl_port *port, +struct cxl_dport *dport) +{ +return NULL ; +}static inline void devm_cxl_dport_ras_setup (struct cxl_dport *dport) { }#endif /* CONFIG_CXL_RAS */ drivers/cxl/core/ras.c +11
-39@@ -218,7 +218,8 @@ 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) + +void __iomem *to_ras_base (struct cxl_port *port,struct cxl_dport *dport) {if (!port)return NULL ;@@ -324,37 +325,7 @@ bool cxl_handle_ras(struct device *dev, void __iomem *ras_base)return true; } -void cxl_cor_error_detected (struct pci_dev *pdev) -{ -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, &cxlmd->dev) { -cxl_handle_rdport_errors (cxlds); - } - } - - scoped_guard(device, &port->dev) { -if (!port->dev.driver) { -dev_warn (&pdev->dev, -"%s: port disabled, abort error handling\n" , -dev_name (&port->dev)); -return ; - } - -cxl_handle_cor_ras (port->uport_dev,to_ras_base (port,NULL )); - } -} -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)@@ -365,14 +336,6 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,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) {@@ -429,6 +392,15 @@ static void cxl_handle_proto_error(struct pci_dev *pdev, struct cxl_port *port,static void __cxl_proto_err_work_fn (struct cxl_proto_err_work_data *wd) { +/* +* For RC_END (RCD) devices, handle RCH Downstream Port errors +* first. cxl_handle_rdport_errors() does its own port lookup +* and locking, keeping the Downstream Port lock separate from the +* Endpoint Port lock taken below. +*/ +if (is_cxl_restricted (wd->pdev)) +cxl_handle_rdport_errors (wd->pdev); + 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,drivers/cxl/core/ras_rch.c +9
-7@@ -1,7 +1,6 @@// SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2025 AMD Corporation. All rights reserved. */ -#include <linux/types.h> #include <linux/aer.h> #include "cxl.h" #include "core.h" @@ -96,18 +95,21 @@ static bool cxl_rch_get_aer_severity(struct aer_capability_regs *aer_regs,return false; } -void cxl_handle_rdport_errors (struct cxl_dev_state *cxlds) +void cxl_handle_rdport_errors (struct pci_dev *pdev) { -struct pci_dev *pdev =to_pci_dev (cxlds->dev);struct aer_capability_regs aer_regs;struct cxl_dport *dport;int severity; - struct cxl_port *port __free(put_cxl_port) = -cxl_pci_find_port (pdev, &dport); + struct cxl_port *port __free(put_cxl_port) = cxl_pci_find_port(pdev, NULL);if (!port)return ; +guard (device)(&port->dev); + dport =cxl_find_dport_by_dev (port, pdev->dev.parent); +if (!dport) +return ; +if (!cxl_rch_get_aer_info (dport->regs.dport_aer, &aer_regs))return ;@@ -116,7 +118,7 @@ void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)pci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (&cxlds->cxlmd->dev, dport->regs.ras); +cxl_handle_cor_ras (&pdev->dev,to_ras_base (port, dport));else -cxl_handle_ras (&cxlds->cxlmd->dev, dport->regs.ras); +cxl_do_recovery (pdev, dport->port, dport); }drivers/cxl/cxlpci.h +0
-3@@ -89,14 +89,11 @@ struct cxl_dev_state;void read_cdat_data (struct cxl_port *port);#ifdef CONFIG_CXL_RAS -void cxl_cor_error_detected (struct pci_dev *pdev);pci_ers_result_t cxl_error_detected (struct pci_dev *pdev,pci_channel_state_t state);void devm_cxl_dport_rch_ras_setup (struct cxl_dport *dport);void devm_cxl_port_ras_setup (struct cxl_port *port);#else -static inline void cxl_cor_error_detected (struct pci_dev *pdev) { } -static inline pci_ers_result_t cxl_error_detected (struct pci_dev *pdev,pci_channel_state_t state) {drivers/cxl/pci.c +0
-1@@ -1004,7 +1004,6 @@ static const struct pci_error_handlers cxl_error_handlers = { .error_detected = cxl_error_detected, .slot_reset = cxl_slot_reset, .resume = cxl_error_resume, - .cor_error_detected = cxl_cor_error_detected, .reset_done = cxl_reset_done, };drivers/pci/pcie/aer.c +1
-3@@ -1185,9 +1185,7 @@ 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); +bool cxl_pending =cxl_rch_handle_error (dev, info);if (is_cxl_error (dev, info)) cxl_pending |=cxl_forward_error (dev, info);drivers/pci/pcie/aer_cxl_rch.c +17
-22@@ -34,42 +34,37 @@ static bool cxl_error_is_native(struct pci_dev *dev)return (pcie_ports_native || host->native_aer); } +struct cxl_rch_error_ctx { +struct aer_err_info *info; +bool enqueued; +}; +static int cxl_rch_handle_error_iter (struct pci_dev *dev,void *data) { -struct aer_err_info *info = (struct aer_err_info *)data; -const struct pci_error_handlers *err_handler; +struct cxl_rch_error_ctx *ctx = data;if (!is_cxl_mem_dev (dev) || !cxl_error_is_native (dev))return 0 ; -guard (device)(&dev->dev); - - err_handler = dev->driver ? dev->driver->err_handler :NULL ; -if (!err_handler) -return 0 ; - -if (info->severity ==AER_CORRECTABLE ) { -if (err_handler->cor_error_detected) - err_handler->cor_error_detected (dev); - }else if (err_handler->error_detected) { -if (info->severity ==AER_NONFATAL ) - err_handler->error_detected (dev, pci_channel_io_normal); -else if (info->severity ==AER_FATAL ) - err_handler->error_detected (dev, pci_channel_io_frozen); - } +if (cxl_forward_error (dev, ctx->info)) + ctx->enqueued = true;return 0 ; } -void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) +bool cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) { +struct cxl_rch_error_ctx ctx = { .info = info }; +/* -* Internal errors of an RCEC indicate an AER error in an -* RCH's downstream port. Check and handle them in the CXL.mem -* device driver. +* An RCEC AER internal error indicates an error in an +* associated RCH Downstream Port or RC_END device or both. +* Forward to the cxl_core module for handling. */ if (pci_pcie_type (dev) ==PCI_EXP_TYPE_RC_EC &&is_aer_internal_error (info)) -pcie_walk_rcec (dev, cxl_rch_handle_error_iter, info); +pcie_walk_rcec (dev, cxl_rch_handle_error_iter, &ctx); + +return ctx.enqueued; }static int handles_cxl_error_iter (struct pci_dev *dev,void *data)drivers/pci/pcie/portdrv.h +2
-2@@ -128,14 +128,14 @@ struct aer_err_info;#ifdef CONFIG_CXL_RAS bool is_aer_internal_error (struct aer_err_info *info); -void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info); +bool cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info);void cxl_rch_enable_rcec (struct pci_dev *rcec);bool is_cxl_error (struct pci_dev *pdev,struct aer_err_info *info);bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info);void cxl_proto_err_flush (void );#else static inline bool is_aer_internal_error (struct aer_err_info *info) {return false; } -static inline void cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) { } +static inline bool cxl_rch_handle_error (struct pci_dev *dev,struct aer_err_info *info) {return false; }static inline void cxl_rch_enable_rcec (struct pci_dev *rcec) { }static inline bool is_cxl_error (struct pci_dev *pdev,struct aer_err_info *info) {return false; }static inline bool cxl_forward_error (struct pci_dev *pdev,struct aer_err_info *info) {return false; }
Jonathan Cameron
maintainerRe: [PATCH v18 07/13] PCI/CXL: Add RCH support to CXL handlers
In reply to Terry BowmanQuoted 11 lines · On Fri, 17 Jul 2026 17:27:00 -0500 Terry Bowman <[email protected]> wrote:
Restricted CXL Host (RCH) error handling is a separate path from the new CXL Port error handling flow. Fold RCH error handling into the Port flow so both share a common entry point.
Update
cxl_rch_handle_error_iter()to forward RCH protocol errors through the AER-CXL kfifo. Changecxl_rch_handle_error()return type from void to bool sohandle_error_source()can determine whether work was enqueued and callcxl_proto_err_flush()before AER recovery proceeds.For
RC_ENDdevices,__cxl_proto_err_work_fn()calls
Can we refer to these as RCiEPs to match the spec? I have no idea where RC_END naming came from but to me it isn't obviously that same thing. Or talk about the narrow case of RCDs here as well.
Quoted 38 lines
cxl_handle_rdport_errors()to process RCH Downstream Port errors, then falls through to the VH path forRC_ENDEndpoint handling.An RCD uncorrectable CXL RAS error now panics via
cxl_do_recovery(). Before this patch the RCH Downstream Port UCE path calledcxl_handle_ras()but ignored its return value - no panic. After this patch the same condition callscxl_do_recovery()which panics on confirmed UCE. The Endpoint UCE path already panicked at the parent commit. This matches the panic policy added in the common CXL Port protocol error flow.Remove
cxl_cor_error_detected()and its .cor_error_detected registration incxl_error_handlers. Correctable Endpoint errors are now routed through the AER-CXL kfifo like all other CXL protocol errors.Drop the
cxlds->rcd/cxl_handle_rdport_errors(cxlds)branches fromcxl_error_detected(). RCH downstream port error handling is now performed by__cxl_proto_err_work_fn()via the kfifo path, which callscxl_handle_rdport_errors(pdev)before the common dispatch.Change
cxl_handle_rdport_errors()to take a structpci_dev* instead of a structcxl_dev_state*, matching the new caller context. Re-fetch dport underguard()to close the TOCTOU window between cxl_pci_find_port()'s locklessxa_load()and the first dereference of the returned pointer.Change
find_cxl_port_by_dev()RC_ENDlookup fromfind_cxl_port_by_dport(dev->parent)tofind_cxl_port_by_uport(dev), matching the Endpoint lookup path.RC_ENDEndpoint port resolution uses the uport (theRC_ENDdevice itself), while the separate RCH Downstream Port lookup is handled bycxl_handle_rdport_errors().The RCH Downstream Port and the RCD Endpoint (
RC_END) are separate devices with independent RAS register blocks.cxl_handle_rdport_errors()handles the RCH Downstream Port RAS. RCD Endpoint (RC_END) is handled incxl_handle_proto_error().
Quoted 8 lines
Use
to_ras_base()incxl_handle_rdport_errors()instead of referencingdport->regs.rasdirectly. Maketo_ras_base()non-static inras.cand declare it incore.hsoras_rch.ccan access it. Route all RAS base address lookups through a single helper to prepare for CXL RAS error injection testing that follows this series.Signed-off-by Terry Bowman <[email protected]>
Other than taking another look at the patch description and seeing if it can be more concise, this one looks fine to me.
Jonathan
PATCH v18 8/13 cxl/pci: Thread port and dport through RAS handling helpers
In reply to Terry BowmanFrom: Dan Williams <[email protected]>
The callers of cxl_handle_ras() and cxl_handle_cor_ras() already hold a struct cxl_port * and struct cxl_dport * for the device being handled. Passing a generic struct device * requires is_cxl_memdev() to distinguish Endpoints from ports at trace emission time. Threading port and dport directly enables is_cxl_endpoint(port) and explicit dport/port branching for cleaner trace dispatch.
Refactor cxl_handle_ras() and cxl_handle_cor_ras() to accept struct cxl_port * and struct cxl_dport * directly. The CXL RAS trace event emission logic is split into three branches: Endpoint events are identified via is_cxl_endpoint(port) and emit with the memdev, dport events emit with dport->dport_dev, and Upstream Port events fall back to port->uport_dev.
Update cxl_handle_rdport_errors() in ras_rch.c and cxl_handle_proto_error() in ras.c to pass port and dport to the refactored functions.
RCH Downstream Port correctable trace events now report the dport device (dport->dport_dev) as a consequence of threading port and dport through the RAS helpers. The following trace event rework ("cxl: Add port and dport identifiers to CXL AER trace events") adds explicit memdev, port, dport, and host fields that provide full context for all device types.
---
Changes in v17 -> v18:
- New patch.
--- drivers/cxl/core/core.h | 12 ++++++++---- drivers/cxl/core/ras.c | 29 +++++++++++++++-------------- drivers/cxl/core/ras_rch.c | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-)
drivers/cxl/core/core.h +8 -4
@@ -185,10 +185,12 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)#ifdef CONFIG_CXL_RAS void cxl_ras_init (void );void cxl_ras_exit (void ); -bool cxl_handle_ras (struct device *dev,void __iomem *ras_base); +bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, +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_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport, +void __iomem *ras_base);void cxl_dport_map_rch_aer (struct cxl_dport *dport);void cxl_disable_rch_root_ints (struct cxl_dport *dport);void cxl_handle_rdport_errors (struct pci_dev *pdev);
@@ -197,13 +199,15 @@ void devm_cxl_dport_ras_setup(struct cxl_dport *dport);#else static inline void cxl_ras_init (void ) { }static inline void cxl_ras_exit (void ) { } -static inline bool cxl_handle_ras (struct device *dev,void __iomem *ras_base) +static inline bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, +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_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport, +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) { }static inline void cxl_handle_rdport_errors (struct pci_dev *pdev) { }
drivers/cxl/core/ras.c +15 -14
@@ -232,7 +232,6 @@ void __iomem *to_ras_base(struct cxl_port *port, struct cxl_dport *dport)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) {
@@ -241,14 +240,14 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dporeturn ; } -if (cxl_handle_ras (dev, ras_base)) +if (cxl_handle_ras (port, dport, 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 cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) {u32 status;void __iomem *addr;
@@ -260,10 +259,12 @@ 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); -if (is_cxl_memdev (dev)) -trace_cxl_aer_correctable_error (to_cxl_memdev (dev), status); +if (is_cxl_endpoint (port)) +trace_cxl_aer_correctable_error (to_cxl_memdev (port->uport_dev), status); +else if (dport) +trace_cxl_port_aer_correctable_error (dport->dport_dev, status);else -trace_cxl_port_aer_correctable_error (dev, status); +trace_cxl_port_aer_correctable_error (port->uport_dev, status); } }
@@ -288,7 +289,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)* Log the state of the RAS status registers and prepare them to log the * next error status. Return 1 if reset needed. */ -bool cxl_handle_ras (struct device *dev,void __iomem *ras_base) +bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) {u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32 ] = {};void __iomem *addr;
@@ -315,10 +316,12 @@ bool cxl_handle_ras(struct device *dev, void __iomem *ras_base) }header_log_copy (ras_base, hl); -if (is_cxl_memdev (dev)) -trace_cxl_aer_uncorrectable_error (to_cxl_memdev (dev), status, fe, hl); +if (is_cxl_endpoint (port)) +trace_cxl_aer_uncorrectable_error (to_cxl_memdev (port->uport_dev), status, fe, hl); +else if (dport) +trace_cxl_port_aer_uncorrectable_error (dport->dport_dev, status, fe, hl);else -trace_cxl_port_aer_uncorrectable_error (dev, status, fe, hl); +trace_cxl_port_aer_uncorrectable_error (port->uport_dev, status, fe, hl);writel (status &CXL_RAS_UNCORRECTABLE_STATUS_MASK , addr);
@@ -351,7 +354,7 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,* 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 (port->uport_dev,to_ras_base (port,NULL )); + ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL )); }/*
@@ -382,10 +385,8 @@ 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)); +cxl_handle_cor_ras (port, dport,to_ras_base (port, dport));else cxl_do_recovery (pdev, port, dport); }
drivers/cxl/core/ras_rch.c +1 -1
@@ -118,7 +118,7 @@ void cxl_handle_rdport_errors(struct pci_dev *pdev)pci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (&pdev->dev,to_ras_base (port, dport)); +cxl_handle_cor_ras (dport->port, dport,to_ras_base (port, dport));else cxl_do_recovery (pdev, dport->port, dport); }
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 08/13] cxl/pci: Thread port and dport through RAS handling helpers
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 27 lines
From: Dan Williams <[email protected]>
The callers of
cxl_handle_ras()andcxl_handle_cor_ras()already hold a structcxl_port* and structcxl_dport* for the device being handled. Passing a generic struct device * requiresis_cxl_memdev()to distinguish Endpoints from ports at trace emission time. Threading port and dport directly enablesis_cxl_endpoint(port)and explicit dport/port branching for cleaner trace dispatch.Refactor
cxl_handle_ras()andcxl_handle_cor_ras()to accept structcxl_port* and structcxl_dport* directly. The CXL RAS trace event emission logic is split into three branches: Endpoint events are identified viais_cxl_endpoint(port)and emit with the memdev, dport events emit withdport->dport_dev, and Upstream Port events fall back toport->uport_dev.Update
cxl_handle_rdport_errors()inras_rch.candcxl_handle_proto_error()inras.cto pass port and dport to the refactored functions.RCH Downstream Port correctable trace events now report the dport device (
dport->dport_dev) as a consequence of threading port and dport through the RAS helpers. The following trace event rework ("cxl: Add port and dport identifiers to CXL AER trace events") adds explicit memdev, port, dport, and host fields that provide full context for all device types.
Quoted 3 lines
Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
Re: [PATCH v18 08/13] cxl/pci: Thread port and dport through RAS handling helpers
In reply to Terry BowmanQuoted 27 lines · Terry Bowman
From: Dan Williams <[email protected]>
The callers of
cxl_handle_ras()andcxl_handle_cor_ras()already hold a structcxl_port* and structcxl_dport* for the device being handled. Passing a generic struct device * requiresis_cxl_memdev()to distinguish Endpoints from ports at trace emission time. Threading port and dport directly enablesis_cxl_endpoint(port)and explicit dport/port branching for cleaner trace dispatch.Refactor
cxl_handle_ras()andcxl_handle_cor_ras()to accept structcxl_port* and structcxl_dport* directly. The CXL RAS trace event emission logic is split into three branches: Endpoint events are identified viais_cxl_endpoint(port)and emit with the memdev, dport events emit withdport->dport_dev, and Upstream Port events fall back toport->uport_dev.Update
cxl_handle_rdport_errors()inras_rch.candcxl_handle_proto_error()inras.cto pass port and dport to the refactored functions.RCH Downstream Port correctable trace events now report the dport device (
dport->dport_dev) as a consequence of threading port and dport through the RAS helpers. The following trace event rework ("cxl: Add port and dport identifiers to CXL AER trace events") adds explicit memdev, port, dport, and host fields that provide full context for all device types.
Quoted 3 lines
Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>
Quoted 152 lines
---
Changes in v17 -> v18:
- New patch.--- drivers/cxl/core/core.h | 12 ++++++++---- drivers/cxl/core/ras.c | 29 +++++++++++++++-------------- drivers/cxl/core/ras_rch.c | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-)drivers/cxl/core/core.h +8
-4@@ -185,10 +185,12 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)#ifdef CONFIG_CXL_RAS void cxl_ras_init (void );void cxl_ras_exit (void ); -bool cxl_handle_ras (struct device *dev,void __iomem *ras_base); +bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, +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_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport, +void __iomem *ras_base);void cxl_dport_map_rch_aer (struct cxl_dport *dport);void cxl_disable_rch_root_ints (struct cxl_dport *dport);void cxl_handle_rdport_errors (struct pci_dev *pdev);@@ -197,13 +199,15 @@ void devm_cxl_dport_ras_setup(struct cxl_dport *dport);#else static inline void cxl_ras_init (void ) { }static inline void cxl_ras_exit (void ) { } -static inline bool cxl_handle_ras (struct device *dev,void __iomem *ras_base) +static inline bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, +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_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport, +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) { }static inline void cxl_handle_rdport_errors (struct pci_dev *pdev) { }drivers/cxl/core/ras.c +15
-14@@ -232,7 +232,6 @@ void __iomem *to_ras_base(struct cxl_port *port, struct cxl_dport *dport)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) {@@ -241,14 +240,14 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dporeturn ; } -if (cxl_handle_ras (dev, ras_base)) +if (cxl_handle_ras (port, dport, 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 cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) {u32 status;void __iomem *addr;@@ -260,10 +259,12 @@ 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); -if (is_cxl_memdev (dev)) -trace_cxl_aer_correctable_error (to_cxl_memdev (dev), status); +if (is_cxl_endpoint (port)) +trace_cxl_aer_correctable_error (to_cxl_memdev (port->uport_dev), status); +else if (dport) +trace_cxl_port_aer_correctable_error (dport->dport_dev, status);else -trace_cxl_port_aer_correctable_error (dev, status); +trace_cxl_port_aer_correctable_error (port->uport_dev, status); } }@@ -288,7 +289,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)* Log the state of the RAS status registers and prepare them to log the * next error status. Return 1 if reset needed. */ -bool cxl_handle_ras (struct device *dev,void __iomem *ras_base) +bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) {u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32 ] = {};void __iomem *addr;@@ -315,10 +316,12 @@ bool cxl_handle_ras(struct device *dev, void __iomem *ras_base) }header_log_copy (ras_base, hl); -if (is_cxl_memdev (dev)) -trace_cxl_aer_uncorrectable_error (to_cxl_memdev (dev), status, fe, hl); +if (is_cxl_endpoint (port)) +trace_cxl_aer_uncorrectable_error (to_cxl_memdev (port->uport_dev), status, fe, hl); +else if (dport) +trace_cxl_port_aer_uncorrectable_error (dport->dport_dev, status, fe, hl);else -trace_cxl_port_aer_uncorrectable_error (dev, status, fe, hl); +trace_cxl_port_aer_uncorrectable_error (port->uport_dev, status, fe, hl);writel (status &CXL_RAS_UNCORRECTABLE_STATUS_MASK , addr);@@ -351,7 +354,7 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,* 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 (port->uport_dev,to_ras_base (port,NULL )); + ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL )); }/* @@ -382,10 +385,8 @@ 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)); +cxl_handle_cor_ras (port, dport,to_ras_base (port, dport));else cxl_do_recovery (pdev, port, dport); }drivers/cxl/core/ras_rch.c +1
-1@@ -118,7 +118,7 @@ void cxl_handle_rdport_errors(struct pci_dev *pdev)pci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (&pdev->dev,to_ras_base (port, dport)); +cxl_handle_cor_ras (dport->port, dport,to_ras_base (port, dport));else cxl_do_recovery (pdev, dport->port, dport); }
Jonathan Cameron
maintainerRe: [PATCH v18 08/13] cxl/pci: Thread port and dport through RAS handling helpers
In reply to Terry BowmanQuoted 5 lines · On Fri, 17 Jul 2026 17:27:01 -0500 Terry Bowman <[email protected]> wrote:
From: Dan Williams <[email protected]>
The callers of
cxl_handle_ras()andcxl_handle_cor_ras()already hold a structcxl_port* and structcxl_dport* for the device being handled.
It seems unlikely that all have both of them given you have handling in the code for dport == NULL. Perhaps reword.
Quoted 12 lines
Passing a generic struct device * requires
is_cxl_memdev()to distinguish Endpoints from ports at trace emission time. Threading port and dport directly enablesis_cxl_endpoint(port)and explicit dport/port branching for cleaner trace dispatch.Refactor
cxl_handle_ras()andcxl_handle_cor_ras()to accept structcxl_port* and structcxl_dport* directly. The CXL RAS trace event emission logic is split into three branches: Endpoint events are identified viais_cxl_endpoint(port)and emit with the memdev, dport events emit withdport->dport_dev, and Upstream Port events fall back toport->uport_dev.
Quoted 3 lines
Update
cxl_handle_rdport_errors()inras_rch.candcxl_handle_proto_error()inras.cto pass port and dport to the refactored functions.
Definitely no need to say which files they are in. If we care we can look at the patch.
Quoted 163 lines
RCH Downstream Port correctable trace events now report the dport device (
dport->dport_dev) as a consequence of threading port and dport through the RAS helpers. The following trace event rework ("cxl: Add port and dport identifiers to CXL AER trace events") adds explicit memdev, port, dport, and host fields that provide full context for all device types.Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>---
Changes in v17 -> v18:
- New patch.--- drivers/cxl/core/core.h | 12 ++++++++---- drivers/cxl/core/ras.c | 29 +++++++++++++++-------------- drivers/cxl/core/ras_rch.c | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-)drivers/cxl/core/core.h +8
-4@@ -185,10 +185,12 @@ static inline struct device *dport_to_host(struct cxl_dport *dport)#ifdef CONFIG_CXL_RAS void cxl_ras_init (void );void cxl_ras_exit (void ); -bool cxl_handle_ras (struct device *dev,void __iomem *ras_base); +bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, +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_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport, +void __iomem *ras_base);void cxl_dport_map_rch_aer (struct cxl_dport *dport);void cxl_disable_rch_root_ints (struct cxl_dport *dport);void cxl_handle_rdport_errors (struct pci_dev *pdev);@@ -197,13 +199,15 @@ void devm_cxl_dport_ras_setup(struct cxl_dport *dport);#else static inline void cxl_ras_init (void ) { }static inline void cxl_ras_exit (void ) { } -static inline bool cxl_handle_ras (struct device *dev,void __iomem *ras_base) +static inline bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, +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_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport, +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) { }static inline void cxl_handle_rdport_errors (struct pci_dev *pdev) { }drivers/cxl/core/ras.c +15
-14@@ -232,7 +232,6 @@ void __iomem *to_ras_base(struct cxl_port *port, struct cxl_dport *dport)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) {@@ -241,14 +240,14 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dporeturn ; } -if (cxl_handle_ras (dev, ras_base)) +if (cxl_handle_ras (port, dport, 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 cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) {u32 status;void __iomem *addr;@@ -260,10 +259,12 @@ 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); -if (is_cxl_memdev (dev)) -trace_cxl_aer_correctable_error (to_cxl_memdev (dev), status); +if (is_cxl_endpoint (port)) +trace_cxl_aer_correctable_error (to_cxl_memdev (port->uport_dev), status); +else if (dport) +trace_cxl_port_aer_correctable_error (dport->dport_dev, status);else -trace_cxl_port_aer_correctable_error (dev, status); +trace_cxl_port_aer_correctable_error (port->uport_dev, status); } }@@ -288,7 +289,7 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)* Log the state of the RAS status registers and prepare them to log the * next error status. Return 1 if reset needed. */ -bool cxl_handle_ras (struct device *dev,void __iomem *ras_base) +bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) {u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32 ] = {};void __iomem *addr;@@ -315,10 +316,12 @@ bool cxl_handle_ras(struct device *dev, void __iomem *ras_base) }header_log_copy (ras_base, hl); -if (is_cxl_memdev (dev)) -trace_cxl_aer_uncorrectable_error (to_cxl_memdev (dev), status, fe, hl); +if (is_cxl_endpoint (port)) +trace_cxl_aer_uncorrectable_error (to_cxl_memdev (port->uport_dev), status, fe, hl); +else if (dport) +trace_cxl_port_aer_uncorrectable_error (dport->dport_dev, status, fe, hl);else -trace_cxl_port_aer_uncorrectable_error (dev, status, fe, hl); +trace_cxl_port_aer_uncorrectable_error (port->uport_dev, status, fe, hl);writel (status &CXL_RAS_UNCORRECTABLE_STATUS_MASK , addr);@@ -351,7 +354,7 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,* 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 (port->uport_dev,to_ras_base (port,NULL )); + ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL )); }/* @@ -382,10 +385,8 @@ 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)); +cxl_handle_cor_ras (port, dport,to_ras_base (port, dport));else cxl_do_recovery (pdev, port, dport); }drivers/cxl/core/ras_rch.c +1
-1@@ -118,7 +118,7 @@ void cxl_handle_rdport_errors(struct pci_dev *pdev)pci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (&pdev->dev,to_ras_base (port, dport)); +cxl_handle_cor_ras (dport->port, dport,to_ras_base (port, dport));else cxl_do_recovery (pdev, dport->port, dport); }
PATCH v18 9/13 cxl: Update CXL Endpoint AER handler
In reply to Terry BowmanRename cxl_error_detected() to cxl_pci_error_detected() and rename the struct pci_error_handlers instance to cxl_pci_error_handlers to avoid shadowing the struct type tag.
Document the unconditional CXL RAS read policy: on a dead link, readl() returns 0xFFFFFFFF which is interpreted as UCE bits set and triggers a panic. If RAS registers are not mapped the read is skipped and the frozen/perm_failure switch cases defer to AER recovery for devices without active CXL.mem traffic.
---
Changes in v17->v18:
- Fix cxl_pci_error_detected() to use find_cxl_port_by_uport() and port->uport_dev
- Read CXL RAS unconditionally; panic on UCE regardless of channel state
- Document unconditional read policy and 0xFFFFFFFF behavior in comment
- Drop guard removal paragraph from commit message (not in this diff)
- Drop Reviewed-by tags pending re-review after message change
Changes in v16->v17:
- Rename pci_error_handlers struct instance to cxl_pci_error_handlers to avoid shadowing the struct type tag.
- Restore scoped_guard(device) and dev->driver check around AER read.
- NULL-check find_cxl_port_by_dev() before deref of port->uport_dev.
- Updated commit message. (Terry)
- Add scope cleanup for port variable in cxl_pci_error_detected() (Terry)
- Drop cxl_uncor_aer_present(), rely on AER state
Changes in v15->v16:
- Update commit message (DaveJ)
- s/cxl_handle_aer()/cxl_uncor_aer_present()/g (Jonathan)
- cxl_uncor_aer_present(): Leave original result calculation based on if a UCE is present and the provided state (Terry)
- Add call to pci_print_aer(). AER fails to log because is upstream link (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/ras.c | 24 +++++++++++++++--------- drivers/cxl/cxlpci.h | 8 ++++---- drivers/cxl/pci.c | 12 ++++++------ 3 files changed, 25 insertions(+), 19 deletions(-)
drivers/cxl/core/ras.c +15 -9
@@ -328,10 +328,8 @@ bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomemreturn true; } - - -pci_ers_result_t cxl_error_detected (struct pci_dev *pdev, -pci_channel_state_t state) +pci_ers_result_t cxl_pci_error_detected (struct pci_dev *pdev, +pci_channel_state_t state) { struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);bool ue = false;
@@ -349,10 +347,18 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, }/* -* 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. +* The CXL RAS read is unconditional regardless of channel +* state. Any uncorrectable error bit set in the CXL RAS +* status register triggers a panic because CXL.mem cache +* coherency is already lost; continuing risks silent data +* corruption across interleaved HDM regions. +* +* On a dead link readl() returns 0xFFFFFFFF which sets all +* UCE bits and also triggers the panic - this is intentional. +* If RAS registers are not mapped the read is skipped, the +* panic is not reached, and the frozen/perm_failure switch +* cases below handle AER recovery for devices without active +* CXL.mem traffic. */ ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL )); }
@@ -380,7 +386,7 @@ 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" ); +EXPORT_SYMBOL_NS_GPL (cxl_pci_error_detected,"CXL" );static void cxl_handle_proto_error (struct pci_dev *pdev,struct cxl_port *port,struct cxl_dport *dport,int severity)
drivers/cxl/cxlpci.h +4 -4
@@ -89,13 +89,13 @@ struct cxl_dev_state;void read_cdat_data (struct cxl_port *port);#ifdef CONFIG_CXL_RAS -pci_ers_result_t cxl_error_detected (struct pci_dev *pdev, -pci_channel_state_t state); +pci_ers_result_t cxl_pci_error_detected (struct pci_dev *pdev, +pci_channel_state_t state);void devm_cxl_dport_rch_ras_setup (struct cxl_dport *dport);void devm_cxl_port_ras_setup (struct cxl_port *port);#else -static inline pci_ers_result_t cxl_error_detected (struct pci_dev *pdev, -pci_channel_state_t state) +static inline pci_ers_result_t cxl_pci_error_detected (struct pci_dev *pdev, +pci_channel_state_t state) {return PCI_ERS_RESULT_NONE ; }
drivers/cxl/pci.c +6 -6
@@ -1000,18 +1000,18 @@ static void cxl_reset_done(struct pci_dev *pdev) } } -static const struct pci_error_handlers cxl_error_handlers = { - .error_detected = cxl_error_detected, - .slot_reset = cxl_slot_reset, - .resume = cxl_error_resume, - .reset_done = cxl_reset_done, +static const struct pci_error_handlers cxl_pci_error_handlers = { + .error_detected = cxl_pci_error_detected, + .slot_reset = cxl_slot_reset, + .resume = cxl_error_resume, + .reset_done = cxl_reset_done, };static struct pci_driver cxl_pci_driver = { .name =KBUILD_MODNAME , .id_table = cxl_mem_pci_tbl, .probe = cxl_pci_probe, - .err_handler = &cxl_error_handlers, + .err_handler = &cxl_pci_error_handlers, .dev_groups = cxl_rcd_groups, .driver = { .probe_type =PROBE_PREFER_ASYNCHRONOUS ,
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 09/13] cxl: Update CXL Endpoint AER handler
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] Unconditional kernel panic on PCIe link failure for idle/unused CXL endpoint devices. --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unconditional kernel panic on PCIe link failure for idle/unused CXL endpoint devices. --
--- Patch [9]: [PATCH v18 09/13] cxl: Update CXL Endpoint AER handler --- commit 01bcb4332c20e7d1dcce013851a595e79f03a892
Author: Terry Bowman <[email protected]>
cxl: Update CXL Endpoint AER handler
This commit updates the CXL endpoint AER error handler. It documents the unconditional CXL RAS read policy and relies on this policy for CXL endpoint error handling.
Quoted 5 lines
Document the unconditional CXL RAS read policy: on a dead link,
readl()returns0xFFFFFFFFwhich is interpreted as UCE bits set and triggers a panic. If RAS registers are not mapped the read is skipped and the frozen/perm_failure switch cases defer to AER recovery for devices without active CXL.mem traffic.
Is this assumption about RAS registers not being mapped accurate?
Looking at cxl_endpoint_port_probe(), it appears to unconditionally map the RAS registers via devm_cxl_port_ras_setup() for any present endpoint.
Quoted 3 lines
drivers/cxl/core/ras.c +0
-0
[ ... ]
Quoted 12 lines
drivers/cxl/core/ras.c +4
-4@@ -349,10 +347,18 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, }/* -* 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. +* The CXL RAS read is unconditional regardless of channel +* state. Any uncorrectable error bit set in the CXL RAS +* status register triggers a panic because CXL.mem cache +* coherency is already lost; continuing risks silent data
drivers/cxl/core/ras.c pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, · line 363
Quoted 10 lines
drivers/cxl/core/ras.c +8
-0+* corruption across interleaved HDM regions. +* +* On a dead link readl() returns 0xFFFFFFFF which sets all +* UCE bits and also triggers the panic - this is intentional. +* If RAS registers are not mapped the read is skipped, the +* panic is not reached, and the frozen/perm_failure switch +* cases below handle AER recovery for devices without active +* CXL.mem traffic. */ ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL ));
[Severity: High]
Does this regression cause a system-wide panic for idle or unused CXL endpoint devices?
If devm_cxl_port_ras_setup() unconditionally maps the RAS registers during probe, cxl_handle_ras() will always execute the readl() here. During a transient PCIe link failure (like an AER frozen state) or a surprise hot unplug, the link is dead, so readl() returns 0xFFFFFFFF.
Because this sets the uncorrectable error (UCE) bits, cxl_handle_ras() will return true. Doesn't this mean any transient PCIe link failure will now unconditionally crash the system due to the subsequent if (ue) panic check, breaking standard PCIe error containment?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
Re: [PATCH v18 09/13] cxl: Update CXL Endpoint AER handler
Quoted 2 lines · On 7/17/2026 5:53 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unconditional kernel panic on PCIe link failure for idle/unused CXL endpoint devices.
This is a false positive.
The comment addresses the corner case when the device is removed from the bus even momentarily or transiently. In this case the memory coherency will be lost as cache lines will not be accessible and continuing operation risks silent data corruption. The kernel panic is intentional.
-Terry
Quoted 66 lines
--
--- Patch [9]: [PATCH v18 09/13] cxl: Update CXL Endpoint AER handler --- commit
01bcb4332c20e7d1dcce013851a595e79f03a892
Author: Terry Bowman <[email protected]>cxl: Update CXL Endpoint AER handler
This commit updates the CXL endpoint AER error handler. It documents the unconditional CXL RAS read policy and relies on this policy for CXL endpoint error handling.
Quoted 5 lines
Document the unconditional CXL RAS read policy: on a dead link,
readl()returns0xFFFFFFFFwhich is interpreted as UCE bits set and triggers a panic. If RAS registers are not mapped the read is skipped and the frozen/perm_failure switch cases defer to AER recovery for devices without active CXL.mem traffic.Is this assumption about RAS registers not being mapped accurate?
Looking at
cxl_endpoint_port_probe(), it appears to unconditionally map the RAS registers viadevm_cxl_port_ras_setup()for any present endpoint.Quoted 3 lines
drivers/cxl/core/ras.c +0
-0[ ... ]
Quoted 12 lines
drivers/cxl/core/ras.c +4
-4@@ -349,10 +347,18 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, }/* -* 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. +* The CXL RAS read is unconditional regardless of channel +* state. Any uncorrectable error bit set in the CXL RAS +* status register triggers a panic because CXL.mem cache +* coherency is already lost; continuing risks silent data drivers/cxl/core/ras.c pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, · line 363
Quoted 10 lines
drivers/cxl/core/ras.c +8
-0+* corruption across interleaved HDM regions. +* +* On a dead link readl() returns 0xFFFFFFFF which sets all +* UCE bits and also triggers the panic - this is intentional. +* If RAS registers are not mapped the read is skipped, the +* panic is not reached, and the frozen/perm_failure switch +* cases below handle AER recovery for devices without active +* CXL.mem traffic. */ ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL ));[Severity: High]
Does this regression cause a system-wide panic for idle or unused CXL endpoint devices?If
devm_cxl_port_ras_setup()unconditionally maps the RAS registers during probe,cxl_handle_ras()will always execute thereadl()here. During a transient PCIe link failure (like an AER frozen state) or a surprise hot unplug, the link is dead, soreadl()returns0xFFFFFFFF.Because this sets the uncorrectable error (UCE) bits,
cxl_handle_ras()will return true. Doesn't this mean any transient PCIe link failure will now unconditionally crash the system due to the subsequent if (ue) panic check, breaking standard PCIe error containment?
Re: [PATCH v18 09/13] cxl: Update CXL Endpoint AER handler
In reply to Terry BowmanQuoted 11 lines · Terry Bowman
Rename
cxl_error_detected()tocxl_pci_error_detected()and rename the structpci_error_handlersinstance tocxl_pci_error_handlersto avoid shadowing the struct type tag.Document the unconditional CXL RAS read policy: on a dead link,
readl()returns0xFFFFFFFFwhich is interpreted as UCE bits set and triggers a panic. If RAS registers are not mapped the read is skipped and the frozen/perm_failure switch cases defer to AER recovery for devices without active CXL.mem traffic.Signed-off-by Terry Bowman <[email protected]>
Quoted 165 lines
---
Changes in
v17->v18:
- Fixcxl_pci_error_detected()to usefind_cxl_port_by_uport()andport->uport_dev
- Read CXL RAS unconditionally; panic on UCE regardless of channel state
- Document unconditional read policy and0xFFFFFFFFbehavior in comment
- Drop guard removal paragraph from commit message (not in this diff)
- Drop Reviewed-by tags pending re-review after message changeChanges in
v16->v17:
- Renamepci_error_handlersstruct instance tocxl_pci_error_handlersto avoid shadowing the struct type tag.
- Restorescoped_guard(device)anddev->drivercheck around AER read.
- NULL-checkfind_cxl_port_by_dev()before deref ofport->uport_dev.
- Updated commit message. (Terry)
- Add scope cleanup for port variable incxl_pci_error_detected()(Terry)
- Dropcxl_uncor_aer_present(), rely on AER stateChanges in
v15->v16:
- Update commit message (DaveJ)
- s/cxl_handle_aer()/cxl_uncor_aer_present()/g (Jonathan)
-cxl_uncor_aer_present(): Leave original result calculation based on if a UCE is present and the provided state (Terry)
- Add call topci_print_aer(). AER fails to log because is upstream link (Terry)Changes in
v14->v15:
- Update commit message and title. Added Bjorn's ack.
- Move CE and UCE handling logic hereChanges 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)
- Removecxl_walk_port()(Dan)
- Removecxl_pci_drv_bound(). Check for 'is_cxl' parent port is sufficient (Dan)
- Removedevice_lock_if()
- Combined CE and UCE here (Terry)Changes in
v12->v13:
- Moveget_pci_cxl_host_dev()andcxl_handle_proto_error()to Dequeue patch (Terry)
- Remove EP case incxl_get_ras_base(), not used. (Terry)
- Remove check fordport->dport_dev(Dave)
- Remove whitespace (Terry)Changes in
v11->v12:
- Add call tocxl_pci_drv_bound()incxl_handle_proto_error()andpci_to_cxl_dev()
- Changecxl_error_detected()->cxl_cor_error_detected()
- Remove NULL variable assignments
- Replacebus_find_device()withfind_cxl_port_by_uport()for upstream port searches.Changes in
v10->v11:
- None--- drivers/cxl/core/ras.c | 24 +++++++++++++++--------- drivers/cxl/cxlpci.h | 8 ++++---- drivers/cxl/pci.c | 12 ++++++------ 3 files changed, 25 insertions(+), 19 deletions(-)drivers/cxl/core/ras.c +15
-9@@ -328,10 +328,8 @@ bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomemreturn true; } - - -pci_ers_result_t cxl_error_detected (struct pci_dev *pdev, -pci_channel_state_t state) +pci_ers_result_t cxl_pci_error_detected (struct pci_dev *pdev, +pci_channel_state_t state) { struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);bool ue = false;@@ -349,10 +347,18 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, }/* -* 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. +* The CXL RAS read is unconditional regardless of channel +* state. Any uncorrectable error bit set in the CXL RAS +* status register triggers a panic because CXL.mem cache +* coherency is already lost; continuing risks silent data +* corruption across interleaved HDM regions. +* +* On a dead link readl() returns 0xFFFFFFFF which sets all +* UCE bits and also triggers the panic - this is intentional. +* If RAS registers are not mapped the read is skipped, the +* panic is not reached, and the frozen/perm_failure switch +* cases below handle AER recovery for devices without active +* CXL.mem traffic. */ ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL )); }@@ -380,7 +386,7 @@ 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" ); +EXPORT_SYMBOL_NS_GPL (cxl_pci_error_detected,"CXL" );static void cxl_handle_proto_error (struct pci_dev *pdev,struct cxl_port *port,struct cxl_dport *dport,int severity)drivers/cxl/cxlpci.h +4
-4@@ -89,13 +89,13 @@ struct cxl_dev_state;void read_cdat_data (struct cxl_port *port);#ifdef CONFIG_CXL_RAS -pci_ers_result_t cxl_error_detected (struct pci_dev *pdev, -pci_channel_state_t state); +pci_ers_result_t cxl_pci_error_detected (struct pci_dev *pdev, +pci_channel_state_t state);void devm_cxl_dport_rch_ras_setup (struct cxl_dport *dport);void devm_cxl_port_ras_setup (struct cxl_port *port);#else -static inline pci_ers_result_t cxl_error_detected (struct pci_dev *pdev, -pci_channel_state_t state) +static inline pci_ers_result_t cxl_pci_error_detected (struct pci_dev *pdev, +pci_channel_state_t state) {return PCI_ERS_RESULT_NONE ; }drivers/cxl/pci.c +6
-6@@ -1000,18 +1000,18 @@ static void cxl_reset_done(struct pci_dev *pdev) } } -static const struct pci_error_handlers cxl_error_handlers = { - .error_detected = cxl_error_detected, - .slot_reset = cxl_slot_reset, - .resume = cxl_error_resume, - .reset_done = cxl_reset_done, +static const struct pci_error_handlers cxl_pci_error_handlers = { + .error_detected = cxl_pci_error_detected, + .slot_reset = cxl_slot_reset, + .resume = cxl_error_resume, + .reset_done = cxl_reset_done, };static struct pci_driver cxl_pci_driver = { .name =KBUILD_MODNAME , .id_table = cxl_mem_pci_tbl, .probe = cxl_pci_probe, - .err_handler = &cxl_error_handlers, + .err_handler = &cxl_pci_error_handlers, .dev_groups = cxl_rcd_groups, .driver = { .probe_type =PROBE_PREFER_ASYNCHRONOUS ,
Re: [PATCH v18 09/13] cxl: Update CXL Endpoint AER handler
In reply to Terry BowmanQuoted 4 lines · On Fri, 17 Jul 2026 17:27:02 -0500 Terry Bowman <[email protected]> wrote:
Rename
cxl_error_detected()tocxl_pci_error_detected()and rename the structpci_error_handlersinstance tocxl_pci_error_handlersto avoid shadowing the struct type tag.
Quoted 8 lines
Document the unconditional CXL RAS read policy: on a dead link,
readl()returns0xFFFFFFFFwhich is interpreted as UCE bits set and triggers a panic. If RAS registers are not mapped the read is skipped and the frozen/perm_failure switch cases defer to AER recovery for devices without active CXL.mem traffic.Signed-off-by Terry Bowman <[email protected]>
A couple of trivial things inline.
Quoted 10 lines
drivers/cxl/core/ras.c | 24 +++++++++++++++--------- drivers/cxl/cxlpci.h | 8 ++++---- drivers/cxl/pci.c | 12 ++++++------ 3 files changed, 25 insertions(+), 19 deletions(-)drivers/cxl/core/ras.c +0
-0
drivers/cxl/core/ras.c bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomem · line 332
Quoted 5 lines
drivers/cxl/core/ras.c +0
-2@@ -328,10 +328,8 @@ bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomemreturn true; } - -
This white space removal should be in patch 7 I think.
Quoted 8 lines
drivers/cxl/core/ras.c +2
-2-pci_ers_result_t cxl_error_detected (struct pci_dev *pdev, -pci_channel_state_t state) +pci_ers_result_t cxl_pci_error_detected (struct pci_dev *pdev, +pci_channel_state_t state) { struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_uport(&pdev->dev);bool ue = false;
drivers/cxl/core/ras.c pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, · line 350
Quoted 8 lines
drivers/cxl/core/ras.c +1
-4@@ -349,10 +347,18 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, }/* -* 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. +* The CXL RAS read is unconditional regardless of channel
Keep the 80 char wrap for comments. Also local style is single space after . (I'm terrible at not following style on that stuff but do as I say not as I do!)
drivers/cxl/core/ras.c pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, · line 361
Quoted 11 lines
drivers/cxl/core/ras.c +11
-0+* state. Any uncorrectable error bit set in the CXL RAS +* status register triggers a panic because CXL.mem cache +* coherency is already lost; continuing risks silent data +* corruption across interleaved HDM regions. +* +* On a dead link readl() returns 0xFFFFFFFF which sets all +* UCE bits and also triggers the panic - this is intentional. +* If RAS registers are not mapped the read is skipped, the +* panic is not reached, and the frozen/perm_failure switch +* cases below handle AER recovery for devices without active +* CXL.mem traffic.
Now this comment I like. Good and clear and explaining the non obvious decision.
Quoted 11 lines
drivers/cxl/core/ras.c +0
-0*/ ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL ));drivers/cxl/pci.c +0
-0@@ -1000,18 +1000,18 @@ static void cxl_reset_done(struct pci_dev *pdev) } }
drivers/cxl/pci.c static void cxl_reset_done(struct pci_dev *pdev) · line 1007
Quoted 10 lines
drivers/cxl/pci.c +5
-5-static const struct pci_error_handlers cxl_error_handlers = { - .error_detected = cxl_error_detected, - .slot_reset = cxl_slot_reset, - .resume = cxl_error_resume, - .reset_done = cxl_reset_done, +static const struct pci_error_handlers cxl_pci_error_handlers = { + .error_detected = cxl_pci_error_detected, + .slot_reset = cxl_slot_reset, + .resume = cxl_error_resume, + .reset_done = cxl_reset_done,
Do we need the re-indent? Nice to make it more obvious what didn't change.
Quoted 1 line
drivers/cxl/pci.c +0
-0};
PATCH v18 10/13 cxl: Add port and dport identifiers to CXL AER trace events
In reply to Terry BowmanFrom: Dan Williams <[email protected]>
Pass struct cxl_port * and struct cxl_dport * to the cxl_aer_* trace events instead of a plain struct device * derived at the caller. The trace event helpers then derive the right strings for endpoints, switch ports, root ports, and RCH downstream ports consistently across the CPER and native AER paths.
The unified cxl_aer_* events keep "memdev" as the legacy field (endpoint events populate it with the memdev name; non-endpoint events emit memdev="") and add new "port" and "dport" string fields populated for all CXL device classes. Updated userspace can key off "port" and "dport" without a parallel set of events.
Remove the separate cxl_port_aer_uncorrectable_error and cxl_port_aer_correctable_error trace events. All CXL AER events now use the unified cxl_aer_* events with port and dport fields.
Rework cxl_cper_handle_prot_err() to use find_cxl_port_by_dev() and the unified trace helpers, replacing the per-port-type branching and bus_find_device() memdev lookup.
The TP_printk format string places "port=%s dport=%s" between "memdev=%s" and "host=%s", changing the text-mode field order from the pre-patch output. This does not affect consumers such as rasdaemon that use libtraceevent to parse fields by name rather than by fixed text position.
For non-endpoint events (switch port, root port, RCH dport), "memdev" is empty and "port"/"dport" carry the topology information.
The serial number is retrieved via pci_get_dsn() which performs live PCI configuration space reads. A following patch ("PCI: Cache PCI DSN into pci_dev->dsn during probe") replaces these with a cached serial number to avoid config space access in error handlers and panic paths.
Below are examples of the different CXL devices' error trace logs after this patch:
---------------------
| CXL RP - 0C:00.0 |
---------------------
|
---------------------
| CXL USP - 0D:00.0 |
---------------------
|
--------------------
| CXL DSP - 0E:00.0 |
--------------------
|
---------------------
| CXL EP - 0F:00.0 |
---------------------Root Port:cxl_aer_correctable_error: memdev= port=port1 dport=0000:0c:00.0 \
host=pci0000:0c serial=0: status: 'Memory Data ECC Error'
cxl_aer_uncorrectable_error: memdev= port=port1 dport=0000:0c:00.0 \
host=pci0000:0c serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'
Upstream Switch Port:cxl_aer_correctable_error: memdev= port=port2 dport= host=0000:0d:00.0 \
serial=0: status: 'Memory Data ECC Error'
UCE NA - Upstream Switch Port UCE's are handled in the portdrv driver's PCI AER callbacks that are not CXL aware.
Downstream Switch Port:cxl_aer_correctable_error: memdev= port=port2 dport=0000:0e:00.0 \
host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'
cxl_aer_uncorrectable_error: memdev= port=port2 dport=0000:0e:00.0 \
host=0000:0d:00.0 serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'
Endpoint:cxl_aer_uncorrectable_error: memdev=mem1 port=endpoint4 dport= \
host=0000:0f:00.0 serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'
cxl_aer_correctable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 \
serial=0: status: 'Memory Data ECC Error'
---
Changes in v17->v18:
- Consolidate double find_cxl_port_by_dev() in cxl_cper_handle_prot_err()
- Add comment noting dport is NULL for Endpoint and Upstream Port devices
- Add cxl_trace_* helpers
- Add CPER refactor
Changes in v16->v17:
- Replace cxlds->serial with pci_get_dsn()
- Change 'memdev' to 'device' (Dan)
- Updated Commit message
Changes in v15->v16:
- Add Dan's review-by
- Incorporate Dan's comment into commit message:
"Add the serial number at the end to preserve compatibility with libtraceevent parsing of the parameters."
Changes in v14->v15:
- Update commit message.
- Moved cxl_handle_ras/cxl_handle_cor_ras() changes to future patch (terry)
Changes in v13->v14:
- Update commit headline (Bjorn)
Changes in v12->v13:
- Added Dave Jiang's review-by
Changes in v11 -> v12:
- Correct parameters to call trace_cxl_aer_correctable_error()
- Add reviewed-by for Jonathan and Shiju
Changes in v10->v11:
- Updated CE and UCE trace routines to maintain consistent TP_Struct ABI and unchanged TP_printk() logging.
--- drivers/cxl/core/core.h | 8 +-- drivers/cxl/core/ras.c | 131 +++++++++++-------------------------- drivers/cxl/core/ras_rch.c | 3 +- drivers/cxl/core/trace.c | 35 ++++++++++ drivers/cxl/core/trace.h | 91 ++++++++------------------ drivers/cxl/cxlmem.h | 7 ++ 6 files changed, 113 insertions(+), 162 deletions(-)
drivers/cxl/core/core.h +4 -4
@@ -186,11 +186,11 @@ 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 cxl_port *port,struct cxl_dport *dport, -void __iomem *ras_base); +void __iomem *ras_base,u64 serial);void cxl_do_recovery (struct pci_dev *pdev,struct cxl_port *port,struct cxl_dport *dport);void cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport, -void __iomem *ras_base); +void __iomem *ras_base,u64 serial);void cxl_dport_map_rch_aer (struct cxl_dport *dport);void cxl_disable_rch_root_ints (struct cxl_dport *dport);void cxl_handle_rdport_errors (struct pci_dev *pdev);
@@ -200,14 +200,14 @@ void devm_cxl_dport_ras_setup(struct cxl_dport *dport);static inline void cxl_ras_init (void ) { }static inline void cxl_ras_exit (void ) { }static inline bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, -void __iomem *ras_base) +void __iomem *ras_base,u64 serial) {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 cxl_port *port,struct cxl_dport *dport, -void __iomem *ras_base) { } +void __iomem *ras_base,u64 serial) { }static inline void cxl_dport_map_rch_aer (struct cxl_dport *dport) { }static inline void cxl_disable_rch_root_ints (struct cxl_dport *dport) { }static inline void cxl_handle_rdport_errors (struct pci_dev *pdev) { }
drivers/cxl/core/ras.c +39 -92
214 lines not on this page · raw message
drivers/cxl/core/ras_rch.c +2 -1
@@ -118,7 +118,8 @@ void cxl_handle_rdport_errors(struct pci_dev *pdev)pci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (dport->port, dport,to_ras_base (port, dport)); +cxl_handle_cor_ras (dport->port, dport,to_ras_base (port, dport), +pci_get_dsn (pdev));else cxl_do_recovery (pdev, dport->port, dport); }
drivers/cxl/core/trace.c +35 -0
@@ -2,7 +2,42 @@/* Copyright(c) 2022 Intel Corporation. All rights reserved. */ #include <cxl.h> +#include <cxlmem.h> #include "core.h" +const char *cxl_trace_memdev_name (struct cxl_port *port) +{ +if (is_cxl_endpoint (port)) { +struct cxl_memdev *cxlmd =to_cxl_memdev (port->uport_dev); + +return dev_name (&cxlmd->dev); + } + +return "" ; +} + +const char *cxl_trace_host_name (struct cxl_port *port) +{ +if (is_cxl_endpoint (port)) { +struct cxl_memdev *cxlmd =to_cxl_memdev (port->uport_dev); + +return dev_name (cxlmd->dev.parent); + } + +return dev_name (port->uport_dev); +} + +const char *cxl_trace_port_name (struct cxl_port *port) +{ +return dev_name (&port->dev); +} + +const char *cxl_trace_dport_name (struct cxl_dport *dport) +{ +if (dport) +return dev_name (dport->dport_dev); +return "" ; +} +#define CREATE_TRACE_POINTS #include "trace.h"
drivers/cxl/core/trace.h +26 -65
128 lines not on this page · raw message
drivers/cxl/cxlmem.h +7 -0
@@ -125,6 +125,13 @@ static inline int cxl_memdev_attach_region(struct cxl_memdev *cxlmd)#endif struct cxl_memdev *devm_cxl_add_classdev (struct cxl_dev_state *cxlds); + +/* trace-event helpers */ +const char *cxl_trace_memdev_name (struct cxl_port *port); +const char *cxl_trace_host_name (struct cxl_port *port); +const char *cxl_trace_port_name (struct cxl_port *port); +const char *cxl_trace_dport_name (struct cxl_dport *dport); +struct cxl_memdev *__devm_cxl_add_memdev (struct cxl_dev_state *cxlds,const struct cxl_memdev_attach *attach); int devm_cxl_sanitize_setup_notifier(struct device *host,
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Asynchronous CPER error handling races with ACPI driver unbind, causing Use-After-Free of…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Asynchronous CPER error handling races with ACPI driver unbind, causing Use-After-Free of cxl_dport.
- [High] Live PCI configuration space reads on a potentially frozen or dead link during AER recovery. --
--- Patch [10]: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events --- commit 069c60a58d08507582ec548c08666c5374faa22d
Author: Dan Williams <[email protected]>
Subject: cxl: Add port and dport identifiers to CXL AER trace events
This commit updates the CXL AER trace events to include port and dport identifiers instead of deriving a plain device pointer at the caller. It replaces the separate uncorrectable and correctable trace events with unified cxl_aer_* events. CPER handling is also reworked to use find_cxl_port_by_dev() and the unified trace helpers.
Quoted 5 lines
The serial number is retrieved via
pci_get_dsn()which performs live PCI configuration space reads. A following patch ("PCI: Cache PCI DSN intopci_dev->dsnduring probe") replaces these with a cached serial number to avoid config space access in error handlers and panic paths.
[Severity: High]
Does calling pci_get_dsn() before the follow-up patch is applied risk causing a lockup?
cxl_pci_error_detected() is called during AER recovery, where the link may be in the pci_channel_io_frozen state. pci_get_dsn() executes live configuration reads (pci_read_config_dword()) to traverse PCIe extended capabilities.
Accessing a frozen link can cause the host bridge to lock up or trigger a secondary master abort. Will this cause completion timeouts and prevent recovery during the window between this patch and the subsequent caching patch?
Quoted 4 lines
drivers/cxl/core/ras.c +0
-0
[ ... ]
Quoted 4 lines
drivers/cxl/core/ras.c +0
-0@@ -109,47 +77,34 @@ static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dporvoid cxl_cper_handle_prot_err (struct cxl_cper_prot_err_work_data *data) {
[ ... ]
drivers/cxl/core/ras.c static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dpor · line 100
Quoted 4 lines
drivers/cxl/core/ras.c +4
-0+guard (device)(&port->dev); + +/* dport is NULL for Endpoint and Upstream Port devices */ + dport =cxl_find_dport_by_dev (port, &pdev->dev);
[Severity: High]
Is it possible for the dport to be freed concurrently here, leading to a use-after-free regression?
While cxl_cper_handle_prot_err() holds the port's device lock, cxl_dport structures for root ports are tied to the parent ACPI device's devres lifecycle.
If the parent driver unbinds (e.g., during ACPI hot-remove), it executes devres_release_all() under the parent's lock, which frees the dport directly via cxl_dport_remove() and free_dport().
Could cxl_find_dport_by_dev() load this freed pointer, which is then dereferenced in the trace event?
drivers/cxl/core/trace.c:cxl_trace_dport_name() {
if (dport)
return dev_name(dport->dport_dev);
...
}Quoted 10 lines
drivers/cxl/core/ras.c +4
-3- cxlmd =to_cxl_memdev (mem_dev);if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_corr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap);else -cxl_cper_trace_uncorr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_uncorr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap); }
[ ... ]
drivers/cxl/core/ras.c pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev, · line 311
Quoted 8 lines
drivers/cxl/core/ras.c +2
-1@@ -360,7 +306,8 @@ pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,* cases below handle AER recovery for devices without active * CXL.mem traffic. */ - ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL )); + ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL ), +pci_get_dsn (pdev)); }
[Severity: High]
Does this live config read trigger the lockups mentioned in the commit message? Since cxl_pci_error_detected() executes when the link state is potentially pci_channel_io_frozen, the pci_get_dsn() call will traverse PCIe extended capabilities on a dead link.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
Re: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events
Quoted 2 lines · On 7/17/2026 5:53 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Asynchronous CPER error handling races with ACPI driver unbind, causing Use-After-Free ofcxl_dport.
This is a false positive.
The Downstream port lifecycle is tied to the Port's xarray and synchronized here using the Port's device lock.
Quoted 1 line
- [High] Live PCI configuration space reads on a potentially frozen or dead link during AER recovery.
This is fixed in patch 11 with introduction of cached PCI DSN.
-Terry
Quoted 95 lines
--
--- Patch [10]: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events --- commit
069c60a58d08507582ec548c08666c5374faa22d
Author: Dan Williams <[email protected]>
Subject: cxl: Add port and dport identifiers to CXL AER trace eventsThis commit updates the CXL AER trace events to include port and dport identifiers instead of deriving a plain device pointer at the caller. It replaces the separate uncorrectable and correctable trace events with unified cxl_aer_* events. CPER handling is also reworked to use
find_cxl_port_by_dev()and the unified trace helpers.Quoted 5 lines
The serial number is retrieved via
pci_get_dsn()which performs live PCI configuration space reads. A following patch ("PCI: Cache PCI DSN intopci_dev->dsnduring probe") replaces these with a cached serial number to avoid config space access in error handlers and panic paths.[Severity: High]
Does callingpci_get_dsn()before the follow-up patch is applied risk causing a lockup?
cxl_pci_error_detected()is called during AER recovery, where the link may be in thepci_channel_io_frozenstate.pci_get_dsn()executes live configuration reads (pci_read_config_dword()) to traverse PCIe extended capabilities.Accessing a frozen link can cause the host bridge to lock up or trigger a secondary master abort. Will this cause completion timeouts and prevent recovery during the window between this patch and the subsequent caching patch?
Quoted 4 lines
drivers/cxl/core/ras.c +0
-0[ ... ]
Quoted 4 lines
drivers/cxl/core/ras.c +0
-0@@ -109,47 +77,34 @@ static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dporvoid cxl_cper_handle_prot_err (struct cxl_cper_prot_err_work_data *data) {[ ... ]
drivers/cxl/core/ras.c static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dpor · line 100
Quoted 4 lines
drivers/cxl/core/ras.c +4
-0+guard (device)(&port->dev); + +/* dport is NULL for Endpoint and Upstream Port devices */ + dport =cxl_find_dport_by_dev (port, &pdev->dev);[Severity: High]
Is it possible for the dport to be freed concurrently here, leading to a use-after-free regression?While
cxl_cper_handle_prot_err()holds the port's device lock,cxl_dportstructures for root ports are tied to the parent ACPI device's devres lifecycle.If the parent driver unbinds (e.g., during ACPI hot-remove), it executes
devres_release_all()under the parent's lock, which frees the dport directly viacxl_dport_remove()andfree_dport().Could
cxl_find_dport_by_dev()load this freed pointer, which is then dereferenced in the trace event?drivers/cxl/core/trace.c:cxl_trace_dport_name() { if (dport) return dev_name(dport->dport_dev); ... }Quoted 10 lines
drivers/cxl/core/ras.c +4
-3- cxlmd =to_cxl_memdev (mem_dev);if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_corr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap);else -cxl_cper_trace_uncorr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_uncorr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap); }[ ... ]
drivers/cxl/core/ras.c pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev, · line 311
Quoted 8 lines
drivers/cxl/core/ras.c +2
-1@@ -360,7 +306,8 @@ pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,* cases below handle AER recovery for devices without active * CXL.mem traffic. */ - ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL )); + ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL ), +pci_get_dsn (pdev)); }[Severity: High]
Does this live config read trigger the lockups mentioned in the commit message? Sincecxl_pci_error_detected()executes when the link state is potentiallypci_channel_io_frozen, thepci_get_dsn()call will traverse PCIe extended capabilities on a dead link.
Jonathan Cameron
maintainerRe: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events
Quoted 10 lines · Terry
Quoted 2 lines · On 7/17/2026 5:53 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Asynchronous CPER error handling races with ACPI driver unbind, causing Use-After-Free ofcxl_dport.This is a false positive.
The Downstream port lifecycle is tied to the Port's xarray and synchronized here using the Port's device lock.
Quoted 1 line
- [High] Live PCI configuration space reads on a potentially frozen or dead link during AER recovery.
This is fixed in patch 11 with introduction of cached PCI DSN.
Why not flip the patch order?
Re: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events
In reply to Terry BowmanQuoted 84 lines · Terry Bowman
From: Dan Williams <[email protected]>
Pass struct
cxl_port* and structcxl_dport* to the cxl_aer_* trace events instead of a plain struct device * derived at the caller. The trace event helpers then derive the right strings for endpoints, switch ports, root ports, and RCH downstream ports consistently across the CPER and native AER paths.The unified cxl_aer_* events keep "memdev" as the legacy field (endpoint events populate it with the memdev name; non-endpoint events emit memdev="") and add new "port" and "dport" string fields populated for all CXL device classes. Updated userspace can key off "port" and "dport" without a parallel set of events.
Remove the separate
cxl_port_aer_uncorrectable_errorandcxl_port_aer_correctable_errortrace events. All CXL AER events now use the unified cxl_aer_* events with port and dport fields.Rework
cxl_cper_handle_prot_err()to usefind_cxl_port_by_dev()and the unified trace helpers, replacing the per-port-type branching andbus_find_device()memdev lookup.The
TP_printkformat string places "port=%s dport=%s" between "memdev=%s" and "host=%s", changing the text-mode field order from the pre-patch output. This does not affect consumers such as rasdaemon that use libtraceevent to parse fields by name rather than by fixed text position.For non-endpoint events (switch port, root port, RCH dport), "memdev" is empty and "port"/"dport" carry the topology information.
The serial number is retrieved via
pci_get_dsn()which performs live PCI configuration space reads. A following patch ("PCI: Cache PCI DSN intopci_dev->dsnduring probe") replaces these with a cached serial number to avoid config space access in error handlers and panic paths.Below are examples of the different CXL devices' error trace logs after this patch:
--------------------- | CXL RP - 0C:00.0 | --------------------- | --------------------- | CXL USP - 0D:00.0 | --------------------- | -------------------- | CXL DSP - 0E:00.0 | -------------------- | --------------------- | CXL EP - 0F:00.0 | ---------------------Root Port:
cxl_aer_correctable_error: memdev= port=port1 dport=0000:0c:00.0 \
host=pci0000:0c serial=0: status: 'Memory Data ECC Error'
cxl_aer_uncorrectable_error: memdev= port=port1 dport=0000:0c:00.0 \
host=pci0000:0c serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'Upstream Switch Port:
cxl_aer_correctable_error: memdev= port=port2 dport= host=0000:0d:00.0 \
serial=0: status: 'Memory Data ECC Error'UCE NA - Upstream Switch Port UCE's are handled in the portdrv driver's PCI AER callbacks that are not CXL aware.
Downstream Switch Port:
cxl_aer_correctable_error: memdev= port=port2 dport=0000:0e:00.0 \
host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'
cxl_aer_uncorrectable_error: memdev= port=port2 dport=0000:0e:00.0 \
host=0000:0d:00.0 serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'Endpoint:
cxl_aer_uncorrectable_error: memdev=mem1 port=endpoint4 dport= \
host=0000:0f:00.0 serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'
Quoted 6 lines
cxl_aer_correctable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 \
serial=0: status: 'Memory Data ECC Error'Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>
Quoted 521 lines
---
Changes inv17->v18:
- Consolidate doublefind_cxl_port_by_dev()incxl_cper_handle_prot_err()
- Add comment noting dport is NULL for Endpoint and Upstream Port devices
- Add cxl_trace_* helpers
- Add CPER refactorChanges in
v16->v17:
- Replacecxlds->serialwithpci_get_dsn()
- Change 'memdev' to 'device' (Dan)
- Updated Commit messageChanges in
v15->v16:
- Add Dan's review-by
- Incorporate Dan's comment into commit message:
"Add the serial number at the end to preserve compatibility with libtraceevent parsing of the parameters."Changes in
v14->v15:
- Update commit message.
- Moved cxl_handle_ras/cxl_handle_cor_ras() changes to future patch (terry)Changes in
v13->v14:
- Update commit headline (Bjorn)Changes in
v12->v13:
- Added Dave Jiang's review-byChanges in v11 -> v12:
- Correct parameters to calltrace_cxl_aer_correctable_error()
- Add reviewed-by for Jonathan and ShijuChanges in
v10->v11:
- Updated CE and UCE trace routines to maintain consistentTP_StructABI and unchangedTP_printk()logging.--- drivers/cxl/core/core.h | 8 +-- drivers/cxl/core/ras.c | 131 +++++++++++-------------------------- drivers/cxl/core/ras_rch.c | 3 +- drivers/cxl/core/trace.c | 35 ++++++++++ drivers/cxl/core/trace.h | 91 ++++++++------------------ drivers/cxl/cxlmem.h | 7 ++ 6 files changed, 113 insertions(+), 162 deletions(-)drivers/cxl/core/core.h +4
-4@@ -186,11 +186,11 @@ 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 cxl_port *port,struct cxl_dport *dport, -void __iomem *ras_base); +void __iomem *ras_base,u64 serial);void cxl_do_recovery (struct pci_dev *pdev,struct cxl_port *port,struct cxl_dport *dport);void cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport, -void __iomem *ras_base); +void __iomem *ras_base,u64 serial);void cxl_dport_map_rch_aer (struct cxl_dport *dport);void cxl_disable_rch_root_ints (struct cxl_dport *dport);void cxl_handle_rdport_errors (struct pci_dev *pdev);@@ -200,14 +200,14 @@ void devm_cxl_dport_ras_setup(struct cxl_dport *dport);static inline void cxl_ras_init (void ) { }static inline void cxl_ras_exit (void ) { }static inline bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, -void __iomem *ras_base) +void __iomem *ras_base,u64 serial) {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 cxl_port *port,struct cxl_dport *dport, -void __iomem *ras_base) { } +void __iomem *ras_base,u64 serial) { }static inline void cxl_dport_map_rch_aer (struct cxl_dport *dport) { }static inline void cxl_disable_rch_root_ints (struct cxl_dport *dport) { }static inline void cxl_handle_rdport_errors (struct pci_dev *pdev) { }drivers/cxl/core/ras.c +39
-92@@ -12,69 +12,37 @@static_assert (CXL_HEADERLOG_TRACE_SIZE_U32 ==128 ,"rasdaemon ABI requires exactly 128 u32s" ); -static void cxl_cper_trace_corr_port_prot_err (struct pci_dev *pdev, -struct cxl_ras_capability_regs ras_cap) -{ -u32 status = ras_cap.cor_status & ~ras_cap.cor_mask; - -trace_cxl_port_aer_correctable_error (&pdev->dev, status); -} - -static void cxl_cper_trace_uncorr_port_prot_err (struct pci_dev *pdev, -struct cxl_ras_capability_regs ras_cap) +static void cxl_cper_trace_uncorr_prot_err (struct cxl_port *port,struct cxl_dport *dport, +u64 serial,struct cxl_ras_capability_regs *ras_cap) {u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32 ] = {}; -u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask; +u32 status = ras_cap->uncor_status & ~ras_cap->uncor_mask;u32 fe;if (hweight32 (status) >1 ) fe =BIT (FIELD_GET (CXL_RAS_CAP_CONTROL_FE_MASK , - ras_cap.cap_control)); -else - fe = status; - -memcpy (hl, ras_cap.header_log,CXL_HEADERLOG_SIZE ); -trace_cxl_port_aer_uncorrectable_error (&pdev->dev, status, fe, hl); -} - -static void cxl_cper_trace_corr_prot_err (struct cxl_memdev *cxlmd, -struct cxl_ras_capability_regs ras_cap) -{ -u32 status = ras_cap.cor_status & ~ras_cap.cor_mask; - -trace_cxl_aer_correctable_error (cxlmd, status); -} - -static void -cxl_cper_trace_uncorr_prot_err (struct cxl_memdev *cxlmd, -struct cxl_ras_capability_regs ras_cap) -{ -u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32 ] = {}; -u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask; -u32 fe; - -if (hweight32 (status) >1 ) - fe =BIT (FIELD_GET (CXL_RAS_CAP_CONTROL_FE_MASK , - ras_cap.cap_control)); + ras_cap->cap_control));else fe = status;/* -* ras_cap.header_log[] holds CXL_HEADERLOG_SIZE_U32 (16) hardware +* ras_cap->header_log[] holds CXL_HEADERLOG_SIZE_U32 (16) hardware * dwords. Copy them into the front of a zero-filled * CXL_HEADERLOG_TRACE_SIZE_U32 (128) u32 staging buffer so the trace * event memcpy sees a full 512-byte source and the userspace ABI * (rasdaemon) is preserved. */ -memcpy (hl, ras_cap.header_log,CXL_HEADERLOG_SIZE ); -trace_cxl_aer_uncorrectable_error (cxlmd, status, fe, hl); +memcpy (hl, ras_cap->header_log,CXL_HEADERLOG_SIZE ); +trace_cxl_aer_uncorrectable_error (port, dport, status, fe, + hl, serial); } -static int match_memdev_by_parent (struct device *dev,const void *uport) +static void cxl_cper_trace_corr_prot_err (struct cxl_port *port,struct cxl_dport *dport, +u64 serial,struct cxl_ras_capability_regs *ras_cap) { -if (is_cxl_memdev (dev) && dev->parent == uport) -return 1 ; -return 0 ; +u32 status = ras_cap->cor_status & ~ras_cap->cor_mask; + +trace_cxl_aer_correctable_error (port, dport, status, serial); }@@ -109,47 +77,34 @@ static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dporvoid cxl_cper_handle_prot_err (struct cxl_cper_prot_err_work_data *data) { +struct cxl_dport *dport;unsigned int devfn =PCI_DEVFN (data->prot_err.agent_addr.device, data->prot_err.agent_addr.function); - struct pci_dev *pdev __free(pci_dev_put) = -pci_get_domain_bus_and_slot (data->prot_err.agent_addr.segment, - data->prot_err.agent_addr.bus, - devfn); -struct cxl_memdev *cxlmd; -int port_type; - -if (!pdev) -return ; - - port_type =pci_pcie_type (pdev); -if (port_type ==PCI_EXP_TYPE_ROOT_PORT || - port_type ==PCI_EXP_TYPE_DOWNSTREAM || - port_type ==PCI_EXP_TYPE_UPSTREAM ) { -if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_port_prot_err (pdev, data->ras_cap); -else -cxl_cper_trace_uncorr_port_prot_err (pdev, data->ras_cap); - + struct pci_dev *pdev __free(pci_dev_put) = pci_get_domain_bus_and_slot( + data->prot_err.agent_addr.segment, data->prot_err.agent_addr.bus, devfn); +if (!pdev) { +pr_err_ratelimited ("Failed to find CPER device in CXL topology\n" );return ; } -guard (device)(&pdev->dev); -if (!pdev->dev.driver) { -dev_warn_ratelimited (&pdev->dev, -"Device is unbound, abort CPER error handling\n" ); + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_dev(&pdev->dev, NULL); +if (!port) { +dev_err_ratelimited (&pdev->dev, +"Failed to find parent port device in CXL topology\n" );return ; } - struct device *mem_dev __free(put_device) = bus_find_device( - &cxl_bus_type,NULL , pdev, match_memdev_by_parent); -if (!mem_dev) -return ; +guard (device)(&port->dev); + +/* dport is NULL for Endpoint and Upstream Port devices */ + dport =cxl_find_dport_by_dev (port, &pdev->dev); - cxlmd =to_cxl_memdev (mem_dev);if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_corr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap);else -cxl_cper_trace_uncorr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_uncorr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap); }EXPORT_SYMBOL_GPL (cxl_cper_handle_prot_err);@@ -240,14 +195,14 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dporeturn ; } -if (cxl_handle_ras (port, dport, ras_base)) +if (cxl_handle_ras (port, dport, ras_base,pci_get_dsn (pdev)))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 cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) +void cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base,u64 serial) {u32 status;void __iomem *addr;@@ -259,12 +214,7 @@ void cxl_handle_cor_ras(struct cxl_port *port, struct cxl_dport *dport, void __i status =readl (addr);if (status &CXL_RAS_CORRECTABLE_STATUS_MASK ) {writel (status &CXL_RAS_CORRECTABLE_STATUS_MASK , addr); -if (is_cxl_endpoint (port)) -trace_cxl_aer_correctable_error (to_cxl_memdev (port->uport_dev), status); -else if (dport) -trace_cxl_port_aer_correctable_error (dport->dport_dev, status); -else -trace_cxl_port_aer_correctable_error (port->uport_dev, status); +trace_cxl_aer_correctable_error (port, dport, status, serial); } }@@ -289,7 +239,8 @@ static void header_log_copy(void __iomem *ras_base, u32 *log)* Log the state of the RAS status registers and prepare them to log the * next error status. Return 1 if reset needed. */ -bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) +bool cxl_handle_ras (struct cxl_port *port,struct cxl_dport *dport, +void __iomem *ras_base,u64 serial) {u32 hl[CXL_HEADERLOG_TRACE_SIZE_U32 ] = {};void __iomem *addr;@@ -316,12 +267,7 @@ bool cxl_handle_ras(struct cxl_port *port, struct cxl_dport *dport, void __iomem }header_log_copy (ras_base, hl); -if (is_cxl_endpoint (port)) -trace_cxl_aer_uncorrectable_error (to_cxl_memdev (port->uport_dev), status, fe, hl); -else if (dport) -trace_cxl_port_aer_uncorrectable_error (dport->dport_dev, status, fe, hl); -else -trace_cxl_port_aer_uncorrectable_error (port->uport_dev, status, fe, hl); +trace_cxl_aer_uncorrectable_error (port, dport, status, fe, hl, serial);writel (status &CXL_RAS_UNCORRECTABLE_STATUS_MASK , addr);@@ -360,7 +306,8 @@ pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,* cases below handle AER recovery for devices without active * CXL.mem traffic. */ - ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL )); + ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL ), +pci_get_dsn (pdev)); }/* @@ -392,7 +339,7 @@ static void cxl_handle_proto_error(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dport *dport, int severity) {if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (port, dport,to_ras_base (port, dport)); +cxl_handle_cor_ras (port, dport,to_ras_base (port, dport),pci_get_dsn (pdev));else cxl_do_recovery (pdev, port, dport); }drivers/cxl/core/ras_rch.c +2
-1@@ -118,7 +118,8 @@ void cxl_handle_rdport_errors(struct pci_dev *pdev)pci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (dport->port, dport,to_ras_base (port, dport)); +cxl_handle_cor_ras (dport->port, dport,to_ras_base (port, dport), +pci_get_dsn (pdev));else cxl_do_recovery (pdev, dport->port, dport); }drivers/cxl/core/trace.c +35
-0@@ -2,7 +2,42 @@/* Copyright(c) 2022 Intel Corporation. All rights reserved. */ #include <cxl.h> +#include <cxlmem.h> #include "core.h" +const char *cxl_trace_memdev_name (struct cxl_port *port) +{ +if (is_cxl_endpoint (port)) { +struct cxl_memdev *cxlmd =to_cxl_memdev (port->uport_dev); + +return dev_name (&cxlmd->dev); + } + +return "" ; +} + +const char *cxl_trace_host_name (struct cxl_port *port) +{ +if (is_cxl_endpoint (port)) { +struct cxl_memdev *cxlmd =to_cxl_memdev (port->uport_dev); + +return dev_name (cxlmd->dev.parent); + } + +return dev_name (port->uport_dev); +} + +const char *cxl_trace_port_name (struct cxl_port *port) +{ +return dev_name (&port->dev); +} + +const char *cxl_trace_dport_name (struct cxl_dport *dport) +{ +if (dport) +return dev_name (dport->dport_dev); +return "" ; +} +#define CREATE_TRACE_POINTS #include "trace.h" drivers/cxl/core/trace.h +26
-65@@ -48,44 +48,15 @@ { CXL_RAS_UC_IDE_RX_ERR, "IDE Rx Error" } \ ) -TRACE_EVENT (cxl_port_aer_uncorrectable_error, - TP_PROTO(struct device *dev, u32 status, u32 fe, u32 *hl), -TP_ARGS (dev, status, fe, hl), -TP_STRUCT__entry ( - __string(device, dev_name(dev)) - __string(host, dev_name(dev->parent)) - __field(u32, status) - __field(u32, first_error) -__array (u32, header_log,CXL_HEADERLOG_TRACE_SIZE_U32 ) - ), -TP_fast_assign ( - __assign_str(device); - __assign_str(host); - __entry->status = status; - __entry->first_error = fe; -/* -* Embed headerlog data for user app retrieval and parsing, -* but no need to print in the trace buffer. Only -* CXL_HEADERLOG_SIZE_U32 (16) dwords are hardware data; -* the remaining entries preserve the 512-byte ABI layout -* rasdaemon depends on and are zero-filled by the caller. -*/ -memcpy (__entry->header_log, hl, - CXL_HEADERLOG_TRACE_SIZE_U32 * sizeof(u32)); - ), -TP_printk ("device=%s host=%s status: '%s' first_error: '%s'" , -__get_str (device),__get_str (host), -show_uc_errs (__entry->status), -show_uc_errs (__entry->first_error) - ) -); - TRACE_EVENT(cxl_aer_uncorrectable_error, - TP_PROTO(const struct cxl_memdev *cxlmd, u32 status, u32 fe, u32 *hl), - TP_ARGS(cxlmd, status, fe, hl), + TP_PROTO(struct cxl_port *port, struct cxl_dport *dport, + u32 status, u32 fe, u32 *hl, u64 serial), + TP_ARGS(port, dport, status, fe, hl, serial), TP_STRUCT__entry( - __string(memdev, dev_name(&cxlmd->dev)) - __string(host, dev_name(cxlmd->dev.parent)) + __string(memdev, cxl_trace_memdev_name(port)) + __string(port, cxl_trace_port_name(port)) + __string(dport, cxl_trace_dport_name(dport)) + __string(host, cxl_trace_host_name(port)) __field(u64, serial) __field(u32, status) __field(u32, first_error)@@ -93,8 +64,10 @@ TRACE_EVENT(cxl_aer_uncorrectable_error, ), TP_fast_assign( __assign_str(memdev); +__assign_str (port); +__assign_str (dport);__assign_str (host); - __entry->serial = cxlmd->cxlds->serial; + __entry->serial = serial; __entry->status = status; __entry->first_error = fe;/* @@ -107,8 +80,9 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,memcpy (__entry->header_log, hl,CXL_HEADERLOG_TRACE_SIZE_U32 *sizeof (u32)); ), -TP_printk ("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'" , -__get_str (memdev),__get_str (host), __entry->serial, +TP_printk ("memdev=%s port=%s dport=%s host=%s serial=%lld: status: '%s' first_error: '%s'" , +__get_str (memdev),__get_str (port),__get_str (dport), +__get_str (host), __entry->serial,show_uc_errs (__entry->status),show_uc_errs (__entry->first_error) )@@ -132,42 +106,29 @@ TRACE_EVENT(cxl_aer_uncorrectable_error, { CXL_RAS_CE_PHYS_LAYER_ERR, "Received Error From Physical Layer" } \ ) -TRACE_EVENT (cxl_port_aer_correctable_error, - TP_PROTO(struct device *dev, u32 status), -TP_ARGS (dev, status), -TP_STRUCT__entry ( - __string(device, dev_name(dev)) - __string(host, dev_name(dev->parent)) -__field (u32, status) - ), -TP_fast_assign ( - __assign_str(device); - __assign_str(host); - __entry->status = status; - ), -TP_printk ("device=%s host=%s status='%s'" , -__get_str (device),__get_str (host), -show_ce_errs (__entry->status) - ) -); -TRACE_EVENT (cxl_aer_correctable_error, - TP_PROTO(const struct cxl_memdev *cxlmd, u32 status), -TP_ARGS (cxlmd, status), + TP_PROTO(struct cxl_port *port, struct cxl_dport *dport, + u32 status, u64 serial), +TP_ARGS (port, dport, status, serial),TP_STRUCT__entry ( - __string(memdev, dev_name(&cxlmd->dev)) - __string(host, dev_name(cxlmd->dev.parent)) + __string(memdev, cxl_trace_memdev_name(port)) + __string(port, cxl_trace_port_name(port)) + __string(dport, cxl_trace_dport_name(dport)) + __string(host, cxl_trace_host_name(port)) __field(u64, serial)__field (u32, status) ),TP_fast_assign ( __assign_str(memdev); + __assign_str(port); + __assign_str(dport); __assign_str(host); - __entry->serial = cxlmd->cxlds->serial; + __entry->serial = serial; __entry->status = status; ), -TP_printk ("memdev=%s host=%s serial=%lld: status: '%s'" , -__get_str (memdev),__get_str (host), __entry->serial, +TP_printk ("memdev=%s port=%s dport=%s host=%s serial=%lld: status: '%s'" , +__get_str (memdev),__get_str (port),__get_str (dport), +__get_str (host), __entry->serial,show_ce_errs (__entry->status) ) );drivers/cxl/cxlmem.h +7
-0@@ -125,6 +125,13 @@ static inline int cxl_memdev_attach_region(struct cxl_memdev *cxlmd)#endif struct cxl_memdev *devm_cxl_add_classdev (struct cxl_dev_state *cxlds); + +/* trace-event helpers */ +const char *cxl_trace_memdev_name (struct cxl_port *port); +const char *cxl_trace_host_name (struct cxl_port *port); +const char *cxl_trace_port_name (struct cxl_port *port); +const char *cxl_trace_dport_name (struct cxl_dport *dport); +struct cxl_memdev *__devm_cxl_add_memdev (struct cxl_dev_state *cxlds,const struct cxl_memdev_attach *attach); int devm_cxl_sanitize_setup_notifier(struct device *host,
Jonathan Cameron
maintainerRe: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events
In reply to Terry BowmanQuoted 84 lines · On Fri, 17 Jul 2026 17:27:03 -0500 Terry Bowman <[email protected]> wrote:
From: Dan Williams <[email protected]>
Pass struct
cxl_port* and structcxl_dport* to the cxl_aer_* trace events instead of a plain struct device * derived at the caller. The trace event helpers then derive the right strings for endpoints, switch ports, root ports, and RCH downstream ports consistently across the CPER and native AER paths.The unified cxl_aer_* events keep "memdev" as the legacy field (endpoint events populate it with the memdev name; non-endpoint events emit memdev="") and add new "port" and "dport" string fields populated for all CXL device classes. Updated userspace can key off "port" and "dport" without a parallel set of events.
Remove the separate
cxl_port_aer_uncorrectable_errorandcxl_port_aer_correctable_errortrace events. All CXL AER events now use the unified cxl_aer_* events with port and dport fields.Rework
cxl_cper_handle_prot_err()to usefind_cxl_port_by_dev()and the unified trace helpers, replacing the per-port-type branching andbus_find_device()memdev lookup.The
TP_printkformat string places "port=%s dport=%s" between "memdev=%s" and "host=%s", changing the text-mode field order from the pre-patch output. This does not affect consumers such as rasdaemon that use libtraceevent to parse fields by name rather than by fixed text position.For non-endpoint events (switch port, root port, RCH dport), "memdev" is empty and "port"/"dport" carry the topology information.
The serial number is retrieved via
pci_get_dsn()which performs live PCI configuration space reads. A following patch ("PCI: Cache PCI DSN intopci_dev->dsnduring probe") replaces these with a cached serial number to avoid config space access in error handlers and panic paths.Below are examples of the different CXL devices' error trace logs after this patch:
--------------------- | CXL RP - 0C:00.0 | --------------------- | --------------------- | CXL USP - 0D:00.0 | --------------------- | -------------------- | CXL DSP - 0E:00.0 | -------------------- | --------------------- | CXL EP - 0F:00.0 | ---------------------Root Port:
cxl_aer_correctable_error: memdev= port=port1 dport=0000:0c:00.0 \
host=pci0000:0c serial=0: status: 'Memory Data ECC Error'
cxl_aer_uncorrectable_error: memdev= port=port1 dport=0000:0c:00.0 \
host=pci0000:0c serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'Upstream Switch Port:
cxl_aer_correctable_error: memdev= port=port2 dport= host=0000:0d:00.0 \
serial=0: status: 'Memory Data ECC Error'UCE NA - Upstream Switch Port UCE's are handled in the portdrv driver's PCI AER callbacks that are not CXL aware.
Downstream Switch Port:
cxl_aer_correctable_error: memdev= port=port2 dport=0000:0e:00.0 \
host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'
cxl_aer_uncorrectable_error: memdev= port=port2 dport=0000:0e:00.0 \
host=0000:0d:00.0 serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'Endpoint:
cxl_aer_uncorrectable_error: memdev=mem1 port=endpoint4 dport= \
host=0000:0f:00.0 serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'
Quoted 6 lines
cxl_aer_correctable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 \
serial=0: status: 'Memory Data ECC Error'Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>
One question inline about reference counts for the port.
Quoted 5 lines
drivers/cxl/core/ras.c +0
-0
...
Quoted 40 lines
drivers/cxl/core/ras.c +7
-23@@ -109,47 +77,34 @@ static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dporvoid cxl_cper_handle_prot_err (struct cxl_cper_prot_err_work_data *data) { +struct cxl_dport *dport;unsigned int devfn =PCI_DEVFN (data->prot_err.agent_addr.device, data->prot_err.agent_addr.function); - struct pci_dev *pdev __free(pci_dev_put) = -pci_get_domain_bus_and_slot (data->prot_err.agent_addr.segment, - data->prot_err.agent_addr.bus, - devfn); -struct cxl_memdev *cxlmd; -int port_type; - -if (!pdev) -return ; - - port_type =pci_pcie_type (pdev); -if (port_type ==PCI_EXP_TYPE_ROOT_PORT || - port_type ==PCI_EXP_TYPE_DOWNSTREAM || - port_type ==PCI_EXP_TYPE_UPSTREAM ) { -if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_port_prot_err (pdev, data->ras_cap); -else -cxl_cper_trace_uncorr_port_prot_err (pdev, data->ras_cap); - + struct pci_dev *pdev __free(pci_dev_put) = pci_get_domain_bus_and_slot( + data->prot_err.agent_addr.segment, data->prot_err.agent_addr.bus, devfn); +if (!pdev) { +pr_err_ratelimited ("Failed to find CPER device in CXL topology\n" );return ; } -guard (device)(&pdev->dev); -if (!pdev->dev.driver) { -dev_warn_ratelimited (&pdev->dev, -"Device is unbound, abort CPER error handling\n" ); + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_dev(&pdev->dev, NULL); +if (!port) {
drivers/cxl/core/ras.c static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dpor · line 97
Quoted 10 lines
drivers/cxl/core/ras.c +3
-4+dev_err_ratelimited (&pdev->dev, +"Failed to find parent port device in CXL topology\n" );return ; } - struct device *mem_dev __free(put_device) = bus_find_device( - &cxl_bus_type,NULL , pdev, match_memdev_by_parent); -if (!mem_dev) -return ; +guard (device)(&port->dev);
Don't we have a reference for this from find_cxl_port_by_dev()?
Superficially scope looks the same.
Quoted 20 lines
drivers/cxl/core/ras.c +7
-3+ +/* dport is NULL for Endpoint and Upstream Port devices */ + dport =cxl_find_dport_by_dev (port, &pdev->dev); - cxlmd =to_cxl_memdev (mem_dev);if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_corr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap);else -cxl_cper_trace_uncorr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_uncorr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap); }EXPORT_SYMBOL_GPL (cxl_cper_handle_prot_err);@@ -240,14 +195,14 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dporeturn ; }
drivers/cxl/core/ras.c void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dpo · line 205
Quoted 10 lines
drivers/cxl/core/ras.c +2
-2-if (cxl_handle_ras (port, dport, ras_base)) +if (cxl_handle_ras (port, dport, ras_base,pci_get_dsn (pdev)))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 cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) +void cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base,u64 serial)
That's over even the modern 100 char limit. Needs a line break.
Quoted 1 line
drivers/cxl/core/ras.c +0
-0{
Re: [PATCH v18 10/13] cxl: Add port and dport identifiers to CXL AER trace events
Quoted 155 lines · Jonathan Cameron
Quoted 84 lines · On Fri, 17 Jul 2026 17:27:03 -0500 Terry Bowman <[email protected]> wrote:
From: Dan Williams <[email protected]>
Pass struct
cxl_port* and structcxl_dport* to the cxl_aer_* trace events instead of a plain struct device * derived at the caller. The trace event helpers then derive the right strings for endpoints, switch ports, root ports, and RCH downstream ports consistently across the CPER and native AER paths.The unified cxl_aer_* events keep "memdev" as the legacy field (endpoint events populate it with the memdev name; non-endpoint events emit memdev="") and add new "port" and "dport" string fields populated for all CXL device classes. Updated userspace can key off "port" and "dport" without a parallel set of events.
Remove the separate
cxl_port_aer_uncorrectable_errorandcxl_port_aer_correctable_errortrace events. All CXL AER events now use the unified cxl_aer_* events with port and dport fields.Rework
cxl_cper_handle_prot_err()to usefind_cxl_port_by_dev()and the unified trace helpers, replacing the per-port-type branching andbus_find_device()memdev lookup.The
TP_printkformat string places "port=%s dport=%s" between "memdev=%s" and "host=%s", changing the text-mode field order from the pre-patch output. This does not affect consumers such as rasdaemon that use libtraceevent to parse fields by name rather than by fixed text position.For non-endpoint events (switch port, root port, RCH dport), "memdev" is empty and "port"/"dport" carry the topology information.
The serial number is retrieved via
pci_get_dsn()which performs live PCI configuration space reads. A following patch ("PCI: Cache PCI DSN intopci_dev->dsnduring probe") replaces these with a cached serial number to avoid config space access in error handlers and panic paths.Below are examples of the different CXL devices' error trace logs after this patch:
--------------------- | CXL RP - 0C:00.0 | --------------------- | --------------------- | CXL USP - 0D:00.0 | --------------------- | -------------------- | CXL DSP - 0E:00.0 | -------------------- | --------------------- | CXL EP - 0F:00.0 | ---------------------Root Port:
cxl_aer_correctable_error: memdev= port=port1 dport=0000:0c:00.0 \
host=pci0000:0c serial=0: status: 'Memory Data ECC Error'
cxl_aer_uncorrectable_error: memdev= port=port1 dport=0000:0c:00.0 \
host=pci0000:0c serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'Upstream Switch Port:
cxl_aer_correctable_error: memdev= port=port2 dport= host=0000:0d:00.0 \
serial=0: status: 'Memory Data ECC Error'UCE NA - Upstream Switch Port UCE's are handled in the portdrv driver's PCI AER callbacks that are not CXL aware.
Downstream Switch Port:
cxl_aer_correctable_error: memdev= port=port2 dport=0000:0e:00.0 \
host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'
cxl_aer_uncorrectable_error: memdev= port=port2 dport=0000:0e:00.0 \
host=0000:0d:00.0 serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'Endpoint:
cxl_aer_uncorrectable_error: memdev=mem1 port=endpoint4 dport= \
host=0000:0f:00.0 serial=0: status: 'Cache Address Parity Error' \
first_error: 'Cache Address Parity Error'Quoted 6 lines
cxl_aer_correctable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 \
serial=0: status: 'Memory Data ECC Error'Co-developed-by Terry Bowman <[email protected]>Signed-off-by Terry Bowman <[email protected]>Signed-off-by Dan Williams <[email protected]>One question inline about reference counts for the port.
Quoted 5 lines
drivers/cxl/core/ras.c +0
-0...
Quoted 40 lines
drivers/cxl/core/ras.c +7
-23@@ -109,47 +77,34 @@ static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dporvoid cxl_cper_handle_prot_err (struct cxl_cper_prot_err_work_data *data) { +struct cxl_dport *dport;unsigned int devfn =PCI_DEVFN (data->prot_err.agent_addr.device, data->prot_err.agent_addr.function); - struct pci_dev *pdev __free(pci_dev_put) = -pci_get_domain_bus_and_slot (data->prot_err.agent_addr.segment, - data->prot_err.agent_addr.bus, - devfn); -struct cxl_memdev *cxlmd; -int port_type; - -if (!pdev) -return ; - - port_type =pci_pcie_type (pdev); -if (port_type ==PCI_EXP_TYPE_ROOT_PORT || - port_type ==PCI_EXP_TYPE_DOWNSTREAM || - port_type ==PCI_EXP_TYPE_UPSTREAM ) { -if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_port_prot_err (pdev, data->ras_cap); -else -cxl_cper_trace_uncorr_port_prot_err (pdev, data->ras_cap); - + struct pci_dev *pdev __free(pci_dev_put) = pci_get_domain_bus_and_slot( + data->prot_err.agent_addr.segment, data->prot_err.agent_addr.bus, devfn); +if (!pdev) { +pr_err_ratelimited ("Failed to find CPER device in CXL topology\n" );return ; } -guard (device)(&pdev->dev); -if (!pdev->dev.driver) { -dev_warn_ratelimited (&pdev->dev, -"Device is unbound, abort CPER error handling\n" ); + struct cxl_port *port __free(put_cxl_port) = find_cxl_port_by_dev(&pdev->dev, NULL); +if (!port) {drivers/cxl/core/ras.c static struct cxl_port *find_cxl_port_by_dev(struct device *dev, struct cxl_dpor · line 97
Quoted 10 lines
drivers/cxl/core/ras.c +3
-4+dev_err_ratelimited (&pdev->dev, +"Failed to find parent port device in CXL topology\n" );return ; } - struct device *mem_dev __free(put_device) = bus_find_device( - &cxl_bus_type,NULL , pdev, match_memdev_by_parent); -if (!mem_dev) -return ; +guard (device)(&port->dev);Don't we have a reference for this from
find_cxl_port_by_dev()?
Quoted 3 lines
Superficially scope looks the same.
I somehow missed this yesterday. Yes, find_cxl_port_by_dev() ref increments.
Quoted 24 lines
Quoted 24 lines
drivers/cxl/core/ras.c +8
-4+ +/* dport is NULL for Endpoint and Upstream Port devices */ + dport =cxl_find_dport_by_dev (port, &pdev->dev); - cxlmd =to_cxl_memdev (mem_dev);if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_corr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap);else -cxl_cper_trace_uncorr_prot_err (cxlmd, data->ras_cap); +cxl_cper_trace_uncorr_prot_err (port, dport,pci_get_dsn (pdev), + &data->ras_cap); }EXPORT_SYMBOL_GPL (cxl_cper_handle_prot_err);@@ -240,14 +195,14 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dporeturn ; } -if (cxl_handle_ras (port, dport, ras_base)) +if (cxl_handle_ras (port, dport, ras_base,pci_get_dsn (pdev)))panic ("CXL cachemem error" );
Quoted 9 lines
drivers/cxl/core/ras.c void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dpo · line 205
Quoted 6 lines
drivers/cxl/core/ras.c +1
-1dev_dbg (&pdev->dev,"CXL UCE signaled but no CXL RAS status bits set\n" ); } -void cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base) +void cxl_handle_cor_ras (struct cxl_port *port,struct cxl_dport *dport,void __iomem *ras_base,u64 serial)That's over even the modern 100 char limit. Needs a line break.
Quoted 1 line
drivers/cxl/core/ras.c +0
-0{
Yup, I'll linewrap at 75-80. Thanks.
- Terry
PATCH v18 11/13 PCI: Cache PCI DSN into pci_dev->dsn during probe
In reply to Terry BowmanSubsequent CXL error-reporting code paths need to log the PCI Device Serial Number (DSN) as part of trace events emitted from interrupt or panic context. Computing the DSN there via pci_get_dsn() requires PCI configuration space reads, which are slow, can fail when the link is down or frozen, and may not be safe in some contexts.
Add a u64 dsn field to struct pci_dev and populate it from pci_get_dsn() during pci_init_capabilities() at probe time via pci_dsn_init(). Only write dev->dsn when the read succeeds. The zero initial value from pci_dev allocation already represents 'no DSN available.'
pci_get_dsn() is not modified because it remains a pure config-space read with no side effects on pci_dev. The cache is written exclusively by pci_dsn_init() at probe time.
---
Changes in v17->v18:
- New commit.
--- drivers/cxl/core/ras.c | 11 ++++++----- drivers/cxl/core/ras_rch.c | 4 ++-- drivers/cxl/pci.c | 2 +- drivers/pci/probe.c | 14 ++++++++++++++ include/linux/pci.h | 1 + 5 files changed, 24 insertions(+), 8 deletions(-)
drivers/cxl/core/ras.c +6 -5
@@ -100,10 +100,10 @@ void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data) dport =cxl_find_dport_by_dev (port, &pdev->dev);if (data->severity ==AER_CORRECTABLE ) -cxl_cper_trace_corr_prot_err (port, dport,pci_get_dsn (pdev), +cxl_cper_trace_corr_prot_err (port, dport, pdev->dsn, &data->ras_cap);else -cxl_cper_trace_uncorr_prot_err (port, dport,pci_get_dsn (pdev), +cxl_cper_trace_uncorr_prot_err (port, dport, pdev->dsn, &data->ras_cap); }EXPORT_SYMBOL_GPL (cxl_cper_handle_prot_err);
@@ -195,7 +195,7 @@ void cxl_do_recovery(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dporeturn ; } -if (cxl_handle_ras (port, dport, ras_base,pci_get_dsn (pdev))) +if (cxl_handle_ras (port, dport, ras_base, pdev->dsn))panic ("CXL cachemem error" ); dev_dbg(&pdev->dev,
@@ -307,7 +307,7 @@ pci_ers_result_t cxl_pci_error_detected(struct pci_dev *pdev,* CXL.mem traffic. */ ue =cxl_handle_ras (port,NULL ,to_ras_base (port,NULL ), -pci_get_dsn (pdev)); + pdev->dsn); }/*
@@ -339,7 +339,8 @@ static void cxl_handle_proto_error(struct pci_dev *pdev, struct cxl_port *port, struct cxl_dport *dport, int severity) {if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (port, dport,to_ras_base (port, dport),pci_get_dsn (pdev)); +cxl_handle_cor_ras (port, dport,to_ras_base (port, dport), + pdev->dsn);else cxl_do_recovery (pdev, port, dport); }
drivers/cxl/core/ras_rch.c +2 -2
@@ -118,8 +118,8 @@ void cxl_handle_rdport_errors(struct pci_dev *pdev)pci_print_aer (pdev, severity, &aer_regs);if (severity ==AER_CORRECTABLE ) -cxl_handle_cor_ras (dport->port, dport,to_ras_base (port, dport), -pci_get_dsn (pdev)); +cxl_handle_cor_ras (dport->port, dport, +to_ras_base (port, dport), pdev->dsn);else cxl_do_recovery (pdev, dport->port, dport); }
drivers/cxl/pci.c +1 -1
@@ -807,7 +807,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)if (!dvsec)pci_warn (pdev,"Device DVSEC not present, skip CXL.mem init\n" ); - mds =cxl_memdev_state_create (&pdev->dev,pci_get_dsn (pdev), dvsec); + mds =cxl_memdev_state_create (&pdev->dev, pdev->dsn, dvsec);if (IS_ERR (mds))return PTR_ERR (mds); cxlds = &mds->cxlds;
drivers/pci/probe.c +14 -0
@@ -2638,6 +2638,19 @@ void pcie_report_downtraining(struct pci_dev *dev)__pcie_print_link_status (dev, false); } +/* +* Cache the Device Serial Number for use in contexts where config-space +* reads are unsafe (interrupt, panic). Process-context callers that +* need a fresh value (e.g. hotplug device replacement) use pci_get_dsn(). +*/ +static void pci_dsn_init (struct pci_dev *dev) +{ +u64 dsn =pci_get_dsn (dev); + +if (dsn) + dev->dsn = dsn; +} +static void pci_imm_ready_init (struct pci_dev *dev) {u16 status;
@@ -2674,6 +2687,7 @@ static void pci_init_capabilities(struct pci_dev *dev)pci_rebar_init (dev);/* Resizable BAR */ pci_dev3_init (dev);/* Device 3 capabilities */ pci_ide_init (dev);/* Link Integrity and Data Encryption */ +pci_dsn_init (dev);/* Serial number */ pcie_report_downtraining (dev);pci_init_reset_methods (dev);
include/linux/pci.h +1 -0
@@ -386,6 +386,7 @@ struct pci_dev {unsigned long *dma_alias_mask;/* Mask of enabled devfn aliases */ struct pci_driver *driver;/* Driver bound to this device */ +u64 dsn;/* PCI Device Serial Number */ u64 dma_mask;/* Mask of the bits of bus address this device implements. Normally this is 0xffffffff. You only need to change
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 11/13] PCI: Cache PCI DSN into pci_dev->dsn during probe
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 11 lines
Subsequent CXL error-reporting code paths need to log the PCI Device Serial Number (DSN) as part of trace events emitted from interrupt or panic context. Computing the DSN there via
pci_get_dsn()requires PCI configuration space reads, which are slow, can fail when the link is down or frozen, and may not be safe in some contexts.Add a u64 dsn field to struct
pci_devand populate it frompci_get_dsn()duringpci_init_capabilities()at probe time viapci_dsn_init(). Only writedev->dsnwhen the read succeeds. The zero initial value frompci_devallocation already represents 'no DSN available.'
Quoted 5 lines
pci_get_dsn()is not modified because it remains a pure config-space read with no side effects onpci_dev. The cache is written exclusively bypci_dsn_init()at probe time.Signed-off-by Terry Bowman <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=11
Re: [PATCH v18 11/13] PCI: Cache PCI DSN into pci_dev->dsn during probe
In reply to Terry BowmanQuoted 4 lines · Terry Bowman
Add a u64 dsn field to struct
pci_devand populate it frompci_get_dsn()duringpci_init_capabilities()at probe time viapci_dsn_init(). Only writedev->dsnwhen the read succeeds. The zero initial value frompci_devallocation already represents 'no DSN available.'
The DSN is already cached on (natively handled) PCIe hotplug ports to detect device replacement during system sleep, see struct controller in drivers/pci/hotplug/pciehp.h.
Please remove that member from struct controller, remove the two assignments to the member in pciehp_configure_device() and pcie_init() and change the comparison in pciehp_device_replaced() to use the new member in struct pci_dev. You can do this either as part of this patch or in a separate patch.
Thanks,
Lukas
Re: [PATCH v18 11/13] PCI: Cache PCI DSN into pci_dev->dsn during probe
Quoted 16 lines · Lukas Wunner
Quoted 4 lines · Terry Bowman
Add a u64 dsn field to struct
pci_devand populate it frompci_get_dsn()duringpci_init_capabilities()at probe time viapci_dsn_init(). Only writedev->dsnwhen the read succeeds. The zero initial value frompci_devallocation already represents 'no DSN available.'The DSN is already cached on (natively handled) PCIe hotplug ports to detect device replacement during system sleep, see struct controller in
drivers/pci/hotplug/pciehp.h.Please remove that member from struct controller, remove the two assignments to the member in
pciehp_configure_device()andpcie_init()and change the comparison inpciehp_device_replaced()to use the new member in structpci_dev. You can do this either as part of this patch or in a separate patch.
Quoted 3 lines
Thanks,
Lukas
Hi Lukas,
Thanks for reviewing. Is this the changes you want?
drivers/pci/hotplug/pciehp.h +0 -1
@@ -90,7 +90,6 @@ extern int pciehp_poll_time;*/ struct controller {struct pcie_device *pcie; -u64 dsn;u32 slot_cap;/* capabilities and quirks */ unsigned int inband_presence_disabled:1 ;
drivers/pci/hotplug/pciehp_hpc.c +1 -3
@@ -587,7 +587,7 @@ bool pciehp_device_replaced(struct controller *ctrl) reg != (pdev->subsystem_vendor | (pdev->subsystem_device << 16))))return true; -if (pci_get_dsn (pdev) != ctrl->dsn) +if (pci_get_dsn (pdev) != pdev->dsn)return true;return false;
@@ -1086,8 +1086,6 @@ struct controller *pcie_init(struct pcie_device *dev) } pdev =pci_get_slot (subordinate,PCI_DEVFN (0 ,0 )); -if (pdev) - ctrl->dsn =pci_get_dsn (pdev);pci_dev_put (pdev);return ctrl;
drivers/pci/hotplug/pciehp_pci.c +0 -1
@@ -73,7 +73,6 @@ int pciehp_configure_device(struct controller *ctrl)down_read_nested (&ctrl->reset_lock, ctrl->depth); dev =pci_get_slot (parent,PCI_DEVFN (0 ,0 )); - ctrl->dsn =pci_get_dsn (dev);pci_dev_put (dev); out:
-Terry
Re: [PATCH v18 11/13] PCI: Cache PCI DSN into pci_dev->dsn during probe
drivers/pci/hotplug/pciehp.h extern int pciehp_poll_time; · line 93
Quoted 7 lines · Terry
+++
b/drivers/pci/hotplug/pciehp.hdrivers/pci/hotplug/pciehp.h +0
-1@@ -90,7 +90,6 @@ extern int pciehp_poll_time;*/ struct controller {struct pcie_device *pcie; -u64 dsn;
Please drop the kernel-doc for this struct member as well.
drivers/pci/hotplug/pciehp_hpc.c struct controller *pcie_init(struct pcie_device *dev) · line 1090
Quoted 9 lines
drivers/pci/hotplug/pciehp_hpc.c +1
-2+++ b/drivers/pci/hotplug/pciehp_hpc.c@@ -1086,8 +1086,6 @@ struct controller *pcie_init(struct pcie_device *dev) } pdev =pci_get_slot (subordinate,PCI_DEVFN (0 ,0 )); -if (pdev) - ctrl->dsn =pci_get_dsn (pdev);pci_dev_put (pdev);
Please drop the pci_get_slot() + pci_dev_put() as well, they're obviously superfluous now.
drivers/pci/hotplug/pciehp_pci.c int pciehp_configure_device(struct controller *ctrl) · line 77
Quoted 8 lines
drivers/pci/hotplug/pciehp_pci.c +1
-1+++ b/drivers/pci/hotplug/pciehp_pci.c@@ -73,7 +73,6 @@ int pciehp_configure_device(struct controller *ctrl)down_read_nested (&ctrl->reset_lock, ctrl->depth); dev =pci_get_slot (parent,PCI_DEVFN (0 ,0 )); - ctrl->dsn =pci_get_dsn (dev);pci_dev_put (dev);
Same here.
Thanks,
Lukas
PATCH v18 12/13 PCI/CXL: Mask/Unmask CXL protocol errors
In reply to Terry BowmanCXL protocol errors are not enabled for all CXL devices after boot. They must be enabled in order to process CXL protocol errors. Provide matching teardown helpers so the masks are restored when a CXL Port or dport goes away.
Add pci_aer_mask_internal_errors() as the symmetric counterpart to pci_aer_unmask_internal_errors() and export both for the cxl_core module.
Introduce cxl_unmask_proto_interrupts() and cxl_mask_proto_interrupts() in cxl_core to wrap the PCI helpers with the dev_is_pci() and pcie_aer_is_native() gating CXL needs. Both helpers tolerate a NULL or non-PCI @dev so callers do not have to special-case it.
Wire cxl_unmask_proto_interrupts() into the success path of cxl_dport_map_ras() and devm_cxl_port_ras_setup() so the unmask only runs when the RAS register block was actually mapped. Pair each unmask with a devm_add_action_or_reset() registration of cxl_mask_proto_irqs() scoped to the host device so the mask is restored when devres is released. This applies to dports, Endpoints, Upstream Switch Ports, Downstream Switch Ports, and Root Ports.
Remove the dev_is_pci(dport->dport_dev) guard in devm_cxl_dport_rch_ras_setup(). On RCH systems dport->dport_dev is the pci_host_bridge device, which is not on pci_bus_type, so this guard caused the function to return early on real hardware without mapping dport RAS or AER registers. The caller already gates on dport->rch, which is sufficient to exclude cxl_test mock devices.
---
Changes in v17->v18:
- Make cxl_unmask_proto_interrupts() and cxl_mask_proto_interrupts() static
- Remove dev_is_pci() guard from devm_cxl_dport_rch_ras_setup(); the guard blocked real RCH hardware because pci_host_bridge is not on pci_bus_type
Changes in v16->v17:
- Drop redundant cxl_mask_proto_interrupts() calls from unregister_port() and cxl_dport_remove(); the devres action registered alongside the unmask is the sole mask path.
- Update title
- Remove unnecessary check for aer_capabilities
- Gate cxl_unmask_proto_interrupts() on pcie_aer_is_native()
- Add pci_aer_mask_internal_errors() and cxl_mask_proto_interrupts()
- Only unmask on successful cxl_map_component_regs()
- NULL-check @dev in cxl_{un,}mask_proto_interrupts()
- Drop static and declare in core/core.h
Change in v15 -> v16:
- None
Change in v14 -> v15:
- None
Changes in v13->v14:
- Update commit title's prefix (Bjorn)
Changes in v12->v13:
- Add dev and dev_is_pci() NULL checks in cxl_unmask_proto_interrupts() (Terry)
- Add Dave Jiang's and Ben's review-by
Changes in v11->v12:
- None
--- drivers/cxl/core/ras.c | 73 +++++++++++++++++++++++++++++++---- drivers/pci/pcie/aer.c | 28 ++++++++++++-- include/linux/aer.h | 2 + tools/testing/cxl/Kbuild | 1 + tools/testing/cxl/test/mock.c | 12 ++++++ 5 files changed, 105 insertions(+), 11 deletions(-)
drivers/cxl/core/ras.c +66 -7
@@ -117,16 +117,64 @@ 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); +static void cxl_unmask_proto_interrupts (struct device *dev) +{ +struct pci_dev *pdev; + +if (!dev || !dev_is_pci (dev)) +return ; + + pdev =to_pci_dev (dev); +if (!pcie_aer_is_native (pdev)) +return ; + +pci_aer_unmask_internal_errors (pdev); +} + +static void cxl_mask_proto_interrupts (struct device *dev) +{ +struct pci_dev *pdev; + +if (!dev || !dev_is_pci (dev)) +return ; + + pdev =to_pci_dev (dev); +if (!pcie_aer_is_native (pdev)) +return ; + +pci_aer_mask_internal_errors (pdev); +} + +static void cxl_mask_proto_irqs (void *dev) +{ +cxl_mask_proto_interrupts (dev); +} +static void cxl_dport_map_ras (struct cxl_dport *dport) {struct cxl_register_map *map = &dport->reg_map;struct device *dev = dport->dport_dev; -if (!map->component_map.ras.valid) +if (!map->component_map.ras.valid) {dev_dbg (dev,"RAS registers not found\n" ); -else if (cxl_map_component_regs (map, &dport->regs.component, -BIT (CXL_CM_CAP_CAP_ID_RAS ))) +return ; + } + +if (cxl_map_component_regs (map, &dport->regs.component, +BIT (CXL_CM_CAP_CAP_ID_RAS ))) {dev_dbg (dev,"Failed to map RAS capability.\n" ); +return ; + } + +if (!dev_is_pci (dev)) +return ; + +cxl_unmask_proto_interrupts (dev); +if (devm_add_action_or_reset (dport_to_host (dport), + cxl_mask_proto_irqs, dev)) { +dev_warn (dev,"failed to defer CXL proto-irq mask; CXL protocol error reporting disabled\n" ); + dport->regs.component.ras =NULL ; + } }/**
@@ -143,9 +191,6 @@ void devm_cxl_dport_rch_ras_setup(struct cxl_dport *dport) {struct pci_host_bridge *host_bridge; -if (!dev_is_pci (dport->dport_dev)) -return ; -devm_cxl_dport_ras_setup (dport); host_bridge =to_pci_host_bridge (dport->dport_dev);
@@ -160,6 +205,7 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_dport_rch_ras_setup, "CXL");void devm_cxl_port_ras_setup (struct cxl_port *port) {struct cxl_register_map *map = &port->reg_map; +struct device *dev;if (!map->component_map.ras.valid) {dev_dbg (&port->dev,"RAS registers not found\n" );
@@ -168,8 +214,21 @@ void devm_cxl_port_ras_setup(struct cxl_port *port) map->host = &port->dev;if (cxl_map_component_regs (map, &port->regs, -BIT (CXL_CM_CAP_CAP_ID_RAS ))) +BIT (CXL_CM_CAP_CAP_ID_RAS ))) {dev_dbg (&port->dev,"Failed to map RAS capability\n" ); +return ; + } + + dev =is_cxl_endpoint (port) ? port->uport_dev->parent : port->uport_dev; +if (!dev_is_pci (dev)) +return ; + +cxl_unmask_proto_interrupts (dev); +if (devm_add_action_or_reset (&port->dev, cxl_mask_proto_irqs, dev)) { +dev_warn (&port->dev, +"failed to defer CXL proto-irq mask; CXL protocol error reporting disabled\n" ); + port->regs.ras =NULL ; + } }EXPORT_SYMBOL_NS_GPL (devm_cxl_port_ras_setup,"CXL" );
drivers/pci/pcie/aer.c +24 -4
@@ -1143,12 +1143,32 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev) mask &= ~PCI_ERR_COR_INTERNAL ;pci_write_config_dword (dev, aer +PCI_ERR_COR_MASK , mask); } +EXPORT_SYMBOL_FOR_MODULES (pci_aer_unmask_internal_errors,"cxl_core" ); -/* -* Internal errors are too device-specific to enable generally, however for CXL -* their behavior is standardized for conveying CXL protocol errors. +/** +* pci_aer_mask_internal_errors - mask internal errors +* @dev: pointer to the pci_dev data structure +* +* Mask internal errors in the Uncorrectable and Correctable Error +* Mask registers. +* +* Note: AER must be enabled and supported by the device which must be +* checked in advance, e.g. with pcie_aer_is_native(). */ -EXPORT_SYMBOL_FOR_MODULES (pci_aer_unmask_internal_errors,"cxl_core" ); +void pci_aer_mask_internal_errors (struct pci_dev *dev) +{ +int aer = dev->aer_cap; +u32 mask; + +pci_read_config_dword (dev, aer +PCI_ERR_UNCOR_MASK , &mask); + mask |=PCI_ERR_UNC_INTN ; +pci_write_config_dword (dev, aer +PCI_ERR_UNCOR_MASK , mask); + +pci_read_config_dword (dev, aer +PCI_ERR_COR_MASK , &mask); + mask |=PCI_ERR_COR_INTERNAL ; +pci_write_config_dword (dev, aer +PCI_ERR_COR_MASK , mask); +} +EXPORT_SYMBOL_FOR_MODULES (pci_aer_mask_internal_errors,"cxl_core" );/** * pci_aer_handle_error - handle logging error into an event log
include/linux/aer.h +2 -0
@@ -58,6 +58,7 @@ struct aer_capability_regs {int pci_aer_clear_nonfatal_status (struct pci_dev *dev);int pcie_aer_is_native (struct pci_dev *dev);void pci_aer_unmask_internal_errors (struct pci_dev *dev); +void pci_aer_mask_internal_errors (struct pci_dev *dev);#else static inline int pci_aer_clear_nonfatal_status (struct pci_dev *dev) {
@@ -65,6 +66,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev) }static inline int pcie_aer_is_native (struct pci_dev *dev) {return 0 ; }static inline void pci_aer_unmask_internal_errors (struct pci_dev *dev) { } +static inline void pci_aer_mask_internal_errors (struct pci_dev *dev) { }#endif #ifdef CONFIG_CXL_RAS
tools/testing/cxl/Kbuild +1 -0
@@ -6,6 +6,7 @@ ldflags-y += --wrap=acpi_pci_find_root ldflags-y += --wrap=nvdimm_bus_register ldflags-y += --wrap=cxl_await_media_ready ldflags-y += --wrap=devm_cxl_add_rch_dport +ldflags-y += --wrap=devm_cxl_dport_rch_ras_setup ldflags-y += --wrap=cxl_endpoint_parse_cdat ldflags-y += --wrap=devm_cxl_endpoint_decoders_setup ldflags-y += --wrap=hmat_get_extended_linear_cache_size
tools/testing/cxl/test/mock.c +12 -0
@@ -220,6 +220,18 @@ struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port, }EXPORT_SYMBOL_NS_GPL (__wrap_devm_cxl_add_rch_dport,"CXL" ); +void __wrap_devm_cxl_dport_rch_ras_setup (struct cxl_dport *dport) +{ +int index; +struct cxl_mock_ops *ops =get_cxl_mock_ops (&index); + +if (!ops || !ops->is_mock_port (dport->dport_dev)) +devm_cxl_dport_rch_ras_setup (dport); + +put_cxl_mock_ops (index); +} +EXPORT_SYMBOL_NS_GPL (__wrap_devm_cxl_dport_rch_ras_setup,"CXL" ); +void __wrap_cxl_endpoint_parse_cdat (struct cxl_port *port) {int index;
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 12/13] PCI/CXL: Mask/Unmask CXL protocol errors
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 14 lines
CXL protocol errors are not enabled for all CXL devices after boot. They must be enabled in order to process CXL protocol errors. Provide matching teardown helpers so the masks are restored when a CXL Port or dport goes away.
Add
pci_aer_mask_internal_errors()as the symmetric counterpart topci_aer_unmask_internal_errors()and export both for thecxl_coremodule.Introduce
cxl_unmask_proto_interrupts()andcxl_mask_proto_interrupts()incxl_coreto wrap the PCI helpers with thedev_is_pci()andpcie_aer_is_native()gating CXL needs. Both helpers tolerate a NULL or non-PCI @dev so callers do not have to special-case it.
Quoted 7 lines
Wire
cxl_unmask_proto_interrupts()into the success path of [ ... ]
which is sufficient to excludecxl_testmock devices.Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=12
Re: [PATCH v18 12/13] PCI/CXL: Mask/Unmask CXL protocol errors
In reply to Terry BowmanQuoted 29 lines · Terry Bowman
CXL protocol errors are not enabled for all CXL devices after boot. They must be enabled in order to process CXL protocol errors. Provide matching teardown helpers so the masks are restored when a CXL Port or dport goes away.
Add
pci_aer_mask_internal_errors()as the symmetric counterpart topci_aer_unmask_internal_errors()and export both for thecxl_coremodule.Introduce
cxl_unmask_proto_interrupts()andcxl_mask_proto_interrupts()incxl_coreto wrap the PCI helpers with thedev_is_pci()andpcie_aer_is_native()gating CXL needs. Both helpers tolerate a NULL or non-PCI @dev so callers do not have to special-case it.Wire
cxl_unmask_proto_interrupts()into the success path ofcxl_dport_map_ras()anddevm_cxl_port_ras_setup()so the unmask only runs when the RAS register block was actually mapped. Pair each unmask with adevm_add_action_or_reset()registration ofcxl_mask_proto_irqs()scoped to the host device so the mask is restored when devres is released. This applies to dports, Endpoints, Upstream Switch Ports, Downstream Switch Ports, and Root Ports.Remove the
dev_is_pci(dport->dport_dev)guard indevm_cxl_dport_rch_ras_setup(). On RCH systemsdport->dport_devis thepci_host_bridgedevice, which is not onpci_bus_type, so this guard caused the function to return early on real hardware without mapping dport RAS or AER registers. The caller already gates ondport->rch, which is sufficient to excludecxl_testmock devices.
Quoted 3 lines
Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>
Quoted 252 lines
---
Changes in
v17->v18:
- Makecxl_unmask_proto_interrupts()andcxl_mask_proto_interrupts()static
- Removedev_is_pci()guard fromdevm_cxl_dport_rch_ras_setup(); the guard blocked real RCH hardware becausepci_host_bridgeis not onpci_bus_typeChanges in
v16->v17:
- Drop redundantcxl_mask_proto_interrupts()calls fromunregister_port()andcxl_dport_remove(); the devres action registered alongside the unmask is the sole mask path.
- Update title
- Remove unnecessary check foraer_capabilities
- Gatecxl_unmask_proto_interrupts()onpcie_aer_is_native()
- Addpci_aer_mask_internal_errors()andcxl_mask_proto_interrupts()
- Only unmask on successfulcxl_map_component_regs()
- NULL-check @dev in cxl_{un,}mask_proto_interrupts()
- Drop static and declare incore/core.hChange in v15 -> v16:
- NoneChange in v14 -> v15:
- NoneChanges in
v13->v14:
- Update commit title's prefix (Bjorn)Changes in
v12->v13:
- Add dev anddev_is_pci()NULL checks incxl_unmask_proto_interrupts()(Terry)
- Add Dave Jiang's and Ben's review-byChanges in
v11->v12:
- None--- drivers/cxl/core/ras.c | 73 +++++++++++++++++++++++++++++++---- drivers/pci/pcie/aer.c | 28 ++++++++++++-- include/linux/aer.h | 2 + tools/testing/cxl/Kbuild | 1 + tools/testing/cxl/test/mock.c | 12 ++++++ 5 files changed, 105 insertions(+), 11 deletions(-)drivers/cxl/core/ras.c +66
-7@@ -117,16 +117,64 @@ 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); +static void cxl_unmask_proto_interrupts (struct device *dev) +{ +struct pci_dev *pdev; + +if (!dev || !dev_is_pci (dev)) +return ; + + pdev =to_pci_dev (dev); +if (!pcie_aer_is_native (pdev)) +return ; + +pci_aer_unmask_internal_errors (pdev); +} + +static void cxl_mask_proto_interrupts (struct device *dev) +{ +struct pci_dev *pdev; + +if (!dev || !dev_is_pci (dev)) +return ; + + pdev =to_pci_dev (dev); +if (!pcie_aer_is_native (pdev)) +return ; + +pci_aer_mask_internal_errors (pdev); +} + +static void cxl_mask_proto_irqs (void *dev) +{ +cxl_mask_proto_interrupts (dev); +} +static void cxl_dport_map_ras (struct cxl_dport *dport) {struct cxl_register_map *map = &dport->reg_map;struct device *dev = dport->dport_dev; -if (!map->component_map.ras.valid) +if (!map->component_map.ras.valid) {dev_dbg (dev,"RAS registers not found\n" ); -else if (cxl_map_component_regs (map, &dport->regs.component, -BIT (CXL_CM_CAP_CAP_ID_RAS ))) +return ; + } + +if (cxl_map_component_regs (map, &dport->regs.component, +BIT (CXL_CM_CAP_CAP_ID_RAS ))) {dev_dbg (dev,"Failed to map RAS capability.\n" ); +return ; + } + +if (!dev_is_pci (dev)) +return ; + +cxl_unmask_proto_interrupts (dev); +if (devm_add_action_or_reset (dport_to_host (dport), + cxl_mask_proto_irqs, dev)) { +dev_warn (dev,"failed to defer CXL proto-irq mask; CXL protocol error reporting disabled\n" ); + dport->regs.component.ras =NULL ; + } }/** @@ -143,9 +191,6 @@ void devm_cxl_dport_rch_ras_setup(struct cxl_dport *dport) {struct pci_host_bridge *host_bridge; -if (!dev_is_pci (dport->dport_dev)) -return ; -devm_cxl_dport_ras_setup (dport); host_bridge =to_pci_host_bridge (dport->dport_dev);@@ -160,6 +205,7 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_dport_rch_ras_setup, "CXL");void devm_cxl_port_ras_setup (struct cxl_port *port) {struct cxl_register_map *map = &port->reg_map; +struct device *dev;if (!map->component_map.ras.valid) {dev_dbg (&port->dev,"RAS registers not found\n" );@@ -168,8 +214,21 @@ void devm_cxl_port_ras_setup(struct cxl_port *port) map->host = &port->dev;if (cxl_map_component_regs (map, &port->regs, -BIT (CXL_CM_CAP_CAP_ID_RAS ))) +BIT (CXL_CM_CAP_CAP_ID_RAS ))) {dev_dbg (&port->dev,"Failed to map RAS capability\n" ); +return ; + } + + dev =is_cxl_endpoint (port) ? port->uport_dev->parent : port->uport_dev; +if (!dev_is_pci (dev)) +return ; + +cxl_unmask_proto_interrupts (dev); +if (devm_add_action_or_reset (&port->dev, cxl_mask_proto_irqs, dev)) { +dev_warn (&port->dev, +"failed to defer CXL proto-irq mask; CXL protocol error reporting disabled\n" ); + port->regs.ras =NULL ; + } }EXPORT_SYMBOL_NS_GPL (devm_cxl_port_ras_setup,"CXL" );drivers/pci/pcie/aer.c +24
-4@@ -1143,12 +1143,32 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev) mask &= ~PCI_ERR_COR_INTERNAL ;pci_write_config_dword (dev, aer +PCI_ERR_COR_MASK , mask); } +EXPORT_SYMBOL_FOR_MODULES (pci_aer_unmask_internal_errors,"cxl_core" ); -/* -* Internal errors are too device-specific to enable generally, however for CXL -* their behavior is standardized for conveying CXL protocol errors. +/** +* pci_aer_mask_internal_errors - mask internal errors +* @dev: pointer to the pci_dev data structure +* +* Mask internal errors in the Uncorrectable and Correctable Error +* Mask registers. +* +* Note: AER must be enabled and supported by the device which must be +* checked in advance, e.g. with pcie_aer_is_native(). */ -EXPORT_SYMBOL_FOR_MODULES (pci_aer_unmask_internal_errors,"cxl_core" ); +void pci_aer_mask_internal_errors (struct pci_dev *dev) +{ +int aer = dev->aer_cap; +u32 mask; + +pci_read_config_dword (dev, aer +PCI_ERR_UNCOR_MASK , &mask); + mask |=PCI_ERR_UNC_INTN ; +pci_write_config_dword (dev, aer +PCI_ERR_UNCOR_MASK , mask); + +pci_read_config_dword (dev, aer +PCI_ERR_COR_MASK , &mask); + mask |=PCI_ERR_COR_INTERNAL ; +pci_write_config_dword (dev, aer +PCI_ERR_COR_MASK , mask); +} +EXPORT_SYMBOL_FOR_MODULES (pci_aer_mask_internal_errors,"cxl_core" );/** * pci_aer_handle_error - handle logging error into an event log include/linux/aer.h +2
-0@@ -58,6 +58,7 @@ struct aer_capability_regs {int pci_aer_clear_nonfatal_status (struct pci_dev *dev);int pcie_aer_is_native (struct pci_dev *dev);void pci_aer_unmask_internal_errors (struct pci_dev *dev); +void pci_aer_mask_internal_errors (struct pci_dev *dev);#else static inline int pci_aer_clear_nonfatal_status (struct pci_dev *dev) {@@ -65,6 +66,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev) }static inline int pcie_aer_is_native (struct pci_dev *dev) {return 0 ; }static inline void pci_aer_unmask_internal_errors (struct pci_dev *dev) { } +static inline void pci_aer_mask_internal_errors (struct pci_dev *dev) { }#endif #ifdef CONFIG_CXL_RAS tools/testing/cxl/Kbuild +1
-0@@ -6,6 +6,7 @@ ldflags-y += --wrap=acpi_pci_find_root ldflags-y += --wrap=nvdimm_bus_register ldflags-y += --wrap=cxl_await_media_ready ldflags-y += --wrap=devm_cxl_add_rch_dport +ldflags-y += --wrap=devm_cxl_dport_rch_ras_setup ldflags-y += --wrap=cxl_endpoint_parse_cdat ldflags-y += --wrap=devm_cxl_endpoint_decoders_setup ldflags-y += --wrap=hmat_get_extended_linear_cache_sizetools/testing/cxl/test/mock.c +12
-0@@ -220,6 +220,18 @@ struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port, }EXPORT_SYMBOL_NS_GPL (__wrap_devm_cxl_add_rch_dport,"CXL" ); +void __wrap_devm_cxl_dport_rch_ras_setup (struct cxl_dport *dport) +{ +int index; +struct cxl_mock_ops *ops =get_cxl_mock_ops (&index); + +if (!ops || !ops->is_mock_port (dport->dport_dev)) +devm_cxl_dport_rch_ras_setup (dport); + +put_cxl_mock_ops (index); +} +EXPORT_SYMBOL_NS_GPL (__wrap_devm_cxl_dport_rch_ras_setup,"CXL" ); +void __wrap_cxl_endpoint_parse_cdat (struct cxl_port *port) {int index;
Re: [PATCH v18 12/13] PCI/CXL: Mask/Unmask CXL protocol errors
In reply to Terry BowmanQuoted 29 lines · On Fri, 17 Jul 2026 17:27:05 -0500 Terry Bowman <[email protected]> wrote:
CXL protocol errors are not enabled for all CXL devices after boot. They must be enabled in order to process CXL protocol errors. Provide matching teardown helpers so the masks are restored when a CXL Port or dport goes away.
Add
pci_aer_mask_internal_errors()as the symmetric counterpart topci_aer_unmask_internal_errors()and export both for thecxl_coremodule.Introduce
cxl_unmask_proto_interrupts()andcxl_mask_proto_interrupts()incxl_coreto wrap the PCI helpers with thedev_is_pci()andpcie_aer_is_native()gating CXL needs. Both helpers tolerate a NULL or non-PCI @dev so callers do not have to special-case it.Wire
cxl_unmask_proto_interrupts()into the success path ofcxl_dport_map_ras()anddevm_cxl_port_ras_setup()so the unmask only runs when the RAS register block was actually mapped. Pair each unmask with adevm_add_action_or_reset()registration ofcxl_mask_proto_irqs()scoped to the host device so the mask is restored when devres is released. This applies to dports, Endpoints, Upstream Switch Ports, Downstream Switch Ports, and Root Ports.Remove the
dev_is_pci(dport->dport_dev)guard indevm_cxl_dport_rch_ras_setup(). On RCH systemsdport->dport_devis thepci_host_bridgedevice, which is not onpci_bus_type, so this guard caused the function to return early on real hardware without mapping dport RAS or AER registers. The caller already gates ondport->rch, which is sufficient to excludecxl_testmock devices.
Quoted 4 lines
Co-developed-by Dan Williams <[email protected]>Signed-off-by Dan Williams <[email protected]>Signed-off-by Terry Bowman <[email protected]>
One minor thing inline and maybe take another spin at a more concise patch description
Either way on both of them.
...
Quoted 22 lines
drivers/pci/pcie/aer.c +10
-3@@ -1143,12 +1143,32 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev) mask &= ~PCI_ERR_COR_INTERNAL ;pci_write_config_dword (dev, aer +PCI_ERR_COR_MASK , mask); } +EXPORT_SYMBOL_FOR_MODULES (pci_aer_unmask_internal_errors,"cxl_core" ); -/* -* Internal errors are too device-specific to enable generally, however for CXL -* their behavior is standardized for conveying CXL protocol errors. +/** +* pci_aer_mask_internal_errors - mask internal errors +* @dev: pointer to the pci_dev data structure +* +* Mask internal errors in the Uncorrectable and Correctable Error +* Mask registers. +* +* Note: AER must be enabled and supported by the device which must be +* checked in advance, e.g. with pcie_aer_is_native().
drivers/pci/pcie/aer.c void pci_aer_unmask_internal_errors(struct pci_dev *dev) · line 1165
Quoted 10 lines
drivers/pci/pcie/aer.c +8
-1*/ -EXPORT_SYMBOL_FOR_MODULES (pci_aer_unmask_internal_errors,"cxl_core" ); +void pci_aer_mask_internal_errors (struct pci_dev *dev) +{ +int aer = dev->aer_cap; +u32 mask; + +pci_read_config_dword (dev, aer +PCI_ERR_UNCOR_MASK , &mask); + mask |=PCI_ERR_UNC_INTN ; +pci_write_config_dword (dev, aer +PCI_ERR_UNCOR_MASK , mask);
Could do
pci_clear_and_set_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, 0, PCI_ERR_COR_INTERNAL);
or something along those lines.
Maybe it is worth wrapping that in some helpers to make it a bit more regmap like in that it could have set and clear only variants.
Quoted 6 lines
drivers/pci/pcie/aer.c +6
-0+ +pci_read_config_dword (dev, aer +PCI_ERR_COR_MASK , &mask); + mask |=PCI_ERR_COR_INTERNAL ; +pci_write_config_dword (dev, aer +PCI_ERR_COR_MASK , mask); +} +EXPORT_SYMBOL_FOR_MODULES (pci_aer_mask_internal_errors,"cxl_core" );
PATCH v18 13/13 Documentation: cxl: Document CXL protocol error handling
In reply to Terry BowmanAdd Documentation/driver-api/cxl/linux/protocol-error-handling.rst describing the end-to-end CXL protocol error path: AER ingress, the AER-CXL kfifo handoff, the cxl_core consumer worker, RCD/RCH special cases, severity policy, trace events, and a source code map.
This documents the architecture introduced by the preceding patches in this series.
---
Changes in v17->v18:
- Simplify document for readability (Jonathan)
- Drop historical context that goes stale (Jonathan)
- Shorten ASCII flow diagram (Jonathan)
- Drop manual backtick markup, use automarkup (Jonathan)
- Clarify USP/DSP as single switch component (Dave)
- Fix line wrapping to 80 chars (Jonathan)
--- Documentation/driver-api/cxl/index.rst | 1 + .../cxl/linux/protocol-error-handling.rst | 222 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 Documentation/driver-api/cxl/linux/protocol-error-handling.rst
Documentation/driver-api/cxl/index.rst +1 -0
@@ -42,6 +42,7 @@ that have impacts on each other. The docs here break up configurations steps. linux/dax-driver linux/memory-hotplug linux/access-coordinates + linux/protocol-error-handling .. toctree:: :maxdepth: 2
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +222 -0
222 lines not on this page · raw message
Signature · 1 line
2.34.1
[email protected]
AI reviewRe: [PATCH v18 13/13] Documentation: cxl: Document CXL protocol error handling
Sashiko has reviewed this patch and found no issues. It looks great!
Quoted 10 lines
Add
Documentation/driver-api/cxl/linux/protocol-error-handling.rstdescribing the end-to-end CXL protocol error path: AER ingress, the AER-CXL kfifo handoff, thecxl_coreconsumer worker, RCD/RCH special cases, severity policy, trace events, and a source code map.This documents the architecture introduced by the preceding patches in this series.
Assisted-by Claude:claude-opus-4.7Signed-off-by Terry Bowman <[email protected]>
Sashiko has reviewed this patch and found no issues. It looks great!
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=13
Re: [PATCH v18 13/13] Documentation: cxl: Document CXL protocol error handling
In reply to Terry BowmanQuoted 10 lines · Terry Bowman
Add
Documentation/driver-api/cxl/linux/protocol-error-handling.rstdescribing the end-to-end CXL protocol error path: AER ingress, the AER-CXL kfifo handoff, thecxl_coreconsumer worker, RCD/RCH special cases, severity policy, trace events, and a source code map.This documents the architecture introduced by the preceding patches in this series.
Assisted-by Claude:claude-opus-4.7Signed-off-by Terry Bowman <[email protected]>
Quoted 255 lines
---
Changes inv17->v18:
- Simplify document for readability (Jonathan)
- Drop historical context that goes stale (Jonathan)
- Shorten ASCII flow diagram (Jonathan)
- Drop manual backtick markup, use automarkup (Jonathan)
- Clarify USP/DSP as single switch component (Dave)
- Fix line wrapping to 80 chars (Jonathan)--- Documentation/driver-api/cxl/index.rst | 1 + .../cxl/linux/protocol-error-handling.rst | 222 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 Documentation/driver-api/cxl/linux/protocol-error-handling.rstDocumentation/driver-api/cxl/index.rst +1
-0@@ -42,6 +42,7 @@ that have impacts on each other. The docs here break up configurations steps. linux/dax-driver linux/memory-hotplug linux/access-coordinates + linux/protocol-error-handling .. toctree:: :maxdepth: 2Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +222
-0@@ -0,0 +1,222 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================== +CXL Protocol Error Handling +============================== + +CXL devices report protocol-layer failures (CXL.cachemem RAS) as PCIe +AER Internal Errors: PCI_ERR_COR_INTERNAL for correctable events and +PCI_ERR_UNC_INTN for uncorrectable events. The actual fault +information lives in CXL RAS capability registers, not in the PCIe AER +status registers. + +The kernel routes every CXL Internal Error through a producer/consumer +pipeline shared by all CXL device types: Root Ports, Upstream/Downstream +Switch Ports, Endpoints, and Restricted CXL Devices (RCDs). + + +Architecture +============ + +Two error planes run side by side: + +* The **PCIe AER plane** handles native PCIe errors (receiver + overflows, malformed TLPs, completion timeouts, etc.). +* The **CXL protocol error plane** handles CXL Internal Errors. + The AER core forwards them to cxl_core via a dedicated kfifo; + cxl_core reads the CXL RAS registers, emits trace events, and + applies recovery/panic policy. + +The boundary between the two planes is enforced by is_cxl_error() in +aer_cxl_vh.c. It checks info->is_cxl, the PCIe device type +(Endpoint, Root Port, Upstream, or Downstream), and whether the AER +status word indicates an internal error. RC_END devices are excluded +from is_cxl_error() because they reach the kfifo via the separate +cxl_rch_handle_error() path instead. + +The pipeline: + +1. **Producer** (aer_cxl_vh.c, aer_cxl_rch.c) - AER threaded + handler context. Classifies and enqueues a + struct cxl_proto_err_work_data into the kfifo. +2. **Queue** - the AER-CXL kfifo plus a backing work_struct. +3. **Consumer** (cxl_core/ras.c) - workqueue context. Resolves + the CXL port topology and dispatches to CE/UE handlers. + + +Topologies +========== + +Virtual Hierarchy (VH) +---------------------- + +Standard PCIe topology: Root Port, optional switch (Upstream Port with +one or more Downstream Ports), and Endpoints. Each component raises +Internal Errors directly via the Root Port's AER interrupt. + +Producer: cxl_forward_error() in aer_cxl_vh.c. + +Restricted CXL Host (RCH) +-------------------------- + +A Root Complex Event Collector (RCEC) aggregates errors from RCDs +attached as Root Complex Integrated Endpoints. The AER driver +iterates RCDs beneath the RCEC via pcie_walk_rcec() and forwards +each qualifying device through cxl_forward_error() into the same +kfifo. + +Producer: cxl_forward_error() in aer_cxl_vh.c, called from +cxl_rch_handle_error_iter() via pcie_walk_rcec(). + + +Error flow +========== + +.. code-block:: text + + CXL device raises AER Internal Error + (PCI_ERR_COR_INTERNAL or PCI_ERR_UNC_INTN) + | + v + +--------------------------------------+ + | AER core (aer.c) | + | aer_irq() -> aer_isr() | + | -> find_source_device() | + | -> handle_error_source(dev, info) | + +--------------------------------------+ + | + v + +--------------------------------------+ + | handle_error_source() dispatch | + | | + | 1. cxl_rch_handle_error() | + | [always; filters internally] | + | | + | 2. if is_cxl_error(): | + | cxl_forward_error() | + | [enqueue to kfifo] | + | | + | 3. if cxl_pending && non-CE: | + | cxl_proto_err_flush() | + | [sync drain before recovery] | + | | + | 4. pci_aer_handle_error() [always] | + +--------------------------------------+ + | + (kfifo -> workqueue) + | + v + +--------------------------------------+ + | __cxl_proto_err_work_fn() consumer | + | | + | if is_cxl_restricted(pdev): | + | cxl_handle_rdport_errors() | + | [RCH dport RAS first] | + | | + | port = find_cxl_port_by_dev( | + | &pdev->dev, NULL) | + | dport = cxl_find_dport_by_dev( | + | port, &pdev->dev) | + | [dport NULL for EP/USP; set RP/DSP] | + | | + | cxl_handle_proto_error() | + +--------------------------------------+ + | | + v v + +-----------------+ +--------------------+ + | CE | | UCE | + | cxl_handle_ | | cxl_do_recovery() | + | cor_ras() | | read RAS status | + | trace + clear | | trace + panic | + +-----------------+ +--------------------+ + +cxl_do_recovery() reads the CXL RAS uncorrectable status register. +If UE bits are set, it emits the trace event and panics. If no bits +are set (e.g. RAS mapped but error already cleared), it logs a +diagnostic and defers to AER recovery. + + +Severity policy +=============== + +**CE** - cxl_handle_cor_ras() reads the CXL RAS correctable status +register, clears set bits, and emits a cxl_aer_correctable_error +trace event. No recovery action. + +**UCE (non-fatal, and fatal on Root Port/Downstream Port)** - cxl_do_recovery() reads the CXL RAS +uncorrectable status register. If UE bits are set, the kernel panics. +CXL.cachemem traffic cannot be safely recovered once an uncorrectable +error is signaled; continuing risks silent data corruption across +interleaved HDM regions. This panic policy applies to the native AER +path. On firmware-first (CPER/GHES) platforms the CPER handler emits +trace events only and does not call cxl_do_recovery(). + +**Fatal UCE on EP/USP** - The AER core driver does not read AER status +registers for Endpoint and Upstream Ports with fatal events because the +link is down. Without AER status, is_cxl_error() cannot classify +the event as a CXL protocol error and it falls through to standard +AER recovery. + +RCH special case +================ + +When the consumer sees is_cxl_restricted(pdev), it calls +cxl_handle_rdport_errors() first to process the RCH Downstream +Port's RAS registers (accessed via RCRB, not standard config space). +It then continues to process the RCD Endpoint's own RAS registers +via the common path. Both register blocks are checked because +errors can appear in either independently. + +cxl_handle_rdport_errors() acquires the port lock internally. +Callers must not hold it. + + +Trace events +============ + +Two trace events cover all device types and both the native AER and +CPER/GHES firmware-first paths: + +* cxl_aer_correctable_error +* cxl_aer_uncorrectable_error + +Fields: + +* ``memdev`` - memdev name for Endpoints; empty for non-Endpoints. +* ``port`` - CXL port device name. +* ``dport`` - Downstream Port device name; empty when not applicable. +* ``host`` - parent host bridge or uport device name. +* ``serial`` - PCI Device Serial Number from pdev->dsn (cached at + enumeration; no config-space read in the error path). + + +Interrupt masking +================= + +CXL Internal Error bits (PCI_ERR_UNC_INTN and PCI_ERR_COR_INTERNAL) +are unmasked in the AER capability only after the CXL RAS register +block is successfully mapped. A devm teardown action restores the +mask when the port or dport is removed, ensuring clean state after +driver removal. + + +Source files +============ + +.. list-table:: + :header-rows: 1 + + * - File + - Role + * - drivers/pci/pcie/aer.c + - AER core; IRQ, dispatch + * - drivers/pci/pcie/aer_cxl_vh.c + - VH producer; kfifo + * - drivers/pci/pcie/aer_cxl_rch.c + - RCH dispatch; RCEC walk + * - drivers/cxl/core/ras.c + - Consumer; CE/UE handlers; CPER + * - drivers/cxl/core/ras_rch.c + - RCH dport RAS handling + * - drivers/acpi/apei/ghes.c + - CPER/GHES kfifo producer
Re: [PATCH v18 13/13] Documentation: cxl: Document CXL protocol error handling
In reply to Terry BowmanQuoted 10 lines · On Fri, 17 Jul 2026 17:27:06 -0500 Terry Bowman <[email protected]> wrote:
Add
Documentation/driver-api/cxl/linux/protocol-error-handling.rstdescribing the end-to-end CXL protocol error path: AER ingress, the AER-CXL kfifo handoff, thecxl_coreconsumer worker, RCD/RCH special cases, severity policy, trace events, and a source code map.This documents the architecture introduced by the preceding patches in this series.
Assisted-by Claude:claude-opus-4.7Signed-off-by Terry Bowman <[email protected]>
A couple of trivial things inline to tidy up. Actual text seems good to me.
Quoted 33 lines
---
Changes inv17->v18:
- Simplify document for readability (Jonathan)
- Drop historical context that goes stale (Jonathan)
- Shorten ASCII flow diagram (Jonathan)
- Drop manual backtick markup, use automarkup (Jonathan)
- Clarify USP/DSP as single switch component (Dave)
- Fix line wrapping to 80 chars (Jonathan)--- Documentation/driver-api/cxl/index.rst | 1 + .../cxl/linux/protocol-error-handling.rst | 222 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 Documentation/driver-api/cxl/linux/protocol-error-handling.rstDocumentation/driver-api/cxl/index.rst +1
-0@@ -42,6 +42,7 @@ that have impacts on each other. The docs here break up configurations steps. linux/dax-driver linux/memory-hotplug linux/access-coordinates + linux/protocol-error-handling .. toctree:: :maxdepth: 2Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +0
-0
Documentation/driver-api/cxl/linux/protocol-error-handling.rst line 7
Quoted 7 lines
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +7
-0@@ -0,0 +1,222 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================== +CXL Protocol Error Handling +============================== + +CXL devices report protocol-layer failures (CXL.cachemem RAS) as PCIe
Why short wrap? Docs are 80 chars I think.
Quoted 19 lines
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +18
-0+AER Internal Errors: PCI_ERR_COR_INTERNAL for correctable events and +PCI_ERR_UNC_INTN for uncorrectable events. The actual fault +information lives in CXL RAS capability registers, not in the PCIe AER +status registers. +Error flow +========== + +.. code-block:: text + + CXL device raises AER Internal Error + (PCI_ERR_COR_INTERNAL or PCI_ERR_UNC_INTN) + | + v + +--------------------------------------+ + | AER core (aer.c) | + | aer_irq() -> aer_isr() | + | -> find_source_device() | + | -> handle_error_source(dev, info) |
Documentation/driver-api/cxl/linux/protocol-error-handling.rst line 95
Quoted 10 lines
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +10
-0+ +--------------------------------------+ + | + v + +--------------------------------------+ + | handle_error_source() dispatch | + | | + | 1. cxl_rch_handle_error() | + | [always; filters internally] | + | | + | 2. if is_cxl_error(): |
Smells like a missing space.
Quoted 15 lines
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +15
-0+ | cxl_forward_error() | + | [enqueue to kfifo] | + | | + | 3. if cxl_pending && non-CE: | + | cxl_proto_err_flush() | + | [sync drain before recovery] | + | | + | 4. pci_aer_handle_error() [always] | + +--------------------------------------+ + | + (kfifo -> workqueue) + | + v + +--------------------------------------+ + | __cxl_proto_err_work_fn() consumer |
Documentation/driver-api/cxl/linux/protocol-error-handling.rst line 120
Quoted 10 lines
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +10
-0+ | | + | if is_cxl_restricted(pdev): | + | cxl_handle_rdport_errors() | + | [RCH dport RAS first] | + | | + | port = find_cxl_port_by_dev( | + | &pdev->dev, NULL) | + | dport = cxl_find_dport_by_dev( | + | port, &pdev->dev) | + | [dport NULL for EP/USP; set RP/DSP] |
check the alignment here as well. A couple of extra spaces in the lines above I think.
Quoted 16 lines
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +16
-0+ | | + | cxl_handle_proto_error() | + +--------------------------------------+ + | | + v v + +-----------------+ +--------------------+ + | CE | | UCE | + | cxl_handle_ | | cxl_do_recovery() | + | cor_ras() | | read RAS status | + | trace + clear | | trace + panic | + +-----------------+ +--------------------+ + +cxl_do_recovery() reads the CXL RAS uncorrectable status register. +If UE bits are set, it emits the trace event and panics. If no bits +are set (e.g. RAS mapped but error already cleared), it logs a +diagnostic and defers to AER recovery.
Documentation/driver-api/cxl/linux/protocol-error-handling.rst line 146
Quoted 10 lines
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +10
-0+ + +Severity policy +=============== + +**CE** - cxl_handle_cor_ras() reads the CXL RAS correctable status +register, clears set bits, and emits a cxl_aer_correctable_error +trace event. No recovery action. + +**UCE (non-fatal, and fatal on Root Port/Downstream Port)** - cxl_do_recovery() reads the CXL RAS
Wrap needs an update here.
Quoted 6 lines
Documentation/driver-api/cxl/linux/protocol-error-handling.rst new file +6
-0+uncorrectable status register. If UE bits are set, the kernel panics. +CXL.cachemem traffic cannot be safely recovered once an uncorrectable +error is signaled; continuing risks silent data corruption across +interleaved HDM regions. This panic policy applies to the native AER +path. On firmware-first (CPER/GHES) platforms the CPER handler emits +trace events only and does not call cxl_do_recovery().
Quoted 23 lines · Terry Bowman
This patch series enables CXL protocol error handling for both CXL Ports and CXL Endpoints (EP). The previous revision is available at:
https://lore.kernel.org/linux-cxl/[email protected]/
Today the kernel handles native CXL.cachemem RAS only for Endpoints and Restricted CXL Host (RCH) Downstream Ports. Root Ports, Upstream Switch Ports, and Downstream Switch Ports are uncovered. This series introduces a unified CXL protocol error path for all CXL device types, in both VH and RCH topologies.
CXL protocol errors are layered as a distinct error plane on top of PCIe AER. CXL RAS conditions are signaled as PCIe correctable (CE) and uncorrectable (UCE) Internal AER Errors. The AER driver classifies these events using
pcie_is_cxl()and hands them off tocxl_corethrough the AER-CXL kfifo.The
cxl_coredriver dequeues each event, resolves thecxl_porttopology, and dispatches to the CE or UCE handler. RCD Endpoints are handled slightly differently: the RCH Downstream Port's RAS state is processed first, then the Endpoint's own RAS follows the common path.
Quoted 5 lines
PCIe AER errors remain a separate plane and are handled independently. This series updates the CXL Endpoint AER UCE handler and removes the Endpoint AER CE handler, which is now redundant since the AER driver clears and logs CE status itself.
Hi Terry,
From the first glance after I read the cover letter, this part make me thought you are seperating CXL CE and CXL UCE, the former put into PCIe AER, which would be a surprising split for me.
But from the following patches I don't think that's your intent ?
For the next version can you tweak this part to say the Endpoint CE callback is removed as duplicate with common CXL protocol-error path, rathter than saying CXL CE is delegated to AER ?
That would saved me a false start.
Quoted 5 lines
PCI_ERS_RESULT_PANIC, introduced in earlier revisions, has been dropped. The panic decision is made directly incxl_do_recovery(): the kernel panics on any uncorrectable CXL RAS error reported bycxl_handle_ras(), or earlier on link disconnect.
Sounds good.
Quoted 1,171 lines
A fatal UCE on an Upstream Switch Port or Endpoint surfaces through the AER path rather than the CXL RAS path. USP devices are bound to the PCIe portdrv driver, so when a USP reports a fatal UCE, the PCIe error handler provided by portdrv is invoked. PCI config reads to the source device are expected to fail in this scenario, so the AER core never retrieves
UNCOR_STATUS, and the event cannot be classified as CXL. See the fatal and non-fatal log excerpts for USP and EP below.== Patch Details ==
Patch 1 - cxl/ras: Fix
cxl_rch_get_aer_severity()wrong severity register Fix RCH Downstream Port severity classification. Was usingPCI_ERR_ROOT_FATAL_RCV(a Root Error Status bit) instead ofuncor_severityto classify fatal vs non-fatal.Patch 2 - acpi/apei/ghes: Use
raw_spinlock_tfor CXL CPER work locks Convertcxl_cper_work_lockandcxl_cper_prot_err_work_lockfromspinlock_ttoraw_spinlock_tto avoid sleeping-in-hardirq deadlock onPREEMPT_RTkernels.Patch 3 - cxl: Tighten CPER kfifo registration API and symbol visibility Replace
EXPORT_SYMBOL_NS_GPL()withEXPORT_SYMBOL_FOR_MODULES()for CPER kfifo helpers. Simplify register/unregister return types to void.Patch 4 - cxl: Rename
find_cxl_port()tofind_cxl_port_by_dport()Renamesfind_cxl_port()tofind_cxl_port_by_dport()to make the lookup method explicit and consistent with the existingfind_cxl_port_by_uport().Patch 5 - PCI/AER: Introduce AER-CXL protocol error kfifo Adds the AER-CXL kfifo in
drivers/pci/pcie/aer_cxl_vh.calong with the producer helpercxl_forward_error()and the consumer registration helperscxl_register_proto_err_work()andcxl_unregister_proto_err_work(). The kfifo delivers CXL VH protocol errors from the AER driver tocxl_core.Patch 6 - PCI: Establish common CXL Port protocol error flow Dequeues work from the AER-CXL kfifo and establishes a common flow for all CXL Port protocol error handling. Panics on any uncorrectable CXL RAS error. The producer dispatch and consumer go live atomically.
Patch 7 - PCI/CXL: Add RCH support to CXL handlers
Folds Restricted CXL Host (RCH) error handling into the common Port flow. An RCD uncorrectable CXL RAS error now panics, matching the policy applied to all other CXL devices.Patch 8 - cxl/pci: Thread port and dport through RAS handling helpers Refactors
cxl_handle_ras()andcxl_handle_cor_ras()to accept structcxl_port* and structcxl_dport* directly, eliminating redundant bus walks on the error path.Patch 9 - cxl: Update CXL Endpoint AER handler
Replacescxl_error_detected()withcxl_pci_error_detected(). Reads CXL RAS unconditionally; panics on UCE regardless of channel state.Patch 10 - cxl: Add port and dport identifiers to CXL AER trace events Passes struct
cxl_port* and structcxl_dport* to trace events. Adds new "port" and "dport" string fields for all CXL device classes.Patch 11 - PCI: Cache PCI DSN into
pci_dev->dsnduring probe Caches the PCI Device Serial Number at probe time so error handlers and panic paths avoid live config-space reads.Patch 12 - PCI/CXL: Mask/Unmask CXL protocol errors
Enables CXL Internal Error reporting on CXL Ports and Endpoints. The unmask is paired with RAS register block mapping; the mask is registered as a devres action.Patch 13 - Documentation: cxl: Document CXL protocol error handling Adds
protocol-error-handling.rstdescribing the end-to-end CXL protocol error path.== Notes ==
- @Bjorn, I kindly request your review for the following patches. Many of the changes are to CXL-specific files in the PCI tree:
Patch 5 - PCI/AER: Introduce AER-CXL protocol error kfifo Patch 6 - PCI: Establish common CXL Port protocol error flow Patch 7 - PCI/CXL: Add RCH support to CXL handlersPatch 11 - PCI: Cache PCI DSN into
pci_dev->dsnduring probe Patch 12 - PCI/CXL: Mask/Unmask CXL protocol errors- USP/EP fatal UCE follows the AER path because of how the AER core collects status.
aer_get_device_error_info()only readsPCI_ERR_UNCOR_STATUSfor Root Ports/RCECs/Downstream Ports or non-fatal severities, where config reads to the source are still expected to succeed. For a fatal UCE signaled by an upstream component, config reads to that device are expected to fail, soUNCOR_STATUSis never retrieved. Without the status word,is_cxl_error()cannot classify the event as CXL and the AER path handles it.- Dan's related series addressing RAS setup has more details:
https://lore.kernel.org/linux-cxl/[email protected]/- TODOs for future series:
- Moveaer_cxl_rch.ctocxl/core/ras_rch.c
- Move RCH traversing for handling from AER driver into CXL driver
- Support user-defined status masks
- Add CXL Port traversing incxl_do_recovery()== Testing ==
Testing included the following:
- cxl-test
- RCH/RCD AER error injection
- CPER GHES (firmware first)
- VH AER error injection** The AER error injection is not included in this series but will be posted as an RFC for review and for others to use. The error injection using AER will be posted separately as ("cxl: Device protocol AER injection").
Below are the testing results.
===
cxl_test===
Thecxl_testCXL testsuite passed on QEMU with no issues.This required changes in patch 12 ("PCI/CXL: Mask/Unmask CXL protocol errors").
__wrap_devm_cxl_dport_rch_ras_setup()is introduced to preventcxl_testfrom trying to map the RCH AER/RAS registers.=== CPER Tests ===
CPER/firmware first error injection was run and passed on real HW using AMD RAS tool for protocol error injection at the CXL Root Port.==== Restricted CXL Host (RCH) ====
Error injection tests for RCH devices were run using CXL2.0 Endpoint that enumerate as a RCiEP.echo "0000:7f:00.0 CE 00000000 00000002 RCH" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:40:00.3:
aer_inject: Injecting errors 00004000/00000000 into device 0000:40:00.3 pcieport 0000:40:00.3: AER: Correctable error message received from 0000:40:00.3
pcieport 0000:40:00.3: PCIe Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:40:00.3: device [1022:14a6] error status/mask=00004000/00002000
pcieport 0000:40:00.3: [14] CorrIntErrcxl_aer_correctable_error: memdev= port=root0 dport=pci0000:7f host=ACPI0017:00 serial=0: status: 'Memory Data ECC Error'echo "0000:7f:00.0 UCE 00000000 00000002 RCH" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:40:00.3:
aer_inject: Injecting errors 00000000/00400000 into device 0000:40:00.3
pcieport 0000:40:00.3: AER: Uncorrectable (Non-Fatal) error message received from 0000:40:00.3
pcieport 0000:40:00.3: PCIe Bus Error: severity=Uncorrectable (Non-Fatal), type=Transaction Layer, (Receiver ID)
pcieport 0000:40:00.3: device [1022:14a6] error status/mask=00400000/00000000
pcieport 0000:40:00.3: [22] UncorrIntErrcxl_aer_uncorrectable_error: memdev= port=root0 dport=pci0000:7f host=ACPI0017:00 serial=0: status: 'Cache Address Parity Error'first_error: 'Cache Address Parity Error'Kernel panic - not syncing: CXL cachemem error CPU: 26 UID: 0 PID: 396 Comm: kworker/26:1 Kdump: loaded Not tainted 7.2.0-rc3-tb-00014-g6346be30306a #1363 PREEMPT(lazy) Hardware name: AMD Corporation ONYX/ONYX, BIOS TOX100HB 12/03/2025 Workqueue: events cxl_proto_err_work_fn [cxl_core] Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_do_recovery+0x66/0x70 [cxl_core] cxl_handle_rdport_errors+0x176/0x190 [cxl_core] ? srso_alias_return_thunk+0x5/0xfbef5 ? update_load_avg+0x5c/0x2b0 ? srso_alias_return_thunk+0x5/0xfbef5 ? dequeue_entities+0x160/0xb40 ? srso_alias_return_thunk+0x5/0xfbef5 ? pick_task_fair+0x164/0x670 ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] __cxl_proto_err_work_fn+0xea/0x1b0 [cxl_core] ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] for_each_cxl_proto_err+0x5a/0x80 cxl_proto_err_work_fn+0x26/0x50 [cxl_core] process_one_work+0x16e/0x3a0 worker_thread+0x172/0x2e0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK>==== Restricted CXL Device (RCD) ====
Error injection tests for RCD devices were run using CXL2.0 Endpoint that enumerate as a RCiEP.echo "0000:7f:00.0 CE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:40:00.3:
aer_inject: Injecting errors 00004000/00000000 into device 0000:40:00.3 pcieport 0000:40:00.3: AER: Correctable error message received from 0000:40:00.3
pcieport 0000:40:00.3: PCIe Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:40:00.3: device [1022:14a6] error status/mask=00004000/00002000
pcieport 0000:40:00.3: [14] CorrIntErrcxl_aer_correctable_error: memdev=mem0 port=endpoint1 dport= host=0000:7f:00.0 serial=0: status: 'Memory Data ECC Error'echo "0000:7f:00.0 UCE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:40:00.3:
aer_inject: Injecting errors 00000000/00400000 into device 0000:40:00.3
pcieport 0000:40:00.3: AER: Uncorrectable (Non-Fatal) error message received from 0000:40:00.3
pcieport 0000:40:00.3: PCIe Bus Error: severity=Uncorrectable (Non-Fatal), type=Transaction Layer, (Receiver ID)
pcieport 0000:40:00.3: device [1022:14a6] error status/mask=00400000/00000000
pcieport 0000:40:00.3: [22] UncorrIntErrcxl_aer_uncorrectable_error: memdev=mem0 port=endpoint1 dport= host=0000:7f:00.0 serial=0: status: 'Cache Address Parity Error'first_error: 'Cache Address Parity Error'Kernel panic - not syncing: CXL cachemem error CPU: 26 UID: 0 PID: 394 Comm: kworker/26:1 Kdump: loaded Not tainted 7.2.0-rc3-tb-00014-g6346be30306a #1363 PREEMPT(lazy) Hardware name: AMD Corporation ONYX/ONYX, BIOS TOX100HB 12/03/2025 Workqueue: events cxl_proto_err_work_fn [cxl_core] Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_do_recovery+0x66/0x70 [cxl_core] __cxl_proto_err_work_fn+0xa0/0x1b0 [cxl_core] ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] for_each_cxl_proto_err+0x5a/0x80 cxl_proto_err_work_fn+0x26/0x50 [cxl_core] process_one_work+0x16e/0x3a0 worker_thread+0x172/0x2e0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK>=== Virtual Hierarchy ===
Below are the VH error injection test results using QEMU with CXL AER error injection via/sys/kernel/debug/cxl/aer_einj_injecton kernel 7.2.0-rc3 based kernel.
The below QEMU testing uses a CXL Root Port, a CXL Upstream Switch Port, a CXL Downstream Switch Port, and a CXL Type3 Endpoint as given below.The sub-topology for the QEMU testing is:
--------------------- | CXL RP - 0C:00.0 | --------------------- | --------------------- | CXL USP - 0D:00.0 | --------------------- | -------------------- | CXL DSP - 0E:00.0 | -------------------- | --------------------- | CXL EP - 0F:00.0 | ---------------------Error Injection Test Results Summary:
| # | Device Type | BDF | Test | Result | AER | RAS | Verdict | |---|------------------|---------|------|-----------|-----|-----|------------------| | 1 | Root Port | 0c:00.0 | CE | Recovered | OK | OK | PASS | | 2 | Root Port | 0c:00.0 | UCE | Panic | OK | OK | PASS | | 3 | Upstream Port | 0d:00.0 | CE | Recovered | OK | OK | PASS | | 4 | Upstream Port | 0d:00.0 | UCE | Recovered | OK | -- | PASS (Known Lim) | | 5 | Downstream Port | 0e:00.0 | CE | Recovered | OK | OK | PASS | | 6 | Downstream Port | 0e:00.0 | UCE | Panic | OK | OK | PASS | | 7 | Endpoint | 0f:00.0 | CE | Recovered | OK | OK | PASS | | 8 | Endpoint | 0f:00.0 | UCE | Panic | OK | OK | PASS |Overall: 8/8 PASS
=== Root Port - CE ===
echo "0000:0c:00.0 CE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:0c:00.0:
aer_inject: Injecting errors 00004000/00000000 into device 0000:0c:00.0 pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0c:00.0
pcieport 0000:0c:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:0c:00.0: device [8086:7075] error status/mask=00004000/0000a000
pcieport 0000:0c:00.0: [14] CorrIntErrcxl_aer_correctable_error: memdev= port=port1 dport=0000:0c:00.0 host=pci0000:0c serial=0: status: 'Memory Data ECC Error'=== Root Port - UCE ===
echo "0000:0c:00.0 UCE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:0c:00.0:
aer_inject: Injecting errors 00000000/00400000 into device 0000:0c:00.0
pcieport 0000:0c:00.0: AER: Uncorrectable (Fatal) error message received from 0000:0c:00.0
pcieport 0000:0c:00.0: CXL Bus Error: severity=Uncorrectable (Fatal), type=Transaction Layer, (Receiver ID)
pcieport 0000:0c:00.0: device [8086:7075] error status/mask=00400000/02000000
pcieport 0000:0c:00.0: [22] UncorrIntErrcxl_aer_uncorrectable_error: memdev= port=port1 dport=0000:0c:00.0 host=pci0000:0c serial=0: status: 'Cache Address Parity Error'first_error: 'Cache Address Parity Error'Kernel panic - not syncing: CXL cachemem error CPU: 58 UID: 0 PID: 409 Comm: kworker/58:1 Not tainted 7.2.0-rc3-tb-00014-g23418142f421 #1291 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 Workqueue: events cxl_proto_err_work_fn [cxl_core] Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_do_recovery+0x66/0x70 [cxl_core] __cxl_proto_err_work_fn+0x9e/0x1b0 [cxl_core] ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] for_each_cxl_proto_err+0x5a/0x80 cxl_proto_err_work_fn+0x26/0x50 [cxl_core] process_one_work+0x16e/0x3a0 worker_thread+0x172/0x2e0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Kernel Offset: disabled ---[ end Kernel panic - not syncing: CXL cachemem error ]---=== Upstream Switch Port - CE ===
echo "0000:0d:00.0 CE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:0c:00.0:
aer_inject: Injecting errors 00004000/00000000 into device 0000:0d:00.0 pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0d:00.0
pcieport 0000:0d:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:0d:00.0: device [19e5:a128] error status/mask=00004000/0000a000
pcieport 0000:0d:00.0: [14] CorrIntErrcxl_aer_correctable_error: memdev= port=port2 dport= host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'=== Upstream Switch Port - UCE (fatal - AER recovery, known limitation) ===
echo "0000:0d:00.0 UCE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:0c:00.0:
aer_inject: Injecting errors 00000000/00400000 into device 0000:0d:00.0 pcieport 0000:0c:00.0: AER: Uncorrectable (Fatal) error message received from 0000:0d:00.0 pcieport 0000:0d:00.0: AER: CXL Bus Error: severity=Uncorrectable (Fatal), type=Inaccessible, (Unregistered Agent ID)cxl_pci0000:0f:00.0: mem0: frozen state error detected, disable CXL.mem
pcieport 0000:0c:00.0: AER: Root Port link has been reset (0)cxl_pci0000:0f:00.0: mem0: restart CXL.mem after slot resetcxl_pci0000:0f:00.0: mem0: error resume successful
pcieport 0000:0c:00.0: AER: device recovery successful=== Downstream Port - CE ===
echo "0000:0e:00.0 CE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:0c:00.0:
aer_inject: Injecting errors 00004000/00000000 into device 0000:0e:00.0
pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0e:00.0
pcieport 0000:0e:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
pcieport 0000:0e:00.0: device [19e5:a129] error status/mask=00004000/0000a000
pcieport 0000:0e:00.0: [14] CorrIntErrcxl_aer_correctable_error: memdev= port=port2 dport=0000:0e:00.0 host=0000:0d:00.0 serial=0: status: 'Memory Data ECC Error'=== Downstream Port - UCE ===
echo "0000:0e:00.0 UCE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:0c:00.0:
aer_inject: Injecting errors 00000000/00400000 into device 0000:0e:00.0
pcieport 0000:0c:00.0: AER: Uncorrectable (Fatal) error message received from 0000:0e:00.0
pcieport 0000:0e:00.0: CXL Bus Error: severity=Uncorrectable (Fatal), type=Transaction Layer, (Receiver ID)
pcieport 0000:0e:00.0: device [19e5:a129] error status/mask=00400000/02000000
pcieport 0000:0e:00.0: [22] UncorrIntErrcxl_aer_uncorrectable_error: memdev= port=port2 dport=0000:0e:00.0 host=0000:0d:00.0 serial=0: status: 'Cache Address Parity Error'first_error: 'Cache Address Parity Error'Kernel panic - not syncing: CXL cachemem error CPU: 7 UID: 0 PID: 299 Comm: kworker/7:1 Not tainted 7.2.0-rc3-tb-00014-g832c50e87f10 #1364 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 Workqueue: events cxl_proto_err_work_fn [cxl_core] Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_do_recovery+0x66/0x70 [cxl_core] __cxl_proto_err_work_fn+0xa0/0x1b0 [cxl_core] ? __pfx___cxl_proto_err_work_fn+0x10/0x10 [cxl_core] for_each_cxl_proto_err+0x5a/0x80 cxl_proto_err_work_fn+0x26/0x50 [cxl_core] process_one_work+0x16e/0x3a0 worker_thread+0x172/0x2e0 ? __pfx_worker_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Kernel Offset: disabled ---[ end Kernel panic - not syncing: CXL cachemem error ]---=== Endpoint - CE ===
echo "0000:0f:00.0 CE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:0c:00.0:
aer_inject: Injecting errors 00004000/00000000 into device 0000:0f:00.0 pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0f:00.0cxl_pci0000:0f:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)cxl_pci0000:0f:00.0: device [8086:0d93] error status/mask=00004000/0000a000cxl_pci0000:0f:00.0: [14] CorrIntErrcxl_aer_correctable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 serial=0: status: 'Memory Data ECC Error'=== Endpoint - UCE ===
echo "0000:0f:00.0 UCE 00000000 00000002" >
/sys/kernel/debug/cxl/aer_einj_injectpcieport 0000:0c:00.0:
aer_inject: Injecting errors 00000000/00400000 into device 0000:0f:00.0
pcieport 0000:0c:00.0: AER: Uncorrectable (Fatal) error message received from 0000:0f:00.0cxl_pci0000:0f:00.0: AER: CXL Bus Error: severity=Uncorrectable (Fatal), type=Inaccessible, (Unregistered Agent ID)cxl_aer_uncorrectable_error: memdev=mem1 port=endpoint4 dport= host=0000:0f:00.0 serial=0: status: 'Cache Address Parity Error'first_error: 'Cache Address Parity Error'Kernel panic - not syncing: CXL cachemem error CPU: 58 UID: 0 PID: 430 Comm: irq/24-aerdrv Not tainted 7.2.0-rc3-tb-00014-g23418142f421 #1291 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> vpanic+0x453/0x4b0 panic+0x56/0x60 cxl_pci_error_detected+0x15c/0x160 [cxl_core] report_error_detected+0xc7/0x1c0 ? __pfx_report_frozen_detected+0x10/0x10 __pci_walk_bus+0x47/0x70 ? __pfx_report_frozen_detected+0x10/0x10 pci_walk_bus+0x2c/0x40 ? __pfx_aer_root_reset+0x10/0x10 pcie_do_recovery+0x234/0x330 ? __pfx_irq_thread_fn+0x10/0x10 aer_isr_one_error_type+0x333/0x340 aer_isr_one_error+0x112/0x140 aer_isr+0x47/0x80 irq_thread_fn+0x1f/0x60 irq_thread+0x123/0x220 ? __pfx_irq_thread_dtor+0x10/0x10 ? __pfx_irq_thread+0x10/0x10 kthread+0xe5/0x120 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x1bd/0x220 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Kernel Offset: disabled ---[ end Kernel panic - not syncing: CXL cachemem error ]---== Changes ==
Changes in
v17->v18:
acpi/apei/ghes: Useraw_spinlock_tfor CXL CPER work locks
- New commit
- Convertcxl_cper_work_lockandcxl_cper_prot_err_work_lockfromspinlock_ttoraw_spinlock_t; useguard(raw_spinlock_irqsave)at
all call sites to avoid sleeping-in-hardirq onPREEMPT_RT.
- Addkfifo_reset(&cxl_cper_fifo)tocxl_cper_unregister_work()
- AddWARN_ONCEtocxl_cper_register_work()for double-registration consistency
- Fixcxl_cper_unregister_work()to clear global pointer beforecancel_work_sync()
- Remove redundantcancel_work_sync()fromcxl_ras_exit()
cxl: Tighten CPER kfifo registration API and symbol visibility
- New commit (split/rework of v17 "Limit CXL-CPER kfifo registration functions scope")
cxl: Renamefind_cxl_port()tofind_cxl_port_by_dport()
- None
PCI/AER: Introduce AER-CXL protocol error kfifo
- Remove correctable status clear fromcxl_forward_error(); the AER core clears all status bits viapci_aer_handle_error()info->statuswriteback
- Schedule consumer on kfifo overflow so existing entries can be drained
PCI: Establish common CXL Port protocol error flow
- Fixhandle_error_source()to callpci_aer_handle_error()unconditionally so AER handling always runs aftercxl_forward_error()
- Addcxl_proto_err_flush()call for CXL UCE to drain kfifo before AER recovery tears down the device
- Fix NULL dereference ofdport->dport_devincxl_handle_cor_ras()andcxl_handle_ras()for UPSTREAM/ENDPOINT port types: usedport->dport_devwhen dport is non-NULL, else fall back toport->uport_dev
- Remove duplicatepcie_clear_device_status()call fromcxl_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) andport->dev.drivercheck
PCI/CXL: Add RCH support to CXL handlers
- Pass&pdev->devinstead ofdport->port->uport_devincxl_handle_rdport_errors()to avoid dropping RCH trace events.
- Document trace event attribution change.
- Document removal ofcxl_cor_error_detected()andcxlds->rcdbranches.
- Capitalize Endpoint per PCI spec convention.
- Useto_ras_base()incxl_handle_rdport_errors()to centralize RAS base address lookup in preparation for error injection testing.
cxl/pci: Thread port and dport through RAS handling helpers
- New commit
cxl: Update CXL Endpoint AER handler
- Fixcxl_pci_error_detected()to usefind_cxl_port_by_uport()andport->uport_dev
- Read CXL RAS unconditionally; panic on UCE regardless of channel state
- Document unconditional read policy and0xFFFFFFFFbehavior in comment
cxl: Add port and dport identifiers to CXL AER trace events
- Consolidate doublefind_cxl_port_by_dev()incxl_cper_handle_prot_err()
- Add comment noting dport is NULL for endpoint and upstream port devices
PCI: Cache PCI DSN intopci_dev->dsnduring probe
- New commit
PCI/CXL: Mask/Unmask CXL protocol errors
- Makecxl_unmask_proto_interrupts()andcxl_mask_proto_interrupts()static
- Removedev_is_pci()guard fromdevm_cxl_dport_rch_ras_setup(); the guard blocked real RCH hardware becausepci_host_bridgeis not onpci_bus_type
Documentation: cxl: Document CXL protocol error handling
- Simplify document for readability (Jonathan)
- Drop historical context that goes stale (Jonathan)
- Shorten ASCII flow diagram (Jonathan)
- Drop manual backtick markup, use automarkup (Jonathan)
- Clarify USP/DSP as single switch component (Dave)
- Fix line wrapping to 80 chars (Jonathan)Changes in
v16->v17:
PCI/AER: Introduce AER-CXL Kfifo
- Reword "kfifo semaphore" to "kfifo spinlock" to matchfifo_lock.
- Defer thehandle_error_source()is_cxl_error()switch to the patch that registers the kfifo consumer to keep each commit bisect-safe.
- Rename rwsema to rwsem
- Change CPER exports to useEXPORT_SYMBOL_FOR_MODULES.
- Add work cancel function.
- Replacekfifo_put()withkfifo_in_spinlocked()for multiple producers
- Addfifo_lockspinlock for concurrent producer serialisation
- Initialize the embedded kfifo withINIT_KFIFO()in asubsys_initcallsokfifo->mask, ->esize and ->data are set before first use.
- ClearPCI_ERR_COR_STATUSincxl_forward_error()before enqueue so the device is acked for correctable events even when the consumer drops the event. Uncorrectable status is left forcxl_do_recovery()to clear after recovery completes, mirroring the AER core convention.
- WARN on double-registration incxl_register_proto_err_work()to make an unintended second consumer visible at runtime.
- Add directrwsem.h,cleanup.handworkqueue.hincludes for symbols used inaer_cxl_vh.c
- AddMAINTAINERSentries fordrivers/pci/pcie/aer_cxl_*.c
- Update message
cxl/ras: Unify Endpoint and Port AER trace events
- Replacecxlds->serialwithpci_get_dsn()
- Change 'memdev' to 'device' (Dan)
- Updated Commit message
cxl: Use common CPER handling for all CXL devices
- New commit
cxl: Renamefind_cxl_port()tofind_cxl_port_by_dport()
- New commit
- Drop the de-staticisation offind_cxl_port_by_uport()and thecore.hdeclarations from this prep patch; both move to the patch that introduces the first cross-file caller.
cxl: Limit CXL-CPER kfifo registration functions scope
- Split from v16 02/10 ("Update unregistration for AER-CXL and CPER-CXL kfifos"); AER-CXL half folded into v17 01/10.
- Convert exports toEXPORT_SYMBOL_FOR_MODULES("cxl_core").
- Change register/unregister return type from int to void.
- Dropwork_structargument fromcxl_cper_unregister_prot_err_work(); it now cancels its own work.
- Remove now-redundantcancel_work_sync()fromcxl_ras_exit().
- AddWARN_ONCE()incxl_cper_register_prot_err_work()for double-registration.
PCI: Establish common CXL Port protocol error flow
-get_cxl_port()->find_cxl_port_by_dev()
- Simplifiedfind_cxl_port_by_dev()
- Replace and removecxl_serial_number()w/pci_get_dsn()
-cxl_get_ras_base()->to_ras_base()
- Drop dependency onPCI_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.
- Drop the redundantPCI_ERR_COR_STATUSRMW incxl_handle_proto_error();cxl_forward_error()already acks the correctable AER status.
- Addis_cxl_error()switch inhandle_error_source()here, paired with the kfifo consumer registration, to keep each commit bisect-safe.
- Droppcie_aer_is_native()guard incxl_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 toget_cxl_port()documentation (Terry)
- Fix__cxl_proto_err_work_fn()to return 0 for transient errors.
- Drop !port check incxl_do_recovery(), caller already validated
- Fix kerneldoc @pdev -> @dev infind_cxl_port_by_dev()
- Fix missing space inpr_err_ratelimited()
- Add disconnect check before access
- Madepcie_clear_device_status()andpci_aer_clear_fatal_status()EXPORT_SYMBOL_FOR_MODULES("cxl_core")(Dan)
- Movefind_cxl_port_by_dport()andfind_cxl_port_by_uport()de-staticisation andcore.hdeclarations from the rename patch to here, where the first cross-file callers infind_cxl_port_by_dev()land.
PCI/CXL: Add RCH support to CXL handlers
- Drop now-deadcxlds->rcdbranches from cxl_{cor_,}error_detected().
- Drop duplicate subject line from commit body.
- Document panic-on-uncorrectable behavior change for RCD path.
- Document trace event device-name change (memN -> PCI BDF) for RCH path.
- Rewritecxl_handle_proto_error()RC_ENDcomment to clarify RCD/RCH shared interrupt relationship
- Rewrite commit message
cxl: Remove Endpoint AER correctable handler
- Update commit message
- Add Reviewed-by from Jonathan and DaveJ
cxl: Update Endpoint AER uncorrectable handler
- Renamepci_error_handlersstruct instance tocxl_pci_error_handlersto avoid shadowing the struct type tag.
- Restorescoped_guard(device)anddev->drivercheck around AER read.
- NULL-checkfind_cxl_port_by_dev()before deref ofport->uport_dev.
- Updated commit message. (Terry)
- Add scope cleanup for port variable incxl_pci_error_detected()(Terry)
- Dropcxl_uncor_aer_present(), rely on AER state
PCI/CXL: Mask/Unmask CXL protocol errors
- Drop redundantcxl_mask_proto_interrupts()calls fromunregister_port()andcxl_dport_remove(); the devres action registered alongside the unmask is the sole mask path.
- Update title
- Remove unnecessary check foraer_capabilities
- Gatecxl_unmask_proto_interrupts()onpcie_aer_is_native()
- Addpci_aer_mask_internal_errors()andcxl_mask_proto_interrupts()
- Only unmask on successfulcxl_map_component_regs()
- NULL-check @dev in cxl_{un,}mask_proto_interrupts()
- Drop static and declare incore/core.h
Documentation: cxl: Document CXL protocol error handling
- New commitChanges in
v15->v16:
PCI/AER: Introduce AER-CXL Kfifo
- Addpci_dev_put()and comment atpci_dev_get()(Dan)
- /rw_sema/rwsema/ (Dan)
- Split validation checks incxl_forward_error()to allow for meaningful reason in log (Terry)
- Shortened commit title to remove wordiness (Terry) PCI/CXL: Update unregistration for AER-CXL and CPER-CXL kfifos
- New commit
cxl: Update CXL Endpoint tracing
- Add Dan's review-by
- Incorporate Dan's comment into commit message:
"Add the serial number at the end to preserve compatibility with libtraceevent parsing of the parameters."
PCI/ERR: IntroducePCI_ERS_RESULT_PANIC
- None
PCI: Establish common CXL Port protocol error flow
-get_ras_base(), initialize dport to NULL (Jonathan)
- Remove guard(device)(&cxlmd->dev) (Jonathan)
- Fixdev_warns()(Jonathan)
- Remove comment incxl_port_error_detected()(Dan)
- Madepcie_clear_device_status()andpci_aer_clear_fatal_status()"CXL" Export namespace (Dan)
- Update switch-case brackets to follow clang-format (Dan)
- AddPCI_EXP_TYPE_RC_ENDforcxl_get_ras_base()(Terry)
- Add NULL port check incxl_serial_number()(Terry) PCI/CXL: Add RCH support to CXL handlers
- New commit
cxl: Update error handlers to support CXL Port devices
- None
cxl: Update Endpoint AER uncorrectable handler
- Update commit message (DaveJ)
- s/cxl_handle_aer()/cxl_uncor_aer_present()/g (Jonathan)
-cxl_uncor_aer_present(): Leave original result calculation based on if a UCE is present and the provided state (Terry)
- Add call topci_print_aer(). AER fails to log because is upstream link (Terry)
cxl: Remove Endpoint AER correctable handler
- None
cxl: Enable CXL protocol error reporting
- NoneChanges in
v14->v15:
PCI/AER: Introduce AER-CXL Kfifo in new file,pcie/aer_cxl_vh.c
- Movepci_dev_get()call to this patch (Dave)
cxl: Update CXL Endpoint tracing
- Update commit message
- Moved cxl_handle_ras/cxl_handle_cor_ras() changes to future patch (Terry) PCI/ERR: IntroducePCI_ERS_RESULT_PANIC
- None
PCI/AER: Dequeue forwarded CXL error
- Movepci_dev_get()tocxl_forward_error()(Dave)
- Move inis_cxl_error()change from later patch (Terry)
PCI: Establish common CXL Port protocol error flow
- Update commit message and title. Added Bjorn's ack.
- Move CE and UCE handling logic here (Terry)
cxl: Update error handlers to support CXL Port protocol errors
- New commit (Terry)
cxl: Update Endpoint AER uncorrectable handler
- Title update (Terry)
- Change cxl_pci_error-detected() to handle & log AER (Terry)
- Update commit message (Terry)
- Moved cxl_handle_ras()/cxl_handle_cor_ras() to earlier patch (Terry)
cxl: Remove Endpoint AER correctable handler
- Removecxl_pci_cor_error_detected(). Is not needed. AER is logged in the AER driver. (Dan)
- Update commit messageChanges in
v13->v14:
PCI: Move CXL DVSEC definitions intouapi/linux/pci_regs.h
- Add Jonathan's and Dan's review-by
- Update commit title prefix (Bjorn)
- Revert format fix forcxl_sbr_masked()(Jonathan)
- Update 'Compute Express Link' comment block (Jonathan)
- MovePCI_DVSEC_CXL_FLEXBUSdefinitions to later patch where
used (Jonathan)
- Removed stray change (Bjorn)
PCI: Update CXL DVSEC definitions
- New patch. Split from previous patch such that there is now a separate move patch and a format fix patch.
- Formatting update requested (Bjorn)
- RemovePCI_DVSEC_HEADER1_LENGTH_MASKbecause it duplicatesPCI_DVSEC_HEADER1_LEN()(Bjorn)
- Add Dan's review-by
PCI: Introducepcie_is_cxl()
- MoveFLEXBUS_STATUSDVSEC here (Jonathan)
- Remove check for EP and USP (Dan)
- Update commit message (Bjorn)
- Fix writing past 80 columns (Bjorn)
- Addpci_is_pcie()parent bridge check at beginning of function (Bjorn)
PCI: Replacecxl_error_is_native()withpcie_aer_is_native()
- New commit
cxl/pci: Move CXL driver's RCH error handling intocore/ras_rch.c
- Add sign-off for Dan and Jonathan
- Revert inadvertent formatting ofcxl_dport_map_rch_aer()(Jonathan)
- Remove default value forCXL_RCH_RAS(Dan)
- Remove unnecessarypci.hinclude incore.h&ras_rch.c(Jonathan)
- Addlinux/types.hinclude inras_rch.c(Jonathan)
- ChangeCONFIG_CXL_RCH_RAS->CONFIG_CXL_RAS(Dan)
PCI/AER: Exportpci_aer_unmask_internal_errors
- New commit. Bjorn requested separating out and adding immediatetly before being used. This is called fromcxl_rch_enable_rcec()in following patch.
PCI/AER: Updateis_internal_error()to be non-staticis_aer_internal_error()
- New commit
PCI/AER: Move CXL RCH error handling toaer_cxl_rch.c
- Add review-by and signed-off for Dan
- Commit message fixup (Dan)
- Update commit message with use-case description (Dan, Lukas)
- Makecxl_error_is_native()static (Dan)
- Makeis_internal_error()non-static, non-export (Terry)
PCI/AER: Useguard()incxl_rch_handle_error_iter()
- Add review-by for Jonathan, Dave Jiang, Dan WIlliams, and Bjorn
- Removecleanup.h(Jonathan)
- Reverted comment removal (Bjorn)
- Move this patch afterpci/pcie/aer_cxl_rch.ccreation (Bjorn) PCI/AER: ReplacePCIEAER_CXLsymbol withCXL_RAS
- New commit
PCI/AER: Report CXL or PCIe bus type in AER trace logging
- Merged with Dan's commit. Changes are movingbus_typethe last parameter in function calls (Dan)
- Removed all DCOs because of changes (Terry)
- Update commit message (Bjorn)
- Add Bjorn's ack-by
PCI/AER: Update structaer_err_infowith kernel-doc formatting
- New commit
cxl/mem: Clarify @host fordevm_cxl_add_nvdimm()
- New commit
cxl/port: Remove "enumerate dports" helpers
- New commit
cxl/port: Fix devm resource leaks around with dport management
- New commit
cxl/port: Move dport operations to a driver event
- New commit
cxl/port: Move dport RAS reporting to a port resource
- New commit
cxl: Map CXL Endpoint Port and CXL Switch Port RAS registers
- Correct message spelling (Terry)
cxl/port: Move endpoint component register management tocxl_port
- Correct message spelling (Terry)
cxl/port: Map Port component registers before switchport init
- Updates to usecxl_port_setup_regs()(Dan)
cxl: Change CXL handlers to useguard()instead ofscoped_guard()
- Add reviewed-by for Jonathan and Dave Jiang
PCI/ERR: IntroducePCI_ERS_RESULT_PANIC
- Add review-by for Dan
- Update Title prefix (Bjorn)
- Removedmerge_result. Only logging error for device reporting the error (Dan)
- RemovePCI_ERS_RESULT_PANICparagraph inpci-error-recovery.rst(Bjorn) PCI/AER: Move AER driver's CXL VH handling topcie/aer_cxl_vh.c
- Replacedworkqueue_types.hinclude with 'structwork_struct' predeclaration (Bjorn)
- Update error message (Bjorn)
- Reordered 'structcxl_proto_err_work_data' (Bjorn)
- Remove export ofcxl_error_is_native()here (Bjorn)
cxl/port: Unify endpoint and switch port lookup
- New patch
PCI/AER: Dequeue forwarded CXL error
- Update commit title's prefix (Bjorn)
- Add pdev ref get in AER driver before enqueue and add pdev ref put in CXL driver after dequeue and handling (Dan)
- Removed handling to simplify patch context (Terry)
PCI: Introduce CXL Port protocol error handlers
- 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)
- Removecxl_walk_port(). Only log the erroring device. No port walking. (Dan)
- Removecxl_pci_drv_bound(). Check for 'is_cxl' parent port is sufficient (Dan)
- Removedevice_lock_if()
- Combine CE and UCE here (Terry)
cxl: Update Endpoint uncorrectable protocol error handling
- Update commit headline (Bjorn)
- Rename pci_error_detected()/pci_cor_error_detected() -> cxl_pci_error_detected/cxl_pci_cor_error_detected() (Jonathan)
- Remove now-invalid comment incxl_error_detected()(Jonathan)
- Split into separate patches for UCE and CE (Terry)
cxl: Update Endpoint correctable protocol error handling
- New commit
- Changecxl_cor_error_detected()parameter to&pdev->devdevice from memdev device. (Terry)
cxl: Enable CXL protocol errors during CXL Port probe
- Update commit title's prefix (Bjorn)
Changes inv12->v13:
CXL/PCI: Move CXL DVSEC definitions intouapi/linux/pci_regs.h
- Add Dave Jiang's reviewed-by
- Remove changes to existing PCI_DVSEC_CXL_PORT* defines. Update commit message. (Jonathan)
PCI/CXL: Introducepcie_is_cxl()
- Add Ben's "reviewed-by"
cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
- None
cxl/pci: Remove unnecessary CXL RCH handling helper functions
- None
cxl: Remove CXL VH handling inCONFIG_PCIEAER_CXLconditional blocks from core
- None
cxl: Move CXL driver's RCH error handling intocore/ras_rch.c
- None
CXL/AER: Replacedevice_lock()incxl_rch_handle_error_iter()withguard()lock
- New patch
CXL/AER: Move AER drivers RCH error handling intopcie/aer_cxl_rch.c
- Add forward declararation of 'structaer_err_info' inpci/pci.h(Terry)
- Changed copyright date from 2025 to 2023 (Jonathan)
- Add David Jiang's, Jonathan's, and Ben's review-by
- Readd 'structaer_err_info' (Bot)
PCI/AER: Report CXL or PCIe bus error type in trace logging
- Remove duplicatedaer_err_infoinline comments. Is already in the kernel-doc header (Ben)
cxl/pci: Update RAS handler interfaces to also support CXL Ports
- None
cxl/pci: Log message if RAS registers are unmapped
- Added Bens review-by
cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
- Added Dave Jiang's review-by
cxl/pci: Updatecxl_handle_cor_ras()to return early if no RAS errors
- Add Ben's review-by
cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
- Change as result of dport delay fix. No longer need switchport and endport approach. Refactor. (Terry)
CXL/PCI: IntroducePCI_ERS_RESULT_PANIC
- Add Dave Jiang's, Jonathan's, Ben's review-by
- Typo fix (Ben)
CXL/AER: Introducepcie/aer_cxl_vh.cin AER driver for forwarding CXL errors
- Add Dave Jiang's review-by
- Update error message (Ben)
cxl: Introducecxl_pci_drv_bound()to check for bound driver
- Add Dave Jiang's review-by.
cxl: Change CXL handlers to useguard()instead ofscoped_guard()
- New patch
cxl/pci: Introduce CXL protocol error handlers for endpoints
- Updated all the implemetnation and commit message. (Terry)
- Refactored cxl_cor_error_detected()/cxl_error_detected() to remove pdev (Dave Jiang)
CXL/PCI: Introduce CXL Port protocol error handlers
- Moveget_pci_cxl_host_dev()andcxl_handle_proto_error()to Dequeue patch (Terry)
- Remove EP case incxl_get_ras_base(), not used. (Terry)
- Remove check fordport->dport_dev(Dave)
- Remove whitespace (Terry)
PCI/AER: Dequeue forwarded CXL error
- Rewritecxl_handle_proto_error()andcxl_proto_err_work_fn()(Terry)
- Renameget_cxl_hostdev()to beget_cxl_port()(Terry)
- Remove exporting of unused function,pci_aer_clear_fatal_status()(Dave Jiang)
- Changepr_err()calls to ratelimited. (Terry)
- Update commit message. (Terry)
- Remove namespace qualifier frompcie_clear_device_status()
export (Dave Jiang)
- Move locks intocxl_proto_err_work_fn()(Dave)
- Update log messages incxl_forward_error()(Ben)
CXL/PCI: Export and renamemerge_result()topci_ers_merge_result()
- Renamedpci_ers_merge_result()topcie_ers_merge_result().pci_ers_merge_result()is already used in eeh driver. (Bot)
CXL/PCI: Introduce CXL uncorrectable protocol error recovery
- Rewritereport_error_detected()andcxl_walk_port(Terry)
- Addguard()before callingcxl_pci_drv_bound()(Dave Jiang)
- Addguard()calls for EP (cxlds->cxlmd->dev&pdev->dev) and ports (pdev->dev& parentcxl_port) incxl_report_error_detected()andcxl_handle_proto_error()(Terry)
- Remove unnecessary check for endpoint port. (Dave Jiang)
- Remove check for RCIEP EP incxl_report_error_detected()(Terry)
CXL/PCI: Enable CXL protocol errors during CXL Port probe
- Add dev anddev_is_pci()NULL checks incxl_unmask_proto_interrupts()(Terry)
- Add Dave Jiang's and Ben's review-by
CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
- Added dev anddev_is_pci()checks incxl_mask_proto_interrupts()(Terry)Changes in v11 -> v12:
cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
- Added Dave Jiang's review by
- Moved to front of series
cxl/pci: Remove unnecessary CXL RCH handling helper functions
- Add reviewed-by for Alejandro & Dave Jiang
- Moved to front of series
cxl: Remove ifdef blocks ofCONFIG_PCIEAER_CXLfromcore/pci.c
- UpdateCONFIG_CXL_RASin CXLKconfigto haveCXL_PCIdependency (Terry)
CXL/AER: RemoveCONFIG_PCIEAER_CXLand replace withCONFIG_CXL_RAS
- Added review-by for Sathyanarayanan
- ChangedKconfigdependency fromPCIEAER_CXLto PCIEAER. Moved
this backwards into this patch.
cxl: Move CXL driver RCH error handling intoCONFIG_CXL_RCH_RASconditio
- MovedCXL_RCH_RASKconfigdefinition here from following commit
CXL/AER: Introduceaer_cxl_rch.cinto AER driver for handling CXL RCH errors
- Renamedrivers/pci/pcie/cxl_rch.ctodrivers/pci/pcie/aer_cxl_rch.c(Lukas)
- Removed forward declararation of 'structaer_err_info' inpci/pci.h(Terry)
CXL/PCI: Move CXL DVSEC definitions intouapi/linux/pci_regs.h
- Change formatting to be same as existing definitions
- ChangeGENMASK()->__GENMASK()andBIT()to_BITUL()
PCI/CXL: Introducepcie_is_cxl()
- Add review-by for Alejandro
- Add comment inset_pcie_cxl()explaining why updating parent status.
PCI/AER: Report CXL or PCIe bus error type in trace logging
- Changeaer_err_info::is_cxlto be bool a bitfield. Update structure padding. (Lukas)
- Add kernel-doc for 'structaer_err_info' (Lukas)
cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
- Correct parameters to calltrace_cxl_aer_correctable_error()(Shiju)
- Add reviewed-by for Jonathan and Shiju
cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
- Add check fordport_parent->rchbefore callingcxl_dport_init_ras_reporting().
- RCH dports are initialized fromcxl_dport_init_ras_reportingcxl_mem_probe().
CXL/PCI: IntroducePCI_ERS_RESULT_PANIC
- Documentation requested by (Lukas)
CXL/AER: Introduceaer_cxl_vh.cin AER driver for forwarding CXL errors
- Renamedrivers/pci/pcie/cxl_aer.ctodrivers/pci/pcie/aer_cxl_vh.c(Lukas)
cxl: Introducecxl_pci_drv_bound()to check for bound driver
- New patch
PCI/AER: Dequeue forwarded CXL error
- Add guard for CE case incxl_handle_proto_error()(Dave)
- Updated commit message (Terry)
CXL/PCI: Introduce CXL Port protocol error handlers
- Add call tocxl_pci_drv_bound()incxl_handle_proto_error()andpci_to_cxl_dev() (Lukas)- Change
cxl_error_detected()->cxl_cor_error_detected()(Terry)
- Remove NULL variable assignments (Jonathan)
- Replacebus_find_device()withfind_cxl_port_by_uport()for upstream port searches. (Dave)
CXL/PCI: Export and renamemerge_result()topci_ers_merge_result()
- Remove static inlinepci_ers_merge_result()definition for !CONFIG_PCIEAER. Is not needed. (Lukas)
CXL/PCI: Introduce CXL uncorrectable protocol error recovery
- Clean up port discovery incxl_do_recovery()(Dave)
- AddPCI_EXP_TYPE_RC_ENDto type check incxl_report_error_detected()Changes in v10 -> v11:
cxl: Remove ifdef blocks ofCONFIG_PCIEAER_CXLfromcore/pci.c
- New patch
CXL/AER: RemoveCONFIG_PCIEAER_CXLand replace withCONFIG_CXL_RAS
- New patch
cxl/pci: Remove unnecessary CXL RCH handling helper functions
- New patch
cxl: Move CXL driver RCH error handling intoCONFIG_CXL_RCH_RASconditional block
- New patch
CXL/AER: Introducerch_aer.cinto AER driver for handling CXL RCH errors
- Remove changes in code-split and move to earlier, new patch
- Add #include <linux/bitfield.h> tocxl_ras.c
- Movecxl_rch_handle_error()&cxl_rch_enable_rcec()declarations frompci.htoaer.h, more localized.
- IntroduceCONFIG_CXL_RCH_RAS, includesMakefilechanges,ras.cifdef changes CXL/PCI: Move CXL DVSEC definitions intouapi/linux/pci_regs.h
- New patch
PCI/CXL: Introducepcie_is_cxl()
- Amendedset_pcie_cxl()to check for Upstream Port's and EP's parent downstream port by callingset_pcie_cxl(). (Dan)
- Retitle patch: 'Add' -> 'Introduce'
- Add check for CXL.mem and CXL.cache (Alejandro, Dan)
PCI/AER: Report CXL or PCIe bus error type in trace logging
- Remove duplicate call totrace_aer_event()(Shiju)
- Added Dan William's and Dave Jiang's reviewed-by
CXL/AER: Update PCI class code check to useFIELD_GET()
- Add #include <linux/bitfield.h> tocxl_ras.c(Terry)
- Removed line wrapping at "(CXL 3.2, 8.1.12.1)". (Jonathan)
cxl/pci: Log message if RAS registers are unmapped
- Added Dave Jiang's review-by (Terry)
cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
- Updated CE and UCE trace routines to maintian consistentTP_StructABI and unchangedTP_printk()logging. (Shiju, Alison)
cxl/pci: Updatecxl_handle_cor_ras()to return early if no RAS errors
- Added Dave Jiang and Jonathan Cameron's review-by
- Changes moved tocore/ras.c
cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
- Use local pointer for readability incxl_switch_port_init_ras()(Jonathan Cameron)
- Rename port to be ep incxl_endpoint_port_init_ras()(Dave Jiang)
- Rename dport to beparent_dportincxl_endpoint_port_init_ras()
andcxl_switch_port_init_ras()(Dave Jiang)
- Port helper changes were incxl/port.c, now incore/ras.c(Dave Jiang) cxl/pci: Introduce CXL Endpoint protocol error handlers
-cxl_error_detected()- Change handlers'scoped_guard()toguard()(Jonathan)
-cxl_error_detected()- Remove extra line (Shiju)
- Changes moved tocore/ras.c(Terry)
-cxl_error_detected(), remove 'ue' and return with function call. (Jonathan)
- Remove extra space in documentation forPCI_ERS_RESULT_PANICdefinition
- Move #include "pci.hfromcxl.htocore.h(Terry)
- Remove unnecessary includes ofcxl.handcore.hinmem.c(Terry) CXL/AER: Introducecxl_aer.cinto AER driver for forwarding CXL errors
- Move RCH implementation tocxl_rch.cand RCH declarations topci/pci.h. (Terry)
- Introduce 'structcxl_proto_err_kfifo' containing semaphore, fifo, and work struct. (Dan)
- Remove embedded struct fromcxl_proto_err_work(Dan)
- Make 'structwork_struct*cxl_proto_err_work' definition static (Jonathan)
- Add check for NULLcxl_proto_err_kfifoto determine if CXL driver is not registered for workqueue. (Dan)
PCI/AER: Dequeue forwarded CXL error
- Reword patch commit message to remove RCiEP details (Jonathan)
- Add #include <linux/bitfield.h> (Terry)
-is_cxl_rcd()- Fix short comment message wrap (Jonathan)
-is_cxl_rcd()- Combine return calls into 1 (Jonathan)
-cxl_handle_proto_error()- Move comment earlier (Jonathan)
- UsseFIELD_GET()in discovering class code (Jonathan)
- Remove BDF fromcxl_proto_err_work_data. Use 'structpci_dev*' (Dan) CXL/PCI: Introduce CXL Port protocol error handlers
- Removed check forPCI_EXP_TYPE_RC_ENDincxl_report_error_detected()(Terry)
- Updateis_cxl_error()to check for acceptable PCI EP and port types CXL/PCI: Export and renamemerge_result()topci_ers_merge_result()
-pci_ers_merge_result()- Change export to non-namespace and rename to bepci_ers_merge_result()(Jonathan)
- Movepci_ers_merge_result()definition topci.h. Needspci_ers_result(Terry) CXL/PCI: Introduce CXL uncorrectable protocol error recovery
-pci_ers_merge_results()- Move to earlier patch
CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
- Removeguard()incxl_mask_proto_interrupts(). Observed device lockup/block during testing. (Terry)Changes in v9 -> v10:
- Adddrivers/pci/pcie/cxl_aer.c
- Adddrivers/cxl/core/native_ras.c
- Change cxl_register_prot_err_work()/cxl_unregister_prot_err_work to return void
- Check forpcie_ports_nativeincxl_do_recovery()
- Remove debug logging incxl_do_recovery()
- UpdatePCI_ERS_RESULT_PANICdefinition to indicate is CXL specific
- Revert trace logging changes: name,parent -> memdev,host.
- UseFIELD_GET()to check for EP class code (cxl_aer.c&native_ras.c).
- Change _prot_ to _proto_ everywhere
-cxl_rch_handle_error_iter(), check if driver iscxl_pci_driver
- Removecxl_create_prot_error_info(). Move logic intoforward_cxl_error()
- Removesbdf_to_pci()and move logic intocxl_handle_proto_error()
- Simplify/refactorget_pci_cxl_host_dev()
- Simplify/refactorcxl_get_ras_base()
- Move patch 'Remove unnecessary CXL Endpoint handling helper functions' to front
- Update description for 'CXL/PCI: Introduce CXL Port protocol error handlers' with why state is not used to determine handling
- Introducecxl_pci_drv_bound()and call fromcxl_rch_handle_error_iter()Changes in v8 -> v9:
- Updated reference counting to use pci_get_device()/pci_put_device() in cxl_disable_prot_errors()/cxl_enable_prot_errors
- Refactoredcxl_create_prot_err_info()to fix reference counting
- Removed 'structcxl_port' driver changes for error handler. Instead check for CXL device type (EP or Port device) and call handler
- Makepcie_is_cxl()static inline ininclude/linux/linux.h
- Remove NULL check increate_prot_err_info()
- Change success return incxl_ras_init()to use hardcoded 0
- Changed 'structwork_structcxl_prot_err_work' declaration to static
- Change to use rate limited log with dev anchor inforward_cxl_error()
- Refactored forward-cxl_error() to remove severity auto variable
- Changedpci_aer_clear_nonfatal_status()to be static inline for !(CONFIG_PCIEAER)
- Renamedmerge_result()to becxl_merge_result()
- Removed 'ue' condition incxl_error_detected()
- Updated 2nd parameter in call to __cxl_handle_cor_ras()/__cxl_handle_ras() in unify patch
- Added log message for failure while assigning interrupt disable callback
- Updatedpci_aer_mask_internal_errors()to usepci_clear_and_set_config_dword()
- Simplified patch titles for clarity
- Moved CXL error interrupt disabling intocxl/core/port.cwith CXL Port teardown
- Updated 'structcxl_port_err_info' to only contain sbdf and severity Removed everything else.
- Added pdev and CXL device get_device()/put_device() before calling handlersChanges in v7 -> v8:
[Dan] Use kfifo. Move handling to CXL driver. AER forwards error to CXL driver
[Dan] Add device reference incrementors where needed throughout [Dan] Initiate CXL Port RAS init from Switch Port and Endpoint Port init [Dan] Combine CXL Port and CXL Endpoint trace routine
[Dan] Introduceaer_info::is_cxl. Use to indicate CXL or PCI errors [Jonathan] Add serial number for all devices in trace [DaveJ] Movefind_cxl_port()change into patch using it [Terry] Move CXL Port RAS init intocxl/port.c
[Terry] Moved kfifo functions intocxl/core/ras.cChanges in v6 -> v7:
[Terry] Move updated trace routine call to later patch. Was causing build error.Changes in v5 -> v6:
[Ira] Movepcie_is_cxl(dev)define to a inline function
[Ira] Update returning value frompcie_is_cxl_port()to bool w/o cast
[Ira] Changecxl_report_error_detected()cleanup to return correct bool
[Ira] Introduce and usePCI_ERS_RESULT_PANIC
[Ira] Reuse comment for PCIe and CXL recovery paths
[Jonathan] Add type check in forcxl_handle_cor_ras()andcxl_handle_ras()[Jonathan] cxl_uport/dport_init_ras_reporting(), added a mutex.
[Jonathan] Add logging example to patches updating trace output
[Jonathan] Make parameter 'const' to eliminate for cast inmatch_uport()[Jonathan] Use__free()incxl_pci_port_ras()
[Terry] Add patch to log the PCIe SBDF along with CXL device name
[Terry] Add patch to handle CXL endpoint and RCH DP errors as CXL errors [Terry] Remove patch w USP UCE fatal support @aer_get_device_error_info()[Terry] Rebase to cxl/next commit5585e342e8d3("cxl/memdev: Remove unused partition values") [Gregory] Pre-initialize pointer to NULL incxl_pci_port_ras()
[Gregory] Move AER driver bus name detection to a static functionChanges in v4 -> v5:
[Alejandro] Refactorcxl_walk_bridgeto simplify 'status' variable usage [Alejandro] AddWARN_ONCE()in__cxl_handle_ras()andcxl_handle_cor_ras()[Ming] Remove unnecessary NULL check incxl_pci_port_ras()[Terry] Add failure check for call toto_cxl_port()incxl_pci_port_ras()[Ming] Useport->devfor call todevm_add_action_or_reset()incxl_dport_init_ras_reporting()andcxl_uport_init_ras_reporting()[Jonathan] Use get_device()/put_device() to prevent race condition incxl_clear_port_error_handlers()andcxl_clear_port_error_handlers()[Terry] Commit message cleanup. Capitalize keywords from CXL and PCI specificationsChanges in v3 -> v4:
[Lukas] Capitalize PCIe and CXL device names as in specifications [Lukas] Move call topcie_is_cxl()intocxl_port_devsec()
[Lukas] Correct namespace spelling
[Lukas] Removed export frompcie_is_cxl_port()
[Lukas] Simplify 'if' blocks incxl_handle_error()
[Lukas] Change panic message to remove redundant 'panic' text
[Ming] Update to callcxl_dport_init_ras_reporting()in RCH case [lkp@intel] 'host' parameter is already removed. Remove parameter description too. [Terry] Added field description forcxl_err_handlersinpci.hcomment blockChanges in v1 -> v2:
[Jonathan] Remove extra NULL check and cleanup incxl_pci_port_ras()[Jonathan] Update description to DSP map patch description
[Jonathan] Updatecxl_pci_port_ras()to check for NULL port [Jonathan] Dont call handler before handler port changes are present (patch order) [Bjorn] Fix linebreak in cover sheet URL
[Bjorn] Remove timestamps from test logs in cover sheet
[Bjorn] Retitle AER commits to use "PCI/AER:"
[Bjorn] Retitle patch#3 to use renaming instead of refactoring [Bjorn] Fix base commit-id on cover sheet
[Bjorn] Add VH spec reference/citation
[Terry] Removed last 2 patches to enable internal errors. Is not needed because internal errors are enabled in AER driver.
[Dan] Createcxl_do_recovery()andpci_driver::cxl_err_handlers. [Dan] Use kernel panic in CXL recovery
[Dan]cxl_port_hndlrs->cxl_port_error_handlersDan Williams (4):
cxl: Tighten CPER kfifo registration API and symbol visibility
cxl: Renamefind_cxl_port()tofind_cxl_port_by_dport()cxl/pci: Thread port and dport through RAS handling helpers
cxl: Add port and dport identifiers to CXL AER trace eventsTerry Bowman (9):
cxl/ras: Fixcxl_rch_get_aer_severity()wrong severity register acpi/apei/ghes: Useraw_spinlock_tfor CXL CPER work locks PCI/AER: Introduce AER-CXL protocol error kfifo
PCI: Establish common CXL Port protocol error flow PCI/CXL: Add RCH support to CXL handlers
cxl: Update CXL Endpoint AER handler
PCI: Cache PCI DSN intopci_dev->dsnduring probe PCI/CXL: Mask/Unmask CXL protocol errors
Documentation: cxl: Document CXL protocol error handlingDocumentation/driver-api/cxl/index.rst | 1 + .../cxl/linux/protocol-error-handling.rst | 222 ++++++++++ MAINTAINERS | 2 + drivers/acpi/apei/ghes.c | 66 +-- drivers/cxl/core/core.h | 36 +- drivers/cxl/core/port.c | 28 +- drivers/cxl/core/ras.c | 395 ++++++++++++------ drivers/cxl/core/ras_rch.c | 20 +- drivers/cxl/core/trace.c | 35 ++ drivers/cxl/core/trace.h | 91 ++-- drivers/cxl/cxlmem.h | 7 + drivers/cxl/cxlpci.h | 11 +- drivers/cxl/pci.c | 16 +- drivers/pci/pci.h | 1 - drivers/pci/pcie/Makefile | 1 + drivers/pci/pcie/aer.c | 45 +- drivers/pci/pcie/aer_cxl_rch.c | 39 +- drivers/pci/pcie/aer_cxl_vh.c | 235 +++++++++++ drivers/pci/pcie/portdrv.h | 10 +- drivers/pci/probe.c | 14 + include/cxl/event.h | 17 +- include/linux/aer.h | 26 ++ include/linux/pci.h | 1 + tools/testing/cxl/Kbuild | 1 + tools/testing/cxl/test/mock.c | 12 + 25 files changed, 1013 insertions(+), 319 deletions(-) create mode 100644 Documentation/driver-api/cxl/linux/protocol-error-handling.rst create mode 100644 drivers/pci/pcie/aer_cxl_vh.cbase-commit:
a13c140cc289c0b7b3770bce5b3ad42ab35074aaSignature · 1 line
2.34.1