linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging
@ 2025-06-03 17:22 Terry Bowman
  2025-06-03 17:22 ` [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl() Terry Bowman
                   ` (15 more replies)
  0 siblings, 16 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

This patchset enhances the CXL Protocol Error handling for both CXL Ports
and CXL Endpoints (EP). Originally focused on CXL Ports, the scope of this
patchset has now expanded to incorporate EPs as well.

This patchset is a continuation of v8 and can be found here:
https://lore.kernel.org/linux-cxl/20250327014717.2988633-1-terry.bowman@amd.com/

The first 2 patches introduce pci_dev::is_cxl, aer_info::is_cxl, and add
bus string to AER log tracing. aer_info::is_cxl will be used to indicate a
CXL or PCI error and will be used to direct the error handling flow in
later patches.

The next 4 patches move, where possible, the existing CXL handling from
the AER driver to the cxl_port driver. This includes introducing the kfifo
for the AER driver to offload CXL protocol error work to the CXL driver.

The next 5 patches prepare the CXL driver for adding the updated protocol
error handlers. This includes adding CXL Port RAS mapping and updating
interfaces for common support. 

The final 5 patches add the CXL error handlers for CXL EPs and CXL Ports.
CXL EPs keep the PCIe error handler for cases the EP error is interpreted
as a PCIe error. These patches also add logic to unmask CXL Protocol Errors
during port probing, and mask CXL Protocol Errors during port device
cleanup.

== Testing ==

Testing below shows the Upstream Switch Port UCE handling is broken. It
executes the native PCIe portdrv handler instead of the CXL handler. This
is because aer_get_device_error_info() does not populate the AER error
severity and status. This is intended because the USP link to access the
device can be compromised. The check for is_cxl_error() and is_internal_error()
fail as a result and then processes the error as a PCI error. I need
feedback how to handle this case.

I rebased to pci/next with Bjorn's 'Rate limit AER logs' series from here:
https://lore.kernel.org/linux-pci/20250522232339.1525671-1-helgaas@kernel.org/#r
I ran into manual merges for the AER print trace routines but nothing difficult.
I confirmed the error handling series functionality was intact after the rebase.
Note, test results below are without rate limiting series.

The sub-topology for Qemu testing is:
                    ---------------------
                    | CXL RP - 0C:00.0  |
                    ---------------------
                              |
                    ---------------------
                    | CXL USP - 0D:00.0 |
                    ---------------------
                              |
                    ---------------------
                    | CXL DSP - 0E:00.0 |
                    ---------------------
                              |
                    ---------------------
                    | CXL EP - 0F:00.0  |
                    ---------------------

 root@tbowman-cxl:~# lspci -t
 -+-[0000:00]-+-00.0
  |           +-01.0
  |           +-02.0
  |           +-03.0
  |           +-1f.0
  |           +-1f.2
  |           \-1f.3
  \-[0000:0c]---00.0-[0d-0f]----00.0-[0e-0f]----00.0-[0f]----00.0

 The topology was created with:
  ${qemu} -boot menu=on \
             -cpu host \
             -nographic \
             -monitor telnet:127.0.0.1:1234,server,nowait \
             -M virt,cxl=on \
             -chardev stdio,id=s1,signal=off,mux=on -serial none \
             -device isa-serial,chardev=s1 -mon chardev=s1,mode=readline \
             -machine q35,cxl=on \
             -m 16G,maxmem=24G,slots=8 \
             -cpu EPYC-v3 \
             -smp 16 \
             -accel kvm \
             -drive file=${img},format=raw,index=0,media=disk \
             -device e1000,netdev=user.0 \
             -netdev user,id=user.0,hostfwd=tcp::5555-:22 \
             -object memory-backend-file,id=cxl-mem0,share=on,mem-path=/tmp/cxltest.raw,size=256M \
             -object memory-backend-file,id=cxl-lsa0,share=on,mem-path=/tmp/lsa0.raw,size=256M \
             -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
             -device cxl-rp,port=0,bus=cxl.1,id=root_port0,chassis=0,slot=0 \
             -device cxl-upstream,bus=root_port0,id=us0 \
             -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
             -device cxl-type3,bus=swport0,volatile-memdev=cxl-mem0,lsa=cxl-lsa0,id=cxl-vmem0 \
             -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k

== CXL Root Port ==
root@tbowman-cxl:~/aer-inject# ./root-ce-inject.sh
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] CorrIntErr            
aer_event: 0000:0c:00.0 CXL Bus Error: severity=Corrected, Corrected Internal Error, TLP Header=Not available
cxl_aer_correctable_error: device=0000:0c:00.0 parent=pci0000:0c serial=0 status='CRC Threshold Hit'

root@tbowman-cxl:~/aer-inject/# ./root-uce-inject.sh
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] UncorrIntErr          
aer_event: 0000:0c:00.0 CXL Bus Error: severity=Fatal, Uncorrectable Internal Error, TLP Header=Not available
cxl_aer_uncorrectable_error: device=0000:0c:00.0 parent=pci0000:0c serial=0 status='Cache Byte Enable Parity Error' first_error='Cache Byte Enable Par'
Kernel panic - not syncing: CXL cachemem error.
CPU: 10 UID: 0 PID: 168 Comm: kworker/10:1 Tainted: G            E       6.15.0-rc4-00065-ga77879da099a-dirty #424 PREEMPT(voluntary) 
Tainted: [E]=UNSIGNED_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
Workqueue: events cxl_prot_err_work_fn [cxl_core]
Call Trace:
 <TASK>
 dump_stack_lvl+0x27/0x90
 dump_stack+0x10/0x20
 panic+0x33d/0x380
 ? preempt_count_add+0x4b/0xc0
 cxl_do_recovery+0xc7/0xd0 [cxl_core]
 cxl_prot_err_work_fn+0x11a/0x1a0 [cxl_core]
 process_scheduled_works+0xa6/0x420
 worker_thread+0x126/0x270
 kthread+0x118/0x230
 ? __pfx_worker_thread+0x10/0x10
 ? _raw_spin_unlock_irq+0x1f/0x40
 ? __pfx_kthread+0x10/0x10
 ret_from_fork+0x3c/0x60
 ? __pfx_kthread+0x10/0x10
 ret_from_fork_asm+0x1a/0x30
 </TASK>
Kernel Offset: 0x18600000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
---[ end Kernel panic - not syncing: CXL cachemem error. ]---

== CXL Upstream Switch Port ==
root@tbowman-cxl:~/aer-inject# ./us-ce-inject.sh
[   26.309121] pcieport 0000:0c:00.0: aer_inject: Injecting errors 00004000/00000000 into device 0000:0d:00.0
[   26.310096] pcieport 0000:0c:00.0: AER: Correctable error message received from 0000:0d:00.0
[   26.310970] pcieport 0000:0d:00.0: CXL Bus Error: severity=Correctable, type=Transaction Layer, (Receiver ID)
[   26.311861] pcieport 0000:0d:00.0:   device [19e5:a128] error status/mask=00004000/0000a000
[   26.312610] pcieport 0000:0d:00.0:    [14] CorrIntErr            
[   26.313312] aer_event: 0000:0d:00.0 CXL Bus Error: severity=Corrected, Corrected Internal Error, TLP Header=Not available
[   26.314520] cxl_aer_correctable_error: device=0000:0d:00.0 parent=0000:0c:00.0 serial=0 status='CRC Threshold Hit'

root@tbowman-cxl:~/aer-inject# ./us-uce-inject.sh                          
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)
aer_event: 0000:0d:00.0 CXL Bus Error: severity=Fatal, , TLP Header=Not available
pcieport 0000:0c:00.0: unlocked secondary bus reset via: pciehp_reset_slot+0xac/0x160
------------[ cut here ]------------
WARNING: CPU: 10 PID: 146 at drivers/pci/access.c:340 pci_cfg_access_unlock+0x54/0x60
Modules linked in: cfg80211(E) binfmt_misc(E) ppdev(E) cxl_pmem(E) intel_rapl_msr(E) parport_pc(E) cxl_mem(E) intel_rapl_common(E) cxl_acpi(E) cxl_pci)
CPU: 10 UID: 0 PID: 146 Comm: irq/24-aerdrv Tainted: G            E       6.15.0-rc4-00065-ga77879da099a-dirty #425 PREEMPT(voluntary) 
Tainted: [E]=UNSIGNED_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
RIP: 0010:pci_cfg_access_unlock+0x54/0x60
Code: 00 fe 48 c7 c7 08 5b 00 b1 e8 88 04 74 00 31 c9 31 d2 be 03 00 00 00 48 c7 c7 b0 8d 84 b0 e8 93 64 8e ff 5b 5d e9 2c 1c 74 00 <0f> 0b eb cd 0f 10
RSP: 0018:ffffa2ccc06efc30 EFLAGS: 00010046
RAX: 0000000000000246 RBX: ffff973dc1c4c000 RCX: 0000000000000000
RDX: 0000000000000001 RSI: 0000000000000246 RDI: ffffffffaf669c39
RBP: ffffa2ccc06efc38 R08: 0000000000000000 R09: ffffffffb084a200
R10: 0000000000000000 R11: 0000000000000001 R12: ffff973dc3550c80
R13: 0000000000000000 R14: 0000000000000000 R15: ffff973dc1c40828
FS:  0000000000000000(0000) GS:ffff97417eeae000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00005642c5514140 CR3: 00000001192a6000 CR4: 00000000003506f0
Call Trace:
 <TASK>
 pci_slot_unlock+0x43/0x70
 pci_slot_reset+0x105/0x160
 pci_bus_error_reset+0xb0/0xe0
 aer_root_reset+0x8e/0x210
 ? srso_return_thunk+0x5/0x5f
 pcie_do_recovery+0x17f/0x2b0
 ? __pfx_aer_root_reset+0x10/0x10
 aer_isr_one_error.isra.0+0x587/0x5a0
 ? srso_return_thunk+0x5/0x5f
 ? _raw_spin_unlock+0x19/0x40
 ? srso_return_thunk+0x5/0x5f
 ? finish_task_switch+0x95/0x290
 ? srso_return_thunk+0x5/0x5f
 ? __schedule+0x5d0/0x11a0
 aer_isr+0x4c/0x80
 irq_thread_fn+0x28/0x70
 irq_thread+0x183/0x270
 ? __pfx_irq_thread_fn+0x10/0x10
 ? __pfx_irq_thread_dtor+0x10/0x10
 kthread+0x118/0x230
 ? __pfx_irq_thread+0x10/0x10
 ? _raw_spin_unlock_irq+0x1f/0x40
 ? __pfx_kthread+0x10/0x10
 ret_from_fork+0x3c/0x60
 ? __pfx_kthread+0x10/0x10
 ret_from_fork_asm+0x1a/0x30
 </TASK>
---[ end trace 0000000000000000 ]---
pcieport 0000:0c:00.0: AER: Root Port link has been reset (0)
cxl_pci 0000:0f:00.0: mem1: restart CXL.mem after slot reset
cxl_pci 0000:10:00.0: mem0: restart CXL.mem after slot reset
cxl_pci 0000:11:00.0: mem2: restart CXL.mem after slot reset
cxl_pci 0000:12:00.0: mem3: restart CXL.mem after slot reset
cxl_pci 0000:0f:00.0: mem1: error resume successful
cxl_pci 0000:10:00.0: mem0: error resume successful
cxl_pci 0000:11:00.0: mem2: error resume successful
cxl_pci 0000:12:00.0: mem3: error resume successful
pcieport 0000:0c:00.0: AER: device recovery successful

== CXL Downstream Swicth Port == 
root@tbowman-cxl:~/aer-inject# ./ds-ce-inject.sh
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] CorrIntErr            
aer_event: 0000:0e:00.0 CXL Bus Error: severity=Corrected, Corrected Internal Error, TLP Header=Not available
cxl_aer_correctable_error: device=0000:0e:00.0 parent=0000:0d:00.0 serial=0 status='CRC Threshold Hit'

root@tbowman-cxl:~/aer-inject# ./ds-uce-inject.sh
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] UncorrIntErr          
aer_event: 0000:0e:00.0 CXL Bus Error: severity=Fatal, Uncorrectable Internal Error, TLP Header=Not available
cxl_aer_uncorrectable_error: device=0000:0e:00.0 parent=0000:0d:00.0 serial=0 status='Cache Byte Enable Parity Error' first_error='Cache Byte Enable P'
cxl_aer_uncorrectable_error: device=mem1 parent=0000:0f:00.0 serial=0 status='Cache Byte Enable Parity Error' first_error='Cache Byte Enable Parity Er'
Kernel panic - not syncing: CXL cachemem error.
CPU: 10 UID: 0 PID: 158 Comm: kworker/10:1 Tainted: G            E       6.15.0-rc4-00065-ga77879da099a-dirty #427 PREEMPT(voluntary) 
Tainted: [E]=UNSIGNED_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
Workqueue: events cxl_prot_err_work_fn [cxl_core]
Call Trace:
 <TASK>
 dump_stack_lvl+0x27/0x90
 dump_stack+0x10/0x20
 panic+0x33d/0x380
 ? preempt_count_add+0x4b/0xc0
 cxl_do_recovery+0xc7/0xd0 [cxl_core]
 cxl_prot_err_work_fn+0x11a/0x1a0 [cxl_core]
 process_scheduled_works+0xa6/0x420
 worker_thread+0x126/0x270
 kthread+0x118/0x230
 ? __pfx_worker_thread+0x10/0x10
 ? _raw_spin_unlock_irq+0x1f/0x40
 ? __pfx_kthread+0x10/0x10
 ret_from_fork+0x3c/0x60
 ? __pfx_kthread+0x10/0x10
 ret_from_fork_asm+0x1a/0x30
 </TASK>
Kernel Offset: 0x2800000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
---[ end Kernel panic - not syncing: CXL cachemem error. ]---

== CXL Endpoint ==
root@tbowman-cxl:~/aer-inject# ./ep-ce-inject.sh
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.0
cxl_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/00000000
cxl_pci 0000:0f:00.0:    [14] CorrIntErr            
aer_event: 0000:0f:00.0 CXL Bus Error: severity=Corrected, Corrected Internal Error, TLP Header=Not available
cxl_aer_correctable_error: device=mem2 parent=0000:0f:00.0 serial=0 status='CRC Threshold Hit'

root@tbowman-cxl:~/aer-inject# ./ep-uce-inject.sh
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.0
cxl_pci 0000:0f:00.0: AER: CXL Bus Error: severity=Uncorrectable (Fatal), type=Inaccessible, (Unregistered Agent ID)
aer_event: 0000:0f:00.0 CXL Bus Error: severity=Fatal, , TLP Header=Not available
cxl_aer_uncorrectable_error: device=mem2 parent=0000:0f:00.0 serial=0 status='Cache Byte Enable Parity Error' first_error='Cache Byte Enable Parity Er'
-3i7n3j0e]c tK# ernel panic - not syncing: CXL cachemem error.
CPU: 10 UID: 0 PID: 146 Comm: irq/24-aerdrv Tainted: G            E       6.15.0-rc4-00065-ga77879da099a-dirty #427 PREEMPT(voluntary) 
Tainted: [E]=UNSIGNED_MODULE
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0x27/0x90
 dump_stack+0x10/0x20
 panic+0x33d/0x380
 pci_error_detected+0x30/0x30 [cxl_core]
 report_error_detected+0x113/0x180
 ? __pm_runtime_resume+0x60/0x90
 ? __pfx_report_frozen_detected+0x10/0x10
 report_frozen_detected+0x16/0x20
 __pci_walk_bus+0x50/0x70
 ? __pfx_report_frozen_detected+0x10/0x10
 pci_walk_bus+0x32/0x50
 pci_walk_bridge+0x1d/0x40
 pcie_do_recovery+0x173/0x2b0
 ? __pfx_aer_root_reset+0x10/0x10
 aer_isr_one_error.isra.0+0x587/0x5a0
 ? srso_return_thunk+0x5/0x5f
 ? _raw_spin_unlock+0x19/0x40
 ? srso_return_thunk+0x5/0x5f
 ? finish_task_switch+0x95/0x290
 ? srso_return_thunk+0x5/0x5f
 ? __schedule+0x5d0/0x11a0
 aer_isr+0x4c/0x80
 irq_thread_fn+0x28/0x70
 irq_thread+0x183/0x270
 ? __pfx_irq_thread_fn+0x10/0x10
 ? __pfx_irq_thread_dtor+0x10/0x10
 kthread+0x118/0x230
 ? __pfx_irq_thread+0x10/0x10
 ? _raw_spin_unlock_irq+0x1f/0x40
 ? __pfx_kthread+0x10/0x10
 ret_from_fork+0x3c/0x60
 ? __pfx_kthread+0x10/0x10
 ret_from_fork_asm+0x1a/0x30
 </TASK>
Kernel Offset: 0x11a00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
---[ end Kernel panic - not syncing: CXL cachemem error. ]---

Changes
=======
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

Terry Bowman (16):
  PCI/CXL: Add pcie_is_cxl()
  PCI/AER: Report CXL or PCIe bus error type in trace logging
  CXL/AER: Introduce kfifo for forwarding CXL errors
  PCI/AER: Dequeue forwarded CXL error
  CXL/PCI: Introduce CXL uncorrectable protocol error recovery
  cxl/pci: Move RAS initialization to cxl_port driver
  cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
  cxl/pci: Update RAS handler interfaces to also support CXL Ports
  cxl/pci: Log message if RAS registers are unmapped
  cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
  cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS
    errors
  cxl/pci: Introduce CXL Endpoint protocol error handlers
  cxl/pci: Introduce CXL Port protocol error handlers
  cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
  CXL/PCI: Enable CXL protocol errors during CXL Port probe
  CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup

 drivers/cxl/core/core.h       |   2 +
 drivers/cxl/core/pci.c        | 238 +++++++++++++---------------
 drivers/cxl/core/port.c       |  10 +-
 drivers/cxl/core/ras.c        | 290 +++++++++++++++++++++++++++++++++-
 drivers/cxl/core/regs.c       |   2 +
 drivers/cxl/core/trace.h      |  84 +++-------
 drivers/cxl/cxl.h             |  25 +++
 drivers/cxl/cxlpci.h          |   7 +-
 drivers/cxl/mem.c             |   3 +-
 drivers/cxl/pci.c             |   8 +-
 drivers/cxl/port.c            | 156 ++++++++++++++++++
 drivers/pci/pci.c             |   1 +
 drivers/pci/pci.h             |  14 +-
 drivers/pci/pcie/aer.c        | 172 ++++++++++++++------
 drivers/pci/pcie/rcec.c       |   1 +
 drivers/pci/probe.c           |  10 ++
 include/linux/aer.h           |  40 +++++
 include/linux/pci.h           |  19 +++
 include/ras/ras_event.h       |   9 +-
 include/uapi/linux/pci_regs.h |   8 +-
 20 files changed, 831 insertions(+), 268 deletions(-)


base-commit: 6eed708a5693709ff0d4dd8512b6934be30d4283
-- 
2.34.1


^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl()
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-04 19:06   ` Sathyanarayanan Kuppuswamy
  2025-06-05 23:24   ` Dave Jiang
  2025-06-03 17:22 ` [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging Terry Bowman
                   ` (14 subsequent siblings)
  15 siblings, 2 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

CXL and AER drivers need the ability to identify CXL devices.

Add set_pcie_cxl() with logic checking for CXL Flexbus DVSEC presence. The
CXL Flexbus DVSEC presence is used because it is required for all the CXL
PCIe devices.[1]

Add boolean 'struct pci_dev::is_cxl' with the purpose to cache the CXL
Flexbus presence.

Add function pcie_is_cxl() to return 'struct pci_dev::is_cxl'.

[1] CXL 3.1 Spec, 8.1.1 PCIe Designated Vendor-Specific Extended
    Capability (DVSEC) ID Assignment, Table 8-2

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
---
 drivers/pci/probe.c           | 10 ++++++++++
 include/linux/pci.h           |  6 ++++++
 include/uapi/linux/pci_regs.h |  8 +++++++-
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 364fa2a514f8..aa29b4b98ad1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1691,6 +1691,14 @@ static void set_pcie_thunderbolt(struct pci_dev *dev)
 		dev->is_thunderbolt = 1;
 }
 
+static void set_pcie_cxl(struct pci_dev *dev)
+{
+	u16 dvsec = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
+					      PCI_DVSEC_CXL_FLEXBUS);
+	if (dvsec)
+		dev->is_cxl = 1;
+}
+
 static void set_pcie_untrusted(struct pci_dev *dev)
 {
 	struct pci_dev *parent = pci_upstream_bridge(dev);
@@ -2021,6 +2029,8 @@ int pci_setup_device(struct pci_dev *dev)
 	/* Need to have dev->cfg_size ready */
 	set_pcie_thunderbolt(dev);
 
+	set_pcie_cxl(dev);
+
 	set_pcie_untrusted(dev);
 
 	if (pci_is_pcie(dev))
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 51e2bd6405cd..bff3009f9ff0 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -455,6 +455,7 @@ struct pci_dev {
 	unsigned int	is_hotplug_bridge:1;
 	unsigned int	shpc_managed:1;		/* SHPC owned by shpchp */
 	unsigned int	is_thunderbolt:1;	/* Thunderbolt controller */
+	unsigned int	is_cxl:1;               /* Compute Express Link (CXL) */
 	/*
 	 * Devices marked being untrusted are the ones that can potentially
 	 * execute DMA attacks and similar. They are typically connected
@@ -746,6 +747,11 @@ static inline bool pci_is_vga(struct pci_dev *pdev)
 	return false;
 }
 
+static inline bool pcie_is_cxl(struct pci_dev *pci_dev)
+{
+	return pci_dev->is_cxl;
+}
+
 #define for_each_pci_bridge(dev, bus)				\
 	list_for_each_entry(dev, &bus->devices, bus_list)	\
 		if (!pci_is_bridge(dev)) {} else
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index ba326710f9c8..c50ffa75d5fc 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -1215,9 +1215,15 @@
 /* Deprecated old name, replaced with PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE */
 #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL		PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE
 
-/* Compute Express Link (CXL r3.1, sec 8.1.5) */
+/* Compute Express Link (CXL r3.2, sec 8.1)
+ *
+ * Note that CXL DVSEC id 3 and 7 to be ignored when the CXL link state
+ * is "disconnected" (CXL r3.2, sec 9.12.3). Re-enumerate these
+ * registers on downstream link-up events.
+ */
 #define PCI_DVSEC_CXL_PORT				3
 #define PCI_DVSEC_CXL_PORT_CTL				0x0c
 #define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR		0x00000001
+#define PCI_DVSEC_CXL_FLEXBUS				7
 
 #endif /* LINUX_PCI_REGS_H */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
  2025-06-03 17:22 ` [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl() Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-03 22:02   ` Sathyanarayanan Kuppuswamy
  2025-06-05 23:28   ` Dave Jiang
  2025-06-03 17:22 ` [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors Terry Bowman
                   ` (13 subsequent siblings)
  15 siblings, 2 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

The AER service driver and aer_event tracing currently log 'PCIe Bus Type'
for all errors. Update the driver and aer_event tracing to log 'CXL Bus
Type' for CXL device errors.

This requires the AER can identify and distinguish between PCIe errors and
CXL errors.

Introduce boolean 'is_cxl' to 'struct aer_err_info'. Add assignment in
aer_get_device_error_info() and pci_print_aer().

Update the aer_event trace routine to accept a bus type string parameter.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
---
 drivers/pci/pci.h       |  6 ++++++
 drivers/pci/pcie/aer.c  | 18 ++++++++++++------
 include/ras/ras_event.h |  9 ++++++---
 3 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index b81e99cd4b62..d6296500b004 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -588,6 +588,7 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
 struct aer_err_info {
 	struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
 	int error_dev_num;
+	bool is_cxl;
 
 	unsigned int id:16;
 
@@ -604,6 +605,11 @@ struct aer_err_info {
 	struct pcie_tlp_log tlp;	/* TLP Header */
 };
 
+static inline const char *aer_err_bus(struct aer_err_info *info)
+{
+	return info->is_cxl ? "CXL" : "PCIe";
+}
+
 int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
 void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
 
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index a1cf8c7ef628..adb4b1123b9b 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -698,13 +698,14 @@ static void __aer_print_error(struct pci_dev *dev,
 
 void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
 {
+	const char *bus_type = aer_err_bus(info);
 	int layer, agent;
 	int id = pci_dev_id(dev);
 	const char *level;
 
 	if (!info->status) {
-		pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
-			aer_error_severity_string[info->severity]);
+		pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
+			bus_type, aer_error_severity_string[info->severity]);
 		goto out;
 	}
 
@@ -713,8 +714,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
 
 	level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR;
 
-	aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
-		   aer_error_severity_string[info->severity],
+	aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
+		   bus_type, aer_error_severity_string[info->severity],
 		   aer_error_layer[layer], aer_agent_string[agent]);
 
 	aer_printk(level, dev, "  device [%04x:%04x] error status/mask=%08x/%08x\n",
@@ -729,7 +730,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
 	if (info->id && info->error_dev_num > 1 && info->id == id)
 		pci_err(dev, "  Error of this Agent is reported first\n");
 
-	trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
+	trace_aer_event(dev_name(&dev->dev), bus_type, (info->status & ~info->mask),
 			info->severity, info->tlp_header_valid, &info->tlp);
 }
 
@@ -763,6 +764,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
 void pci_print_aer(struct pci_dev *dev, int aer_severity,
 		   struct aer_capability_regs *aer)
 {
+	const char *bus_type;
 	int layer, agent, tlp_header_valid = 0;
 	u32 status, mask;
 	struct aer_err_info info;
@@ -784,6 +786,9 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
 	info.status = status;
 	info.mask = mask;
 	info.first_error = PCI_ERR_CAP_FEP(aer->cap_control);
+	info.is_cxl = pcie_is_cxl(dev);
+
+	bus_type = aer_err_bus(&info);
 
 	pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
 	__aer_print_error(dev, &info);
@@ -797,7 +802,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
 	if (tlp_header_valid)
 		pcie_print_tlp_log(dev, &aer->header_log, dev_fmt("  "));
 
-	trace_aer_event(dev_name(&dev->dev), (status & ~mask),
+	trace_aer_event(dev_name(&dev->dev), bus_type, (status & ~mask),
 			aer_severity, tlp_header_valid, &aer->header_log);
 }
 EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
@@ -1215,6 +1220,7 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
 	/* Must reset in this function */
 	info->status = 0;
 	info->tlp_header_valid = 0;
+	info->is_cxl = pcie_is_cxl(dev);
 
 	/* The device might not support AER */
 	if (!aer)
diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
index 14c9f943d53f..080829d59c36 100644
--- a/include/ras/ras_event.h
+++ b/include/ras/ras_event.h
@@ -297,15 +297,17 @@ TRACE_EVENT(non_standard_event,
 
 TRACE_EVENT(aer_event,
 	TP_PROTO(const char *dev_name,
+		 const char *bus_type,
 		 const u32 status,
 		 const u8 severity,
 		 const u8 tlp_header_valid,
 		 struct pcie_tlp_log *tlp),
 
-	TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
+	TP_ARGS(dev_name, bus_type, status, severity, tlp_header_valid, tlp),
 
 	TP_STRUCT__entry(
 		__string(	dev_name,	dev_name	)
+		__string(	bus_type,	bus_type	)
 		__field(	u32,		status		)
 		__field(	u8,		severity	)
 		__field(	u8, 		tlp_header_valid)
@@ -314,6 +316,7 @@ TRACE_EVENT(aer_event,
 
 	TP_fast_assign(
 		__assign_str(dev_name);
+		__assign_str(bus_type);
 		__entry->status		= status;
 		__entry->severity	= severity;
 		__entry->tlp_header_valid = tlp_header_valid;
@@ -325,8 +328,8 @@ TRACE_EVENT(aer_event,
 		}
 	),
 
-	TP_printk("%s PCIe Bus Error: severity=%s, %s, TLP Header=%s\n",
-		__get_str(dev_name),
+	TP_printk("%s %s Bus Error: severity=%s, %s, TLP Header=%s\n",
+		__get_str(dev_name), __get_str(bus_type),
 		__entry->severity == AER_CORRECTABLE ? "Corrected" :
 			__entry->severity == AER_FATAL ?
 			"Fatal" : "Uncorrected, non-fatal",
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
  2025-06-03 17:22 ` [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl() Terry Bowman
  2025-06-03 17:22 ` [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-04  6:01   ` Dan Carpenter
                     ` (3 more replies)
  2025-06-03 17:22 ` [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error Terry Bowman
                   ` (12 subsequent siblings)
  15 siblings, 4 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

CXL error handling will soon be moved from the AER driver into the CXL
driver. This requires a notification mechanism for the AER driver to share
the AER interrupt with the CXL driver. The notification will be used
as an indication for the CXL drivers to handle and log the CXL RAS errors.

Add a kfifo work queue to be used by the AER driver and CXL driver. The AER
driver will be the sole kfifo producer adding work and the cxl_core will be
the sole kfifo consumer removing work. Add the boilerplate kfifo support.

Add CXL work queue handler registration functions in the AER driver. Export
the functions allowing CXL driver to access. Implement registration
functions for the CXL driver to assign or clear the work handler function.

Introduce function cxl_create_prot_err_info() and 'struct cxl_prot_err_info'.
Implement cxl_create_prot_err_info() to populate a 'struct cxl_prot_err_info'
instance with the AER severity and the erring device's PCI SBDF. The SBDF
details will be used to rediscover the erring device after the CXL driver
dequeues the kfifo work. The device rediscovery will be introduced along
with the CXL handling in future patches.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/ras.c |  31 +++++++++-
 drivers/cxl/cxlpci.h   |   1 +
 drivers/pci/pcie/aer.c | 132 ++++++++++++++++++++++++++++-------------
 include/linux/aer.h    |  36 +++++++++++
 4 files changed, 157 insertions(+), 43 deletions(-)

diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 485a831695c7..d35525e79e04 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -5,6 +5,7 @@
 #include <linux/aer.h>
 #include <cxl/event.h>
 #include <cxlmem.h>
+#include <cxlpci.h>
 #include "trace.h"
 
 static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
@@ -107,13 +108,41 @@ 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);
 
+#ifdef CONFIG_PCIEAER_CXL
+
+static void cxl_prot_err_work_fn(struct work_struct *work)
+{
+}
+
+#else
+static void cxl_prot_err_work_fn(struct work_struct *work) { }
+#endif /* CONFIG_PCIEAER_CXL */
+
+static struct work_struct cxl_prot_err_work;
+static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
+
 int cxl_ras_init(void)
 {
-	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
+	int rc;
+
+	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
+	if (rc)
+		pr_err("Failed to register CPER AER kfifo (%x)", rc);
+
+	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
+	if (rc) {
+		pr_err("Failed to register native AER kfifo (%x)", rc);
+		return rc;
+	}
+
+	return 0;
 }
 
 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_unregister_prot_err_work();
+	cancel_work_sync(&cxl_prot_err_work);
 }
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 54e219b0049e..6f1396ef7b77 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -4,6 +4,7 @@
 #define __CXL_PCI_H__
 #include <linux/pci.h>
 #include "cxl.h"
+#include "linux/aer.h"
 
 #define CXL_MEMORY_PROGIF	0x10
 
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index adb4b1123b9b..5350fa5be784 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -114,6 +114,14 @@ struct aer_stats {
 static int pcie_aer_disable;
 static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
 
+#if defined(CONFIG_PCIEAER_CXL)
+#define CXL_ERROR_SOURCES_MAX          128
+static DEFINE_KFIFO(cxl_prot_err_fifo, struct cxl_prot_err_work_data,
+		    CXL_ERROR_SOURCES_MAX);
+static DEFINE_SPINLOCK(cxl_prot_err_fifo_lock);
+struct work_struct *cxl_prot_err_work;
+#endif
+
 void pci_no_aer(void)
 {
 	pcie_aer_disable = 1;
@@ -1004,45 +1012,17 @@ static bool is_internal_error(struct aer_err_info *info)
 	return info->status & PCI_ERR_UNC_INTN;
 }
 
-static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
+static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
 {
-	struct aer_err_info *info = (struct aer_err_info *)data;
-	const struct pci_error_handlers *err_handler;
+	if (!info || !info->is_cxl)
+		return false;
 
-	if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
-		return 0;
+	/* Only CXL Endpoints are currently supported */
+	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
+	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))
+		return false;
 
-	/* Protect dev->driver */
-	device_lock(&dev->dev);
-
-	err_handler = dev->driver ? dev->driver->err_handler : NULL;
-	if (!err_handler)
-		goto out;
-
-	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);
-	}
-out:
-	device_unlock(&dev->dev);
-	return 0;
-}
-
-static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_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.
-	 */
-	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
-	    is_internal_error(info))
-		pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
+	return is_internal_error(info);
 }
 
 static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
@@ -1056,13 +1036,17 @@ static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
 	return *handles_cxl;
 }
 
-static bool handles_cxl_errors(struct pci_dev *rcec)
+static bool handles_cxl_errors(struct pci_dev *dev)
 {
 	bool handles_cxl = false;
 
-	if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
-	    pcie_aer_is_native(rcec))
-		pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
+	if (!pcie_aer_is_native(dev))
+		return false;
+
+	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
+		pcie_walk_rcec(dev, handles_cxl_error_iter, &handles_cxl);
+	else
+		handles_cxl = pcie_is_cxl(dev);
 
 	return handles_cxl;
 }
@@ -1076,10 +1060,46 @@ static void cxl_rch_enable_rcec(struct pci_dev *rcec)
 	pci_info(rcec, "CXL: Internal errors unmasked");
 }
 
+static int cxl_create_prot_error_info(struct pci_dev *pdev,
+				      struct aer_err_info *aer_err_info,
+				      struct cxl_prot_error_info *cxl_err_info)
+{
+	cxl_err_info->severity = aer_err_info->severity;
+
+	cxl_err_info->function = PCI_FUNC(pdev->devfn);
+	cxl_err_info->device = PCI_SLOT(pdev->devfn);
+	cxl_err_info->bus = pdev->bus->number;
+	cxl_err_info->segment = pci_domain_nr(pdev->bus);
+
+	return 0;
+}
+
+static void forward_cxl_error(struct pci_dev *pdev, struct aer_err_info *aer_err_info)
+{
+	struct cxl_prot_err_work_data wd;
+	struct cxl_prot_error_info *cxl_err_info = &wd.err_info;
+
+	cxl_create_prot_error_info(pdev, aer_err_info, cxl_err_info);
+
+	if (!kfifo_put(&cxl_prot_err_fifo, wd)) {
+		dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
+		return;
+	}
+
+	schedule_work(cxl_prot_err_work);
+}
+
 #else
 static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
 static inline void cxl_rch_handle_error(struct pci_dev *dev,
 					struct aer_err_info *info) { }
+static inline void forward_cxl_error(struct pci_dev *dev,
+				    struct aer_err_info *info) { }
+static inline bool handles_cxl_errors(struct pci_dev *dev)
+{
+	return false;
+}
+static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return 0; };
 #endif
 
 /**
@@ -1117,8 +1137,11 @@ 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)
 {
-	cxl_rch_handle_error(dev, info);
-	pci_aer_handle_error(dev, info);
+	if (is_cxl_error(dev, info))
+		forward_cxl_error(dev, info);
+	else
+		pci_aer_handle_error(dev, info);
+
 	pci_dev_put(dev);
 }
 
@@ -1582,6 +1605,31 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
 	return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
 }
 
+#if defined(CONFIG_PCIEAER_CXL)
+
+int cxl_register_prot_err_work(struct work_struct *work)
+{
+	guard(spinlock)(&cxl_prot_err_fifo_lock);
+	cxl_prot_err_work = work;
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_register_prot_err_work, "CXL");
+
+int cxl_unregister_prot_err_work(void)
+{
+	guard(spinlock)(&cxl_prot_err_fifo_lock);
+	cxl_prot_err_work = NULL;
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_unregister_prot_err_work, "CXL");
+
+int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd)
+{
+	return kfifo_get(&cxl_prot_err_fifo, wd);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_prot_err_kfifo_get, "CXL");
+#endif
+
 static struct pcie_port_service_driver aerdriver = {
 	.name		= "aer",
 	.port_type	= PCIE_ANY_PORT,
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 02940be66324..550407240ab5 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -10,6 +10,7 @@
 
 #include <linux/errno.h>
 #include <linux/types.h>
+#include <linux/workqueue_types.h>
 
 #define AER_NONFATAL			0
 #define AER_FATAL			1
@@ -53,6 +54,27 @@ struct aer_capability_regs {
 	u16 uncor_err_source;
 };
 
+/**
+ * struct cxl_prot_err_info - Error information used in CXL error handling
+ * @severity: AER severity
+ * @function: Device's PCI function
+ * @device: Device's PCI device
+ * @bus: Device's PCI bus
+ * @segment: Device's PCI segment
+ */
+struct cxl_prot_error_info {
+	int severity;
+
+	u8 function;
+	u8 device;
+	u8 bus;
+	u16 segment;
+};
+
+struct cxl_prot_err_work_data {
+	struct cxl_prot_error_info err_info;
+};
+
 #if defined(CONFIG_PCIEAER)
 int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
 int pcie_aer_is_native(struct pci_dev *dev);
@@ -64,6 +86,20 @@ 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; }
 #endif
 
+#if defined(CONFIG_PCIEAER_CXL)
+int cxl_register_prot_err_work(struct work_struct *work);
+int cxl_unregister_prot_err_work(void);
+int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd);
+#else
+static inline int
+cxl_register_prot_err_work(struct work_struct *work)
+{
+	return 0;
+}
+static inline int cxl_unregister_prot_err_work(void) { return 0; }
+static inline int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd) { return 0; }
+#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);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (2 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-04  6:05   ` Dan Carpenter
                     ` (4 more replies)
  2025-06-03 17:22 ` [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
                   ` (11 subsequent siblings)
  15 siblings, 5 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

The AER driver is now designed to forward CXL protocol errors to the CXL
driver. Update the CXL driver with functionality to dequeue the forwarded
CXL error from the kfifo. Also, update the CXL driver to begin the protocol
error handling processing using the work received from the FIFO.

Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
AER service driver. This will begin the CXL protocol error processing
with a call to cxl_handle_prot_error().

Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
previously in the AER driver.

Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
and use in discovering the erring PCI device. Make scope based reference
increments/decrements for the discovered PCI device and the associated
CXL device.

Implement cxl_handle_prot_error() to differentiate between Restricted CXL
Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
RCH errors will be processed with a call to walk the associated Root
Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
so the CXL driver can walk the RCEC's downstream bus, searching for
the RCiEP.

VH correctable error (CE) processing will call the CXL CE handler. VH
uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
and pci_clean_device_status() used to clean up AER status after handling.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
 drivers/pci/pci.c       |  1 +
 drivers/pci/pci.h       |  8 ----
 drivers/pci/pcie/aer.c  |  1 +
 drivers/pci/pcie/rcec.c |  1 +
 include/linux/aer.h     |  2 +
 include/linux/pci.h     | 10 +++++
 7 files changed, 107 insertions(+), 8 deletions(-)

diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index d35525e79e04..9ed5c682e128 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
 
 #ifdef CONFIG_PCIEAER_CXL
 
+static void cxl_do_recovery(struct pci_dev *pdev)
+{
+}
+
+static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
+{
+	struct cxl_prot_error_info *err_info = data;
+	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
+	struct cxl_dev_state *cxlds;
+
+	/*
+	 * The capability, status, and control fields in Device 0,
+	 * Function 0 DVSEC control the CXL functionality of the
+	 * entire device (CXL 3.0, 8.1.3).
+	 */
+	if (pdev->devfn != PCI_DEVFN(0, 0))
+		return 0;
+
+	/*
+	 * CXL Memory Devices must have the 502h class code set (CXL
+	 * 3.0, 8.1.12.1).
+	 */
+	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
+		return 0;
+
+	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
+		return 0;
+
+	cxlds = pci_get_drvdata(pdev);
+	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
+
+	if (err_info->severity == AER_CORRECTABLE)
+		cxl_cor_error_detected(pdev);
+	else
+		cxl_do_recovery(pdev);
+
+	return 1;
+}
+
+static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
+{
+	unsigned int devfn = PCI_DEVFN(err_info->device,
+				       err_info->function);
+	struct pci_dev *pdev __free(pci_dev_put) =
+		pci_get_domain_bus_and_slot(err_info->segment,
+					    err_info->bus,
+					    devfn);
+	return pdev;
+}
+
+static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
+{
+	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
+
+	if (!pdev) {
+		pr_err("Failed to find the CXL device\n");
+		return;
+	}
+
+	/*
+	 * 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.
+	 */
+	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
+		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
+
+	if (err_info->severity == AER_CORRECTABLE) {
+		int aer = pdev->aer_cap;
+		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
+
+		if (aer)
+			pci_clear_and_set_config_dword(pdev,
+						       aer + PCI_ERR_COR_STATUS,
+						       0, PCI_ERR_COR_INTERNAL);
+
+		cxl_cor_error_detected(pdev);
+
+		pcie_clear_device_status(pdev);
+	} else {
+		cxl_do_recovery(pdev);
+	}
+}
+
 static void cxl_prot_err_work_fn(struct work_struct *work)
 {
+	struct cxl_prot_err_work_data wd;
+
+	while (cxl_prot_err_kfifo_get(&wd)) {
+		struct cxl_prot_error_info *err_info = &wd.err_info;
+
+		cxl_handle_prot_error(err_info);
+	}
 }
 
 #else
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e77d5b53c0ce..524ac32b744a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
 	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
 	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
 }
+EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
 #endif
 
 /**
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index d6296500b004..3c54a5ed803e 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
 void pci_rcec_init(struct pci_dev *dev);
 void pci_rcec_exit(struct pci_dev *dev);
 void pcie_link_rcec(struct pci_dev *rcec);
-void pcie_walk_rcec(struct pci_dev *rcec,
-		    int (*cb)(struct pci_dev *, void *),
-		    void *userdata);
 #else
 static inline void pci_rcec_init(struct pci_dev *dev) { }
 static inline void pci_rcec_exit(struct pci_dev *dev) { }
 static inline void pcie_link_rcec(struct pci_dev *rcec) { }
-static inline void pcie_walk_rcec(struct pci_dev *rcec,
-				  int (*cb)(struct pci_dev *, void *),
-				  void *userdata) { }
 #endif
 
 #ifdef CONFIG_PCI_ATS
@@ -967,7 +961,6 @@ void pci_no_aer(void);
 void pci_aer_init(struct pci_dev *dev);
 void pci_aer_exit(struct pci_dev *dev);
 extern const struct attribute_group aer_stats_attr_group;
-void pci_aer_clear_fatal_status(struct pci_dev *dev);
 int pci_aer_clear_status(struct pci_dev *dev);
 int pci_aer_raw_clear_status(struct pci_dev *dev);
 void pci_save_aer_state(struct pci_dev *dev);
@@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
 static inline void pci_no_aer(void) { }
 static inline void pci_aer_init(struct pci_dev *d) { }
 static inline void pci_aer_exit(struct pci_dev *d) { }
-static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
 static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
 static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
 static inline void pci_save_aer_state(struct pci_dev *dev) { }
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 5350fa5be784..6e88331c6303 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
 	if (status)
 		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
 }
+EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
 
 /**
  * pci_aer_raw_clear_status - Clear AER error registers.
diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
index d0bcd141ac9c..fb6cf6449a1d 100644
--- a/drivers/pci/pcie/rcec.c
+++ b/drivers/pci/pcie/rcec.c
@@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
 
 	walk_rcec(walk_rcec_helper, &rcec_data);
 }
+EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
 
 void pci_rcec_init(struct pci_dev *dev)
 {
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 550407240ab5..c9a18eca16f8 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
 
 #if defined(CONFIG_PCIEAER)
 int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
+void pci_aer_clear_fatal_status(struct pci_dev *dev);
 int pcie_aer_is_native(struct pci_dev *dev);
 #else
 static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
 {
 	return -EINVAL;
 }
+static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
 static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
 #endif
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index bff3009f9ff0..cd53715d53f3 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
 
 int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
 			  bool use_lt);
+void pcie_walk_rcec(struct pci_dev *rcec,
+		    int (*cb)(struct pci_dev *, void *),
+		    void *userdata);
 #else
 #define pcie_ports_disabled	true
 #define pcie_ports_native	false
@@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
 {
 	return -EOPNOTSUPP;
 }
+
+static inline void pcie_walk_rcec(struct pci_dev *rcec,
+				  int (*cb)(struct pci_dev *, void *),
+				  void *userdata) { }
+
 #endif
 
+void pcie_clear_device_status(struct pci_dev *dev);
+
 #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
 #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
 #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (3 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-05 15:14   ` Sathyanarayanan Kuppuswamy
                     ` (2 more replies)
  2025-06-03 17:22 ` [PATCH v9 06/16] cxl/pci: Move RAS initialization to cxl_port driver Terry Bowman
                   ` (10 subsequent siblings)
  15 siblings, 3 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

Create cxl_do_recovery() to provide uncorrectable protocol error (UCE)
handling. Follow similar design as found in PCIe error driver,
pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
as fatal with a kernel panic. This is to prevent corruption on CXL memory.

Copy the PCI error driver's merge_result() and rename as cxl_merge_result().
Introduce PCI_ERS_RESULT_PANIC and add support in the cxl_merge_result()
routine.

Copy pci_walk_bridge() to cxl_walk_bridge(). Make a change to walk the
first device in all cases.

Copy the PCI error driver's report_error_detected() to cxl_report_error_detected().
Note, only CXL Endpoints are currently supported. Add locking for PCI
device as done in PCI's report_error_detected(). Add reference counting for
the CXL device responsible for cleanup of the CXL RAS. This is necessary
to prevent the RAS registers from disappearing before logging is completed.

Call panic() to halt the system in the case of uncorrectable errors (UCE)
in cxl_do_recovery(). Export pci_aer_clear_fatal_status() for CXL to use
if a UCE is not found. In this case the AER status must be cleared and
uses pci_aer_clear_fatal_status().

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/ras.c | 79 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci.h    |  3 ++
 2 files changed, 82 insertions(+)

diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 9ed5c682e128..715f7221ea3a 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -110,8 +110,87 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
 
 #ifdef CONFIG_PCIEAER_CXL
 
+static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
+					 enum pci_ers_result new)
+{
+	if (new == PCI_ERS_RESULT_PANIC)
+		return PCI_ERS_RESULT_PANIC;
+
+	if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
+		return PCI_ERS_RESULT_NO_AER_DRIVER;
+
+	if (new == PCI_ERS_RESULT_NONE)
+		return orig;
+
+	switch (orig) {
+	case PCI_ERS_RESULT_CAN_RECOVER:
+	case PCI_ERS_RESULT_RECOVERED:
+		orig = new;
+		break;
+	case PCI_ERS_RESULT_DISCONNECT:
+		if (new == PCI_ERS_RESULT_NEED_RESET)
+			orig = PCI_ERS_RESULT_NEED_RESET;
+		break;
+	default:
+		break;
+	}
+
+	return orig;
+}
+
+static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
+{
+	pci_ers_result_t vote, *result = data;
+	struct cxl_dev_state *cxlds;
+
+	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
+	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
+		return 0;
+
+	cxlds = pci_get_drvdata(pdev);
+	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
+
+	device_lock(&pdev->dev);
+	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
+	*result = cxl_merge_result(*result, vote);
+	device_unlock(&pdev->dev);
+
+	return 0;
+}
+
+static void cxl_walk_bridge(struct pci_dev *bridge,
+			    int (*cb)(struct pci_dev *, void *),
+			    void *userdata)
+{
+	if (cb(bridge, userdata))
+		return;
+
+	if (bridge->subordinate)
+		pci_walk_bus(bridge->subordinate, cb, userdata);
+}
+
 static void cxl_do_recovery(struct pci_dev *pdev)
 {
+	struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
+	pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
+
+	cxl_walk_bridge(pdev, cxl_report_error_detected, &status);
+	if (status == PCI_ERS_RESULT_PANIC)
+		panic("CXL cachemem error.");
+
+	/*
+	 * If we have native control of AER, clear error status in the device
+	 * that detected the error.  If the platform retained control of AER,
+	 * it is responsible for clearing this status.  In that case, the
+	 * signaling device may not even be visible to the OS.
+	 */
+	if (host->native_aer) {
+		pcie_clear_device_status(pdev);
+		pci_aer_clear_nonfatal_status(pdev);
+		pci_aer_clear_fatal_status(pdev);
+	}
+
+	pci_info(pdev, "CXL uncorrectable error.\n");
 }
 
 static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index cd53715d53f3..b0e7545162de 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -870,6 +870,9 @@ enum pci_ers_result {
 
 	/* No AER capabilities registered for the driver */
 	PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
+
+	/* System is unstable, panic  */
+	PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,
 };
 
 /* PCI bus error event callbacks */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 06/16] cxl/pci: Move RAS initialization to cxl_port driver
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (4 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-06 17:04   ` Dave Jiang
  2025-06-03 17:22 ` [PATCH v9 07/16] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers Terry Bowman
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

The cxl_port driver is intended to manage CXL Endpoint Ports and CXL Switch
Ports. Move existing RAS initialization to the cxl_port driver.

Restricted CXL Host (RCH) Downstream Port RAS initialization currently
resides in cxl/core/pci.c. The PCI source file is not otherwise associated
with CXL Port management.

Additional CXL Port RAS initialization will be added in future patches to
support a CXL Port device's CXL errors.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/pci.c  | 73 --------------------------------------
 drivers/cxl/core/regs.c |  2 ++
 drivers/cxl/cxl.h       |  6 ++++
 drivers/cxl/port.c      | 78 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 86 insertions(+), 73 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index b50551601c2e..317cd0a91ffe 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -748,79 +748,6 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
 
 #ifdef CONFIG_PCIEAER_CXL
 
-static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
-{
-	resource_size_t aer_phys;
-	struct device *host;
-	u16 aer_cap;
-
-	aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
-	if (aer_cap) {
-		host = dport->reg_map.host;
-		aer_phys = aer_cap + dport->rcrb.base;
-		dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
-						sizeof(struct aer_capability_regs));
-	}
-}
-
-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)
-		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)))
-		dev_dbg(dev, "Failed to map RAS capability.\n");
-}
-
-static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
-{
-	void __iomem *aer_base = dport->regs.dport_aer;
-	u32 aer_cmd_mask, aer_cmd;
-
-	if (!aer_base)
-		return;
-
-	/*
-	 * Disable RCH root port command interrupts.
-	 * CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
-	 *
-	 * This sequence may not be necessary. CXL spec states disabling
-	 * the root cmd register's interrupts is required. But, PCI spec
-	 * shows these are disabled by default on reset.
-	 */
-	aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
-			PCI_ERR_ROOT_CMD_NONFATAL_EN |
-			PCI_ERR_ROOT_CMD_FATAL_EN);
-	aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
-	aer_cmd &= ~aer_cmd_mask;
-	writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
-}
-
-/**
- * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
- * @dport: the cxl_dport that needs to be initialized
- * @host: host device for devm operations
- */
-void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
-{
-	dport->reg_map.host = host;
-	cxl_dport_map_ras(dport);
-
-	if (dport->rch) {
-		struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
-
-		if (!host_bridge->native_aer)
-			return;
-
-		cxl_dport_map_rch_aer(dport);
-		cxl_disable_rch_root_ints(dport);
-	}
-}
-EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
-
 static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
 					  struct cxl_dport *dport)
 {
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 5ca7b0eed568..b8e767a9571c 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -199,6 +199,7 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
 
 	return ret_val;
 }
+EXPORT_SYMBOL_NS_GPL(devm_cxl_iomap_block, "CXL");
 
 int cxl_map_component_regs(const struct cxl_register_map *map,
 			   struct cxl_component_regs *regs,
@@ -517,6 +518,7 @@ u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb)
 
 	return offset;
 }
+EXPORT_SYMBOL_NS_GPL(cxl_rcrb_to_aer, "CXL");
 
 static resource_size_t cxl_rcrb_to_linkcap(struct device *dev, struct cxl_dport *dport)
 {
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index ba08b77b65da..0dc43bfba76a 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -313,6 +313,12 @@ int cxl_setup_regs(struct cxl_register_map *map);
 struct cxl_dport;
 resource_size_t cxl_rcd_component_reg_phys(struct device *dev,
 					   struct cxl_dport *dport);
+
+u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb);
+
+void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
+				   resource_size_t length);
+
 int cxl_dport_map_rcd_linkcap(struct pci_dev *pdev, struct cxl_dport *dport);
 
 #define CXL_RESOURCE_NONE ((resource_size_t) -1)
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index fe4b593331da..7b61f09347a5 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -6,6 +6,7 @@
 
 #include "cxlmem.h"
 #include "cxlpci.h"
+#include "cxl.h"
 
 /**
  * DOC: cxl port
@@ -57,6 +58,83 @@ static int discover_region(struct device *dev, void *unused)
 	return 0;
 }
 
+#ifdef CONFIG_PCIEAER_CXL
+
+static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
+{
+	resource_size_t aer_phys;
+	struct device *host;
+	u16 aer_cap;
+
+	aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
+	if (aer_cap) {
+		host = dport->reg_map.host;
+		aer_phys = aer_cap + dport->rcrb.base;
+		dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
+						sizeof(struct aer_capability_regs));
+	}
+}
+
+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)
+		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)))
+		dev_dbg(dev, "Failed to map RAS capability.\n");
+}
+
+static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
+{
+	void __iomem *aer_base = dport->regs.dport_aer;
+	u32 aer_cmd_mask, aer_cmd;
+
+	if (!aer_base)
+		return;
+
+	/*
+	 * Disable RCH root port command interrupts.
+	 * CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
+	 *
+	 * This sequence may not be necessary. CXL spec states disabling
+	 * the root cmd register's interrupts is required. But, PCI spec
+	 * shows these are disabled by default on reset.
+	 */
+	aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
+			PCI_ERR_ROOT_CMD_NONFATAL_EN |
+			PCI_ERR_ROOT_CMD_FATAL_EN);
+	aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
+	aer_cmd &= ~aer_cmd_mask;
+	writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
+}
+
+/**
+ * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
+ * @dport: the cxl_dport that needs to be initialized
+ * @host: host device for devm operations
+ */
+void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
+{
+	dport->reg_map.host = host;
+	cxl_dport_map_ras(dport);
+
+	if (dport->rch) {
+		struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
+
+		if (!host_bridge->native_aer)
+			return;
+
+		cxl_dport_map_rch_aer(dport);
+		cxl_disable_rch_root_ints(dport);
+	}
+}
+EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
+
+#endif /* CONFIG_PCIEAER_CXL */
+
 static int cxl_switch_port_probe(struct cxl_port *port)
 {
 	struct cxl_hdm *cxlhdm;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 07/16] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (5 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 06/16] cxl/pci: Move RAS initialization to cxl_port driver Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-03 17:22 ` [PATCH v9 08/16] cxl/pci: Update RAS handler interfaces to also support CXL Ports Terry Bowman
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

CXL Endpoint (EP) Ports may include Root Ports (RP) or Downstream Switch
Ports (DSP). CXL RPs and DSPs contain RAS registers that require memory
mapping to enable RAS logging. This initialization is currently missing and
must be added for CXL RPs and DSPs.

Update cxl_dport_init_ras_reporting() to support RP and DSP RAS mapping.
Add alongside the existing Restricted CXL Host Downstream Port RAS mapping.

Update cxl_endpoint_port_probe() to invoke cxl_dport_init_ras_reporting().
This will initiate the RAS mapping for CXL RPs and DSPs when each CXL EP is
created and added to the EP port.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/cxl.h  |  2 ++
 drivers/cxl/mem.c  |  3 ++-
 drivers/cxl/port.c | 55 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 0dc43bfba76a..73be66ef36a2 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -590,6 +590,7 @@ struct cxl_dax_region {
  * @parent_dport: dport that points to this port in the parent
  * @decoder_ida: allocator for decoder ids
  * @reg_map: component and ras register mapping parameters
+ * @uport_regs: mapped component registers
  * @nr_dports: number of entries in @dports
  * @hdm_end: track last allocated HDM decoder instance for allocation ordering
  * @commit_end: cursor to track highest committed decoder for commit ordering
@@ -610,6 +611,7 @@ struct cxl_port {
 	struct cxl_dport *parent_dport;
 	struct ida decoder_ida;
 	struct cxl_register_map reg_map;
+	struct cxl_component_regs uport_regs;
 	int nr_dports;
 	int hdm_end;
 	int commit_end;
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index 9675243bd05b..29dc4a624b15 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -166,7 +166,8 @@ static int cxl_mem_probe(struct device *dev)
 	else
 		endpoint_parent = &parent_port->dev;
 
-	cxl_dport_init_ras_reporting(dport, dev);
+	if (dport->rch)
+		cxl_dport_init_ras_reporting(dport, dev);
 
 	scoped_guard(device, endpoint_parent) {
 		if (!endpoint_parent->driver) {
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 7b61f09347a5..0f7c4010ba58 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -111,6 +111,17 @@ static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
 	writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
 }
 
+static void cxl_uport_init_ras_reporting(struct cxl_port *port,
+					 struct device *host)
+{
+	struct cxl_register_map *map = &port->reg_map;
+
+	map->host = host;
+	if (cxl_map_component_regs(map, &port->uport_regs,
+				   BIT(CXL_CM_CAP_CAP_ID_RAS)))
+		dev_dbg(&port->dev, "Failed to map RAS capability\n");
+}
+
 /**
  * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
  * @dport: the cxl_dport that needs to be initialized
@@ -119,7 +130,6 @@ static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
 void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
 {
 	dport->reg_map.host = host;
-	cxl_dport_map_ras(dport);
 
 	if (dport->rch) {
 		struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
@@ -127,12 +137,51 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
 		if (!host_bridge->native_aer)
 			return;
 
+		cxl_dport_map_ras(dport);
 		cxl_dport_map_rch_aer(dport);
 		cxl_disable_rch_root_ints(dport);
+		return;
 	}
+
+	if (cxl_map_component_regs(&dport->reg_map, &dport->regs.component,
+				   BIT(CXL_CM_CAP_CAP_ID_RAS)))
+		dev_dbg(dport->dport_dev, "Failed to map RAS capability\n");
+
 }
 EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
 
+static void cxl_switch_port_init_ras(struct cxl_port *port)
+{
+	struct device *dev __free(put_device) = get_device(&port->dev);
+
+	if (is_cxl_root(to_cxl_port(port->dev.parent)))
+		return;
+
+	/* Check for parent DSP */
+	if (port->parent_dport)
+		cxl_dport_init_ras_reporting(port->parent_dport, dev);
+
+	cxl_uport_init_ras_reporting(port, dev);
+}
+
+static void cxl_endpoint_port_init_ras(struct cxl_port *port)
+{
+	struct cxl_dport *dport;
+	struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+	struct cxl_port *parent_port __free(put_cxl_port) =
+		cxl_mem_find_port(cxlmd, &dport);
+
+	if (!dport || !dev_is_pci(dport->dport_dev)) {
+		dev_err(&port->dev, "CXL port topology not found\n");
+		return;
+	}
+
+	cxl_dport_init_ras_reporting(dport, &cxlmd->dev);
+}
+
+#else
+static void cxl_endpoint_port_init_ras(struct cxl_port *port) { }
+static void cxl_switch_port_init_ras(struct cxl_port *port) { }
 #endif /* CONFIG_PCIEAER_CXL */
 
 static int cxl_switch_port_probe(struct cxl_port *port)
@@ -149,6 +198,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
 
 	cxl_switch_parse_cdat(port);
 
+	cxl_switch_port_init_ras(port);
+
 	cxlhdm = devm_cxl_setup_hdm(port, NULL);
 	if (!IS_ERR(cxlhdm))
 		return devm_cxl_enumerate_decoders(cxlhdm, NULL);
@@ -203,6 +254,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 	if (rc)
 		return rc;
 
+	cxl_endpoint_port_init_ras(port);
+
 	/*
 	 * Now that all endpoint decoders are successfully enumerated, try to
 	 * assemble regions from committed decoders
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 08/16] cxl/pci: Update RAS handler interfaces to also support CXL Ports
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (6 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 07/16] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-05 16:42   ` Sathyanarayanan Kuppuswamy
  2025-06-03 17:22 ` [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped Terry Bowman
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

CXL PCIe Port Protocol Error handling support will be added to the
CXL drivers in the future. In preparation, rename the existing
interfaces to support handling all CXL PCIe Port Protocol Errors.

The driver's RAS support functions currently rely on a 'struct
cxl_dev_state' type parameter, which is not available for CXL Port
devices. However, since the same CXL RAS capability structure is
needed across most CXL components and devices, a common handling
approach should be adopted.

To accommodate this, update the __cxl_handle_cor_ras() and
__cxl_handle_ras() functions to use a `struct device` instead of
`struct cxl_dev_state`.

No functional changes are introduced.

[1] CXL 3.1 Spec, 8.2.4 CXL.cache and CXL.mem Registers

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Gregory Price <gourry@gourry.net>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/cxl/core/pci.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 317cd0a91ffe..78735da7e63d 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -664,7 +664,7 @@ void read_cdat_data(struct cxl_port *port)
 }
 EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
 
-static void __cxl_handle_cor_ras(struct cxl_dev_state *cxlds,
+static void __cxl_handle_cor_ras(struct device *dev,
 				 void __iomem *ras_base)
 {
 	void __iomem *addr;
@@ -677,13 +677,13 @@ static void __cxl_handle_cor_ras(struct cxl_dev_state *cxlds,
 	status = readl(addr);
 	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
 		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
-		trace_cxl_aer_correctable_error(cxlds->cxlmd, status);
+		trace_cxl_aer_correctable_error(to_cxl_memdev(dev), status);
 	}
 }
 
 static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
 {
-	return __cxl_handle_cor_ras(cxlds, cxlds->regs.ras);
+	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
 }
 
 /* CXL spec rev3.0 8.2.4.16.1 */
@@ -707,8 +707,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.
  */
-static bool __cxl_handle_ras(struct cxl_dev_state *cxlds,
-				  void __iomem *ras_base)
+static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
 {
 	u32 hl[CXL_HEADERLOG_SIZE_U32];
 	void __iomem *addr;
@@ -735,7 +734,7 @@ static bool __cxl_handle_ras(struct cxl_dev_state *cxlds,
 	}
 
 	header_log_copy(ras_base, hl);
-	trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe, hl);
+	trace_cxl_aer_uncorrectable_error(to_cxl_memdev(dev), status, fe, hl);
 	writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
 
 	return true;
@@ -743,7 +742,7 @@ static bool __cxl_handle_ras(struct cxl_dev_state *cxlds,
 
 static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
 {
-	return __cxl_handle_ras(cxlds, cxlds->regs.ras);
+	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
 }
 
 #ifdef CONFIG_PCIEAER_CXL
@@ -751,13 +750,13 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
 static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
 					  struct cxl_dport *dport)
 {
-	return __cxl_handle_cor_ras(cxlds, dport->regs.ras);
+	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, dport->regs.ras);
 }
 
 static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
 				       struct cxl_dport *dport)
 {
-	return __cxl_handle_ras(cxlds, dport->regs.ras);
+	return __cxl_handle_ras(&cxlds->cxlmd->dev, dport->regs.ras);
 }
 
 /*
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (7 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 08/16] cxl/pci: Update RAS handler interfaces to also support CXL Ports Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-05 16:42   ` Sathyanarayanan Kuppuswamy
  2025-06-06 17:27   ` Dave Jiang
  2025-06-03 17:22 ` [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports Terry Bowman
                   ` (6 subsequent siblings)
  15 siblings, 2 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

The CXL RAS handlers do not currently log if the RAS registers are
unmapped. This is needed in order to help debug CXL error handling. Update
the CXL driver to log a warning message if the RAS register block is
unmapped during RAS error handling.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/cxl/core/pci.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 78735da7e63d..186a5a20b951 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -670,8 +670,10 @@ static void __cxl_handle_cor_ras(struct device *dev,
 	void __iomem *addr;
 	u32 status;
 
-	if (!ras_base)
+	if (!ras_base) {
+		dev_warn_once(dev, "CXL RAS register block is not mapped");
 		return;
+	}
 
 	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
 	status = readl(addr);
@@ -714,8 +716,10 @@ static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
 	u32 status;
 	u32 fe;
 
-	if (!ras_base)
+	if (!ras_base) {
+		dev_warn_once(dev, "CXL RAS register block is not mapped");
 		return false;
+	}
 
 	addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
 	status = readl(addr);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (8 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-05 16:49   ` Sathyanarayanan Kuppuswamy
  2025-06-06  9:08   ` Shiju Jose
  2025-06-03 17:22 ` [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
                   ` (5 subsequent siblings)
  15 siblings, 2 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

CXL currently has separate trace routines for CXL Port errors and CXL
Endpoint errors. This is inconvenient for the user because they must enable
2 sets of trace routines. Make updates to the trace logging such that a
single trace routine logs both CXL Endpoint and CXL Port protocol errors.

Rename the 'host' field from the CXL Endpoint trace to 'parent' in the
unified trace routines. 'host' does not correctly apply to CXL Port
devices. Parent is more general and applies to CXL Port devices and CXL
Endpoints.

Add serial number parameter to the trace logging. This is used for EPs
and 0 is provided for CXL port devices without a serial number.

Below is output of correctable and uncorrectable protocol error logging.
CXL Root Port and CXL Endpoint examples are included below.

Root Port:
cxl_aer_correctable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0 status='CRC Threshold Hit'
cxl_aer_uncorrectable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0 status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity Error'

Endpoint:
cxl_aer_correctable_error: device=mem3 parent=0000:0f:00.0 serial=0 status='CRC Threshold Hit'
cxl_aer_uncorrectable_error: device=mem3 parent=0000:0f:00.0 serial: 0 status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity Error'

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/pci.c   | 18 +++++----
 drivers/cxl/core/ras.c   | 14 ++++---
 drivers/cxl/core/trace.h | 84 +++++++++-------------------------------
 3 files changed, 37 insertions(+), 79 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 186a5a20b951..0f4c07fd64a5 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -664,7 +664,7 @@ void read_cdat_data(struct cxl_port *port)
 }
 EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
 
-static void __cxl_handle_cor_ras(struct device *dev,
+static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
 				 void __iomem *ras_base)
 {
 	void __iomem *addr;
@@ -679,13 +679,13 @@ static void __cxl_handle_cor_ras(struct device *dev,
 	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);
+		trace_cxl_aer_correctable_error(dev, serial, status);
 	}
 }
 
 static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
 {
-	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
+	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
 }
 
 /* CXL spec rev3.0 8.2.4.16.1 */
@@ -709,7 +709,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.
  */
-static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
+static bool __cxl_handle_ras(struct device *dev, u64 serial,
+			     void __iomem *ras_base)
 {
 	u32 hl[CXL_HEADERLOG_SIZE_U32];
 	void __iomem *addr;
@@ -738,7 +739,7 @@ static 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);
+	trace_cxl_aer_uncorrectable_error(dev, serial, status, fe, hl);
 	writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
 
 	return true;
@@ -746,7 +747,8 @@ static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
 
 static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
 {
-	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
+
+	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
 }
 
 #ifdef CONFIG_PCIEAER_CXL
@@ -754,13 +756,13 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
 static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
 					  struct cxl_dport *dport)
 {
-	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, dport->regs.ras);
+	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
 }
 
 static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
 				       struct cxl_dport *dport)
 {
-	return __cxl_handle_ras(&cxlds->cxlmd->dev, dport->regs.ras);
+	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
 }
 
 /*
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 715f7221ea3a..0ef8c2068c0c 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -13,7 +13,7 @@ static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
 {
 	u32 status = ras_cap.cor_status & ~ras_cap.cor_mask;
 
-	trace_cxl_port_aer_correctable_error(&pdev->dev, status);
+	trace_cxl_aer_correctable_error(&pdev->dev, 0, status);
 }
 
 static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
@@ -28,8 +28,8 @@ static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
 	else
 		fe = status;
 
-	trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe,
-					       ras_cap.header_log);
+	trace_cxl_aer_uncorrectable_error(&pdev->dev, 0, status, fe,
+					  ras_cap.header_log);
 }
 
 static void cxl_cper_trace_corr_prot_err(struct pci_dev *pdev,
@@ -42,7 +42,8 @@ static void cxl_cper_trace_corr_prot_err(struct pci_dev *pdev,
 	if (!cxlds)
 		return;
 
-	trace_cxl_aer_correctable_error(cxlds->cxlmd, status);
+	trace_cxl_aer_correctable_error(&cxlds->cxlmd->dev, cxlds->serial,
+					status);
 }
 
 static void cxl_cper_trace_uncorr_prot_err(struct pci_dev *pdev,
@@ -62,8 +63,9 @@ static void cxl_cper_trace_uncorr_prot_err(struct pci_dev *pdev,
 	else
 		fe = status;
 
-	trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe,
-					  ras_cap.header_log);
+	trace_cxl_aer_uncorrectable_error(&cxlds->cxlmd->dev,
+					  cxlds->serial, status,
+					  fe, ras_cap.header_log);
 }
 
 static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
index 25ebfbc1616c..8c91b0f3d165 100644
--- a/drivers/cxl/core/trace.h
+++ b/drivers/cxl/core/trace.h
@@ -48,49 +48,22 @@
 	{ 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_SIZE_U32)
-	),
-	TP_fast_assign(
-		__assign_str(device);
-		__assign_str(host);
-		__entry->status = status;
-		__entry->first_error = fe;
-		/*
-		 * Embed the 512B headerlog data for user app retrieval and
-		 * parsing, but no need to print this in the trace buffer.
-		 */
-		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
-	),
-	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 device *dev, u64 serial, u32 status, u32 fe,
+		 u32 *hl),
+	TP_ARGS(dev, serial, status, fe, hl),
 	TP_STRUCT__entry(
-		__string(memdev, dev_name(&cxlmd->dev))
-		__string(host, dev_name(cxlmd->dev.parent))
+		__string(name, dev_name(dev))
+		__string(parent, dev_name(dev->parent))
 		__field(u64, serial)
 		__field(u32, status)
 		__field(u32, first_error)
 		__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
 	),
 	TP_fast_assign(
-		__assign_str(memdev);
-		__assign_str(host);
-		__entry->serial = cxlmd->cxlds->serial;
+		__assign_str(name);
+		__assign_str(parent);
+		__entry->serial = serial;
 		__entry->status = status;
 		__entry->first_error = fe;
 		/*
@@ -99,8 +72,8 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
 		 */
 		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
 	),
-	TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'",
-		  __get_str(memdev), __get_str(host), __entry->serial,
+	TP_printk("device=%s parent=%s serial=%lld status='%s' first_error='%s'",
+		  __get_str(name), __get_str(parent), __entry->serial,
 		  show_uc_errs(__entry->status),
 		  show_uc_errs(__entry->first_error)
 	)
@@ -124,42 +97,23 @@ 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 device *dev, u64 serial, u32 status),
+	TP_ARGS(dev, serial, status),
 	TP_STRUCT__entry(
-		__string(memdev, dev_name(&cxlmd->dev))
-		__string(host, dev_name(cxlmd->dev.parent))
+		__string(name, dev_name(dev))
+		__string(parent, dev_name(dev->parent))
 		__field(u64, serial)
 		__field(u32, status)
 	),
 	TP_fast_assign(
-		__assign_str(memdev);
-		__assign_str(host);
-		__entry->serial = cxlmd->cxlds->serial;
+		__assign_str(name);
+		__assign_str(parent);
+		__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("device=%s parent=%s serial=%lld status='%s'",
+		  __get_str(name), __get_str(parent), __entry->serial,
 		  show_ce_errs(__entry->status)
 	)
 );
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (9 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-05 18:37   ` Sathyanarayanan Kuppuswamy
                     ` (2 more replies)
  2025-06-03 17:22 ` [PATCH v9 12/16] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
                   ` (4 subsequent siblings)
  15 siblings, 3 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

__cxl_handle_cor_ras() is missing logic to leave the function early in the
case there is no RAS error. Update __cxl_handle_cor_ras() to exit early in
the case there is no RAS errors detected after applying the mask.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/pci.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 0f4c07fd64a5..f5f87c2c3fd5 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -677,10 +677,11 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
 
 	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
 	status = readl(addr);
-	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
-		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
-		trace_cxl_aer_correctable_error(dev, serial, status);
-	}
+	if (!(status & CXL_RAS_CORRECTABLE_STATUS_MASK))
+		return;
+	writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
+
+	trace_cxl_aer_correctable_error(dev, serial, status);
 }
 
 static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 12/16] cxl/pci: Introduce CXL Endpoint protocol error handlers
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (10 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-06  0:22   ` Sathyanarayanan Kuppuswamy
  2025-06-12 16:55   ` Jonathan Cameron
  2025-06-03 17:22 ` [PATCH v9 13/16] cxl/pci: Introduce CXL Port " Terry Bowman
                   ` (3 subsequent siblings)
  15 siblings, 2 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

CXL Endpoint protocol errors are currently handled using PCI error
handlers. The CXL Endpoint requires CXL specific handling in the case of
uncorrectable error handling not provided by the PCI handlers.

Add CXL specific handlers for CXL Endpoints. Rename the existing
cxl_error_handlers to be pci_error_handlers to more correctly indicate
the error type and follow naming consistency.

Keep the existing PCI Endpoint handlers. PCI handlers can be called if the
CXL device is not trained for alternate protocol (CXL). Update the CXL
Endpoint PCI handlers to call the CXL handler. If the CXL uncorrectable
handler returns PCI_ERS_RESULT_PANIC then the PCI handler invokes panic().

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/pci.c | 80 ++++++++++++++++++++++--------------------
 drivers/cxl/core/ras.c | 10 +++---
 drivers/cxl/cxl.h      |  4 +++
 drivers/cxl/cxlpci.h   |  6 ++--
 drivers/cxl/pci.c      |  8 ++---
 5 files changed, 58 insertions(+), 50 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index f5f87c2c3fd5..e094ef518e0a 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -710,8 +710,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.
  */
-static bool __cxl_handle_ras(struct device *dev, u64 serial,
-			     void __iomem *ras_base)
+static pci_ers_result_t __cxl_handle_ras(struct device *dev, u64 serial,
+					 void __iomem *ras_base)
 {
 	u32 hl[CXL_HEADERLOG_SIZE_U32];
 	void __iomem *addr;
@@ -720,13 +720,13 @@ static bool __cxl_handle_ras(struct device *dev, u64 serial,
 
 	if (!ras_base) {
 		dev_warn_once(dev, "CXL RAS register block is not mapped");
-		return false;
+		return PCI_ERS_RESULT_NONE;
 	}
 
 	addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
 	status = readl(addr);
 	if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
-		return false;
+		return PCI_ERS_RESULT_NONE;
 
 	/* If multiple errors, log header points to first error from ctrl reg */
 	if (hweight32(status) > 1) {
@@ -743,12 +743,11 @@ static bool __cxl_handle_ras(struct device *dev, u64 serial,
 	trace_cxl_aer_uncorrectable_error(dev, serial, status, fe, hl);
 	writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
 
-	return true;
+	return PCI_ERS_RESULT_PANIC;
 }
 
 static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
 {
-
 	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
 }
 
@@ -844,14 +843,15 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
 static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
 #endif
 
-void cxl_cor_error_detected(struct pci_dev *pdev)
+void cxl_cor_error_detected(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
 	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
-	struct device *dev = &cxlds->cxlmd->dev;
+	struct device *cxlmd_dev = &cxlds->cxlmd->dev;
 
-	scoped_guard(device, dev) {
-		if (!dev->driver) {
-			dev_warn(&pdev->dev,
+	scoped_guard(device, cxlmd_dev) {
+		if (!cxlmd_dev->driver) {
+			dev_warn(dev,
 				 "%s: memdev disabled, abort error handling\n",
 				 dev_name(dev));
 			return;
@@ -865,20 +865,28 @@ void cxl_cor_error_detected(struct pci_dev *pdev)
 }
 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)
+void pci_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 = &cxlmd->dev;
-	bool ue;
+	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
 
-	scoped_guard(device, dev) {
+	cxl_cor_error_detected(&pdev->dev);
+}
+EXPORT_SYMBOL_NS_GPL(pci_cor_error_detected, "CXL");
+
+pci_ers_result_t cxl_error_detected(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+	struct device *cxlmd_dev = &cxlds->cxlmd->dev;
+	pci_ers_result_t ue;
+
+	scoped_guard(device, cxlmd_dev) {
 		if (!dev->driver) {
 			dev_warn(&pdev->dev,
 				 "%s: memdev disabled, abort error handling\n",
 				 dev_name(dev));
-			return PCI_ERS_RESULT_DISCONNECT;
+			return PCI_ERS_RESULT_PANIC;
 		}
 
 		if (cxlds->rcd)
@@ -892,29 +900,25 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
 		ue = cxl_handle_endpoint_ras(cxlds);
 	}
 
-
-	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);
-		return PCI_ERS_RESULT_NEED_RESET;
-	case pci_channel_io_perm_failure:
-		dev_warn(&pdev->dev,
-			 "failure state error detected, request disconnect\n");
-		return PCI_ERS_RESULT_DISCONNECT;
-	}
-	return PCI_ERS_RESULT_NEED_RESET;
+	return ue;
 }
 EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
 
+pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
+				    pci_channel_state_t error)
+{
+	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+	struct device *cxlmd_dev __free(put_device) = &cxlds->cxlmd->dev;
+	pci_ers_result_t rc;
+
+	rc = cxl_error_detected(&pdev->dev);
+	if (rc == PCI_ERS_RESULT_PANIC)
+		panic("CXL cachemem error.");
+
+	return rc;
+}
+EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
+
 static int cxl_flit_size(struct pci_dev *pdev)
 {
 	if (cxl_pci_flit_256(pdev))
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 0ef8c2068c0c..664f532cc838 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -153,7 +153,7 @@ static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
 	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
 
 	device_lock(&pdev->dev);
-	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
+	vote = cxl_error_detected(&pdev->dev);
 	*result = cxl_merge_result(*result, vote);
 	device_unlock(&pdev->dev);
 
@@ -223,7 +223,7 @@ static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
 	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
 
 	if (err_info->severity == AER_CORRECTABLE)
-		cxl_cor_error_detected(pdev);
+		cxl_cor_error_detected(dev);
 	else
 		cxl_do_recovery(pdev);
 
@@ -244,6 +244,8 @@ static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
 static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
 {
 	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
+	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
 
 	if (!pdev) {
 		pr_err("Failed to find the CXL device\n");
@@ -260,15 +262,13 @@ static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
 
 	if (err_info->severity == AER_CORRECTABLE) {
 		int aer = pdev->aer_cap;
-		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
-		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
 
 		if (aer)
 			pci_clear_and_set_config_dword(pdev,
 						       aer + PCI_ERR_COR_STATUS,
 						       0, PCI_ERR_COR_INTERNAL);
 
-		cxl_cor_error_detected(pdev);
+		cxl_cor_error_detected(&pdev->dev);
 
 		pcie_clear_device_status(pdev);
 	} else {
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 73be66ef36a2..6fd9a42eb304 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -11,6 +11,7 @@
 #include <linux/log2.h>
 #include <linux/node.h>
 #include <linux/io.h>
+#include <linux/pci.h>
 
 extern const struct nvdimm_security_ops *cxl_security_ops;
 
@@ -797,6 +798,9 @@ static inline int cxl_root_decoder_autoremove(struct device *host,
 }
 int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
 
+void cxl_cor_error_detected(struct device *dev);
+pci_ers_result_t cxl_error_detected(struct device *dev);
+
 /**
  * struct cxl_endpoint_dvsec_info - Cached DVSEC info
  * @mem_enabled: cached value of mem_enabled in the DVSEC at init time
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 6f1396ef7b77..a572c57c6c63 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -133,7 +133,7 @@ struct cxl_dev_state;
 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
 			struct cxl_endpoint_dvsec_info *info);
 void read_cdat_data(struct cxl_port *port);
-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 pci_cor_error_detected(struct pci_dev *pdev);
+pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
+				    pci_channel_state_t error);
 #endif /* __CXL_PCI_H__ */
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 785aa2af5eaa..2b948e94bc97 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -1112,11 +1112,11 @@ static void cxl_reset_done(struct pci_dev *pdev)
 	}
 }
 
-static const struct pci_error_handlers cxl_error_handlers = {
-	.error_detected	= cxl_error_detected,
+static const struct pci_error_handlers pci_error_handlers = {
+	.error_detected = pci_error_detected,
 	.slot_reset	= cxl_slot_reset,
 	.resume		= cxl_error_resume,
-	.cor_error_detected	= cxl_cor_error_detected,
+	.cor_error_detected	= pci_cor_error_detected,
 	.reset_done	= cxl_reset_done,
 };
 
@@ -1124,7 +1124,7 @@ 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		= &pci_error_handlers,
 	.dev_groups		= cxl_rcd_groups,
 	.driver	= {
 		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (11 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 12/16] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-06  0:50   ` Sathyanarayanan Kuppuswamy
  2025-06-12 17:14   ` Jonathan Cameron
  2025-06-03 17:22 ` [PATCH v9 14/16] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions Terry Bowman
                   ` (2 subsequent siblings)
  15 siblings, 2 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

Introduce CXL error handlers for CXL Port devices.

Add functions cxl_port_cor_error_detected() and cxl_port_error_detected().
These will serve as the handlers for all CXL Port devices. Introduce
cxl_get_ras_base() to provide the RAS base address needed by the handlers.

Update cxl_handle_prot_error() to call the CXL Port or CXL Endpoint handler
depending on which CXL device reports the error.

Implement pci_get_ras_base() to return the cached RAS register address of a
CXL Root Port, CXL Downstream Port, or CXL Upstream Port.

Update the AER driver's is_cxl_error() to remove the filter PCI type check
because CXL Port devices are now supported.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/cxl/core/core.h |  2 +
 drivers/cxl/core/pci.c  | 61 ++++++++++++++++++++++++++
 drivers/cxl/core/port.c |  4 +-
 drivers/cxl/core/ras.c  | 96 ++++++++++++++++++++++++++++++++++++-----
 drivers/cxl/cxl.h       |  5 +++
 drivers/pci/pcie/aer.c  |  5 ---
 6 files changed, 155 insertions(+), 18 deletions(-)

diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index c73f39d14dd7..23d15eef01d2 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -122,6 +122,8 @@ void cxl_ras_exit(void);
 int cxl_gpf_port_setup(struct cxl_dport *dport);
 int cxl_acpi_get_extended_linear_cache_size(struct resource *backing_res,
 					    int nid, resource_size_t *size);
+struct cxl_port *find_cxl_port(struct device *dport_dev,
+			       struct cxl_dport **dport);
 
 #ifdef CONFIG_CXL_FEATURES
 size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index e094ef518e0a..b6836825e8df 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -753,6 +753,67 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
 
 #ifdef CONFIG_PCIEAER_CXL
 
+static void __iomem *cxl_get_ras_base(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	void __iomem *ras_base;
+
+	switch (pci_pcie_type(pdev)) {
+	case PCI_EXP_TYPE_ROOT_PORT:
+	case PCI_EXP_TYPE_DOWNSTREAM:
+	{
+		struct cxl_dport *dport = NULL;
+		struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
+
+		if (!dport || !dport->dport_dev) {
+			pci_err(pdev, "Failed to find the CXL device");
+			return NULL;
+		}
+
+		ras_base = dport ? dport->regs.ras : NULL;
+		break;
+	}
+	case PCI_EXP_TYPE_UPSTREAM:
+	{
+		struct cxl_port *port;
+		struct device *dev __free(put_device) = bus_find_device(&cxl_bus_type, NULL,
+									&pdev->dev, match_uport);
+
+		if (!dev || !is_cxl_port(dev)) {
+			pci_err(pdev, "Failed to find the CXL device");
+			return NULL;
+		}
+
+		port = to_cxl_port(dev);
+		ras_base = port ? port->uport_regs.ras : NULL;
+		break;
+	}
+	default:
+	{
+		pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
+		return NULL;
+	}
+	}
+
+	return ras_base;
+}
+
+void cxl_port_cor_error_detected(struct device *dev)
+{
+	void __iomem *ras_base = cxl_get_ras_base(dev);
+
+	__cxl_handle_cor_ras(dev, 0, ras_base);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_port_cor_error_detected, "CXL");
+
+pci_ers_result_t cxl_port_error_detected(struct device *dev)
+{
+	void __iomem *ras_base = cxl_get_ras_base(dev);
+
+	return  __cxl_handle_ras(dev, 0, ras_base);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_port_error_detected, "CXL");
+
 static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
 					  struct cxl_dport *dport)
 {
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index eb46c6764d20..07b9bb0f601f 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1341,8 +1341,8 @@ 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)
+struct cxl_port *find_cxl_port(struct device *dport_dev,
+			       struct cxl_dport **dport)
 {
 	struct cxl_find_port_ctx ctx = {
 		.dport_dev = dport_dev,
diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
index 664f532cc838..6093e70ece37 100644
--- a/drivers/cxl/core/ras.c
+++ b/drivers/cxl/core/ras.c
@@ -140,20 +140,85 @@ static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
 	return orig;
 }
 
-static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
+int match_uport(struct device *dev, const void *data)
 {
-	pci_ers_result_t vote, *result = data;
-	struct cxl_dev_state *cxlds;
+	const struct device *uport_dev = data;
+	struct cxl_port *port;
 
-	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
-	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
+	if (!is_cxl_port(dev))
 		return 0;
 
-	cxlds = pci_get_drvdata(pdev);
-	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
+	port = to_cxl_port(dev);
+
+	return port->uport_dev == uport_dev;
+}
+EXPORT_SYMBOL_NS_GPL(match_uport, "CXL");
+
+/* Return 'struct device*' responsible for freeing pdev's CXL resources */
+static struct device *get_pci_cxl_host_dev(struct pci_dev *pdev)
+{
+	struct device *host_dev;
+
+	switch (pci_pcie_type(pdev)) {
+	case PCI_EXP_TYPE_ROOT_PORT:
+	case PCI_EXP_TYPE_DOWNSTREAM:
+	{
+		struct cxl_dport *dport = NULL;
+		struct cxl_port *port = find_cxl_port(&pdev->dev, &dport);
+
+		if (!dport || !dport->dport_dev)
+			return NULL;
+
+		host_dev = &port->dev;
+		break;
+	}
+	case PCI_EXP_TYPE_UPSTREAM:
+	{
+		struct cxl_port *port;
+		struct device *cxl_dev = bus_find_device(&cxl_bus_type, NULL,
+							 &pdev->dev, match_uport);
+
+		if (!cxl_dev || !is_cxl_port(cxl_dev))
+			return NULL;
+
+		port = to_cxl_port(cxl_dev);
+		host_dev = &port->dev;
+		break;
+	}
+	case PCI_EXP_TYPE_ENDPOINT:
+	case PCI_EXP_TYPE_RC_END:
+	{
+		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+
+		if (!cxlds)
+			return NULL;
+
+		host_dev = get_device(&cxlds->cxlmd->dev);
+		break;
+	}
+	default:
+	{
+		pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
+		return NULL;
+	}
+	}
+
+	return host_dev;
+}
+
+static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
+{
+	struct device *dev = &pdev->dev;
+	struct device *host_dev __free(put_device) = get_pci_cxl_host_dev(pdev);
+	pci_ers_result_t vote, *result = data;
 
 	device_lock(&pdev->dev);
-	vote = cxl_error_detected(&pdev->dev);
+	if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
+	    (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
+		vote = cxl_error_detected(dev);
+	} else {
+		vote = cxl_port_error_detected(dev);
+	}
 	*result = cxl_merge_result(*result, vote);
 	device_unlock(&pdev->dev);
 
@@ -244,14 +309,18 @@ static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
 static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
 {
 	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
-	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
-	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
 
 	if (!pdev) {
 		pr_err("Failed to find the CXL device\n");
 		return;
 	}
 
+	struct device *host_dev __free(put_device) = get_pci_cxl_host_dev(pdev);
+	if (!host_dev) {
+		pr_err("Failed to find the CXL device's host\n");
+		return;
+	}
+
 	/*
 	 * Internal errors of an RCEC indicate an AER error in an
 	 * RCH's downstream port. Check and handle them in the CXL.mem
@@ -261,6 +330,7 @@ static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
 		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
 
 	if (err_info->severity == AER_CORRECTABLE) {
+		struct device *dev = &pdev->dev;
 		int aer = pdev->aer_cap;
 
 		if (aer)
@@ -268,7 +338,11 @@ static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
 						       aer + PCI_ERR_COR_STATUS,
 						       0, PCI_ERR_COR_INTERNAL);
 
-		cxl_cor_error_detected(&pdev->dev);
+		if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
+		    (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END))
+			cxl_cor_error_detected(dev);
+		else
+			cxl_port_cor_error_detected(dev);
 
 		pcie_clear_device_status(pdev);
 	} else {
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 6fd9a42eb304..2c1c00466a25 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -801,6 +801,9 @@ int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint)
 void cxl_cor_error_detected(struct device *dev);
 pci_ers_result_t cxl_error_detected(struct device *dev);
 
+void cxl_port_cor_error_detected(struct device *dev);
+pci_ers_result_t cxl_port_error_detected(struct device *dev);
+
 /**
  * struct cxl_endpoint_dvsec_info - Cached DVSEC info
  * @mem_enabled: cached value of mem_enabled in the DVSEC at init time
@@ -915,6 +918,8 @@ void cxl_coordinates_combine(struct access_coordinate *out,
 
 bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port);
 
+int match_uport(struct device *dev, const void *data);
+
 /*
  * Unit test builds overrides this to __weak, find the 'strong' version
  * of these symbols in tools/testing/cxl/.
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 6e88331c6303..5efe5a718960 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -1018,11 +1018,6 @@ static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
 	if (!info || !info->is_cxl)
 		return false;
 
-	/* Only CXL Endpoints are currently supported */
-	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
-	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))
-		return false;
-
 	return is_internal_error(info);
 }
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 14/16] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (12 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 13/16] cxl/pci: Introduce CXL Port " Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-06  0:50   ` Sathyanarayanan Kuppuswamy
  2025-06-12 17:16   ` Jonathan Cameron
  2025-06-03 17:22 ` [PATCH v9 15/16] CXL/PCI: Enable CXL protocol errors during CXL Port probe Terry Bowman
  2025-06-03 17:22 ` [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
  15 siblings, 2 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

The CXL driver's cxl_handle_endpoint_cor_ras()/cxl_handle_endpoint_ras()
are unnecessary helper functions used only for Endpoints. Remove these
functions as they are not common for all CXL devices and do not provide
value for EP handling.

Rename __cxl_handle_ras to cxl_handle_ras() and __cxl_handle_cor_ras()
to cxl_handle_cor_ras().

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/pci.c | 32 ++++++++++++--------------------
 1 file changed, 12 insertions(+), 20 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index b6836825e8df..b36a58607041 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -664,8 +664,8 @@ void read_cdat_data(struct cxl_port *port)
 }
 EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
 
-static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
-				 void __iomem *ras_base)
+static void cxl_handle_cor_ras(struct device *dev, u64 serial,
+			       void __iomem *ras_base)
 {
 	void __iomem *addr;
 	u32 status;
@@ -684,11 +684,6 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
 	trace_cxl_aer_correctable_error(dev, serial, status);
 }
 
-static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
-{
-	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
-}
-
 /* CXL spec rev3.0 8.2.4.16.1 */
 static void header_log_copy(void __iomem *ras_base, u32 *log)
 {
@@ -710,8 +705,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.
  */
-static pci_ers_result_t __cxl_handle_ras(struct device *dev, u64 serial,
-					 void __iomem *ras_base)
+static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial,
+				       void __iomem *ras_base)
 {
 	u32 hl[CXL_HEADERLOG_SIZE_U32];
 	void __iomem *addr;
@@ -746,11 +741,6 @@ static pci_ers_result_t __cxl_handle_ras(struct device *dev, u64 serial,
 	return PCI_ERS_RESULT_PANIC;
 }
 
-static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
-{
-	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
-}
-
 #ifdef CONFIG_PCIEAER_CXL
 
 static void __iomem *cxl_get_ras_base(struct device *dev)
@@ -802,7 +792,7 @@ void cxl_port_cor_error_detected(struct device *dev)
 {
 	void __iomem *ras_base = cxl_get_ras_base(dev);
 
-	__cxl_handle_cor_ras(dev, 0, ras_base);
+	cxl_handle_cor_ras(dev, 0, ras_base);
 }
 EXPORT_SYMBOL_NS_GPL(cxl_port_cor_error_detected, "CXL");
 
@@ -810,20 +800,20 @@ pci_ers_result_t cxl_port_error_detected(struct device *dev)
 {
 	void __iomem *ras_base = cxl_get_ras_base(dev);
 
-	return  __cxl_handle_ras(dev, 0, ras_base);
+	return  cxl_handle_ras(dev, 0, ras_base);
 }
 EXPORT_SYMBOL_NS_GPL(cxl_port_error_detected, "CXL");
 
 static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
 					  struct cxl_dport *dport)
 {
-	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
+	return cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
 }
 
 static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
 				       struct cxl_dport *dport)
 {
-	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
+	return cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
 }
 
 /*
@@ -921,7 +911,8 @@ void cxl_cor_error_detected(struct device *dev)
 		if (cxlds->rcd)
 			cxl_handle_rdport_errors(cxlds);
 
-		cxl_handle_endpoint_cor_ras(cxlds);
+		cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial,
+				   cxlds->regs.ras);
 	}
 }
 EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
@@ -958,7 +949,8 @@ pci_ers_result_t cxl_error_detected(struct device *dev)
 		 * chance the situation is recoverable dump the status of the RAS
 		 * capability registers and bounce the active state of the memdev.
 		 */
-		ue = cxl_handle_endpoint_ras(cxlds);
+		ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial,
+				    cxlds->regs.ras);
 	}
 
 	return ue;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 15/16] CXL/PCI: Enable CXL protocol errors during CXL Port probe
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (13 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 14/16] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-06  0:51   ` Sathyanarayanan Kuppuswamy
  2025-06-03 17:22 ` [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
  15 siblings, 1 reply; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

CXL protocol errors are not enabled for all CXL devices after boot. These
must be enabled inorder to process CXL protocol errors.

Export the AER service driver's pci_aer_unmask_internal_errors().

Introduce cxl_unmask_prot_interrupts() to call pci_aer_unmask_internal_errors().
pci_aer_unmask_internal_errors() expects the pdev->aer_cap is initialized.
But, dev->aer_cap is not initialized for CXL Upstream Switch Ports and CXL
Downstream Switch Ports. Initialize the dev->aer_cap if necessary. Enable AER
correctable internal errors and uncorrectable internal errors for all CXL
devices.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/cxl/port.c     | 29 +++++++++++++++++++++++++++--
 drivers/pci/pcie/aer.c |  3 ++-
 include/linux/aer.h    |  1 +
 3 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 0f7c4010ba58..3687848ae772 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -3,6 +3,7 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/pci.h>
 
 #include "cxlmem.h"
 #include "cxlpci.h"
@@ -60,6 +61,21 @@ static int discover_region(struct device *dev, void *unused)
 
 #ifdef CONFIG_PCIEAER_CXL
 
+static void cxl_unmask_prot_interrupts(struct device *dev)
+{
+	struct pci_dev *pdev __free(pci_dev_put) =
+		pci_dev_get(to_pci_dev(dev));
+
+	if (!pdev->aer_cap) {
+		pdev->aer_cap = pci_find_ext_capability(pdev,
+							PCI_EXT_CAP_ID_ERR);
+		if (!pdev->aer_cap)
+			return;
+	}
+
+	pci_aer_unmask_internal_errors(pdev);
+}
+
 static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
 {
 	resource_size_t aer_phys;
@@ -118,8 +134,12 @@ static void cxl_uport_init_ras_reporting(struct cxl_port *port,
 
 	map->host = host;
 	if (cxl_map_component_regs(map, &port->uport_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;
+	}
+
+	cxl_unmask_prot_interrupts(port->uport_dev);
 }
 
 /**
@@ -144,9 +164,12 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
 	}
 
 	if (cxl_map_component_regs(&dport->reg_map, &dport->regs.component,
-				   BIT(CXL_CM_CAP_CAP_ID_RAS)))
+				   BIT(CXL_CM_CAP_CAP_ID_RAS))) {
 		dev_dbg(dport->dport_dev, "Failed to map RAS capability\n");
+		return;
+	}
 
+	cxl_unmask_prot_interrupts(dport->dport_dev);
 }
 EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
 
@@ -177,6 +200,8 @@ static void cxl_endpoint_port_init_ras(struct cxl_port *port)
 	}
 
 	cxl_dport_init_ras_reporting(dport, &cxlmd->dev);
+
+	cxl_unmask_prot_interrupts(cxlmd->cxlds->dev);
 }
 
 #else
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 5efe5a718960..2d202ad1453a 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -964,7 +964,7 @@ static bool find_source_device(struct pci_dev *parent,
  * Note: AER must be enabled and supported by the device which must be
  * checked in advance, e.g. with pcie_aer_is_native().
  */
-static void pci_aer_unmask_internal_errors(struct pci_dev *dev)
+void pci_aer_unmask_internal_errors(struct pci_dev *dev)
 {
 	int aer = dev->aer_cap;
 	u32 mask;
@@ -977,6 +977,7 @@ static 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_NS_GPL(pci_aer_unmask_internal_errors, "CXL");
 
 static bool is_cxl_mem_dev(struct pci_dev *dev)
 {
diff --git a/include/linux/aer.h b/include/linux/aer.h
index c9a18eca16f8..74600e75705f 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -107,5 +107,6 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
 int cper_severity_to_aer(int cper_severity);
 void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
 		       int severity, struct aer_capability_regs *aer_regs);
+void pci_aer_unmask_internal_errors(struct pci_dev *dev);
 #endif //_AER_H_
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
  2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
                   ` (14 preceding siblings ...)
  2025-06-03 17:22 ` [PATCH v9 15/16] CXL/PCI: Enable CXL protocol errors during CXL Port probe Terry Bowman
@ 2025-06-03 17:22 ` Terry Bowman
  2025-06-06  0:52   ` Sathyanarayanan Kuppuswamy
                     ` (2 more replies)
  15 siblings, 3 replies; 90+ messages in thread
From: Terry Bowman @ 2025-06-03 17:22 UTC (permalink / raw)
  To: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, terry.bowman,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

During CXL device cleanup the CXL PCIe Port device interrupts remain
enabled. This potentially allows unnecessary interrupt processing on
behalf of the CXL errors while the device is destroyed.

Disable CXL protocol errors by setting the CXL devices' AER mask register.

Introduce pci_aer_mask_internal_errors() similar to pci_aer_unmask_internal_errors().

Introduce cxl_mask_prot_interrupts() to call pci_aer_mask_internal_errors().
Add calls to cxl_mask_prot_interrupts() within CXL Port teardown for CXL
Root Ports, CXL Downstream Switch Ports, CXL Upstream Switch Ports, and CXL
Endpoints. Follow the same "bottom-up" approach used during CXL Port
teardown.

Implement cxl_mask_prot_interrupts() in a header file to avoid introducing
Kconfig ifdefs in cxl/core/port.c.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/port.c |  6 ++++++
 drivers/cxl/cxl.h       |  8 ++++++++
 drivers/pci/pcie/aer.c  | 21 +++++++++++++++++++++
 include/linux/aer.h     |  1 +
 4 files changed, 36 insertions(+)

diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 07b9bb0f601f..6aaaad002a7f 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1433,6 +1433,9 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, "CXL");
  */
 static void delete_switch_port(struct cxl_port *port)
 {
+	cxl_mask_prot_interrupts(port->uport_dev);
+	cxl_mask_prot_interrupts(port->parent_dport->dport_dev);
+
 	devm_release_action(port->dev.parent, cxl_unlink_parent_dport, port);
 	devm_release_action(port->dev.parent, cxl_unlink_uport, port);
 	devm_release_action(port->dev.parent, unregister_port, port);
@@ -1446,6 +1449,7 @@ static void reap_dports(struct cxl_port *port)
 	device_lock_assert(&port->dev);
 
 	xa_for_each(&port->dports, index, dport) {
+		cxl_mask_prot_interrupts(dport->dport_dev);
 		devm_release_action(&port->dev, cxl_dport_unlink, dport);
 		devm_release_action(&port->dev, cxl_dport_remove, dport);
 		devm_kfree(&port->dev, dport);
@@ -1476,6 +1480,8 @@ static void cxl_detach_ep(void *data)
 {
 	struct cxl_memdev *cxlmd = data;
 
+	cxl_mask_prot_interrupts(cxlmd->cxlds->dev);
+
 	for (int i = cxlmd->depth - 1; i >= 1; i--) {
 		struct cxl_port *port, *parent_port;
 		struct detach_ctx ctx = {
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 2c1c00466a25..2753db3d473e 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -12,6 +12,7 @@
 #include <linux/node.h>
 #include <linux/io.h>
 #include <linux/pci.h>
+#include <linux/aer.h>
 
 extern const struct nvdimm_security_ops *cxl_security_ops;
 
@@ -771,9 +772,16 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
 #ifdef CONFIG_PCIEAER_CXL
 void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
 void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
+static inline void cxl_mask_prot_interrupts(struct device *dev)
+{
+	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(to_pci_dev(dev));
+
+	pci_aer_mask_internal_errors(pdev);
+}
 #else
 static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
 						struct device *host) { }
+static inline void cxl_mask_prot_interrupts(struct device *dev) { }
 #endif
 
 struct cxl_decoder *to_cxl_decoder(struct device *dev);
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 2d202ad1453a..69230cf87d79 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -979,6 +979,27 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_NS_GPL(pci_aer_unmask_internal_errors, "CXL");
 
+/**
+ * pci_aer_mask_internal_errors - mask internal errors
+ * @dev: pointer to the pcie_dev data structure
+ *
+ * Masks 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().
+ */
+void pci_aer_mask_internal_errors(struct pci_dev *dev)
+{
+	int aer = dev->aer_cap;
+
+	pci_clear_and_set_config_dword(dev, aer + PCI_ERR_UNCOR_MASK,
+				       0, PCI_ERR_UNC_INTN);
+	pci_clear_and_set_config_dword(dev, aer + PCI_ERR_COR_MASK,
+				       0, PCI_ERR_COR_INTERNAL);
+}
+EXPORT_SYMBOL_NS_GPL(pci_aer_mask_internal_errors, "CXL");
+
 static bool is_cxl_mem_dev(struct pci_dev *dev)
 {
 	/*
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 74600e75705f..41167ad3797a 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -108,5 +108,6 @@ int cper_severity_to_aer(int cper_severity);
 void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
 		       int severity, struct aer_capability_regs *aer_regs);
 void pci_aer_unmask_internal_errors(struct pci_dev *dev);
+void pci_aer_mask_internal_errors(struct pci_dev *dev);
 #endif //_AER_H_
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging
  2025-06-03 17:22 ` [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging Terry Bowman
@ 2025-06-03 22:02   ` Sathyanarayanan Kuppuswamy
  2025-06-04 14:32     ` Bowman, Terry
  2025-06-05 23:28   ` Dave Jiang
  1 sibling, 1 reply; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-03 22:02 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> The AER service driver and aer_event tracing currently log 'PCIe Bus Type'
> for all errors. Update the driver and aer_event tracing to log 'CXL Bus
> Type' for CXL device errors.
>
> This requires the AER can identify and distinguish between PCIe errors and
> CXL errors.
>
> Introduce boolean 'is_cxl' to 'struct aer_err_info'. Add assignment in
> aer_get_device_error_info() and pci_print_aer().
>
> Update the aer_event trace routine to accept a bus type string parameter.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> ---
>   drivers/pci/pci.h       |  6 ++++++
>   drivers/pci/pcie/aer.c  | 18 ++++++++++++------
>   include/ras/ras_event.h |  9 ++++++---
>   3 files changed, 24 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index b81e99cd4b62..d6296500b004 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -588,6 +588,7 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
>   struct aer_err_info {
>   	struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
>   	int error_dev_num;
> +	bool is_cxl;

Do you really need this member ? Why not just use pcie_is_cxl() in aer_err_bus()?

>   
>   	unsigned int id:16;
>   
> @@ -604,6 +605,11 @@ struct aer_err_info {
>   	struct pcie_tlp_log tlp;	/* TLP Header */
>   };
>   
> +static inline const char *aer_err_bus(struct aer_err_info *info)
> +{
> +	return info->is_cxl ? "CXL" : "PCIe";
> +}
> +
>   int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
>   void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
>   
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index a1cf8c7ef628..adb4b1123b9b 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -698,13 +698,14 @@ static void __aer_print_error(struct pci_dev *dev,
>   
>   void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>   {
> +	const char *bus_type = aer_err_bus(info);
>   	int layer, agent;
>   	int id = pci_dev_id(dev);
>   	const char *level;
>   
>   	if (!info->status) {
> -		pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
> -			aer_error_severity_string[info->severity]);
> +		pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
> +			bus_type, aer_error_severity_string[info->severity]);
>   		goto out;
>   	}
>   
> @@ -713,8 +714,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>   
>   	level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR;
>   
> -	aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
> -		   aer_error_severity_string[info->severity],
> +	aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
> +		   bus_type, aer_error_severity_string[info->severity],
>   		   aer_error_layer[layer], aer_agent_string[agent]);
>   
>   	aer_printk(level, dev, "  device [%04x:%04x] error status/mask=%08x/%08x\n",
> @@ -729,7 +730,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>   	if (info->id && info->error_dev_num > 1 && info->id == id)
>   		pci_err(dev, "  Error of this Agent is reported first\n");
>   
> -	trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
> +	trace_aer_event(dev_name(&dev->dev), bus_type, (info->status & ~info->mask),
>   			info->severity, info->tlp_header_valid, &info->tlp);
>   }
>   
> @@ -763,6 +764,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
>   void pci_print_aer(struct pci_dev *dev, int aer_severity,
>   		   struct aer_capability_regs *aer)
>   {
> +	const char *bus_type;
>   	int layer, agent, tlp_header_valid = 0;
>   	u32 status, mask;
>   	struct aer_err_info info;
> @@ -784,6 +786,9 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>   	info.status = status;
>   	info.mask = mask;
>   	info.first_error = PCI_ERR_CAP_FEP(aer->cap_control);
> +	info.is_cxl = pcie_is_cxl(dev);
> +
> +	bus_type = aer_err_bus(&info);
>   
>   	pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
>   	__aer_print_error(dev, &info);
> @@ -797,7 +802,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>   	if (tlp_header_valid)
>   		pcie_print_tlp_log(dev, &aer->header_log, dev_fmt("  "));
>   
> -	trace_aer_event(dev_name(&dev->dev), (status & ~mask),
> +	trace_aer_event(dev_name(&dev->dev), bus_type, (status & ~mask),
>   			aer_severity, tlp_header_valid, &aer->header_log);
>   }
>   EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
> @@ -1215,6 +1220,7 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
>   	/* Must reset in this function */
>   	info->status = 0;
>   	info->tlp_header_valid = 0;
> +	info->is_cxl = pcie_is_cxl(dev);
>   
>   	/* The device might not support AER */
>   	if (!aer)
> diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
> index 14c9f943d53f..080829d59c36 100644
> --- a/include/ras/ras_event.h
> +++ b/include/ras/ras_event.h
> @@ -297,15 +297,17 @@ TRACE_EVENT(non_standard_event,
>   
>   TRACE_EVENT(aer_event,
>   	TP_PROTO(const char *dev_name,
> +		 const char *bus_type,
>   		 const u32 status,
>   		 const u8 severity,
>   		 const u8 tlp_header_valid,
>   		 struct pcie_tlp_log *tlp),
>   
> -	TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
> +	TP_ARGS(dev_name, bus_type, status, severity, tlp_header_valid, tlp),
>   
>   	TP_STRUCT__entry(
>   		__string(	dev_name,	dev_name	)
> +		__string(	bus_type,	bus_type	)
>   		__field(	u32,		status		)
>   		__field(	u8,		severity	)
>   		__field(	u8, 		tlp_header_valid)
> @@ -314,6 +316,7 @@ TRACE_EVENT(aer_event,
>   
>   	TP_fast_assign(
>   		__assign_str(dev_name);
> +		__assign_str(bus_type);
>   		__entry->status		= status;
>   		__entry->severity	= severity;
>   		__entry->tlp_header_valid = tlp_header_valid;
> @@ -325,8 +328,8 @@ TRACE_EVENT(aer_event,
>   		}
>   	),
>   
> -	TP_printk("%s PCIe Bus Error: severity=%s, %s, TLP Header=%s\n",
> -		__get_str(dev_name),
> +	TP_printk("%s %s Bus Error: severity=%s, %s, TLP Header=%s\n",
> +		__get_str(dev_name), __get_str(bus_type),
>   		__entry->severity == AER_CORRECTABLE ? "Corrected" :
>   			__entry->severity == AER_FATAL ?
>   			"Fatal" : "Uncorrected, non-fatal",

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-03 17:22 ` [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors Terry Bowman
@ 2025-06-04  6:01   ` Dan Carpenter
  2025-06-04 14:37     ` Bowman, Terry
  2025-06-04 22:50   ` Sathyanarayanan Kuppuswamy
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 90+ messages in thread
From: Dan Carpenter @ 2025-06-04  6:01 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, Jun 03, 2025 at 12:22:26PM -0500, Terry Bowman wrote:
> +static struct work_struct cxl_prot_err_work;
> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
> +
>  int cxl_ras_init(void)
>  {
> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> +	int rc;
> +
> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> +	if (rc)
> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);

This shouldn't return rc;?

> +
> +	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
> +	if (rc) {
> +		pr_err("Failed to register native AER kfifo (%x)", rc);
> +		return rc;
> +	}
> +
> +	return 0;
>  }

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-03 17:22 ` [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error Terry Bowman
@ 2025-06-04  6:05   ` Dan Carpenter
  2025-06-04 14:38     ` Bowman, Terry
  2025-06-04 23:58   ` Sathyanarayanan Kuppuswamy
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 90+ messages in thread
From: Dan Carpenter @ 2025-06-04  6:05 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, Jun 03, 2025 at 12:22:27PM -0500, Terry Bowman wrote:
> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
> +{
> +	unsigned int devfn = PCI_DEVFN(err_info->device,
> +				       err_info->function);
> +	struct pci_dev *pdev __free(pci_dev_put) =

What?  Why is it freeing the returned pointer?  That should happen in
the caller, surely?

> +		pci_get_domain_bus_and_slot(err_info->segment,
> +					    err_info->bus,
> +					    devfn);
> +	return pdev;
> +}
> +
> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
> +{
> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));

Ok, it does happen in the caller, but dropping and then incrementing
the reference count  like this is racy.

regards,
dan carpenter

> +
> +	if (!pdev) {
> +		pr_err("Failed to find the CXL device\n");
> +		return;
> +	}
> +
> +	/*
> +	 * 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.
> +	 */
> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
> +
> +	if (err_info->severity == AER_CORRECTABLE) {
> +		int aer = pdev->aer_cap;
> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +
> +		if (aer)
> +			pci_clear_and_set_config_dword(pdev,
> +						       aer + PCI_ERR_COR_STATUS,
> +						       0, PCI_ERR_COR_INTERNAL);
> +
> +		cxl_cor_error_detected(pdev);
> +
> +		pcie_clear_device_status(pdev);
> +	} else {
> +		cxl_do_recovery(pdev);
> +	}
> +}
> +


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging
  2025-06-03 22:02   ` Sathyanarayanan Kuppuswamy
@ 2025-06-04 14:32     ` Bowman, Terry
  2025-06-04 19:24       ` Sathyanarayanan Kuppuswamy
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-04 14:32 UTC (permalink / raw)
  To: Sathyanarayanan Kuppuswamy, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, dave.jiang, alison.schofield, vishal.l.verma,
	ira.weiny, dan.j.williams, bhelgaas, bp, ming.li, shiju.jose,
	dan.carpenter, Smita.KoralahalliChannabasappa, kobayashi.da-06,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/3/2025 5:02 PM, Sathyanarayanan Kuppuswamy wrote:
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> The AER service driver and aer_event tracing currently log 'PCIe Bus Type'
>> for all errors. Update the driver and aer_event tracing to log 'CXL Bus
>> Type' for CXL device errors.
>>
>> This requires the AER can identify and distinguish between PCIe errors and
>> CXL errors.
>>
>> Introduce boolean 'is_cxl' to 'struct aer_err_info'. Add assignment in
>> aer_get_device_error_info() and pci_print_aer().
>>
>> Update the aer_event trace routine to accept a bus type string parameter.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
>> ---
>>   drivers/pci/pci.h       |  6 ++++++
>>   drivers/pci/pcie/aer.c  | 18 ++++++++++++------
>>   include/ras/ras_event.h |  9 ++++++---
>>   3 files changed, 24 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>> index b81e99cd4b62..d6296500b004 100644
>> --- a/drivers/pci/pci.h
>> +++ b/drivers/pci/pci.h
>> @@ -588,6 +588,7 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
>>   struct aer_err_info {
>>   	struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
>>   	int error_dev_num;
>> +	bool is_cxl;
> Do you really need this member ? Why not just use pcie_is_cxl() in aer_err_bus()?

This was added per Dan's request instead of using pcie_is_cxl().[1]

[1] https://lore.kernel.org/linux-cxl/67abe1903a8ed_2d1e2942f@dwillia2-xfh.jf.intel.com.notmuch/

-Terry

>>   
>>   	unsigned int id:16;
>>   
>> @@ -604,6 +605,11 @@ struct aer_err_info {
>>   	struct pcie_tlp_log tlp;	/* TLP Header */
>>   };
>>   
>> +static inline const char *aer_err_bus(struct aer_err_info *info)
>> +{
>> +	return info->is_cxl ? "CXL" : "PCIe";
>> +}
>> +
>>   int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
>>   void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
>>   
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index a1cf8c7ef628..adb4b1123b9b 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -698,13 +698,14 @@ static void __aer_print_error(struct pci_dev *dev,
>>   
>>   void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>   {
>> +	const char *bus_type = aer_err_bus(info);
>>   	int layer, agent;
>>   	int id = pci_dev_id(dev);
>>   	const char *level;
>>   
>>   	if (!info->status) {
>> -		pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
>> -			aer_error_severity_string[info->severity]);
>> +		pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
>> +			bus_type, aer_error_severity_string[info->severity]);
>>   		goto out;
>>   	}
>>   
>> @@ -713,8 +714,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>   
>>   	level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR;
>>   
>> -	aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
>> -		   aer_error_severity_string[info->severity],
>> +	aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
>> +		   bus_type, aer_error_severity_string[info->severity],
>>   		   aer_error_layer[layer], aer_agent_string[agent]);
>>   
>>   	aer_printk(level, dev, "  device [%04x:%04x] error status/mask=%08x/%08x\n",
>> @@ -729,7 +730,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>   	if (info->id && info->error_dev_num > 1 && info->id == id)
>>   		pci_err(dev, "  Error of this Agent is reported first\n");
>>   
>> -	trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
>> +	trace_aer_event(dev_name(&dev->dev), bus_type, (info->status & ~info->mask),
>>   			info->severity, info->tlp_header_valid, &info->tlp);
>>   }
>>   
>> @@ -763,6 +764,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
>>   void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>   		   struct aer_capability_regs *aer)
>>   {
>> +	const char *bus_type;
>>   	int layer, agent, tlp_header_valid = 0;
>>   	u32 status, mask;
>>   	struct aer_err_info info;
>> @@ -784,6 +786,9 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>   	info.status = status;
>>   	info.mask = mask;
>>   	info.first_error = PCI_ERR_CAP_FEP(aer->cap_control);
>> +	info.is_cxl = pcie_is_cxl(dev);
>> +
>> +	bus_type = aer_err_bus(&info);
>>   
>>   	pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
>>   	__aer_print_error(dev, &info);
>> @@ -797,7 +802,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>   	if (tlp_header_valid)
>>   		pcie_print_tlp_log(dev, &aer->header_log, dev_fmt("  "));
>>   
>> -	trace_aer_event(dev_name(&dev->dev), (status & ~mask),
>> +	trace_aer_event(dev_name(&dev->dev), bus_type, (status & ~mask),
>>   			aer_severity, tlp_header_valid, &aer->header_log);
>>   }
>>   EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
>> @@ -1215,6 +1220,7 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
>>   	/* Must reset in this function */
>>   	info->status = 0;
>>   	info->tlp_header_valid = 0;
>> +	info->is_cxl = pcie_is_cxl(dev);
>>   
>>   	/* The device might not support AER */
>>   	if (!aer)
>> diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
>> index 14c9f943d53f..080829d59c36 100644
>> --- a/include/ras/ras_event.h
>> +++ b/include/ras/ras_event.h
>> @@ -297,15 +297,17 @@ TRACE_EVENT(non_standard_event,
>>   
>>   TRACE_EVENT(aer_event,
>>   	TP_PROTO(const char *dev_name,
>> +		 const char *bus_type,
>>   		 const u32 status,
>>   		 const u8 severity,
>>   		 const u8 tlp_header_valid,
>>   		 struct pcie_tlp_log *tlp),
>>   
>> -	TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
>> +	TP_ARGS(dev_name, bus_type, status, severity, tlp_header_valid, tlp),
>>   
>>   	TP_STRUCT__entry(
>>   		__string(	dev_name,	dev_name	)
>> +		__string(	bus_type,	bus_type	)
>>   		__field(	u32,		status		)
>>   		__field(	u8,		severity	)
>>   		__field(	u8, 		tlp_header_valid)
>> @@ -314,6 +316,7 @@ TRACE_EVENT(aer_event,
>>   
>>   	TP_fast_assign(
>>   		__assign_str(dev_name);
>> +		__assign_str(bus_type);
>>   		__entry->status		= status;
>>   		__entry->severity	= severity;
>>   		__entry->tlp_header_valid = tlp_header_valid;
>> @@ -325,8 +328,8 @@ TRACE_EVENT(aer_event,
>>   		}
>>   	),
>>   
>> -	TP_printk("%s PCIe Bus Error: severity=%s, %s, TLP Header=%s\n",
>> -		__get_str(dev_name),
>> +	TP_printk("%s %s Bus Error: severity=%s, %s, TLP Header=%s\n",
>> +		__get_str(dev_name), __get_str(bus_type),
>>   		__entry->severity == AER_CORRECTABLE ? "Corrected" :
>>   			__entry->severity == AER_FATAL ?
>>   			"Fatal" : "Uncorrected, non-fatal",


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-04  6:01   ` Dan Carpenter
@ 2025-06-04 14:37     ` Bowman, Terry
  2025-06-04 17:24       ` Dan Carpenter
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-04 14:37 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/4/2025 1:01 AM, Dan Carpenter wrote:
> On Tue, Jun 03, 2025 at 12:22:26PM -0500, Terry Bowman wrote:
>> +static struct work_struct cxl_prot_err_work;
>> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
>> +
>>  int cxl_ras_init(void)
>>  {
>> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>> +	int rc;
>> +
>> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>> +	if (rc)
>> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);
> This shouldn't return rc;?

This was implemented to allow for native CXL handling initialization even if
FW-first (CPER) initialization fails. This can be changed to return rc.

Thanks for reviewing dan Carpenter.

-Terry

>
>> +
>> +	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
>> +	if (rc) {
>> +		pr_err("Failed to register native AER kfifo (%x)", rc);
>> +		return rc;
>> +	}
>> +
>> +	return 0;
>>  }
> regards,
> dan carpenter
>


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-04  6:05   ` Dan Carpenter
@ 2025-06-04 14:38     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-04 14:38 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/4/2025 1:05 AM, Dan Carpenter wrote:
> On Tue, Jun 03, 2025 at 12:22:27PM -0500, Terry Bowman wrote:
>> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>> +{
>> +	unsigned int devfn = PCI_DEVFN(err_info->device,
>> +				       err_info->function);
>> +	struct pci_dev *pdev __free(pci_dev_put) =
> What?  Why is it freeing the returned pointer?  That should happen in
> the caller, surely?
>
>> +		pci_get_domain_bus_and_slot(err_info->segment,
>> +					    err_info->bus,
>> +					    devfn);
>> +	return pdev;
>> +}
>> +
>> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>> +{
>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> Ok, it does happen in the caller, but dropping and then incrementing
> the reference count  like this is racy.
>
> regards,
> dan carpenter

Thanks dan. This was an oversight on my part. I'll change.

-Terry
>> +
>> +	if (!pdev) {
>> +		pr_err("Failed to find the CXL device\n");
>> +		return;
>> +	}
>> +
>> +	/*
>> +	 * 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.
>> +	 */
>> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
>> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>> +
>> +	if (err_info->severity == AER_CORRECTABLE) {
>> +		int aer = pdev->aer_cap;
>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>> +
>> +		if (aer)
>> +			pci_clear_and_set_config_dword(pdev,
>> +						       aer + PCI_ERR_COR_STATUS,
>> +						       0, PCI_ERR_COR_INTERNAL);
>> +
>> +		cxl_cor_error_detected(pdev);
>> +
>> +		pcie_clear_device_status(pdev);
>> +	} else {
>> +		cxl_do_recovery(pdev);
>> +	}
>> +}
>> +


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-04 14:37     ` Bowman, Terry
@ 2025-06-04 17:24       ` Dan Carpenter
  2025-06-04 19:21         ` Bowman, Terry
  0 siblings, 1 reply; 90+ messages in thread
From: Dan Carpenter @ 2025-06-04 17:24 UTC (permalink / raw)
  To: Bowman, Terry
  Cc: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Wed, Jun 04, 2025 at 09:37:02AM -0500, Bowman, Terry wrote:
> 
> 
> On 6/4/2025 1:01 AM, Dan Carpenter wrote:
> > On Tue, Jun 03, 2025 at 12:22:26PM -0500, Terry Bowman wrote:
> >> +static struct work_struct cxl_prot_err_work;
> >> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
> >> +
> >>  int cxl_ras_init(void)
> >>  {
> >> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> >> +	int rc;
> >> +
> >> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> >> +	if (rc)
> >> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);
> > This shouldn't return rc;?
> 
> This was implemented to allow for native CXL handling initialization even if
> FW-first (CPER) initialization fails. This can be changed to return rc.

No no.  I'm fine with it either way so long as it's deliberate.  But
maybe add a comment if we can continue.

	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
	if (rc) {
		pr_err("Failed to register CPER AER kfifo (%x)", rc);
		/* Continuing regardless.  Thanks. */
	}

	rc = cxl_register_prot_err_work(&cxl_prot_err_work);

regards,
dan carpenter


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl()
  2025-06-03 17:22 ` [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl() Terry Bowman
@ 2025-06-04 19:06   ` Sathyanarayanan Kuppuswamy
  2025-06-04 19:18     ` Bowman, Terry
  2025-06-05 23:24   ` Dave Jiang
  1 sibling, 1 reply; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-04 19:06 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> CXL and AER drivers need the ability to identify CXL devices.
>
> Add set_pcie_cxl() with logic checking for CXL Flexbus DVSEC presence. The
> CXL Flexbus DVSEC presence is used because it is required for all the CXL
> PCIe devices.[1]
>
> Add boolean 'struct pci_dev::is_cxl' with the purpose to cache the CXL
> Flexbus presence.
>
> Add function pcie_is_cxl() to return 'struct pci_dev::is_cxl'.
>
> [1] CXL 3.1 Spec, 8.1.1 PCIe Designated Vendor-Specific Extended
>      Capability (DVSEC) ID Assignment, Table 8-2
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/pci/probe.c           | 10 ++++++++++
>   include/linux/pci.h           |  6 ++++++
>   include/uapi/linux/pci_regs.h |  8 +++++++-
>   3 files changed, 23 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 364fa2a514f8..aa29b4b98ad1 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1691,6 +1691,14 @@ static void set_pcie_thunderbolt(struct pci_dev *dev)
>   		dev->is_thunderbolt = 1;
>   }
>   
> +static void set_pcie_cxl(struct pci_dev *dev)
> +{
> +	u16 dvsec = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
> +					      PCI_DVSEC_CXL_FLEXBUS);
> +	if (dvsec)
> +		dev->is_cxl = 1;
> +}
> +
>   static void set_pcie_untrusted(struct pci_dev *dev)
>   {
>   	struct pci_dev *parent = pci_upstream_bridge(dev);
> @@ -2021,6 +2029,8 @@ int pci_setup_device(struct pci_dev *dev)
>   	/* Need to have dev->cfg_size ready */
>   	set_pcie_thunderbolt(dev);
>   
> +	set_pcie_cxl(dev);
> +
>   	set_pcie_untrusted(dev);
>   
>   	if (pci_is_pcie(dev))
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 51e2bd6405cd..bff3009f9ff0 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -455,6 +455,7 @@ struct pci_dev {
>   	unsigned int	is_hotplug_bridge:1;
>   	unsigned int	shpc_managed:1;		/* SHPC owned by shpchp */
>   	unsigned int	is_thunderbolt:1;	/* Thunderbolt controller */
> +	unsigned int	is_cxl:1;               /* Compute Express Link (CXL) */
>   	/*
>   	 * Devices marked being untrusted are the ones that can potentially
>   	 * execute DMA attacks and similar. They are typically connected
> @@ -746,6 +747,11 @@ static inline bool pci_is_vga(struct pci_dev *pdev)
>   	return false;
>   }
>   
> +static inline bool pcie_is_cxl(struct pci_dev *pci_dev)
> +{
> +	return pci_dev->is_cxl;
> +}
> +
>   #define for_each_pci_bridge(dev, bus)				\
>   	list_for_each_entry(dev, &bus->devices, bus_list)	\
>   		if (!pci_is_bridge(dev)) {} else
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index ba326710f9c8..c50ffa75d5fc 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -1215,9 +1215,15 @@
>   /* Deprecated old name, replaced with PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE */
>   #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL		PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE
>   
> -/* Compute Express Link (CXL r3.1, sec 8.1.5) */
> +/* Compute Express Link (CXL r3.2, sec 8.1)
> + *
> + * Note that CXL DVSEC id 3 and 7 to be ignored when the CXL link state
> + * is "disconnected" (CXL r3.2, sec 9.12.3). Re-enumerate these
> + * registers on downstream link-up events.
> + */
>   #define PCI_DVSEC_CXL_PORT				3
>   #define PCI_DVSEC_CXL_PORT_CTL				0x0c
>   #define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR		0x00000001
> +#define PCI_DVSEC_CXL_FLEXBUS				7
>   
>   #endif /* LINUX_PCI_REGS_H */

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl()
  2025-06-04 19:06   ` Sathyanarayanan Kuppuswamy
@ 2025-06-04 19:18     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-04 19:18 UTC (permalink / raw)
  To: Sathyanarayanan Kuppuswamy, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, dave.jiang, alison.schofield, vishal.l.verma,
	ira.weiny, dan.j.williams, bhelgaas, bp, ming.li, shiju.jose,
	dan.carpenter, Smita.KoralahalliChannabasappa, kobayashi.da-06,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/4/2025 2:06 PM, Sathyanarayanan Kuppuswamy wrote:
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> CXL and AER drivers need the ability to identify CXL devices.
>>
>> Add set_pcie_cxl() with logic checking for CXL Flexbus DVSEC presence. The
>> CXL Flexbus DVSEC presence is used because it is required for all the CXL
>> PCIe devices.[1]
>>
>> Add boolean 'struct pci_dev::is_cxl' with the purpose to cache the CXL
>> Flexbus presence.
>>
>> Add function pcie_is_cxl() to return 'struct pci_dev::is_cxl'.
>>
>> [1] CXL 3.1 Spec, 8.1.1 PCIe Designated Vendor-Specific Extended
>>      Capability (DVSEC) ID Assignment, Table 8-2
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
>> ---
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
Thanks for reviewing Kuppuswamy. Terry

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-04 17:24       ` Dan Carpenter
@ 2025-06-04 19:21         ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-04 19:21 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/4/2025 12:24 PM, Dan Carpenter wrote:
> On Wed, Jun 04, 2025 at 09:37:02AM -0500, Bowman, Terry wrote:
>>
>> On 6/4/2025 1:01 AM, Dan Carpenter wrote:
>>> On Tue, Jun 03, 2025 at 12:22:26PM -0500, Terry Bowman wrote:
>>>> +static struct work_struct cxl_prot_err_work;
>>>> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
>>>> +
>>>>  int cxl_ras_init(void)
>>>>  {
>>>> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>>>> +	int rc;
>>>> +
>>>> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>>>> +	if (rc)
>>>> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);
>>> This shouldn't return rc;?
>> This was implemented to allow for native CXL handling initialization even if
>> FW-first (CPER) initialization fails. This can be changed to return rc.
> No no.  I'm fine with it either way so long as it's deliberate.  But
> maybe add a comment if we can continue.
>
> 	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> 	if (rc) {
> 		pr_err("Failed to register CPER AER kfifo (%x)", rc);
> 		/* Continuing regardless.  Thanks. */
> 	}
>
> 	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
>
> regards,
> dan carpenter
>
Good idea. I made the change as you recommended.

Terry

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging
  2025-06-04 14:32     ` Bowman, Terry
@ 2025-06-04 19:24       ` Sathyanarayanan Kuppuswamy
  2025-06-04 21:30         ` Bowman, Terry
  0 siblings, 1 reply; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-04 19:24 UTC (permalink / raw)
  To: Bowman, Terry, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, dave.jiang, alison.schofield, vishal.l.verma,
	ira.weiny, dan.j.williams, bhelgaas, bp, ming.li, shiju.jose,
	dan.carpenter, Smita.KoralahalliChannabasappa, kobayashi.da-06,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci


On 6/4/25 7:32 AM, Bowman, Terry wrote:
>
> On 6/3/2025 5:02 PM, Sathyanarayanan Kuppuswamy wrote:
>> On 6/3/25 10:22 AM, Terry Bowman wrote:
>>> The AER service driver and aer_event tracing currently log 'PCIe Bus Type'
>>> for all errors. Update the driver and aer_event tracing to log 'CXL Bus
>>> Type' for CXL device errors.
>>>
>>> This requires the AER can identify and distinguish between PCIe errors and
>>> CXL errors.
>>>
>>> Introduce boolean 'is_cxl' to 'struct aer_err_info'. Add assignment in
>>> aer_get_device_error_info() and pci_print_aer().
>>>
>>> Update the aer_event trace routine to accept a bus type string parameter.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
>>> ---
>>>    drivers/pci/pci.h       |  6 ++++++
>>>    drivers/pci/pcie/aer.c  | 18 ++++++++++++------
>>>    include/ras/ras_event.h |  9 ++++++---
>>>    3 files changed, 24 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>>> index b81e99cd4b62..d6296500b004 100644
>>> --- a/drivers/pci/pci.h
>>> +++ b/drivers/pci/pci.h
>>> @@ -588,6 +588,7 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
>>>    struct aer_err_info {
>>>    	struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
>>>    	int error_dev_num;
>>> +	bool is_cxl;
>> Do you really need this member ? Why not just use pcie_is_cxl() in aer_err_bus()?
> This was added per Dan's request instead of using pcie_is_cxl().[1]
>
> [1] https://lore.kernel.org/linux-cxl/67abe1903a8ed_2d1e2942f@dwillia2-xfh.jf.intel.com.notmuch/
>
> -Terry

It looks like it is added to accommodate some future use cases. May be add some info about it in the aer_err_info struct. Just looking at the code, that member value mirrors pci_dev->is_cxl and where ever you read info->cxl, you can also read the value from pci_dev->is_cxl.
>>>    
>>>    	unsigned int id:16;
>>>    
>>> @@ -604,6 +605,11 @@ struct aer_err_info {
>>>    	struct pcie_tlp_log tlp;	/* TLP Header */
>>>    };
>>>    
>>> +static inline const char *aer_err_bus(struct aer_err_info *info)
>>> +{
>>> +	return info->is_cxl ? "CXL" : "PCIe";
>>> +}
>>> +
>>>    int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
>>>    void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
>>>    
>>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>>> index a1cf8c7ef628..adb4b1123b9b 100644
>>> --- a/drivers/pci/pcie/aer.c
>>> +++ b/drivers/pci/pcie/aer.c
>>> @@ -698,13 +698,14 @@ static void __aer_print_error(struct pci_dev *dev,
>>>    
>>>    void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>>    {
>>> +	const char *bus_type = aer_err_bus(info);
>>>    	int layer, agent;
>>>    	int id = pci_dev_id(dev);
>>>    	const char *level;
>>>    
>>>    	if (!info->status) {
>>> -		pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
>>> -			aer_error_severity_string[info->severity]);
>>> +		pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
>>> +			bus_type, aer_error_severity_string[info->severity]);
>>>    		goto out;
>>>    	}
>>>    
>>> @@ -713,8 +714,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>>    
>>>    	level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR;
>>>    
>>> -	aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
>>> -		   aer_error_severity_string[info->severity],
>>> +	aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
>>> +		   bus_type, aer_error_severity_string[info->severity],
>>>    		   aer_error_layer[layer], aer_agent_string[agent]);
>>>    
>>>    	aer_printk(level, dev, "  device [%04x:%04x] error status/mask=%08x/%08x\n",
>>> @@ -729,7 +730,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>>    	if (info->id && info->error_dev_num > 1 && info->id == id)
>>>    		pci_err(dev, "  Error of this Agent is reported first\n");
>>>    
>>> -	trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
>>> +	trace_aer_event(dev_name(&dev->dev), bus_type, (info->status & ~info->mask),
>>>    			info->severity, info->tlp_header_valid, &info->tlp);
>>>    }
>>>    
>>> @@ -763,6 +764,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
>>>    void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>>    		   struct aer_capability_regs *aer)
>>>    {
>>> +	const char *bus_type;
>>>    	int layer, agent, tlp_header_valid = 0;
>>>    	u32 status, mask;
>>>    	struct aer_err_info info;
>>> @@ -784,6 +786,9 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>>    	info.status = status;
>>>    	info.mask = mask;
>>>    	info.first_error = PCI_ERR_CAP_FEP(aer->cap_control);
>>> +	info.is_cxl = pcie_is_cxl(dev);
>>> +
>>> +	bus_type = aer_err_bus(&info);
>>>    
>>>    	pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
>>>    	__aer_print_error(dev, &info);
>>> @@ -797,7 +802,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>>    	if (tlp_header_valid)
>>>    		pcie_print_tlp_log(dev, &aer->header_log, dev_fmt("  "));
>>>    
>>> -	trace_aer_event(dev_name(&dev->dev), (status & ~mask),
>>> +	trace_aer_event(dev_name(&dev->dev), bus_type, (status & ~mask),
>>>    			aer_severity, tlp_header_valid, &aer->header_log);
>>>    }
>>>    EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
>>> @@ -1215,6 +1220,7 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
>>>    	/* Must reset in this function */
>>>    	info->status = 0;
>>>    	info->tlp_header_valid = 0;
>>> +	info->is_cxl = pcie_is_cxl(dev);
>>>    
>>>    	/* The device might not support AER */
>>>    	if (!aer)
>>> diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
>>> index 14c9f943d53f..080829d59c36 100644
>>> --- a/include/ras/ras_event.h
>>> +++ b/include/ras/ras_event.h
>>> @@ -297,15 +297,17 @@ TRACE_EVENT(non_standard_event,
>>>    
>>>    TRACE_EVENT(aer_event,
>>>    	TP_PROTO(const char *dev_name,
>>> +		 const char *bus_type,
>>>    		 const u32 status,
>>>    		 const u8 severity,
>>>    		 const u8 tlp_header_valid,
>>>    		 struct pcie_tlp_log *tlp),
>>>    
>>> -	TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
>>> +	TP_ARGS(dev_name, bus_type, status, severity, tlp_header_valid, tlp),
>>>    
>>>    	TP_STRUCT__entry(
>>>    		__string(	dev_name,	dev_name	)
>>> +		__string(	bus_type,	bus_type	)
>>>    		__field(	u32,		status		)
>>>    		__field(	u8,		severity	)
>>>    		__field(	u8, 		tlp_header_valid)
>>> @@ -314,6 +316,7 @@ TRACE_EVENT(aer_event,
>>>    
>>>    	TP_fast_assign(
>>>    		__assign_str(dev_name);
>>> +		__assign_str(bus_type);
>>>    		__entry->status		= status;
>>>    		__entry->severity	= severity;
>>>    		__entry->tlp_header_valid = tlp_header_valid;
>>> @@ -325,8 +328,8 @@ TRACE_EVENT(aer_event,
>>>    		}
>>>    	),
>>>    
>>> -	TP_printk("%s PCIe Bus Error: severity=%s, %s, TLP Header=%s\n",
>>> -		__get_str(dev_name),
>>> +	TP_printk("%s %s Bus Error: severity=%s, %s, TLP Header=%s\n",
>>> +		__get_str(dev_name), __get_str(bus_type),
>>>    		__entry->severity == AER_CORRECTABLE ? "Corrected" :
>>>    			__entry->severity == AER_FATAL ?
>>>    			"Fatal" : "Uncorrected, non-fatal",
>
-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging
  2025-06-04 19:24       ` Sathyanarayanan Kuppuswamy
@ 2025-06-04 21:30         ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-04 21:30 UTC (permalink / raw)
  To: Sathyanarayanan Kuppuswamy, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, dave.jiang, alison.schofield, vishal.l.verma,
	ira.weiny, dan.j.williams, bhelgaas, bp, ming.li, shiju.jose,
	dan.carpenter, Smita.KoralahalliChannabasappa, kobayashi.da-06,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On 6/4/2025 2:24 PM, Sathyanarayanan Kuppuswamy wrote:
> 
> On 6/4/25 7:32 AM, Bowman, Terry wrote:
>>
>> On 6/3/2025 5:02 PM, Sathyanarayanan Kuppuswamy wrote:
>>> On 6/3/25 10:22 AM, Terry Bowman wrote:
>>>> The AER service driver and aer_event tracing currently log 'PCIe Bus Type'
>>>> for all errors. Update the driver and aer_event tracing to log 'CXL Bus
>>>> Type' for CXL device errors.
>>>>
>>>> This requires the AER can identify and distinguish between PCIe errors and
>>>> CXL errors.
>>>>
>>>> Introduce boolean 'is_cxl' to 'struct aer_err_info'. Add assignment in
>>>> aer_get_device_error_info() and pci_print_aer().
>>>>
>>>> Update the aer_event trace routine to accept a bus type string parameter.
>>>>
>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
>>>> ---
>>>>    drivers/pci/pci.h       |  6 ++++++
>>>>    drivers/pci/pcie/aer.c  | 18 ++++++++++++------
>>>>    include/ras/ras_event.h |  9 ++++++---
>>>>    3 files changed, 24 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>>>> index b81e99cd4b62..d6296500b004 100644
>>>> --- a/drivers/pci/pci.h
>>>> +++ b/drivers/pci/pci.h
>>>> @@ -588,6 +588,7 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
>>>>    struct aer_err_info {
>>>>    	struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
>>>>    	int error_dev_num;
>>>> +	bool is_cxl;
>>> Do you really need this member ? Why not just use pcie_is_cxl() in aer_err_bus()?
>> This was added per Dan's request instead of using pcie_is_cxl().[1]
>>
>> [1] https://lore.kernel.org/linux-cxl/67abe1903a8ed_2d1e2942f@dwillia2-xfh.jf.intel.com.notmuch/
>>
>> -Terry
> 
> It looks like it is added to accommodate some future use cases. May be add some info about it in the aer_err_info struct. Just looking at the code, that member value mirrors pci_dev->is_cxl and where ever you read info->cxl, you can also read the value from pci_dev->is_cxl.

Right. pci_dev::is_cxl is currently only updated at device creation but could be tied 
to alternate protocol training and link status changes.

Terry

>>>>    
>>>>    	unsigned int id:16;
>>>>    
>>>> @@ -604,6 +605,11 @@ struct aer_err_info {
>>>>    	struct pcie_tlp_log tlp;	/* TLP Header */
>>>>    };
>>>>    
>>>> +static inline const char *aer_err_bus(struct aer_err_info *info)
>>>> +{
>>>> +	return info->is_cxl ? "CXL" : "PCIe";
>>>> +}
>>>> +
>>>>    int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
>>>>    void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
>>>>    
>>>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>>>> index a1cf8c7ef628..adb4b1123b9b 100644
>>>> --- a/drivers/pci/pcie/aer.c
>>>> +++ b/drivers/pci/pcie/aer.c
>>>> @@ -698,13 +698,14 @@ static void __aer_print_error(struct pci_dev *dev,
>>>>    
>>>>    void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>>>    {
>>>> +	const char *bus_type = aer_err_bus(info);
>>>>    	int layer, agent;
>>>>    	int id = pci_dev_id(dev);
>>>>    	const char *level;
>>>>    
>>>>    	if (!info->status) {
>>>> -		pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
>>>> -			aer_error_severity_string[info->severity]);
>>>> +		pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
>>>> +			bus_type, aer_error_severity_string[info->severity]);
>>>>    		goto out;
>>>>    	}
>>>>    
>>>> @@ -713,8 +714,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>>>    
>>>>    	level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR;
>>>>    
>>>> -	aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
>>>> -		   aer_error_severity_string[info->severity],
>>>> +	aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
>>>> +		   bus_type, aer_error_severity_string[info->severity],
>>>>    		   aer_error_layer[layer], aer_agent_string[agent]);
>>>>    
>>>>    	aer_printk(level, dev, "  device [%04x:%04x] error status/mask=%08x/%08x\n",
>>>> @@ -729,7 +730,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>>>>    	if (info->id && info->error_dev_num > 1 && info->id == id)
>>>>    		pci_err(dev, "  Error of this Agent is reported first\n");
>>>>    
>>>> -	trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
>>>> +	trace_aer_event(dev_name(&dev->dev), bus_type, (info->status & ~info->mask),
>>>>    			info->severity, info->tlp_header_valid, &info->tlp);
>>>>    }
>>>>    
>>>> @@ -763,6 +764,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
>>>>    void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>>>    		   struct aer_capability_regs *aer)
>>>>    {
>>>> +	const char *bus_type;
>>>>    	int layer, agent, tlp_header_valid = 0;
>>>>    	u32 status, mask;
>>>>    	struct aer_err_info info;
>>>> @@ -784,6 +786,9 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>>>    	info.status = status;
>>>>    	info.mask = mask;
>>>>    	info.first_error = PCI_ERR_CAP_FEP(aer->cap_control);
>>>> +	info.is_cxl = pcie_is_cxl(dev);
>>>> +
>>>> +	bus_type = aer_err_bus(&info);
>>>>    
>>>>    	pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
>>>>    	__aer_print_error(dev, &info);
>>>> @@ -797,7 +802,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>>>>    	if (tlp_header_valid)
>>>>    		pcie_print_tlp_log(dev, &aer->header_log, dev_fmt("  "));
>>>>    
>>>> -	trace_aer_event(dev_name(&dev->dev), (status & ~mask),
>>>> +	trace_aer_event(dev_name(&dev->dev), bus_type, (status & ~mask),
>>>>    			aer_severity, tlp_header_valid, &aer->header_log);
>>>>    }
>>>>    EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
>>>> @@ -1215,6 +1220,7 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
>>>>    	/* Must reset in this function */
>>>>    	info->status = 0;
>>>>    	info->tlp_header_valid = 0;
>>>> +	info->is_cxl = pcie_is_cxl(dev);
>>>>    
>>>>    	/* The device might not support AER */
>>>>    	if (!aer)
>>>> diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
>>>> index 14c9f943d53f..080829d59c36 100644
>>>> --- a/include/ras/ras_event.h
>>>> +++ b/include/ras/ras_event.h
>>>> @@ -297,15 +297,17 @@ TRACE_EVENT(non_standard_event,
>>>>    
>>>>    TRACE_EVENT(aer_event,
>>>>    	TP_PROTO(const char *dev_name,
>>>> +		 const char *bus_type,
>>>>    		 const u32 status,
>>>>    		 const u8 severity,
>>>>    		 const u8 tlp_header_valid,
>>>>    		 struct pcie_tlp_log *tlp),
>>>>    
>>>> -	TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
>>>> +	TP_ARGS(dev_name, bus_type, status, severity, tlp_header_valid, tlp),
>>>>    
>>>>    	TP_STRUCT__entry(
>>>>    		__string(	dev_name,	dev_name	)
>>>> +		__string(	bus_type,	bus_type	)
>>>>    		__field(	u32,		status		)
>>>>    		__field(	u8,		severity	)
>>>>    		__field(	u8, 		tlp_header_valid)
>>>> @@ -314,6 +316,7 @@ TRACE_EVENT(aer_event,
>>>>    
>>>>    	TP_fast_assign(
>>>>    		__assign_str(dev_name);
>>>> +		__assign_str(bus_type);
>>>>    		__entry->status		= status;
>>>>    		__entry->severity	= severity;
>>>>    		__entry->tlp_header_valid = tlp_header_valid;
>>>> @@ -325,8 +328,8 @@ TRACE_EVENT(aer_event,
>>>>    		}
>>>>    	),
>>>>    
>>>> -	TP_printk("%s PCIe Bus Error: severity=%s, %s, TLP Header=%s\n",
>>>> -		__get_str(dev_name),
>>>> +	TP_printk("%s %s Bus Error: severity=%s, %s, TLP Header=%s\n",
>>>> +		__get_str(dev_name), __get_str(bus_type),
>>>>    		__entry->severity == AER_CORRECTABLE ? "Corrected" :
>>>>    			__entry->severity == AER_FATAL ?
>>>>    			"Fatal" : "Uncorrected, non-fatal",
>>


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-03 17:22 ` [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors Terry Bowman
  2025-06-04  6:01   ` Dan Carpenter
@ 2025-06-04 22:50   ` Sathyanarayanan Kuppuswamy
  2025-06-05 14:04     ` Bowman, Terry
  2025-06-06  0:27   ` Dave Jiang
  2025-06-12 11:04   ` Jonathan Cameron
  3 siblings, 1 reply; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-04 22:50 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> CXL error handling will soon be moved from the AER driver into the CXL
> driver. This requires a notification mechanism for the AER driver to share
> the AER interrupt with the CXL driver. The notification will be used
> as an indication for the CXL drivers to handle and log the CXL RAS errors.
>
> Add a kfifo work queue to be used by the AER driver and CXL driver. The AER
> driver will be the sole kfifo producer adding work and the cxl_core will be
> the sole kfifo consumer removing work. Add the boilerplate kfifo support.
>
> Add CXL work queue handler registration functions in the AER driver. Export
> the functions allowing CXL driver to access. Implement registration
> functions for the CXL driver to assign or clear the work handler function.
>
> Introduce function cxl_create_prot_err_info() and 'struct cxl_prot_err_info'.
> Implement cxl_create_prot_err_info() to populate a 'struct cxl_prot_err_info'
> instance with the AER severity and the erring device's PCI SBDF. The SBDF
> details will be used to rediscover the erring device after the CXL driver
> dequeues the kfifo work. The device rediscovery will be introduced along
> with the CXL handling in future patches.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>   drivers/cxl/core/ras.c |  31 +++++++++-
>   drivers/cxl/cxlpci.h   |   1 +
>   drivers/pci/pcie/aer.c | 132 ++++++++++++++++++++++++++++-------------
>   include/linux/aer.h    |  36 +++++++++++
>   4 files changed, 157 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 485a831695c7..d35525e79e04 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -5,6 +5,7 @@
>   #include <linux/aer.h>
>   #include <cxl/event.h>
>   #include <cxlmem.h>
> +#include <cxlpci.h>
>   #include "trace.h"
>   
>   static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
> @@ -107,13 +108,41 @@ 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);
>   
> +#ifdef CONFIG_PCIEAER_CXL
> +
> +static void cxl_prot_err_work_fn(struct work_struct *work)
> +{
> +}
> +
> +#else
> +static void cxl_prot_err_work_fn(struct work_struct *work) { }
> +#endif /* CONFIG_PCIEAER_CXL */
> +
> +static struct work_struct cxl_prot_err_work;
> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
> +
>   int cxl_ras_init(void)
>   {
> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> +	int rc;
> +
> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> +	if (rc)
> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);
> +
> +	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
> +	if (rc) {
> +		pr_err("Failed to register native AER kfifo (%x)", rc);
> +		return rc;
> +	}
> +
> +	return 0;
>   }
>   
>   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_unregister_prot_err_work();
> +	cancel_work_sync(&cxl_prot_err_work);
>   }
> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
> index 54e219b0049e..6f1396ef7b77 100644
> --- a/drivers/cxl/cxlpci.h
> +++ b/drivers/cxl/cxlpci.h
> @@ -4,6 +4,7 @@
>   #define __CXL_PCI_H__
>   #include <linux/pci.h>
>   #include "cxl.h"
> +#include "linux/aer.h"
>   
>   #define CXL_MEMORY_PROGIF	0x10
>   
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index adb4b1123b9b..5350fa5be784 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -114,6 +114,14 @@ struct aer_stats {
>   static int pcie_aer_disable;
>   static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
>   
> +#if defined(CONFIG_PCIEAER_CXL)
> +#define CXL_ERROR_SOURCES_MAX          128
> +static DEFINE_KFIFO(cxl_prot_err_fifo, struct cxl_prot_err_work_data,
> +		    CXL_ERROR_SOURCES_MAX);
> +static DEFINE_SPINLOCK(cxl_prot_err_fifo_lock);
> +struct work_struct *cxl_prot_err_work;
> +#endif
> +
>   void pci_no_aer(void)
>   {
>   	pcie_aer_disable = 1;
> @@ -1004,45 +1012,17 @@ static bool is_internal_error(struct aer_err_info *info)
>   	return info->status & PCI_ERR_UNC_INTN;
>   }
>   
> -static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
>   {
> -	struct aer_err_info *info = (struct aer_err_info *)data;
> -	const struct pci_error_handlers *err_handler;
> +	if (!info || !info->is_cxl)
> +		return false;
>   
> -	if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
> -		return 0;
> +	/* Only CXL Endpoints are currently supported */
> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))
> +		return false;
>   
> -	/* Protect dev->driver */
> -	device_lock(&dev->dev);
> -
> -	err_handler = dev->driver ? dev->driver->err_handler : NULL;
> -	if (!err_handler)
> -		goto out;
> -
> -	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);
> -	}
> -out:
> -	device_unlock(&dev->dev);
> -	return 0;
> -}
> -
> -static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_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.
> -	 */
> -	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
> -	    is_internal_error(info))
> -		pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
> +	return is_internal_error(info);
>   }
>   
>   static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
> @@ -1056,13 +1036,17 @@ static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
>   	return *handles_cxl;
>   }
>   
> -static bool handles_cxl_errors(struct pci_dev *rcec)
> +static bool handles_cxl_errors(struct pci_dev *dev)
>   {
>   	bool handles_cxl = false;
>   
> -	if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
> -	    pcie_aer_is_native(rcec))
> -		pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
> +	if (!pcie_aer_is_native(dev))
> +		return false;
> +
> +	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
> +		pcie_walk_rcec(dev, handles_cxl_error_iter, &handles_cxl);
> +	else
> +		handles_cxl = pcie_is_cxl(dev);
>   
>   	return handles_cxl;
>   }
> @@ -1076,10 +1060,46 @@ static void cxl_rch_enable_rcec(struct pci_dev *rcec)
>   	pci_info(rcec, "CXL: Internal errors unmasked");
>   }
>   
> +static int cxl_create_prot_error_info(struct pci_dev *pdev,
> +				      struct aer_err_info *aer_err_info,
> +				      struct cxl_prot_error_info *cxl_err_info)
> +{
> +	cxl_err_info->severity = aer_err_info->severity;
> +
> +	cxl_err_info->function = PCI_FUNC(pdev->devfn);
> +	cxl_err_info->device = PCI_SLOT(pdev->devfn);
> +	cxl_err_info->bus = pdev->bus->number;
> +	cxl_err_info->segment = pci_domain_nr(pdev->bus);
> +
> +	return 0;
> +}
> +
> +static void forward_cxl_error(struct pci_dev *pdev, struct aer_err_info *aer_err_info)
> +{
> +	struct cxl_prot_err_work_data wd;
> +	struct cxl_prot_error_info *cxl_err_info = &wd.err_info;
> +
> +	cxl_create_prot_error_info(pdev, aer_err_info, cxl_err_info);
> +
> +	if (!kfifo_put(&cxl_prot_err_fifo, wd)) {
> +		dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
> +		return;
> +	}
> +
> +	schedule_work(cxl_prot_err_work);
> +}
> +
>   #else
>   static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
>   static inline void cxl_rch_handle_error(struct pci_dev *dev,
>   					struct aer_err_info *info) { }
> +static inline void forward_cxl_error(struct pci_dev *dev,
> +				    struct aer_err_info *info) { }
> +static inline bool handles_cxl_errors(struct pci_dev *dev)
> +{
> +	return false;
> +}
> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return 0; };
>   #endif
>   
>   /**
> @@ -1117,8 +1137,11 @@ 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)
>   {
> -	cxl_rch_handle_error(dev, info);
> -	pci_aer_handle_error(dev, info);
> +	if (is_cxl_error(dev, info))
> +		forward_cxl_error(dev, info);
> +	else
> +		pci_aer_handle_error(dev, info);
> +
>   	pci_dev_put(dev);
>   }
>   
> @@ -1582,6 +1605,31 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
>   	return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
>   }
>   
> +#if defined(CONFIG_PCIEAER_CXL)
> +
> +int cxl_register_prot_err_work(struct work_struct *work)
> +{
> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
> +	cxl_prot_err_work = work;
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_register_prot_err_work, "CXL");
> +
> +int cxl_unregister_prot_err_work(void)
> +{
> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
> +	cxl_prot_err_work = NULL;
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_unregister_prot_err_work, "CXL");
> +

Above two functions can never fail, right? What not make them return void?

> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd)
> +{
> +	return kfifo_get(&cxl_prot_err_fifo, wd);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_prot_err_kfifo_get, "CXL");
> +#endif
> +
>   static struct pcie_port_service_driver aerdriver = {
>   	.name		= "aer",
>   	.port_type	= PCIE_ANY_PORT,
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 02940be66324..550407240ab5 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -10,6 +10,7 @@
>   
>   #include <linux/errno.h>
>   #include <linux/types.h>
> +#include <linux/workqueue_types.h>
>   
>   #define AER_NONFATAL			0
>   #define AER_FATAL			1
> @@ -53,6 +54,27 @@ struct aer_capability_regs {
>   	u16 uncor_err_source;
>   };
>   
> +/**
> + * struct cxl_prot_err_info - Error information used in CXL error handling
> + * @severity: AER severity
> + * @function: Device's PCI function
> + * @device: Device's PCI device
> + * @bus: Device's PCI bus
> + * @segment: Device's PCI segment
> + */
> +struct cxl_prot_error_info {
> +	int severity;
> +
> +	u8 function;
> +	u8 device;
> +	u8 bus;
> +	u16 segment;
> +};
> +
> +struct cxl_prot_err_work_data {
> +	struct cxl_prot_error_info err_info;
> +};
> +
>   #if defined(CONFIG_PCIEAER)
>   int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>   int pcie_aer_is_native(struct pci_dev *dev);
> @@ -64,6 +86,20 @@ 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; }
>   #endif
>   
> +#if defined(CONFIG_PCIEAER_CXL)
> +int cxl_register_prot_err_work(struct work_struct *work);
> +int cxl_unregister_prot_err_work(void);
> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd);
> +#else
> +static inline int
> +cxl_register_prot_err_work(struct work_struct *work)
> +{
> +	return 0;
> +}
> +static inline int cxl_unregister_prot_err_work(void) { return 0; }
> +static inline int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd) { return 0; }
> +#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);

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-03 17:22 ` [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error Terry Bowman
  2025-06-04  6:05   ` Dan Carpenter
@ 2025-06-04 23:58   ` Sathyanarayanan Kuppuswamy
  2025-06-06 15:57   ` Dave Jiang
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-04 23:58 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> The AER driver is now designed to forward CXL protocol errors to the CXL
> driver. Update the CXL driver with functionality to dequeue the forwarded
> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
> error handling processing using the work received from the FIFO.
>
> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
> AER service driver. This will begin the CXL protocol error processing
> with a call to cxl_handle_prot_error().
>
> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
> previously in the AER driver.
>
> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
> and use in discovering the erring PCI device. Make scope based reference
> increments/decrements for the discovered PCI device and the associated
> CXL device.
>
> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
> RCH errors will be processed with a call to walk the associated Root
> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
> so the CXL driver can walk the RCEC's downstream bus, searching for
> the RCiEP.
>
> VH correctable error (CE) processing will call the CXL CE handler. VH
> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
> and pci_clean_device_status() used to clean up AER status after handling.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>   drivers/pci/pci.c       |  1 +
>   drivers/pci/pci.h       |  8 ----
>   drivers/pci/pcie/aer.c  |  1 +
>   drivers/pci/pcie/rcec.c |  1 +
>   include/linux/aer.h     |  2 +
>   include/linux/pci.h     | 10 +++++
>   7 files changed, 107 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index d35525e79e04..9ed5c682e128 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>   
>   #ifdef CONFIG_PCIEAER_CXL
>   
> +static void cxl_do_recovery(struct pci_dev *pdev)
> +{
> +}
> +
> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> +{
> +	struct cxl_prot_error_info *err_info = data;
> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
> +	struct cxl_dev_state *cxlds;
> +
> +	/*
> +	 * The capability, status, and control fields in Device 0,
> +	 * Function 0 DVSEC control the CXL functionality of the
> +	 * entire device (CXL 3.0, 8.1.3).

Nit: I think you give spec references with different versions across your code (v3.0, v3.1, v3.2).
May be you can stick to the latest?

> +	 */
> +	if (pdev->devfn != PCI_DEVFN(0, 0))
> +		return 0;
> +
> +	/*
> +	 * CXL Memory Devices must have the 502h class code set (CXL
> +	 * 3.0, 8.1.12.1).
> +	 */
> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> +		return 0;
> +
> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
> +		return 0;
> +
> +	cxlds = pci_get_drvdata(pdev);
> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +
> +	if (err_info->severity == AER_CORRECTABLE)
> +		cxl_cor_error_detected(pdev);
> +	else
> +		cxl_do_recovery(pdev);
> +
> +	return 1;
> +}
> +
> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
> +{
> +	unsigned int devfn = PCI_DEVFN(err_info->device,
> +				       err_info->function);
> +	struct pci_dev *pdev __free(pci_dev_put) =
> +		pci_get_domain_bus_and_slot(err_info->segment,
> +					    err_info->bus,
> +					    devfn);
> +	return pdev;
> +}
> +
> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
> +{
> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> +
> +	if (!pdev) {
> +		pr_err("Failed to find the CXL device\n");

Nit: Maybe including BDF value is more informative.

> +		return;
> +	}
> +
> +	/*
> +	 * 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.
> +	 */
> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
> +
> +	if (err_info->severity == AER_CORRECTABLE) {
> +		int aer = pdev->aer_cap;
> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +
> +		if (aer)
> +			pci_clear_and_set_config_dword(pdev,
> +						       aer + PCI_ERR_COR_STATUS,
> +						       0, PCI_ERR_COR_INTERNAL);
> +
> +		cxl_cor_error_detected(pdev);
> +
> +		pcie_clear_device_status(pdev);
> +	} else {
> +		cxl_do_recovery(pdev);
> +	}
> +}
> +
>   static void cxl_prot_err_work_fn(struct work_struct *work)
>   {
> +	struct cxl_prot_err_work_data wd;
> +
> +	while (cxl_prot_err_kfifo_get(&wd)) {
> +		struct cxl_prot_error_info *err_info = &wd.err_info;
> +
> +		cxl_handle_prot_error(err_info);
> +	}
>   }
>   
>   #else
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index e77d5b53c0ce..524ac32b744a 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
>   	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
>   	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
>   }
> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
>   #endif
>   
>   /**
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index d6296500b004..3c54a5ed803e 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
>   void pci_rcec_init(struct pci_dev *dev);
>   void pci_rcec_exit(struct pci_dev *dev);
>   void pcie_link_rcec(struct pci_dev *rcec);
> -void pcie_walk_rcec(struct pci_dev *rcec,
> -		    int (*cb)(struct pci_dev *, void *),
> -		    void *userdata);
>   #else
>   static inline void pci_rcec_init(struct pci_dev *dev) { }
>   static inline void pci_rcec_exit(struct pci_dev *dev) { }
>   static inline void pcie_link_rcec(struct pci_dev *rcec) { }
> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
> -				  int (*cb)(struct pci_dev *, void *),
> -				  void *userdata) { }
>   #endif
>   
>   #ifdef CONFIG_PCI_ATS
> @@ -967,7 +961,6 @@ void pci_no_aer(void);
>   void pci_aer_init(struct pci_dev *dev);
>   void pci_aer_exit(struct pci_dev *dev);
>   extern const struct attribute_group aer_stats_attr_group;
> -void pci_aer_clear_fatal_status(struct pci_dev *dev);
>   int pci_aer_clear_status(struct pci_dev *dev);
>   int pci_aer_raw_clear_status(struct pci_dev *dev);
>   void pci_save_aer_state(struct pci_dev *dev);
> @@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
>   static inline void pci_no_aer(void) { }
>   static inline void pci_aer_init(struct pci_dev *d) { }
>   static inline void pci_aer_exit(struct pci_dev *d) { }
> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>   static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
>   static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
>   static inline void pci_save_aer_state(struct pci_dev *dev) { }
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 5350fa5be784..6e88331c6303 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
>   	if (status)
>   		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
>   }
> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>   
>   /**
>    * pci_aer_raw_clear_status - Clear AER error registers.
> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
> index d0bcd141ac9c..fb6cf6449a1d 100644
> --- a/drivers/pci/pcie/rcec.c
> +++ b/drivers/pci/pcie/rcec.c
> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>   
>   	walk_rcec(walk_rcec_helper, &rcec_data);
>   }
> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
>   
>   void pci_rcec_init(struct pci_dev *dev)
>   {
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 550407240ab5..c9a18eca16f8 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
>   
>   #if defined(CONFIG_PCIEAER)
>   int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
>   int pcie_aer_is_native(struct pci_dev *dev);
>   #else
>   static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>   {
>   	return -EINVAL;
>   }
> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>   static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>   #endif
>   
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index bff3009f9ff0..cd53715d53f3 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
>   
>   int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
>   			  bool use_lt);
> +void pcie_walk_rcec(struct pci_dev *rcec,
> +		    int (*cb)(struct pci_dev *, void *),
> +		    void *userdata);
>   #else
>   #define pcie_ports_disabled	true
>   #define pcie_ports_native	false
> @@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
>   {
>   	return -EOPNOTSUPP;
>   }
> +
> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
> +				  int (*cb)(struct pci_dev *, void *),
> +				  void *userdata) { }
> +
>   #endif
>   
> +void pcie_clear_device_status(struct pci_dev *dev);
> +
>   #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
>   #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
>   #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-04 22:50   ` Sathyanarayanan Kuppuswamy
@ 2025-06-05 14:04     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-05 14:04 UTC (permalink / raw)
  To: Sathyanarayanan Kuppuswamy, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, dave.jiang, alison.schofield, vishal.l.verma,
	ira.weiny, dan.j.williams, bhelgaas, bp, ming.li, shiju.jose,
	dan.carpenter, Smita.KoralahalliChannabasappa, kobayashi.da-06,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/4/2025 5:50 PM, Sathyanarayanan Kuppuswamy wrote:
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> CXL error handling will soon be moved from the AER driver into the CXL
>> driver. This requires a notification mechanism for the AER driver to share
>> the AER interrupt with the CXL driver. The notification will be used
>> as an indication for the CXL drivers to handle and log the CXL RAS errors.
>>
>> Add a kfifo work queue to be used by the AER driver and CXL driver. The AER
>> driver will be the sole kfifo producer adding work and the cxl_core will be
>> the sole kfifo consumer removing work. Add the boilerplate kfifo support.
>>
>> Add CXL work queue handler registration functions in the AER driver. Export
>> the functions allowing CXL driver to access. Implement registration
>> functions for the CXL driver to assign or clear the work handler function.
>>
>> Introduce function cxl_create_prot_err_info() and 'struct cxl_prot_err_info'.
>> Implement cxl_create_prot_err_info() to populate a 'struct cxl_prot_err_info'
>> instance with the AER severity and the erring device's PCI SBDF. The SBDF
>> details will be used to rediscover the erring device after the CXL driver
>> dequeues the kfifo work. The device rediscovery will be introduced along
>> with the CXL handling in future patches.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>   drivers/cxl/core/ras.c |  31 +++++++++-
>>   drivers/cxl/cxlpci.h   |   1 +
>>   drivers/pci/pcie/aer.c | 132 ++++++++++++++++++++++++++++-------------
>>   include/linux/aer.h    |  36 +++++++++++
>>   4 files changed, 157 insertions(+), 43 deletions(-)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 485a831695c7..d35525e79e04 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -5,6 +5,7 @@
>>   #include <linux/aer.h>
>>   #include <cxl/event.h>
>>   #include <cxlmem.h>
>> +#include <cxlpci.h>
>>   #include "trace.h"
>>   
>>   static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
>> @@ -107,13 +108,41 @@ 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);
>>   
>> +#ifdef CONFIG_PCIEAER_CXL
>> +
>> +static void cxl_prot_err_work_fn(struct work_struct *work)
>> +{
>> +}
>> +
>> +#else
>> +static void cxl_prot_err_work_fn(struct work_struct *work) { }
>> +#endif /* CONFIG_PCIEAER_CXL */
>> +
>> +static struct work_struct cxl_prot_err_work;
>> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
>> +
>>   int cxl_ras_init(void)
>>   {
>> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>> +	int rc;
>> +
>> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>> +	if (rc)
>> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);
>> +
>> +	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
>> +	if (rc) {
>> +		pr_err("Failed to register native AER kfifo (%x)", rc);
>> +		return rc;
>> +	}
>> +
>> +	return 0;
>>   }
>>   
>>   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_unregister_prot_err_work();
>> +	cancel_work_sync(&cxl_prot_err_work);
>>   }
>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>> index 54e219b0049e..6f1396ef7b77 100644
>> --- a/drivers/cxl/cxlpci.h
>> +++ b/drivers/cxl/cxlpci.h
>> @@ -4,6 +4,7 @@
>>   #define __CXL_PCI_H__
>>   #include <linux/pci.h>
>>   #include "cxl.h"
>> +#include "linux/aer.h"
>>   
>>   #define CXL_MEMORY_PROGIF	0x10
>>   
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index adb4b1123b9b..5350fa5be784 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -114,6 +114,14 @@ struct aer_stats {
>>   static int pcie_aer_disable;
>>   static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
>>   
>> +#if defined(CONFIG_PCIEAER_CXL)
>> +#define CXL_ERROR_SOURCES_MAX          128
>> +static DEFINE_KFIFO(cxl_prot_err_fifo, struct cxl_prot_err_work_data,
>> +		    CXL_ERROR_SOURCES_MAX);
>> +static DEFINE_SPINLOCK(cxl_prot_err_fifo_lock);
>> +struct work_struct *cxl_prot_err_work;
>> +#endif
>> +
>>   void pci_no_aer(void)
>>   {
>>   	pcie_aer_disable = 1;
>> @@ -1004,45 +1012,17 @@ static bool is_internal_error(struct aer_err_info *info)
>>   	return info->status & PCI_ERR_UNC_INTN;
>>   }
>>   
>> -static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
>> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
>>   {
>> -	struct aer_err_info *info = (struct aer_err_info *)data;
>> -	const struct pci_error_handlers *err_handler;
>> +	if (!info || !info->is_cxl)
>> +		return false;
>>   
>> -	if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
>> -		return 0;
>> +	/* Only CXL Endpoints are currently supported */
>> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
>> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))
>> +		return false;
>>   
>> -	/* Protect dev->driver */
>> -	device_lock(&dev->dev);
>> -
>> -	err_handler = dev->driver ? dev->driver->err_handler : NULL;
>> -	if (!err_handler)
>> -		goto out;
>> -
>> -	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);
>> -	}
>> -out:
>> -	device_unlock(&dev->dev);
>> -	return 0;
>> -}
>> -
>> -static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_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.
>> -	 */
>> -	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
>> -	    is_internal_error(info))
>> -		pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
>> +	return is_internal_error(info);
>>   }
>>   
>>   static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
>> @@ -1056,13 +1036,17 @@ static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
>>   	return *handles_cxl;
>>   }
>>   
>> -static bool handles_cxl_errors(struct pci_dev *rcec)
>> +static bool handles_cxl_errors(struct pci_dev *dev)
>>   {
>>   	bool handles_cxl = false;
>>   
>> -	if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
>> -	    pcie_aer_is_native(rcec))
>> -		pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
>> +	if (!pcie_aer_is_native(dev))
>> +		return false;
>> +
>> +	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
>> +		pcie_walk_rcec(dev, handles_cxl_error_iter, &handles_cxl);
>> +	else
>> +		handles_cxl = pcie_is_cxl(dev);
>>   
>>   	return handles_cxl;
>>   }
>> @@ -1076,10 +1060,46 @@ static void cxl_rch_enable_rcec(struct pci_dev *rcec)
>>   	pci_info(rcec, "CXL: Internal errors unmasked");
>>   }
>>   
>> +static int cxl_create_prot_error_info(struct pci_dev *pdev,
>> +				      struct aer_err_info *aer_err_info,
>> +				      struct cxl_prot_error_info *cxl_err_info)
>> +{
>> +	cxl_err_info->severity = aer_err_info->severity;
>> +
>> +	cxl_err_info->function = PCI_FUNC(pdev->devfn);
>> +	cxl_err_info->device = PCI_SLOT(pdev->devfn);
>> +	cxl_err_info->bus = pdev->bus->number;
>> +	cxl_err_info->segment = pci_domain_nr(pdev->bus);
>> +
>> +	return 0;
>> +}
>> +
>> +static void forward_cxl_error(struct pci_dev *pdev, struct aer_err_info *aer_err_info)
>> +{
>> +	struct cxl_prot_err_work_data wd;
>> +	struct cxl_prot_error_info *cxl_err_info = &wd.err_info;
>> +
>> +	cxl_create_prot_error_info(pdev, aer_err_info, cxl_err_info);
>> +
>> +	if (!kfifo_put(&cxl_prot_err_fifo, wd)) {
>> +		dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
>> +		return;
>> +	}
>> +
>> +	schedule_work(cxl_prot_err_work);
>> +}
>> +
>>   #else
>>   static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
>>   static inline void cxl_rch_handle_error(struct pci_dev *dev,
>>   					struct aer_err_info *info) { }
>> +static inline void forward_cxl_error(struct pci_dev *dev,
>> +				    struct aer_err_info *info) { }
>> +static inline bool handles_cxl_errors(struct pci_dev *dev)
>> +{
>> +	return false;
>> +}
>> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return 0; };
>>   #endif
>>   
>>   /**
>> @@ -1117,8 +1137,11 @@ 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)
>>   {
>> -	cxl_rch_handle_error(dev, info);
>> -	pci_aer_handle_error(dev, info);
>> +	if (is_cxl_error(dev, info))
>> +		forward_cxl_error(dev, info);
>> +	else
>> +		pci_aer_handle_error(dev, info);
>> +
>>   	pci_dev_put(dev);
>>   }
>>   
>> @@ -1582,6 +1605,31 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
>>   	return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
>>   }
>>   
>> +#if defined(CONFIG_PCIEAER_CXL)
>> +
>> +int cxl_register_prot_err_work(struct work_struct *work)
>> +{
>> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
>> +	cxl_prot_err_work = work;
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_register_prot_err_work, "CXL");
>> +
>> +int cxl_unregister_prot_err_work(void)
>> +{
>> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
>> +	cxl_prot_err_work = NULL;
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_unregister_prot_err_work, "CXL");
>> +
> Above two functions can never fail, right? What not make them return void?

You are correct. Good point. Thanks, I'll make the change.

Terry
>> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd)
>> +{
>> +	return kfifo_get(&cxl_prot_err_fifo, wd);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_prot_err_kfifo_get, "CXL");
>> +#endif
>> +
>>   static struct pcie_port_service_driver aerdriver = {
>>   	.name		= "aer",
>>   	.port_type	= PCIE_ANY_PORT,
>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>> index 02940be66324..550407240ab5 100644
>> --- a/include/linux/aer.h
>> +++ b/include/linux/aer.h
>> @@ -10,6 +10,7 @@
>>   
>>   #include <linux/errno.h>
>>   #include <linux/types.h>
>> +#include <linux/workqueue_types.h>
>>   
>>   #define AER_NONFATAL			0
>>   #define AER_FATAL			1
>> @@ -53,6 +54,27 @@ struct aer_capability_regs {
>>   	u16 uncor_err_source;
>>   };
>>   
>> +/**
>> + * struct cxl_prot_err_info - Error information used in CXL error handling
>> + * @severity: AER severity
>> + * @function: Device's PCI function
>> + * @device: Device's PCI device
>> + * @bus: Device's PCI bus
>> + * @segment: Device's PCI segment
>> + */
>> +struct cxl_prot_error_info {
>> +	int severity;
>> +
>> +	u8 function;
>> +	u8 device;
>> +	u8 bus;
>> +	u16 segment;
>> +};
>> +
>> +struct cxl_prot_err_work_data {
>> +	struct cxl_prot_error_info err_info;
>> +};
>> +
>>   #if defined(CONFIG_PCIEAER)
>>   int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>>   int pcie_aer_is_native(struct pci_dev *dev);
>> @@ -64,6 +86,20 @@ 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; }
>>   #endif
>>   
>> +#if defined(CONFIG_PCIEAER_CXL)
>> +int cxl_register_prot_err_work(struct work_struct *work);
>> +int cxl_unregister_prot_err_work(void);
>> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd);
>> +#else
>> +static inline int
>> +cxl_register_prot_err_work(struct work_struct *work)
>> +{
>> +	return 0;
>> +}
>> +static inline int cxl_unregister_prot_err_work(void) { return 0; }
>> +static inline int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd) { return 0; }
>> +#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);


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
  2025-06-03 17:22 ` [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
@ 2025-06-05 15:14   ` Sathyanarayanan Kuppuswamy
  2025-06-05 16:01     ` Bowman, Terry
  2025-06-06 16:45   ` Dave Jiang
  2025-06-12 16:06   ` Jonathan Cameron
  2 siblings, 1 reply; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-05 15:14 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> Create cxl_do_recovery() to provide uncorrectable protocol error (UCE)
> handling. Follow similar design as found in PCIe error driver,
> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>
> Copy the PCI error driver's merge_result() and rename as cxl_merge_result().
> Introduce PCI_ERS_RESULT_PANIC and add support in the cxl_merge_result()
> routine.
>
> Copy pci_walk_bridge() to cxl_walk_bridge(). Make a change to walk the
> first device in all cases.
>
> Copy the PCI error driver's report_error_detected() to cxl_report_error_detected().
> Note, only CXL Endpoints are currently supported. Add locking for PCI
> device as done in PCI's report_error_detected(). Add reference counting for
> the CXL device responsible for cleanup of the CXL RAS. This is necessary
> to prevent the RAS registers from disappearing before logging is completed.
>
> Call panic() to halt the system in the case of uncorrectable errors (UCE)
> in cxl_do_recovery(). Export pci_aer_clear_fatal_status() for CXL to use
> if a UCE is not found. In this case the AER status must be cleared and
> uses pci_aer_clear_fatal_status().
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>   drivers/cxl/core/ras.c | 79 ++++++++++++++++++++++++++++++++++++++++++
>   include/linux/pci.h    |  3 ++
>   2 files changed, 82 insertions(+)
>
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 9ed5c682e128..715f7221ea3a 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -110,8 +110,87 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>   
>   #ifdef CONFIG_PCIEAER_CXL
>   
> +static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
> +					 enum pci_ers_result new)
> +{
> +	if (new == PCI_ERS_RESULT_PANIC)
> +		return PCI_ERS_RESULT_PANIC;
> +
> +	if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
> +		return PCI_ERS_RESULT_NO_AER_DRIVER;
> +
> +	if (new == PCI_ERS_RESULT_NONE)
> +		return orig;
> +
> +	switch (orig) {
> +	case PCI_ERS_RESULT_CAN_RECOVER:
> +	case PCI_ERS_RESULT_RECOVERED:
> +		orig = new;
> +		break;
> +	case PCI_ERS_RESULT_DISCONNECT:
> +		if (new == PCI_ERS_RESULT_NEED_RESET)
> +			orig = PCI_ERS_RESULT_NEED_RESET;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return orig;
> +}
> +
> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
> +{
> +	pci_ers_result_t vote, *result = data;
> +	struct cxl_dev_state *cxlds;
> +
> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
> +		return 0;
> +
> +	cxlds = pci_get_drvdata(pdev);
> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +
> +	device_lock(&pdev->dev);
> +	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
> +	*result = cxl_merge_result(*result, vote);
> +	device_unlock(&pdev->dev);
> +
> +	return 0;
> +}
> +
> +static void cxl_walk_bridge(struct pci_dev *bridge,
> +			    int (*cb)(struct pci_dev *, void *),
> +			    void *userdata)
> +{
> +	if (cb(bridge, userdata))
> +		return;
> +
> +	if (bridge->subordinate)
> +		pci_walk_bus(bridge->subordinate, cb, userdata);
> +}
> +
>   static void cxl_do_recovery(struct pci_dev *pdev)
>   {
> +	struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
> +	pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
> +
> +	cxl_walk_bridge(pdev, cxl_report_error_detected, &status);
> +	if (status == PCI_ERS_RESULT_PANIC)
> +		panic("CXL cachemem error.");
> +
> +	/*
> +	 * If we have native control of AER, clear error status in the device
> +	 * that detected the error.  If the platform retained control of AER,
> +	 * it is responsible for clearing this status.  In that case, the
> +	 * signaling device may not even be visible to the OS.
> +	 */
> +	if (host->native_aer) {

You don't need to check for pcie_ports_native ?

> +		pcie_clear_device_status(pdev);
> +		pci_aer_clear_nonfatal_status(pdev);
> +		pci_aer_clear_fatal_status(pdev);
> +	}

Since you want to clear all AER error status, what about correctable status?

> +
> +	pci_info(pdev, "CXL uncorrectable error.\n");

pci_errr?

>   }
>   
>   static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index cd53715d53f3..b0e7545162de 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -870,6 +870,9 @@ enum pci_ers_result {
>   
>   	/* No AER capabilities registered for the driver */
>   	PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
> +
> +	/* System is unstable, panic  */
> +	PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,

Since this error state is specific to CXL, add it part of the comment. Otherwise,
other PCIe drivers may also use it.


>   };
>   
>   /* PCI bus error event callbacks */

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
  2025-06-05 15:14   ` Sathyanarayanan Kuppuswamy
@ 2025-06-05 16:01     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-05 16:01 UTC (permalink / raw)
  To: Sathyanarayanan Kuppuswamy, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, dave.jiang, alison.schofield, vishal.l.verma,
	ira.weiny, dan.j.williams, bhelgaas, bp, ming.li, shiju.jose,
	dan.carpenter, Smita.KoralahalliChannabasappa, kobayashi.da-06,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/5/2025 10:14 AM, Sathyanarayanan Kuppuswamy wrote:
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> Create cxl_do_recovery() to provide uncorrectable protocol error (UCE)
>> handling. Follow similar design as found in PCIe error driver,
>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>
>> Copy the PCI error driver's merge_result() and rename as cxl_merge_result().
>> Introduce PCI_ERS_RESULT_PANIC and add support in the cxl_merge_result()
>> routine.
>>
>> Copy pci_walk_bridge() to cxl_walk_bridge(). Make a change to walk the
>> first device in all cases.
>>
>> Copy the PCI error driver's report_error_detected() to cxl_report_error_detected().
>> Note, only CXL Endpoints are currently supported. Add locking for PCI
>> device as done in PCI's report_error_detected(). Add reference counting for
>> the CXL device responsible for cleanup of the CXL RAS. This is necessary
>> to prevent the RAS registers from disappearing before logging is completed.
>>
>> Call panic() to halt the system in the case of uncorrectable errors (UCE)
>> in cxl_do_recovery(). Export pci_aer_clear_fatal_status() for CXL to use
>> if a UCE is not found. In this case the AER status must be cleared and
>> uses pci_aer_clear_fatal_status().
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>   drivers/cxl/core/ras.c | 79 ++++++++++++++++++++++++++++++++++++++++++
>>   include/linux/pci.h    |  3 ++
>>   2 files changed, 82 insertions(+)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 9ed5c682e128..715f7221ea3a 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -110,8 +110,87 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>   
>>   #ifdef CONFIG_PCIEAER_CXL
>>   
>> +static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
>> +					 enum pci_ers_result new)
>> +{
>> +	if (new == PCI_ERS_RESULT_PANIC)
>> +		return PCI_ERS_RESULT_PANIC;
>> +
>> +	if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
>> +		return PCI_ERS_RESULT_NO_AER_DRIVER;
>> +
>> +	if (new == PCI_ERS_RESULT_NONE)
>> +		return orig;
>> +
>> +	switch (orig) {
>> +	case PCI_ERS_RESULT_CAN_RECOVER:
>> +	case PCI_ERS_RESULT_RECOVERED:
>> +		orig = new;
>> +		break;
>> +	case PCI_ERS_RESULT_DISCONNECT:
>> +		if (new == PCI_ERS_RESULT_NEED_RESET)
>> +			orig = PCI_ERS_RESULT_NEED_RESET;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return orig;
>> +}
>> +
>> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
>> +{
>> +	pci_ers_result_t vote, *result = data;
>> +	struct cxl_dev_state *cxlds;
>> +
>> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
>> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
>> +		return 0;
>> +
>> +	cxlds = pci_get_drvdata(pdev);
>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>> +
>> +	device_lock(&pdev->dev);
>> +	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
>> +	*result = cxl_merge_result(*result, vote);
>> +	device_unlock(&pdev->dev);
>> +
>> +	return 0;
>> +}
>> +
>> +static void cxl_walk_bridge(struct pci_dev *bridge,
>> +			    int (*cb)(struct pci_dev *, void *),
>> +			    void *userdata)
>> +{
>> +	if (cb(bridge, userdata))
>> +		return;
>> +
>> +	if (bridge->subordinate)
>> +		pci_walk_bus(bridge->subordinate, cb, userdata);
>> +}
>> +
>>   static void cxl_do_recovery(struct pci_dev *pdev)
>>   {
>> +	struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
>> +	pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
>> +
>> +	cxl_walk_bridge(pdev, cxl_report_error_detected, &status);
>> +	if (status == PCI_ERS_RESULT_PANIC)
>> +		panic("CXL cachemem error.");
>> +
>> +	/*
>> +	 * If we have native control of AER, clear error status in the device
>> +	 * that detected the error.  If the platform retained control of AER,
>> +	 * it is responsible for clearing this status.  In that case, the
>> +	 * signaling device may not even be visible to the OS.
>> +	 */
>> +	if (host->native_aer) {
> You don't need to check for pcie_ports_native ?
You're correct. I need to check pcie_ports_native for case when the user commandline includes
'pcie_ports=native'. I'll add call to AER driver's cxl_error_is_native() that checks
pcie_ports_native and host->native_aer. Thanks.

>> +		pcie_clear_device_status(pdev);
>> +		pci_aer_clear_nonfatal_status(pdev);
>> +		pci_aer_clear_fatal_status(pdev);
>> +	}
> Since you want to clear all AER error status, what about correctable status?
I intentionally left out the CE status clear as it should be properly logged
in the CE handlers.
>
>> +
>> +	pci_info(pdev, "CXL uncorrectable error.\n");
> pci_errr?
I think this can be removed. I believe this was left over from debugging. At this point the
UCE logging has already occurred making this unnecessary in production. Let me know if
you want to keep it with the recommended change.

>>   }
>>   
>>   static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index cd53715d53f3..b0e7545162de 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -870,6 +870,9 @@ enum pci_ers_result {
>>   
>>   	/* No AER capabilities registered for the driver */
>>   	PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
>> +
>> +	/* System is unstable, panic  */
>> +	PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,
> Since this error state is specific to CXL, add it part of the comment. Otherwise,
> other PCIe drivers may also use it.
Yes, good point. I'll change.

Thanks for reviewing.

Terry

>
>>   };
>>   
>>   /* PCI bus error event callbacks */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 08/16] cxl/pci: Update RAS handler interfaces to also support CXL Ports
  2025-06-03 17:22 ` [PATCH v9 08/16] cxl/pci: Update RAS handler interfaces to also support CXL Ports Terry Bowman
@ 2025-06-05 16:42   ` Sathyanarayanan Kuppuswamy
  0 siblings, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-05 16:42 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> CXL PCIe Port Protocol Error handling support will be added to the
> CXL drivers in the future. In preparation, rename the existing
> interfaces to support handling all CXL PCIe Port Protocol Errors.
>
> The driver's RAS support functions currently rely on a 'struct
> cxl_dev_state' type parameter, which is not available for CXL Port
> devices. However, since the same CXL RAS capability structure is
> needed across most CXL components and devices, a common handling
> approach should be adopted.
>
> To accommodate this, update the __cxl_handle_cor_ras() and
> __cxl_handle_ras() functions to use a `struct device` instead of
> `struct cxl_dev_state`.
>
> No functional changes are introduced.
>
> [1] CXL 3.1 Spec, 8.2.4 CXL.cache and CXL.mem Registers
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Alejandro Lucero <alucerop@amd.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>
> Reviewed-by: Gregory Price <gourry@gourry.net>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/cxl/core/pci.c | 17 ++++++++---------
>   1 file changed, 8 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index 317cd0a91ffe..78735da7e63d 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -664,7 +664,7 @@ void read_cdat_data(struct cxl_port *port)
>   }
>   EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
>   
> -static void __cxl_handle_cor_ras(struct cxl_dev_state *cxlds,
> +static void __cxl_handle_cor_ras(struct device *dev,
>   				 void __iomem *ras_base)
>   {
>   	void __iomem *addr;
> @@ -677,13 +677,13 @@ static void __cxl_handle_cor_ras(struct cxl_dev_state *cxlds,
>   	status = readl(addr);
>   	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
>   		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
> -		trace_cxl_aer_correctable_error(cxlds->cxlmd, status);
> +		trace_cxl_aer_correctable_error(to_cxl_memdev(dev), status);
>   	}
>   }
>   
>   static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
>   {
> -	return __cxl_handle_cor_ras(cxlds, cxlds->regs.ras);
> +	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
>   }
>   
>   /* CXL spec rev3.0 8.2.4.16.1 */
> @@ -707,8 +707,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.
>    */
> -static bool __cxl_handle_ras(struct cxl_dev_state *cxlds,
> -				  void __iomem *ras_base)
> +static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
>   {
>   	u32 hl[CXL_HEADERLOG_SIZE_U32];
>   	void __iomem *addr;
> @@ -735,7 +734,7 @@ static bool __cxl_handle_ras(struct cxl_dev_state *cxlds,
>   	}
>   
>   	header_log_copy(ras_base, hl);
> -	trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe, hl);
> +	trace_cxl_aer_uncorrectable_error(to_cxl_memdev(dev), status, fe, hl);
>   	writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
>   
>   	return true;
> @@ -743,7 +742,7 @@ static bool __cxl_handle_ras(struct cxl_dev_state *cxlds,
>   
>   static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>   {
> -	return __cxl_handle_ras(cxlds, cxlds->regs.ras);
> +	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
>   }
>   
>   #ifdef CONFIG_PCIEAER_CXL
> @@ -751,13 +750,13 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>   static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
>   					  struct cxl_dport *dport)
>   {
> -	return __cxl_handle_cor_ras(cxlds, dport->regs.ras);
> +	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, dport->regs.ras);
>   }
>   
>   static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
>   				       struct cxl_dport *dport)
>   {
> -	return __cxl_handle_ras(cxlds, dport->regs.ras);
> +	return __cxl_handle_ras(&cxlds->cxlmd->dev, dport->regs.ras);
>   }
>   
>   /*

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped
  2025-06-03 17:22 ` [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped Terry Bowman
@ 2025-06-05 16:42   ` Sathyanarayanan Kuppuswamy
  2025-06-06 17:27   ` Dave Jiang
  1 sibling, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-05 16:42 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> The CXL RAS handlers do not currently log if the RAS registers are
> unmapped. This is needed in order to help debug CXL error handling. Update
> the CXL driver to log a warning message if the RAS register block is
> unmapped during RAS error handling.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/cxl/core/pci.c | 8 ++++++--
>   1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index 78735da7e63d..186a5a20b951 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -670,8 +670,10 @@ static void __cxl_handle_cor_ras(struct device *dev,
>   	void __iomem *addr;
>   	u32 status;
>   
> -	if (!ras_base)
> +	if (!ras_base) {
> +		dev_warn_once(dev, "CXL RAS register block is not mapped");
>   		return;
> +	}
>   
>   	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
>   	status = readl(addr);
> @@ -714,8 +716,10 @@ static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
>   	u32 status;
>   	u32 fe;
>   
> -	if (!ras_base)
> +	if (!ras_base) {
> +		dev_warn_once(dev, "CXL RAS register block is not mapped");
>   		return false;
> +	}
>   
>   	addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
>   	status = readl(addr);

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
  2025-06-03 17:22 ` [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports Terry Bowman
@ 2025-06-05 16:49   ` Sathyanarayanan Kuppuswamy
  2025-06-06  9:08   ` Shiju Jose
  1 sibling, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-05 16:49 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> CXL currently has separate trace routines for CXL Port errors and CXL
> Endpoint errors. This is inconvenient for the user because they must enable
> 2 sets of trace routines. Make updates to the trace logging such that a
> single trace routine logs both CXL Endpoint and CXL Port protocol errors.
>
> Rename the 'host' field from the CXL Endpoint trace to 'parent' in the
> unified trace routines. 'host' does not correctly apply to CXL Port
> devices. Parent is more general and applies to CXL Port devices and CXL
> Endpoints.
>
> Add serial number parameter to the trace logging. This is used for EPs
> and 0 is provided for CXL port devices without a serial number.
>
> Below is output of correctable and uncorrectable protocol error logging.
> CXL Root Port and CXL Endpoint examples are included below.
>
> Root Port:
> cxl_aer_correctable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0 status='CRC Threshold Hit'
> cxl_aer_uncorrectable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0 status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity Error'
>
> Endpoint:
> cxl_aer_correctable_error: device=mem3 parent=0000:0f:00.0 serial=0 status='CRC Threshold Hit'
> cxl_aer_uncorrectable_error: device=mem3 parent=0000:0f:00.0 serial: 0 status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity Error'
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---


Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>


>   drivers/cxl/core/pci.c   | 18 +++++----
>   drivers/cxl/core/ras.c   | 14 ++++---
>   drivers/cxl/core/trace.h | 84 +++++++++-------------------------------
>   3 files changed, 37 insertions(+), 79 deletions(-)
>
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index 186a5a20b951..0f4c07fd64a5 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -664,7 +664,7 @@ void read_cdat_data(struct cxl_port *port)
>   }
>   EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
>   
> -static void __cxl_handle_cor_ras(struct device *dev,
> +static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>   				 void __iomem *ras_base)
>   {
>   	void __iomem *addr;
> @@ -679,13 +679,13 @@ static void __cxl_handle_cor_ras(struct device *dev,
>   	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);
> +		trace_cxl_aer_correctable_error(dev, serial, status);
>   	}
>   }
>   
>   static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
>   {
> -	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
> +	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>   }
>   
>   /* CXL spec rev3.0 8.2.4.16.1 */
> @@ -709,7 +709,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.
>    */
> -static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
> +static bool __cxl_handle_ras(struct device *dev, u64 serial,
> +			     void __iomem *ras_base)
>   {
>   	u32 hl[CXL_HEADERLOG_SIZE_U32];
>   	void __iomem *addr;
> @@ -738,7 +739,7 @@ static 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);
> +	trace_cxl_aer_uncorrectable_error(dev, serial, status, fe, hl);
>   	writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
>   
>   	return true;
> @@ -746,7 +747,8 @@ static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
>   
>   static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>   {
> -	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->regs.ras);
> +
> +	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>   }
>   
>   #ifdef CONFIG_PCIEAER_CXL
> @@ -754,13 +756,13 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>   static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
>   					  struct cxl_dport *dport)
>   {
> -	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, dport->regs.ras);
> +	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
>   }
>   
>   static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
>   				       struct cxl_dport *dport)
>   {
> -	return __cxl_handle_ras(&cxlds->cxlmd->dev, dport->regs.ras);
> +	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
>   }
>   
>   /*
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 715f7221ea3a..0ef8c2068c0c 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -13,7 +13,7 @@ static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
>   {
>   	u32 status = ras_cap.cor_status & ~ras_cap.cor_mask;
>   
> -	trace_cxl_port_aer_correctable_error(&pdev->dev, status);
> +	trace_cxl_aer_correctable_error(&pdev->dev, 0, status);
>   }
>   
>   static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
> @@ -28,8 +28,8 @@ static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev,
>   	else
>   		fe = status;
>   
> -	trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe,
> -					       ras_cap.header_log);
> +	trace_cxl_aer_uncorrectable_error(&pdev->dev, 0, status, fe,
> +					  ras_cap.header_log);
>   }
>   
>   static void cxl_cper_trace_corr_prot_err(struct pci_dev *pdev,
> @@ -42,7 +42,8 @@ static void cxl_cper_trace_corr_prot_err(struct pci_dev *pdev,
>   	if (!cxlds)
>   		return;
>   
> -	trace_cxl_aer_correctable_error(cxlds->cxlmd, status);
> +	trace_cxl_aer_correctable_error(&cxlds->cxlmd->dev, cxlds->serial,
> +					status);
>   }
>   
>   static void cxl_cper_trace_uncorr_prot_err(struct pci_dev *pdev,
> @@ -62,8 +63,9 @@ static void cxl_cper_trace_uncorr_prot_err(struct pci_dev *pdev,
>   	else
>   		fe = status;
>   
> -	trace_cxl_aer_uncorrectable_error(cxlds->cxlmd, status, fe,
> -					  ras_cap.header_log);
> +	trace_cxl_aer_uncorrectable_error(&cxlds->cxlmd->dev,
> +					  cxlds->serial, status,
> +					  fe, ras_cap.header_log);
>   }
>   
>   static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data)
> diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
> index 25ebfbc1616c..8c91b0f3d165 100644
> --- a/drivers/cxl/core/trace.h
> +++ b/drivers/cxl/core/trace.h
> @@ -48,49 +48,22 @@
>   	{ 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_SIZE_U32)
> -	),
> -	TP_fast_assign(
> -		__assign_str(device);
> -		__assign_str(host);
> -		__entry->status = status;
> -		__entry->first_error = fe;
> -		/*
> -		 * Embed the 512B headerlog data for user app retrieval and
> -		 * parsing, but no need to print this in the trace buffer.
> -		 */
> -		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
> -	),
> -	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 device *dev, u64 serial, u32 status, u32 fe,
> +		 u32 *hl),
> +	TP_ARGS(dev, serial, status, fe, hl),
>   	TP_STRUCT__entry(
> -		__string(memdev, dev_name(&cxlmd->dev))
> -		__string(host, dev_name(cxlmd->dev.parent))
> +		__string(name, dev_name(dev))
> +		__string(parent, dev_name(dev->parent))
>   		__field(u64, serial)
>   		__field(u32, status)
>   		__field(u32, first_error)
>   		__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
>   	),
>   	TP_fast_assign(
> -		__assign_str(memdev);
> -		__assign_str(host);
> -		__entry->serial = cxlmd->cxlds->serial;
> +		__assign_str(name);
> +		__assign_str(parent);
> +		__entry->serial = serial;
>   		__entry->status = status;
>   		__entry->first_error = fe;
>   		/*
> @@ -99,8 +72,8 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
>   		 */
>   		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
>   	),
> -	TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error: '%s'",
> -		  __get_str(memdev), __get_str(host), __entry->serial,
> +	TP_printk("device=%s parent=%s serial=%lld status='%s' first_error='%s'",
> +		  __get_str(name), __get_str(parent), __entry->serial,
>   		  show_uc_errs(__entry->status),
>   		  show_uc_errs(__entry->first_error)
>   	)
> @@ -124,42 +97,23 @@ 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 device *dev, u64 serial, u32 status),
> +	TP_ARGS(dev, serial, status),
>   	TP_STRUCT__entry(
> -		__string(memdev, dev_name(&cxlmd->dev))
> -		__string(host, dev_name(cxlmd->dev.parent))
> +		__string(name, dev_name(dev))
> +		__string(parent, dev_name(dev->parent))
>   		__field(u64, serial)
>   		__field(u32, status)
>   	),
>   	TP_fast_assign(
> -		__assign_str(memdev);
> -		__assign_str(host);
> -		__entry->serial = cxlmd->cxlds->serial;
> +		__assign_str(name);
> +		__assign_str(parent);
> +		__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("device=%s parent=%s serial=%lld status='%s'",
> +		  __get_str(name), __get_str(parent), __entry->serial,
>   		  show_ce_errs(__entry->status)
>   	)
>   );

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors
  2025-06-03 17:22 ` [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
@ 2025-06-05 18:37   ` Sathyanarayanan Kuppuswamy
  2025-06-06 20:30   ` Dave Jiang
  2025-06-12 16:46   ` Jonathan Cameron
  2 siblings, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-05 18:37 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> __cxl_handle_cor_ras() is missing logic to leave the function early in the
> case there is no RAS error. Update __cxl_handle_cor_ras() to exit early in
> the case there is no RAS errors detected after applying the mask.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>   drivers/cxl/core/pci.c | 9 +++++----
>   1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index 0f4c07fd64a5..f5f87c2c3fd5 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -677,10 +677,11 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>   
>   	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
>   	status = readl(addr);
> -	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
> -		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
> -		trace_cxl_aer_correctable_error(dev, serial, status);
> -	}
> +	if (!(status & CXL_RAS_CORRECTABLE_STATUS_MASK))
> +		return;
> +	writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
> +
> +	trace_cxl_aer_correctable_error(dev, serial, status);
>   }
>   
>   static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl()
  2025-06-03 17:22 ` [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl() Terry Bowman
  2025-06-04 19:06   ` Sathyanarayanan Kuppuswamy
@ 2025-06-05 23:24   ` Dave Jiang
  1 sibling, 0 replies; 90+ messages in thread
From: Dave Jiang @ 2025-06-05 23:24 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> CXL and AER drivers need the ability to identify CXL devices.
> 
> Add set_pcie_cxl() with logic checking for CXL Flexbus DVSEC presence. The
> CXL Flexbus DVSEC presence is used because it is required for all the CXL
> PCIe devices.[1]
> 
> Add boolean 'struct pci_dev::is_cxl' with the purpose to cache the CXL
> Flexbus presence.
> 
> Add function pcie_is_cxl() to return 'struct pci_dev::is_cxl'.
> 
> [1] CXL 3.1 Spec, 8.1.1 PCIe Designated Vendor-Specific Extended
>     Capability (DVSEC) ID Assignment, Table 8-2
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  drivers/pci/probe.c           | 10 ++++++++++
>  include/linux/pci.h           |  6 ++++++
>  include/uapi/linux/pci_regs.h |  8 +++++++-
>  3 files changed, 23 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 364fa2a514f8..aa29b4b98ad1 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1691,6 +1691,14 @@ static void set_pcie_thunderbolt(struct pci_dev *dev)
>  		dev->is_thunderbolt = 1;
>  }
>  
> +static void set_pcie_cxl(struct pci_dev *dev)
> +{
> +	u16 dvsec = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
> +					      PCI_DVSEC_CXL_FLEXBUS);
> +	if (dvsec)
> +		dev->is_cxl = 1;
> +}
> +
>  static void set_pcie_untrusted(struct pci_dev *dev)
>  {
>  	struct pci_dev *parent = pci_upstream_bridge(dev);
> @@ -2021,6 +2029,8 @@ int pci_setup_device(struct pci_dev *dev)
>  	/* Need to have dev->cfg_size ready */
>  	set_pcie_thunderbolt(dev);
>  
> +	set_pcie_cxl(dev);
> +
>  	set_pcie_untrusted(dev);
>  
>  	if (pci_is_pcie(dev))
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 51e2bd6405cd..bff3009f9ff0 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -455,6 +455,7 @@ struct pci_dev {
>  	unsigned int	is_hotplug_bridge:1;
>  	unsigned int	shpc_managed:1;		/* SHPC owned by shpchp */
>  	unsigned int	is_thunderbolt:1;	/* Thunderbolt controller */
> +	unsigned int	is_cxl:1;               /* Compute Express Link (CXL) */
>  	/*
>  	 * Devices marked being untrusted are the ones that can potentially
>  	 * execute DMA attacks and similar. They are typically connected
> @@ -746,6 +747,11 @@ static inline bool pci_is_vga(struct pci_dev *pdev)
>  	return false;
>  }
>  
> +static inline bool pcie_is_cxl(struct pci_dev *pci_dev)
> +{
> +	return pci_dev->is_cxl;
> +}
> +
>  #define for_each_pci_bridge(dev, bus)				\
>  	list_for_each_entry(dev, &bus->devices, bus_list)	\
>  		if (!pci_is_bridge(dev)) {} else
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index ba326710f9c8..c50ffa75d5fc 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -1215,9 +1215,15 @@
>  /* Deprecated old name, replaced with PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE */
>  #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL		PCI_DOE_DATA_OBJECT_DISC_RSP_3_TYPE
>  
> -/* Compute Express Link (CXL r3.1, sec 8.1.5) */
> +/* Compute Express Link (CXL r3.2, sec 8.1)
> + *
> + * Note that CXL DVSEC id 3 and 7 to be ignored when the CXL link state
> + * is "disconnected" (CXL r3.2, sec 9.12.3). Re-enumerate these
> + * registers on downstream link-up events.
> + */
>  #define PCI_DVSEC_CXL_PORT				3
>  #define PCI_DVSEC_CXL_PORT_CTL				0x0c
>  #define PCI_DVSEC_CXL_PORT_CTL_UNMASK_SBR		0x00000001
> +#define PCI_DVSEC_CXL_FLEXBUS				7
>  
>  #endif /* LINUX_PCI_REGS_H */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging
  2025-06-03 17:22 ` [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging Terry Bowman
  2025-06-03 22:02   ` Sathyanarayanan Kuppuswamy
@ 2025-06-05 23:28   ` Dave Jiang
  1 sibling, 0 replies; 90+ messages in thread
From: Dave Jiang @ 2025-06-05 23:28 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> The AER service driver and aer_event tracing currently log 'PCIe Bus Type'
> for all errors. Update the driver and aer_event tracing to log 'CXL Bus
> Type' for CXL device errors.
> 
> This requires the AER can identify and distinguish between PCIe errors and
> CXL errors.
> 
> Introduce boolean 'is_cxl' to 'struct aer_err_info'. Add assignment in
> aer_get_device_error_info() and pci_print_aer().
> 
> Update the aer_event trace routine to accept a bus type string parameter.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Ira Weiny <ira.weiny@intel.com>

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  drivers/pci/pci.h       |  6 ++++++
>  drivers/pci/pcie/aer.c  | 18 ++++++++++++------
>  include/ras/ras_event.h |  9 ++++++---
>  3 files changed, 24 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index b81e99cd4b62..d6296500b004 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -588,6 +588,7 @@ static inline bool pci_dev_test_and_set_removed(struct pci_dev *dev)
>  struct aer_err_info {
>  	struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES];
>  	int error_dev_num;
> +	bool is_cxl;
>  
>  	unsigned int id:16;
>  
> @@ -604,6 +605,11 @@ struct aer_err_info {
>  	struct pcie_tlp_log tlp;	/* TLP Header */
>  };
>  
> +static inline const char *aer_err_bus(struct aer_err_info *info)
> +{
> +	return info->is_cxl ? "CXL" : "PCIe";
> +}
> +
>  int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
>  void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
>  
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index a1cf8c7ef628..adb4b1123b9b 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -698,13 +698,14 @@ static void __aer_print_error(struct pci_dev *dev,
>  
>  void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>  {
> +	const char *bus_type = aer_err_bus(info);
>  	int layer, agent;
>  	int id = pci_dev_id(dev);
>  	const char *level;
>  
>  	if (!info->status) {
> -		pci_err(dev, "PCIe Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
> -			aer_error_severity_string[info->severity]);
> +		pci_err(dev, "%s Bus Error: severity=%s, type=Inaccessible, (Unregistered Agent ID)\n",
> +			bus_type, aer_error_severity_string[info->severity]);
>  		goto out;
>  	}
>  
> @@ -713,8 +714,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>  
>  	level = (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR;
>  
> -	aer_printk(level, dev, "PCIe Bus Error: severity=%s, type=%s, (%s)\n",
> -		   aer_error_severity_string[info->severity],
> +	aer_printk(level, dev, "%s Bus Error: severity=%s, type=%s, (%s)\n",
> +		   bus_type, aer_error_severity_string[info->severity],
>  		   aer_error_layer[layer], aer_agent_string[agent]);
>  
>  	aer_printk(level, dev, "  device [%04x:%04x] error status/mask=%08x/%08x\n",
> @@ -729,7 +730,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
>  	if (info->id && info->error_dev_num > 1 && info->id == id)
>  		pci_err(dev, "  Error of this Agent is reported first\n");
>  
> -	trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
> +	trace_aer_event(dev_name(&dev->dev), bus_type, (info->status & ~info->mask),
>  			info->severity, info->tlp_header_valid, &info->tlp);
>  }
>  
> @@ -763,6 +764,7 @@ EXPORT_SYMBOL_GPL(cper_severity_to_aer);
>  void pci_print_aer(struct pci_dev *dev, int aer_severity,
>  		   struct aer_capability_regs *aer)
>  {
> +	const char *bus_type;
>  	int layer, agent, tlp_header_valid = 0;
>  	u32 status, mask;
>  	struct aer_err_info info;
> @@ -784,6 +786,9 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>  	info.status = status;
>  	info.mask = mask;
>  	info.first_error = PCI_ERR_CAP_FEP(aer->cap_control);
> +	info.is_cxl = pcie_is_cxl(dev);
> +
> +	bus_type = aer_err_bus(&info);
>  
>  	pci_err(dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
>  	__aer_print_error(dev, &info);
> @@ -797,7 +802,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>  	if (tlp_header_valid)
>  		pcie_print_tlp_log(dev, &aer->header_log, dev_fmt("  "));
>  
> -	trace_aer_event(dev_name(&dev->dev), (status & ~mask),
> +	trace_aer_event(dev_name(&dev->dev), bus_type, (status & ~mask),
>  			aer_severity, tlp_header_valid, &aer->header_log);
>  }
>  EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL");
> @@ -1215,6 +1220,7 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
>  	/* Must reset in this function */
>  	info->status = 0;
>  	info->tlp_header_valid = 0;
> +	info->is_cxl = pcie_is_cxl(dev);
>  
>  	/* The device might not support AER */
>  	if (!aer)
> diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h
> index 14c9f943d53f..080829d59c36 100644
> --- a/include/ras/ras_event.h
> +++ b/include/ras/ras_event.h
> @@ -297,15 +297,17 @@ TRACE_EVENT(non_standard_event,
>  
>  TRACE_EVENT(aer_event,
>  	TP_PROTO(const char *dev_name,
> +		 const char *bus_type,
>  		 const u32 status,
>  		 const u8 severity,
>  		 const u8 tlp_header_valid,
>  		 struct pcie_tlp_log *tlp),
>  
> -	TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
> +	TP_ARGS(dev_name, bus_type, status, severity, tlp_header_valid, tlp),
>  
>  	TP_STRUCT__entry(
>  		__string(	dev_name,	dev_name	)
> +		__string(	bus_type,	bus_type	)
>  		__field(	u32,		status		)
>  		__field(	u8,		severity	)
>  		__field(	u8, 		tlp_header_valid)
> @@ -314,6 +316,7 @@ TRACE_EVENT(aer_event,
>  
>  	TP_fast_assign(
>  		__assign_str(dev_name);
> +		__assign_str(bus_type);
>  		__entry->status		= status;
>  		__entry->severity	= severity;
>  		__entry->tlp_header_valid = tlp_header_valid;
> @@ -325,8 +328,8 @@ TRACE_EVENT(aer_event,
>  		}
>  	),
>  
> -	TP_printk("%s PCIe Bus Error: severity=%s, %s, TLP Header=%s\n",
> -		__get_str(dev_name),
> +	TP_printk("%s %s Bus Error: severity=%s, %s, TLP Header=%s\n",
> +		__get_str(dev_name), __get_str(bus_type),
>  		__entry->severity == AER_CORRECTABLE ? "Corrected" :
>  			__entry->severity == AER_FATAL ?
>  			"Fatal" : "Uncorrected, non-fatal",


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 12/16] cxl/pci: Introduce CXL Endpoint protocol error handlers
  2025-06-03 17:22 ` [PATCH v9 12/16] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
@ 2025-06-06  0:22   ` Sathyanarayanan Kuppuswamy
  2025-06-12 16:55   ` Jonathan Cameron
  1 sibling, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-06  0:22 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> CXL Endpoint protocol errors are currently handled using PCI error
> handlers. The CXL Endpoint requires CXL specific handling in the case of
> uncorrectable error handling not provided by the PCI handlers.
>
> Add CXL specific handlers for CXL Endpoints. Rename the existing
> cxl_error_handlers to be pci_error_handlers to more correctly indicate
> the error type and follow naming consistency.
>
> Keep the existing PCI Endpoint handlers. PCI handlers can be called if the
> CXL device is not trained for alternate protocol (CXL). Update the CXL
> Endpoint PCI handlers to call the CXL handler. If the CXL uncorrectable
> handler returns PCI_ERS_RESULT_PANIC then the PCI handler invokes panic().
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/cxl/core/pci.c | 80 ++++++++++++++++++++++--------------------
>   drivers/cxl/core/ras.c | 10 +++---
>   drivers/cxl/cxl.h      |  4 +++
>   drivers/cxl/cxlpci.h   |  6 ++--
>   drivers/cxl/pci.c      |  8 ++---
>   5 files changed, 58 insertions(+), 50 deletions(-)
>
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index f5f87c2c3fd5..e094ef518e0a 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -710,8 +710,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.
>    */
> -static bool __cxl_handle_ras(struct device *dev, u64 serial,
> -			     void __iomem *ras_base)
> +static pci_ers_result_t __cxl_handle_ras(struct device *dev, u64 serial,
> +					 void __iomem *ras_base)
>   {
>   	u32 hl[CXL_HEADERLOG_SIZE_U32];
>   	void __iomem *addr;
> @@ -720,13 +720,13 @@ static bool __cxl_handle_ras(struct device *dev, u64 serial,
>   
>   	if (!ras_base) {
>   		dev_warn_once(dev, "CXL RAS register block is not mapped");
> -		return false;
> +		return PCI_ERS_RESULT_NONE;
>   	}
>   
>   	addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
>   	status = readl(addr);
>   	if (!(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK))
> -		return false;
> +		return PCI_ERS_RESULT_NONE;
>   
>   	/* If multiple errors, log header points to first error from ctrl reg */
>   	if (hweight32(status) > 1) {
> @@ -743,12 +743,11 @@ static bool __cxl_handle_ras(struct device *dev, u64 serial,
>   	trace_cxl_aer_uncorrectable_error(dev, serial, status, fe, hl);
>   	writel(status & CXL_RAS_UNCORRECTABLE_STATUS_MASK, addr);
>   
> -	return true;
> +	return PCI_ERS_RESULT_PANIC;
>   }
>   
>   static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>   {
> -
>   	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>   }
>   
> @@ -844,14 +843,15 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
>   static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
>   #endif
>   
> -void cxl_cor_error_detected(struct pci_dev *pdev)
> +void cxl_cor_error_detected(struct device *dev)
>   {
> +	struct pci_dev *pdev = to_pci_dev(dev);
>   	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> -	struct device *dev = &cxlds->cxlmd->dev;
> +	struct device *cxlmd_dev = &cxlds->cxlmd->dev;
>   
> -	scoped_guard(device, dev) {
> -		if (!dev->driver) {
> -			dev_warn(&pdev->dev,
> +	scoped_guard(device, cxlmd_dev) {
> +		if (!cxlmd_dev->driver) {
> +			dev_warn(dev,
>   				 "%s: memdev disabled, abort error handling\n",
>   				 dev_name(dev));
>   			return;
> @@ -865,20 +865,28 @@ void cxl_cor_error_detected(struct pci_dev *pdev)
>   }
>   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)
> +void pci_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 = &cxlmd->dev;
> -	bool ue;
> +	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>   
> -	scoped_guard(device, dev) {
> +	cxl_cor_error_detected(&pdev->dev);
> +}
> +EXPORT_SYMBOL_NS_GPL(pci_cor_error_detected, "CXL");
> +
> +pci_ers_result_t cxl_error_detected(struct device *dev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +	struct device *cxlmd_dev = &cxlds->cxlmd->dev;
> +	pci_ers_result_t ue;
> +
> +	scoped_guard(device, cxlmd_dev) {
>   		if (!dev->driver) {
>   			dev_warn(&pdev->dev,
>   				 "%s: memdev disabled, abort error handling\n",
>   				 dev_name(dev));
> -			return PCI_ERS_RESULT_DISCONNECT;
> +			return PCI_ERS_RESULT_PANIC;
>   		}
>   
>   		if (cxlds->rcd)
> @@ -892,29 +900,25 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>   		ue = cxl_handle_endpoint_ras(cxlds);
>   	}
>   
> -
> -	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);
> -		return PCI_ERS_RESULT_NEED_RESET;
> -	case pci_channel_io_perm_failure:
> -		dev_warn(&pdev->dev,
> -			 "failure state error detected, request disconnect\n");
> -		return PCI_ERS_RESULT_DISCONNECT;
> -	}
> -	return PCI_ERS_RESULT_NEED_RESET;
> +	return ue;
>   }
>   EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");
>   
> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> +				    pci_channel_state_t error)
> +{
> +	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +	struct device *cxlmd_dev __free(put_device) = &cxlds->cxlmd->dev;
> +	pci_ers_result_t rc;
> +
> +	rc = cxl_error_detected(&pdev->dev);
> +	if (rc == PCI_ERS_RESULT_PANIC)
> +		panic("CXL cachemem error.");
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL_NS_GPL(pci_error_detected, "CXL");
> +
>   static int cxl_flit_size(struct pci_dev *pdev)
>   {
>   	if (cxl_pci_flit_256(pdev))
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 0ef8c2068c0c..664f532cc838 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -153,7 +153,7 @@ static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
>   	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>   
>   	device_lock(&pdev->dev);
> -	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
> +	vote = cxl_error_detected(&pdev->dev);
>   	*result = cxl_merge_result(*result, vote);
>   	device_unlock(&pdev->dev);
>   
> @@ -223,7 +223,7 @@ static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>   	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>   
>   	if (err_info->severity == AER_CORRECTABLE)
> -		cxl_cor_error_detected(pdev);
> +		cxl_cor_error_detected(dev);
>   	else
>   		cxl_do_recovery(pdev);
>   
> @@ -244,6 +244,8 @@ static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>   static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>   {
>   	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> +	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>   
>   	if (!pdev) {
>   		pr_err("Failed to find the CXL device\n");
> @@ -260,15 +262,13 @@ static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>   
>   	if (err_info->severity == AER_CORRECTABLE) {
>   		int aer = pdev->aer_cap;
> -		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> -		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>   
>   		if (aer)
>   			pci_clear_and_set_config_dword(pdev,
>   						       aer + PCI_ERR_COR_STATUS,
>   						       0, PCI_ERR_COR_INTERNAL);
>   
> -		cxl_cor_error_detected(pdev);
> +		cxl_cor_error_detected(&pdev->dev);
>   
>   		pcie_clear_device_status(pdev);
>   	} else {
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 73be66ef36a2..6fd9a42eb304 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -11,6 +11,7 @@
>   #include <linux/log2.h>
>   #include <linux/node.h>
>   #include <linux/io.h>
> +#include <linux/pci.h>
>   
>   extern const struct nvdimm_security_ops *cxl_security_ops;
>   
> @@ -797,6 +798,9 @@ static inline int cxl_root_decoder_autoremove(struct device *host,
>   }
>   int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
>   
> +void cxl_cor_error_detected(struct device *dev);
> +pci_ers_result_t cxl_error_detected(struct device *dev);
> +
>   /**
>    * struct cxl_endpoint_dvsec_info - Cached DVSEC info
>    * @mem_enabled: cached value of mem_enabled in the DVSEC at init time
> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
> index 6f1396ef7b77..a572c57c6c63 100644
> --- a/drivers/cxl/cxlpci.h
> +++ b/drivers/cxl/cxlpci.h
> @@ -133,7 +133,7 @@ struct cxl_dev_state;
>   int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
>   			struct cxl_endpoint_dvsec_info *info);
>   void read_cdat_data(struct cxl_port *port);
> -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 pci_cor_error_detected(struct pci_dev *pdev);
> +pci_ers_result_t pci_error_detected(struct pci_dev *pdev,
> +				    pci_channel_state_t error);
>   #endif /* __CXL_PCI_H__ */
> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index 785aa2af5eaa..2b948e94bc97 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -1112,11 +1112,11 @@ static void cxl_reset_done(struct pci_dev *pdev)
>   	}
>   }
>   
> -static const struct pci_error_handlers cxl_error_handlers = {
> -	.error_detected	= cxl_error_detected,
> +static const struct pci_error_handlers pci_error_handlers = {
> +	.error_detected = pci_error_detected,
>   	.slot_reset	= cxl_slot_reset,
>   	.resume		= cxl_error_resume,
> -	.cor_error_detected	= cxl_cor_error_detected,
> +	.cor_error_detected	= pci_cor_error_detected,
>   	.reset_done	= cxl_reset_done,
>   };
>   
> @@ -1124,7 +1124,7 @@ 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		= &pci_error_handlers,
>   	.dev_groups		= cxl_rcd_groups,
>   	.driver	= {
>   		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-03 17:22 ` [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors Terry Bowman
  2025-06-04  6:01   ` Dan Carpenter
  2025-06-04 22:50   ` Sathyanarayanan Kuppuswamy
@ 2025-06-06  0:27   ` Dave Jiang
  2025-06-06 14:27     ` Bowman, Terry
  2025-06-12 11:04   ` Jonathan Cameron
  3 siblings, 1 reply; 90+ messages in thread
From: Dave Jiang @ 2025-06-06  0:27 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> CXL error handling will soon be moved from the AER driver into the CXL
> driver. This requires a notification mechanism for the AER driver to share
> the AER interrupt with the CXL driver. The notification will be used
> as an indication for the CXL drivers to handle and log the CXL RAS errors.
> 
> Add a kfifo work queue to be used by the AER driver and CXL driver. The AER
> driver will be the sole kfifo producer adding work and the cxl_core will be
> the sole kfifo consumer removing work. Add the boilerplate kfifo support.
> 
> Add CXL work queue handler registration functions in the AER driver. Export
> the functions allowing CXL driver to access. Implement registration
> functions for the CXL driver to assign or clear the work handler function.
> 
> Introduce function cxl_create_prot_err_info() and 'struct cxl_prot_err_info'.
> Implement cxl_create_prot_err_info() to populate a 'struct cxl_prot_err_info'
> instance with the AER severity and the erring device's PCI SBDF. The SBDF
> details will be used to rediscover the erring device after the CXL driver
> dequeues the kfifo work. The device rediscovery will be introduced along
> with the CXL handling in future patches.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>  drivers/cxl/core/ras.c |  31 +++++++++-
>  drivers/cxl/cxlpci.h   |   1 +
>  drivers/pci/pcie/aer.c | 132 ++++++++++++++++++++++++++++-------------
>  include/linux/aer.h    |  36 +++++++++++
>  4 files changed, 157 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 485a831695c7..d35525e79e04 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -5,6 +5,7 @@
>  #include <linux/aer.h>
>  #include <cxl/event.h>
>  #include <cxlmem.h>
> +#include <cxlpci.h>
>  #include "trace.h"
>  
>  static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
> @@ -107,13 +108,41 @@ 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);
>  
> +#ifdef CONFIG_PCIEAER_CXL
> +
> +static void cxl_prot_err_work_fn(struct work_struct *work)
> +{
> +}
> +
> +#else
> +static void cxl_prot_err_work_fn(struct work_struct *work) { }
> +#endif /* CONFIG_PCIEAER_CXL */

I wonder instead of the ifdef block we can just do:

static void cxl_prot_err_work_fn(...)
{
	if (!IS_ENABLED(CONFIG_PCIEAER_CXL))
		return;

	....
}

In general we want to avoid ifdefs in C files. 

Also, where is CONFIG_PCIEAER_CXL defined? I'm having trouble finding the Kconfig that declares it.

$ git grep CONFIG_PCIEAER_CXL
drivers/cxl/core/pci.c:#ifdef CONFIG_PCIEAER_CXL
drivers/cxl/core/ras.c:#ifdef CONFIG_PCIEAER_CXL
drivers/cxl/core/ras.c:#endif /* CONFIG_PCIEAER_CXL */
drivers/cxl/cxl.h:#ifdef CONFIG_PCIEAER_CXL
drivers/cxl/port.c:#ifdef CONFIG_PCIEAER_CXL
drivers/cxl/port.c:#endif /* CONFIG_PCIEAER_CXL */
drivers/pci/pcie/aer.c:#if defined(CONFIG_PCIEAER_CXL)
drivers/pci/pcie/aer.c:#ifdef CONFIG_PCIEAER_CXL
drivers/pci/pcie/aer.c:#if defined(CONFIG_PCIEAER_CXL)
include/linux/aer.h:#if defined(CONFIG_PCIEAER_CXL)


> +
> +static struct work_struct cxl_prot_err_work;
> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
> +
>  int cxl_ras_init(void)
>  {
> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> +	int rc;
> +
> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
> +	if (rc)
> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);
> +
> +	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
> +	if (rc) {
> +		pr_err("Failed to register native AER kfifo (%x)", rc);
> +		return rc;
> +	}
> +
> +	return 0;
>  }
>  
>  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_unregister_prot_err_work();
> +	cancel_work_sync(&cxl_prot_err_work);
>  }
> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
> index 54e219b0049e..6f1396ef7b77 100644
> --- a/drivers/cxl/cxlpci.h
> +++ b/drivers/cxl/cxlpci.h
> @@ -4,6 +4,7 @@
>  #define __CXL_PCI_H__
>  #include <linux/pci.h>
>  #include "cxl.h"
> +#include "linux/aer.h"
>  
>  #define CXL_MEMORY_PROGIF	0x10
>  
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index adb4b1123b9b..5350fa5be784 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -114,6 +114,14 @@ struct aer_stats {
>  static int pcie_aer_disable;
>  static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
>  
> +#if defined(CONFIG_PCIEAER_CXL)

Would it make sense to move all the CXL bits to a cxl_aer.c instead of all the ifdefs in this C file?

DJ

> +#define CXL_ERROR_SOURCES_MAX          128
> +static DEFINE_KFIFO(cxl_prot_err_fifo, struct cxl_prot_err_work_data,
> +		    CXL_ERROR_SOURCES_MAX);
> +static DEFINE_SPINLOCK(cxl_prot_err_fifo_lock);
> +struct work_struct *cxl_prot_err_work;
> +#endif
> +
>  void pci_no_aer(void)
>  {
>  	pcie_aer_disable = 1;
> @@ -1004,45 +1012,17 @@ static bool is_internal_error(struct aer_err_info *info)
>  	return info->status & PCI_ERR_UNC_INTN;
>  }
>  
> -static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
>  {
> -	struct aer_err_info *info = (struct aer_err_info *)data;
> -	const struct pci_error_handlers *err_handler;
> +	if (!info || !info->is_cxl)
> +		return false;
>  
> -	if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
> -		return 0;
> +	/* Only CXL Endpoints are currently supported */
> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))
> +		return false;
>  
> -	/* Protect dev->driver */
> -	device_lock(&dev->dev);
> -
> -	err_handler = dev->driver ? dev->driver->err_handler : NULL;
> -	if (!err_handler)
> -		goto out;
> -
> -	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);
> -	}
> -out:
> -	device_unlock(&dev->dev);
> -	return 0;
> -}
> -
> -static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_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.
> -	 */
> -	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
> -	    is_internal_error(info))
> -		pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
> +	return is_internal_error(info);
>  }
>  
>  static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
> @@ -1056,13 +1036,17 @@ static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
>  	return *handles_cxl;
>  }
>  
> -static bool handles_cxl_errors(struct pci_dev *rcec)
> +static bool handles_cxl_errors(struct pci_dev *dev)
>  {
>  	bool handles_cxl = false;
>  
> -	if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
> -	    pcie_aer_is_native(rcec))
> -		pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
> +	if (!pcie_aer_is_native(dev))
> +		return false;
> +
> +	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
> +		pcie_walk_rcec(dev, handles_cxl_error_iter, &handles_cxl);
> +	else
> +		handles_cxl = pcie_is_cxl(dev);
>  
>  	return handles_cxl;
>  }
> @@ -1076,10 +1060,46 @@ static void cxl_rch_enable_rcec(struct pci_dev *rcec)
>  	pci_info(rcec, "CXL: Internal errors unmasked");
>  }
>  
> +static int cxl_create_prot_error_info(struct pci_dev *pdev,
> +				      struct aer_err_info *aer_err_info,
> +				      struct cxl_prot_error_info *cxl_err_info)
> +{
> +	cxl_err_info->severity = aer_err_info->severity;
> +
> +	cxl_err_info->function = PCI_FUNC(pdev->devfn);
> +	cxl_err_info->device = PCI_SLOT(pdev->devfn);
> +	cxl_err_info->bus = pdev->bus->number;
> +	cxl_err_info->segment = pci_domain_nr(pdev->bus);
> +
> +	return 0;
> +}
> +
> +static void forward_cxl_error(struct pci_dev *pdev, struct aer_err_info *aer_err_info)
> +{
> +	struct cxl_prot_err_work_data wd;
> +	struct cxl_prot_error_info *cxl_err_info = &wd.err_info;
> +
> +	cxl_create_prot_error_info(pdev, aer_err_info, cxl_err_info);
> +
> +	if (!kfifo_put(&cxl_prot_err_fifo, wd)) {
> +		dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
> +		return;
> +	}
> +
> +	schedule_work(cxl_prot_err_work);
> +}
> +
>  #else
>  static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
>  static inline void cxl_rch_handle_error(struct pci_dev *dev,
>  					struct aer_err_info *info) { }
> +static inline void forward_cxl_error(struct pci_dev *dev,
> +				    struct aer_err_info *info) { }
> +static inline bool handles_cxl_errors(struct pci_dev *dev)
> +{
> +	return false;
> +}
> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return 0; };
>  #endif
>  
>  /**
> @@ -1117,8 +1137,11 @@ 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)
>  {
> -	cxl_rch_handle_error(dev, info);
> -	pci_aer_handle_error(dev, info);
> +	if (is_cxl_error(dev, info))
> +		forward_cxl_error(dev, info);
> +	else
> +		pci_aer_handle_error(dev, info);
> +
>  	pci_dev_put(dev);
>  }
>  
> @@ -1582,6 +1605,31 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
>  	return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
>  }
>  
> +#if defined(CONFIG_PCIEAER_CXL)
> +
> +int cxl_register_prot_err_work(struct work_struct *work)
> +{
> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
> +	cxl_prot_err_work = work;
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_register_prot_err_work, "CXL");
> +
> +int cxl_unregister_prot_err_work(void)
> +{
> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
> +	cxl_prot_err_work = NULL;
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_unregister_prot_err_work, "CXL");
> +
> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd)
> +{
> +	return kfifo_get(&cxl_prot_err_fifo, wd);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_prot_err_kfifo_get, "CXL");
> +#endif
> +
>  static struct pcie_port_service_driver aerdriver = {
>  	.name		= "aer",
>  	.port_type	= PCIE_ANY_PORT,
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 02940be66324..550407240ab5 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -10,6 +10,7 @@
>  
>  #include <linux/errno.h>
>  #include <linux/types.h>
> +#include <linux/workqueue_types.h>
>  
>  #define AER_NONFATAL			0
>  #define AER_FATAL			1
> @@ -53,6 +54,27 @@ struct aer_capability_regs {
>  	u16 uncor_err_source;
>  };
>  
> +/**
> + * struct cxl_prot_err_info - Error information used in CXL error handling
> + * @severity: AER severity
> + * @function: Device's PCI function
> + * @device: Device's PCI device
> + * @bus: Device's PCI bus
> + * @segment: Device's PCI segment
> + */
> +struct cxl_prot_error_info {
> +	int severity;
> +
> +	u8 function;
> +	u8 device;
> +	u8 bus;
> +	u16 segment;
> +};
> +
> +struct cxl_prot_err_work_data {
> +	struct cxl_prot_error_info err_info;
> +};
> +
>  #if defined(CONFIG_PCIEAER)
>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>  int pcie_aer_is_native(struct pci_dev *dev);
> @@ -64,6 +86,20 @@ 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; }
>  #endif
>  
> +#if defined(CONFIG_PCIEAER_CXL)
> +int cxl_register_prot_err_work(struct work_struct *work);
> +int cxl_unregister_prot_err_work(void);
> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd);
> +#else
> +static inline int
> +cxl_register_prot_err_work(struct work_struct *work)
> +{
> +	return 0;
> +}
> +static inline int cxl_unregister_prot_err_work(void) { return 0; }
> +static inline int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd) { return 0; }
> +#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);


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers
  2025-06-03 17:22 ` [PATCH v9 13/16] cxl/pci: Introduce CXL Port " Terry Bowman
@ 2025-06-06  0:50   ` Sathyanarayanan Kuppuswamy
  2025-06-12 17:14   ` Jonathan Cameron
  1 sibling, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-06  0:50 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> Introduce CXL error handlers for CXL Port devices.
>
> Add functions cxl_port_cor_error_detected() and cxl_port_error_detected().
> These will serve as the handlers for all CXL Port devices. Introduce
> cxl_get_ras_base() to provide the RAS base address needed by the handlers.
>
> Update cxl_handle_prot_error() to call the CXL Port or CXL Endpoint handler
> depending on which CXL device reports the error.
>
> Implement pci_get_ras_base() to return the cached RAS register address of a
> CXL Root Port, CXL Downstream Port, or CXL Upstream Port.
>
> Update the AER driver's is_cxl_error() to remove the filter PCI type check
> because CXL Port devices are now supported.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/cxl/core/core.h |  2 +
>   drivers/cxl/core/pci.c  | 61 ++++++++++++++++++++++++++
>   drivers/cxl/core/port.c |  4 +-
>   drivers/cxl/core/ras.c  | 96 ++++++++++++++++++++++++++++++++++++-----
>   drivers/cxl/cxl.h       |  5 +++
>   drivers/pci/pcie/aer.c  |  5 ---
>   6 files changed, 155 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
> index c73f39d14dd7..23d15eef01d2 100644
> --- a/drivers/cxl/core/core.h
> +++ b/drivers/cxl/core/core.h
> @@ -122,6 +122,8 @@ void cxl_ras_exit(void);
>   int cxl_gpf_port_setup(struct cxl_dport *dport);
>   int cxl_acpi_get_extended_linear_cache_size(struct resource *backing_res,
>   					    int nid, resource_size_t *size);
> +struct cxl_port *find_cxl_port(struct device *dport_dev,
> +			       struct cxl_dport **dport);
>   
>   #ifdef CONFIG_CXL_FEATURES
>   size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index e094ef518e0a..b6836825e8df 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -753,6 +753,67 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>   
>   #ifdef CONFIG_PCIEAER_CXL
>   
> +static void __iomem *cxl_get_ras_base(struct device *dev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	void __iomem *ras_base;
> +
> +	switch (pci_pcie_type(pdev)) {
> +	case PCI_EXP_TYPE_ROOT_PORT:
> +	case PCI_EXP_TYPE_DOWNSTREAM:
> +	{
> +		struct cxl_dport *dport = NULL;
> +		struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> +		if (!dport || !dport->dport_dev) {
> +			pci_err(pdev, "Failed to find the CXL device");
> +			return NULL;
> +		}
> +
> +		ras_base = dport ? dport->regs.ras : NULL;
> +		break;
> +	}
> +	case PCI_EXP_TYPE_UPSTREAM:
> +	{
> +		struct cxl_port *port;
> +		struct device *dev __free(put_device) = bus_find_device(&cxl_bus_type, NULL,
> +									&pdev->dev, match_uport);
> +
> +		if (!dev || !is_cxl_port(dev)) {
> +			pci_err(pdev, "Failed to find the CXL device");
> +			return NULL;
> +		}
> +
> +		port = to_cxl_port(dev);
> +		ras_base = port ? port->uport_regs.ras : NULL;
> +		break;
> +	}
> +	default:
> +	{
> +		pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> +		return NULL;
> +	}
> +	}
> +
> +	return ras_base;
> +}
> +
> +void cxl_port_cor_error_detected(struct device *dev)
> +{
> +	void __iomem *ras_base = cxl_get_ras_base(dev);
> +
> +	__cxl_handle_cor_ras(dev, 0, ras_base);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_port_cor_error_detected, "CXL");
> +
> +pci_ers_result_t cxl_port_error_detected(struct device *dev)
> +{
> +	void __iomem *ras_base = cxl_get_ras_base(dev);
> +
> +	return  __cxl_handle_ras(dev, 0, ras_base);
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_port_error_detected, "CXL");
> +
>   static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
>   					  struct cxl_dport *dport)
>   {
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index eb46c6764d20..07b9bb0f601f 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -1341,8 +1341,8 @@ 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)
> +struct cxl_port *find_cxl_port(struct device *dport_dev,
> +			       struct cxl_dport **dport)
>   {
>   	struct cxl_find_port_ctx ctx = {
>   		.dport_dev = dport_dev,
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 664f532cc838..6093e70ece37 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -140,20 +140,85 @@ static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
>   	return orig;
>   }
>   
> -static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
> +int match_uport(struct device *dev, const void *data)
>   {
> -	pci_ers_result_t vote, *result = data;
> -	struct cxl_dev_state *cxlds;
> +	const struct device *uport_dev = data;
> +	struct cxl_port *port;
>   
> -	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
> -	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
> +	if (!is_cxl_port(dev))
>   		return 0;
>   
> -	cxlds = pci_get_drvdata(pdev);
> -	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +	port = to_cxl_port(dev);
> +
> +	return port->uport_dev == uport_dev;
> +}
> +EXPORT_SYMBOL_NS_GPL(match_uport, "CXL");
> +
> +/* Return 'struct device*' responsible for freeing pdev's CXL resources */
> +static struct device *get_pci_cxl_host_dev(struct pci_dev *pdev)
> +{
> +	struct device *host_dev;
> +
> +	switch (pci_pcie_type(pdev)) {
> +	case PCI_EXP_TYPE_ROOT_PORT:
> +	case PCI_EXP_TYPE_DOWNSTREAM:
> +	{
> +		struct cxl_dport *dport = NULL;
> +		struct cxl_port *port = find_cxl_port(&pdev->dev, &dport);
> +
> +		if (!dport || !dport->dport_dev)
> +			return NULL;
> +
> +		host_dev = &port->dev;
> +		break;
> +	}
> +	case PCI_EXP_TYPE_UPSTREAM:
> +	{
> +		struct cxl_port *port;
> +		struct device *cxl_dev = bus_find_device(&cxl_bus_type, NULL,
> +							 &pdev->dev, match_uport);
> +
> +		if (!cxl_dev || !is_cxl_port(cxl_dev))
> +			return NULL;
> +
> +		port = to_cxl_port(cxl_dev);
> +		host_dev = &port->dev;
> +		break;
> +	}
> +	case PCI_EXP_TYPE_ENDPOINT:
> +	case PCI_EXP_TYPE_RC_END:
> +	{
> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +
> +		if (!cxlds)
> +			return NULL;
> +
> +		host_dev = get_device(&cxlds->cxlmd->dev);
> +		break;
> +	}
> +	default:
> +	{
> +		pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> +		return NULL;
> +	}
> +	}
> +
> +	return host_dev;
> +}
> +
> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device *host_dev __free(put_device) = get_pci_cxl_host_dev(pdev);
> +	pci_ers_result_t vote, *result = data;
>   
>   	device_lock(&pdev->dev);
> -	vote = cxl_error_detected(&pdev->dev);
> +	if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
> +	    (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
> +		vote = cxl_error_detected(dev);
> +	} else {
> +		vote = cxl_port_error_detected(dev);
> +	}
>   	*result = cxl_merge_result(*result, vote);
>   	device_unlock(&pdev->dev);
>   
> @@ -244,14 +309,18 @@ static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>   static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>   {
>   	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> -	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> -	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>   
>   	if (!pdev) {
>   		pr_err("Failed to find the CXL device\n");
>   		return;
>   	}
>   
> +	struct device *host_dev __free(put_device) = get_pci_cxl_host_dev(pdev);
> +	if (!host_dev) {
> +		pr_err("Failed to find the CXL device's host\n");
> +		return;
> +	}
> +
>   	/*
>   	 * Internal errors of an RCEC indicate an AER error in an
>   	 * RCH's downstream port. Check and handle them in the CXL.mem
> @@ -261,6 +330,7 @@ static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>   		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>   
>   	if (err_info->severity == AER_CORRECTABLE) {
> +		struct device *dev = &pdev->dev;
>   		int aer = pdev->aer_cap;
>   
>   		if (aer)
> @@ -268,7 +338,11 @@ static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>   						       aer + PCI_ERR_COR_STATUS,
>   						       0, PCI_ERR_COR_INTERNAL);
>   
> -		cxl_cor_error_detected(&pdev->dev);
> +		if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
> +		    (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END))
> +			cxl_cor_error_detected(dev);
> +		else
> +			cxl_port_cor_error_detected(dev);
>   
>   		pcie_clear_device_status(pdev);
>   	} else {
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 6fd9a42eb304..2c1c00466a25 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -801,6 +801,9 @@ int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint)
>   void cxl_cor_error_detected(struct device *dev);
>   pci_ers_result_t cxl_error_detected(struct device *dev);
>   
> +void cxl_port_cor_error_detected(struct device *dev);
> +pci_ers_result_t cxl_port_error_detected(struct device *dev);
> +
>   /**
>    * struct cxl_endpoint_dvsec_info - Cached DVSEC info
>    * @mem_enabled: cached value of mem_enabled in the DVSEC at init time
> @@ -915,6 +918,8 @@ void cxl_coordinates_combine(struct access_coordinate *out,
>   
>   bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port);
>   
> +int match_uport(struct device *dev, const void *data);
> +
>   /*
>    * Unit test builds overrides this to __weak, find the 'strong' version
>    * of these symbols in tools/testing/cxl/.
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 6e88331c6303..5efe5a718960 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -1018,11 +1018,6 @@ static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
>   	if (!info || !info->is_cxl)
>   		return false;
>   
> -	/* Only CXL Endpoints are currently supported */
> -	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
> -	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))
> -		return false;
> -
>   	return is_internal_error(info);
>   }
>   

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 14/16] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
  2025-06-03 17:22 ` [PATCH v9 14/16] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions Terry Bowman
@ 2025-06-06  0:50   ` Sathyanarayanan Kuppuswamy
  2025-06-12 17:16   ` Jonathan Cameron
  1 sibling, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-06  0:50 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> The CXL driver's cxl_handle_endpoint_cor_ras()/cxl_handle_endpoint_ras()
> are unnecessary helper functions used only for Endpoints. Remove these
> functions as they are not common for all CXL devices and do not provide
> value for EP handling.
>
> Rename __cxl_handle_ras to cxl_handle_ras() and __cxl_handle_cor_ras()
> to cxl_handle_cor_ras().
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/cxl/core/pci.c | 32 ++++++++++++--------------------
>   1 file changed, 12 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index b6836825e8df..b36a58607041 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -664,8 +664,8 @@ void read_cdat_data(struct cxl_port *port)
>   }
>   EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
>   
> -static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
> -				 void __iomem *ras_base)
> +static void cxl_handle_cor_ras(struct device *dev, u64 serial,
> +			       void __iomem *ras_base)
>   {
>   	void __iomem *addr;
>   	u32 status;
> @@ -684,11 +684,6 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>   	trace_cxl_aer_correctable_error(dev, serial, status);
>   }
>   
> -static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
> -{
> -	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> -}
> -
>   /* CXL spec rev3.0 8.2.4.16.1 */
>   static void header_log_copy(void __iomem *ras_base, u32 *log)
>   {
> @@ -710,8 +705,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.
>    */
> -static pci_ers_result_t __cxl_handle_ras(struct device *dev, u64 serial,
> -					 void __iomem *ras_base)
> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial,
> +				       void __iomem *ras_base)
>   {
>   	u32 hl[CXL_HEADERLOG_SIZE_U32];
>   	void __iomem *addr;
> @@ -746,11 +741,6 @@ static pci_ers_result_t __cxl_handle_ras(struct device *dev, u64 serial,
>   	return PCI_ERS_RESULT_PANIC;
>   }
>   
> -static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
> -{
> -	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> -}
> -
>   #ifdef CONFIG_PCIEAER_CXL
>   
>   static void __iomem *cxl_get_ras_base(struct device *dev)
> @@ -802,7 +792,7 @@ void cxl_port_cor_error_detected(struct device *dev)
>   {
>   	void __iomem *ras_base = cxl_get_ras_base(dev);
>   
> -	__cxl_handle_cor_ras(dev, 0, ras_base);
> +	cxl_handle_cor_ras(dev, 0, ras_base);
>   }
>   EXPORT_SYMBOL_NS_GPL(cxl_port_cor_error_detected, "CXL");
>   
> @@ -810,20 +800,20 @@ pci_ers_result_t cxl_port_error_detected(struct device *dev)
>   {
>   	void __iomem *ras_base = cxl_get_ras_base(dev);
>   
> -	return  __cxl_handle_ras(dev, 0, ras_base);
> +	return  cxl_handle_ras(dev, 0, ras_base);
>   }
>   EXPORT_SYMBOL_NS_GPL(cxl_port_error_detected, "CXL");
>   
>   static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
>   					  struct cxl_dport *dport)
>   {
> -	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
> +	return cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
>   }
>   
>   static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
>   				       struct cxl_dport *dport)
>   {
> -	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
> +	return cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
>   }
>   
>   /*
> @@ -921,7 +911,8 @@ void cxl_cor_error_detected(struct device *dev)
>   		if (cxlds->rcd)
>   			cxl_handle_rdport_errors(cxlds);
>   
> -		cxl_handle_endpoint_cor_ras(cxlds);
> +		cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial,
> +				   cxlds->regs.ras);
>   	}
>   }
>   EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
> @@ -958,7 +949,8 @@ pci_ers_result_t cxl_error_detected(struct device *dev)
>   		 * chance the situation is recoverable dump the status of the RAS
>   		 * capability registers and bounce the active state of the memdev.
>   		 */
> -		ue = cxl_handle_endpoint_ras(cxlds);
> +		ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial,
> +				    cxlds->regs.ras);
>   	}
>   
>   	return ue;

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 15/16] CXL/PCI: Enable CXL protocol errors during CXL Port probe
  2025-06-03 17:22 ` [PATCH v9 15/16] CXL/PCI: Enable CXL protocol errors during CXL Port probe Terry Bowman
@ 2025-06-06  0:51   ` Sathyanarayanan Kuppuswamy
  0 siblings, 0 replies; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-06  0:51 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> CXL protocol errors are not enabled for all CXL devices after boot. These
> must be enabled inorder to process CXL protocol errors.
>
> Export the AER service driver's pci_aer_unmask_internal_errors().
>
> Introduce cxl_unmask_prot_interrupts() to call pci_aer_unmask_internal_errors().
> pci_aer_unmask_internal_errors() expects the pdev->aer_cap is initialized.
> But, dev->aer_cap is not initialized for CXL Upstream Switch Ports and CXL
> Downstream Switch Ports. Initialize the dev->aer_cap if necessary. Enable AER
> correctable internal errors and uncorrectable internal errors for all CXL
> devices.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/cxl/port.c     | 29 +++++++++++++++++++++++++++--
>   drivers/pci/pcie/aer.c |  3 ++-
>   include/linux/aer.h    |  1 +
>   3 files changed, 30 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index 0f7c4010ba58..3687848ae772 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -3,6 +3,7 @@
>   #include <linux/device.h>
>   #include <linux/module.h>
>   #include <linux/slab.h>
> +#include <linux/pci.h>
>   
>   #include "cxlmem.h"
>   #include "cxlpci.h"
> @@ -60,6 +61,21 @@ static int discover_region(struct device *dev, void *unused)
>   
>   #ifdef CONFIG_PCIEAER_CXL
>   
> +static void cxl_unmask_prot_interrupts(struct device *dev)
> +{
> +	struct pci_dev *pdev __free(pci_dev_put) =
> +		pci_dev_get(to_pci_dev(dev));
> +
> +	if (!pdev->aer_cap) {
> +		pdev->aer_cap = pci_find_ext_capability(pdev,
> +							PCI_EXT_CAP_ID_ERR);
> +		if (!pdev->aer_cap)
> +			return;
> +	}
> +
> +	pci_aer_unmask_internal_errors(pdev);
> +}
> +
>   static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
>   {
>   	resource_size_t aer_phys;
> @@ -118,8 +134,12 @@ static void cxl_uport_init_ras_reporting(struct cxl_port *port,
>   
>   	map->host = host;
>   	if (cxl_map_component_regs(map, &port->uport_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;
> +	}
> +
> +	cxl_unmask_prot_interrupts(port->uport_dev);
>   }
>   
>   /**
> @@ -144,9 +164,12 @@ void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>   	}
>   
>   	if (cxl_map_component_regs(&dport->reg_map, &dport->regs.component,
> -				   BIT(CXL_CM_CAP_CAP_ID_RAS)))
> +				   BIT(CXL_CM_CAP_CAP_ID_RAS))) {
>   		dev_dbg(dport->dport_dev, "Failed to map RAS capability\n");
> +		return;
> +	}
>   
> +	cxl_unmask_prot_interrupts(dport->dport_dev);
>   }
>   EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>   
> @@ -177,6 +200,8 @@ static void cxl_endpoint_port_init_ras(struct cxl_port *port)
>   	}
>   
>   	cxl_dport_init_ras_reporting(dport, &cxlmd->dev);
> +
> +	cxl_unmask_prot_interrupts(cxlmd->cxlds->dev);
>   }
>   
>   #else
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 5efe5a718960..2d202ad1453a 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -964,7 +964,7 @@ static bool find_source_device(struct pci_dev *parent,
>    * Note: AER must be enabled and supported by the device which must be
>    * checked in advance, e.g. with pcie_aer_is_native().
>    */
> -static void pci_aer_unmask_internal_errors(struct pci_dev *dev)
> +void pci_aer_unmask_internal_errors(struct pci_dev *dev)
>   {
>   	int aer = dev->aer_cap;
>   	u32 mask;
> @@ -977,6 +977,7 @@ static 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_NS_GPL(pci_aer_unmask_internal_errors, "CXL");
>   
>   static bool is_cxl_mem_dev(struct pci_dev *dev)
>   {
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index c9a18eca16f8..74600e75705f 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -107,5 +107,6 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
>   int cper_severity_to_aer(int cper_severity);
>   void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
>   		       int severity, struct aer_capability_regs *aer_regs);
> +void pci_aer_unmask_internal_errors(struct pci_dev *dev);
>   #endif //_AER_H_
>   

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
  2025-06-03 17:22 ` [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
@ 2025-06-06  0:52   ` Sathyanarayanan Kuppuswamy
  2025-06-06 13:51     ` Bowman, Terry
  2025-06-06 22:59   ` Dave Jiang
  2025-06-12 17:19   ` Jonathan Cameron
  2 siblings, 1 reply; 90+ messages in thread
From: Sathyanarayanan Kuppuswamy @ 2025-06-06  0:52 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	dave.jiang, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci


On 6/3/25 10:22 AM, Terry Bowman wrote:
> During CXL device cleanup the CXL PCIe Port device interrupts remain
> enabled. This potentially allows unnecessary interrupt processing on
> behalf of the CXL errors while the device is destroyed.
>
> Disable CXL protocol errors by setting the CXL devices' AER mask register.
>
> Introduce pci_aer_mask_internal_errors() similar to pci_aer_unmask_internal_errors().
>
> Introduce cxl_mask_prot_interrupts() to call pci_aer_mask_internal_errors().
> Add calls to cxl_mask_prot_interrupts() within CXL Port teardown for CXL
> Root Ports, CXL Downstream Switch Ports, CXL Upstream Switch Ports, and CXL
> Endpoints. Follow the same "bottom-up" approach used during CXL Port
> teardown.
>
> Implement cxl_mask_prot_interrupts() in a header file to avoid introducing
> Kconfig ifdefs in cxl/core/port.c.
>
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---

Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

>   drivers/cxl/core/port.c |  6 ++++++
>   drivers/cxl/cxl.h       |  8 ++++++++
>   drivers/pci/pcie/aer.c  | 21 +++++++++++++++++++++
>   include/linux/aer.h     |  1 +
>   4 files changed, 36 insertions(+)
>
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 07b9bb0f601f..6aaaad002a7f 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -1433,6 +1433,9 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, "CXL");
>    */
>   static void delete_switch_port(struct cxl_port *port)
>   {
> +	cxl_mask_prot_interrupts(port->uport_dev);
> +	cxl_mask_prot_interrupts(port->parent_dport->dport_dev);
> +
>   	devm_release_action(port->dev.parent, cxl_unlink_parent_dport, port);
>   	devm_release_action(port->dev.parent, cxl_unlink_uport, port);
>   	devm_release_action(port->dev.parent, unregister_port, port);
> @@ -1446,6 +1449,7 @@ static void reap_dports(struct cxl_port *port)
>   	device_lock_assert(&port->dev);
>   
>   	xa_for_each(&port->dports, index, dport) {
> +		cxl_mask_prot_interrupts(dport->dport_dev);
>   		devm_release_action(&port->dev, cxl_dport_unlink, dport);
>   		devm_release_action(&port->dev, cxl_dport_remove, dport);
>   		devm_kfree(&port->dev, dport);
> @@ -1476,6 +1480,8 @@ static void cxl_detach_ep(void *data)
>   {
>   	struct cxl_memdev *cxlmd = data;
>   
> +	cxl_mask_prot_interrupts(cxlmd->cxlds->dev);
> +
>   	for (int i = cxlmd->depth - 1; i >= 1; i--) {
>   		struct cxl_port *port, *parent_port;
>   		struct detach_ctx ctx = {
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 2c1c00466a25..2753db3d473e 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -12,6 +12,7 @@
>   #include <linux/node.h>
>   #include <linux/io.h>
>   #include <linux/pci.h>
> +#include <linux/aer.h>
>   
>   extern const struct nvdimm_security_ops *cxl_security_ops;
>   
> @@ -771,9 +772,16 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
>   #ifdef CONFIG_PCIEAER_CXL
>   void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
>   void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
> +static inline void cxl_mask_prot_interrupts(struct device *dev)
> +{
> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(to_pci_dev(dev));
> +
> +	pci_aer_mask_internal_errors(pdev);
> +}
>   #else
>   static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>   						struct device *host) { }
> +static inline void cxl_mask_prot_interrupts(struct device *dev) { }
>   #endif
>   
>   struct cxl_decoder *to_cxl_decoder(struct device *dev);
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 2d202ad1453a..69230cf87d79 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -979,6 +979,27 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
>   }
>   EXPORT_SYMBOL_NS_GPL(pci_aer_unmask_internal_errors, "CXL");
>   
> +/**
> + * pci_aer_mask_internal_errors - mask internal errors
> + * @dev: pointer to the pcie_dev data structure
> + *
> + * Masks 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().
> + */
> +void pci_aer_mask_internal_errors(struct pci_dev *dev)
> +{
> +	int aer = dev->aer_cap;
> +
> +	pci_clear_and_set_config_dword(dev, aer + PCI_ERR_UNCOR_MASK,
> +				       0, PCI_ERR_UNC_INTN);
> +	pci_clear_and_set_config_dword(dev, aer + PCI_ERR_COR_MASK,
> +				       0, PCI_ERR_COR_INTERNAL);
> +}
> +EXPORT_SYMBOL_NS_GPL(pci_aer_mask_internal_errors, "CXL");
> +
>   static bool is_cxl_mem_dev(struct pci_dev *dev)
>   {
>   	/*
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 74600e75705f..41167ad3797a 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -108,5 +108,6 @@ int cper_severity_to_aer(int cper_severity);
>   void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
>   		       int severity, struct aer_capability_regs *aer_regs);
>   void pci_aer_unmask_internal_errors(struct pci_dev *dev);
> +void pci_aer_mask_internal_errors(struct pci_dev *dev);
>   #endif //_AER_H_
>   

-- 
Sathyanarayanan Kuppuswamy
Linux Kernel Developer


^ permalink raw reply	[flat|nested] 90+ messages in thread

* RE: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
  2025-06-03 17:22 ` [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports Terry Bowman
  2025-06-05 16:49   ` Sathyanarayanan Kuppuswamy
@ 2025-06-06  9:08   ` Shiju Jose
  2025-06-06 14:41     ` Bowman, Terry
  1 sibling, 1 reply; 90+ messages in thread
From: Shiju Jose @ 2025-06-06  9:08 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati@amd.com,
	dave@stgolabs.net, Jonathan Cameron, dave.jiang@intel.com,
	alison.schofield@intel.com, vishal.l.verma@intel.com,
	ira.weiny@intel.com, dan.j.williams@intel.com,
	bhelgaas@google.com, bp@alien8.de, ming.li@zohomail.com,
	dan.carpenter@linaro.org, Smita.KoralahalliChannabasappa@amd.com,
	kobayashi.da-06@fujitsu.com, yanfei.xu@intel.com,
	rrichter@amd.com, peterz@infradead.org, colyli@suse.de,
	uaisheng.ye@intel.com, fabio.m.de.francesco@linux.intel.com,
	ilpo.jarvinen@linux.intel.com, yazen.ghannam@amd.com,
	linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org

>-----Original Message-----
>From: Terry Bowman <terry.bowman@amd.com>
>Sent: 03 June 2025 18:23
>To: PradeepVineshReddy.Kodamati@amd.com; dave@stgolabs.net; Jonathan
>Cameron <jonathan.cameron@huawei.com>; dave.jiang@intel.com;
>alison.schofield@intel.com; vishal.l.verma@intel.com; ira.weiny@intel.com;
>dan.j.williams@intel.com; bhelgaas@google.com; bp@alien8.de;
>ming.li@zohomail.com; Shiju Jose <shiju.jose@huawei.com>;
>dan.carpenter@linaro.org; Smita.KoralahalliChannabasappa@amd.com;
>kobayashi.da-06@fujitsu.com; terry.bowman@amd.com; yanfei.xu@intel.com;
>rrichter@amd.com; peterz@infradead.org; colyli@suse.de;
>uaisheng.ye@intel.com; fabio.m.de.francesco@linux.intel.com;
>ilpo.jarvinen@linux.intel.com; yazen.ghannam@amd.com; linux-
>cxl@vger.kernel.org; linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org
>Subject: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and
>CXL Ports
>
>CXL currently has separate trace routines for CXL Port errors and CXL Endpoint
>errors. This is inconvenient for the user because they must enable
>2 sets of trace routines. Make updates to the trace logging such that a single
>trace routine logs both CXL Endpoint and CXL Port protocol errors.
>
>Rename the 'host' field from the CXL Endpoint trace to 'parent' in the unified
>trace routines. 'host' does not correctly apply to CXL Port devices. Parent is more
>general and applies to CXL Port devices and CXL Endpoints.
>
>Add serial number parameter to the trace logging. This is used for EPs and 0 is
>provided for CXL port devices without a serial number.
>
>Below is output of correctable and uncorrectable protocol error logging.
>CXL Root Port and CXL Endpoint examples are included below.
>
>Root Port:
>cxl_aer_correctable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0
>status='CRC Threshold Hit'
>cxl_aer_uncorrectable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0
>status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity
>Error'
>
>Endpoint:
>cxl_aer_correctable_error: device=mem3 parent=0000:0f:00.0 serial=0
>status='CRC Threshold Hit'
>cxl_aer_uncorrectable_error: device=mem3 parent=0000:0f:00.0 serial: 0
>status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity
>Error'
>
>Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>---
> drivers/cxl/core/pci.c   | 18 +++++----
> drivers/cxl/core/ras.c   | 14 ++++---
> drivers/cxl/core/trace.h | 84 +++++++++-------------------------------
> 3 files changed, 37 insertions(+), 79 deletions(-)
>
>diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index
>186a5a20b951..0f4c07fd64a5 100644
>--- a/drivers/cxl/core/pci.c
>+++ b/drivers/cxl/core/pci.c
>@@ -664,7 +664,7 @@ void read_cdat_data(struct cxl_port *port)  }
>EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
>
[...]
> static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data
>*data) diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h index
>25ebfbc1616c..8c91b0f3d165 100644
>--- a/drivers/cxl/core/trace.h
>+++ b/drivers/cxl/core/trace.h
>@@ -48,49 +48,22 @@
> 	{ 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_SIZE_U32)
>-	),
>-	TP_fast_assign(
>-		__assign_str(device);
>-		__assign_str(host);
>-		__entry->status = status;
>-		__entry->first_error = fe;
>-		/*
>-		 * Embed the 512B headerlog data for user app retrieval and
>-		 * parsing, but no need to print this in the trace buffer.
>-		 */
>-		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
>-	),
>-	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 device *dev, u64 serial, u32 status, u32 fe,
>+		 u32 *hl),
>+	TP_ARGS(dev, serial, status, fe, hl),
> 	TP_STRUCT__entry(
>-		__string(memdev, dev_name(&cxlmd->dev))
>-		__string(host, dev_name(cxlmd->dev.parent))
>+		__string(name, dev_name(dev))
>+		__string(parent, dev_name(dev->parent))

Hi Terry,

As we pointed out in v8, renaming the fields "memdev" to "name" and "host" to "parent"
causes issues and failures in userspace rasdaemon  while parsing the trace event data.
Additionally, we can't rename these fields in rasdaemon  due to backward compatibility.

> 		__field(u64, serial)
> 		__field(u32, status)
> 		__field(u32, first_error)
> 		__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
> 	),
> 	TP_fast_assign(
>-		__assign_str(memdev);
>-		__assign_str(host);
>-		__entry->serial = cxlmd->cxlds->serial;
>+		__assign_str(name);
>+		__assign_str(parent);
>+		__entry->serial = serial;
> 		__entry->status = status;
> 		__entry->first_error = fe;
> 		/*
>@@ -99,8 +72,8 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
> 		 */
> 		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
> 	),
>-	TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error:
>'%s'",
>-		  __get_str(memdev), __get_str(host), __entry->serial,
>+	TP_printk("device=%s parent=%s serial=%lld status='%s'
>first_error='%s'",
>+		  __get_str(name), __get_str(parent), __entry->serial,
> 		  show_uc_errs(__entry->status),
> 		  show_uc_errs(__entry->first_error)
> 	)
>@@ -124,42 +97,23 @@ 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 device *dev, u64 serial, u32 status),
>+	TP_ARGS(dev, serial, status),
> 	TP_STRUCT__entry(
>-		__string(memdev, dev_name(&cxlmd->dev))
>-		__string(host, dev_name(cxlmd->dev.parent))
>+		__string(name, dev_name(dev))
>+		__string(parent, dev_name(dev->parent))

Renaming these fields is an issue for userspace as mentioned above 
in cxl_aer_uncorrectable_error.

> 		__field(u64, serial)
> 		__field(u32, status)
> 	),
> 	TP_fast_assign(
>-		__assign_str(memdev);
>-		__assign_str(host);
>-		__entry->serial = cxlmd->cxlds->serial;
>+		__assign_str(name);
>+		__assign_str(parent);
>+		__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("device=%s parent=%s serial=%lld status='%s'",
>+		  __get_str(name), __get_str(parent), __entry->serial,
> 		  show_ce_errs(__entry->status)
> 	)
> );
>--
>2.34.1


Thanks,
Shiju

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
  2025-06-06  0:52   ` Sathyanarayanan Kuppuswamy
@ 2025-06-06 13:51     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 13:51 UTC (permalink / raw)
  To: Sathyanarayanan Kuppuswamy, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, dave.jiang, alison.schofield, vishal.l.verma,
	ira.weiny, dan.j.williams, bhelgaas, bp, ming.li, shiju.jose,
	dan.carpenter, Smita.KoralahalliChannabasappa, kobayashi.da-06,
	yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/5/2025 7:52 PM, Sathyanarayanan Kuppuswamy wrote:
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> During CXL device cleanup the CXL PCIe Port device interrupts remain
>> enabled. This potentially allows unnecessary interrupt processing on
>> behalf of the CXL errors while the device is destroyed.
>>
>> Disable CXL protocol errors by setting the CXL devices' AER mask register.
>>
>> Introduce pci_aer_mask_internal_errors() similar to pci_aer_unmask_internal_errors().
>>
>> Introduce cxl_mask_prot_interrupts() to call pci_aer_mask_internal_errors().
>> Add calls to cxl_mask_prot_interrupts() within CXL Port teardown for CXL
>> Root Ports, CXL Downstream Switch Ports, CXL Upstream Switch Ports, and CXL
>> Endpoints. Follow the same "bottom-up" approach used during CXL Port
>> teardown.
>>
>> Implement cxl_mask_prot_interrupts() in a header file to avoid introducing
>> Kconfig ifdefs in cxl/core/port.c.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
> Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Kuppuswamy, thank you for the series patchset reviews and reviewed-by's. I 

Regards,
Terry


>>   drivers/cxl/core/port.c |  6 ++++++
>>   drivers/cxl/cxl.h       |  8 ++++++++
>>   drivers/pci/pcie/aer.c  | 21 +++++++++++++++++++++
>>   include/linux/aer.h     |  1 +
>>   4 files changed, 36 insertions(+)
>>
>> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
>> index 07b9bb0f601f..6aaaad002a7f 100644
>> --- a/drivers/cxl/core/port.c
>> +++ b/drivers/cxl/core/port.c
>> @@ -1433,6 +1433,9 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, "CXL");
>>    */
>>   static void delete_switch_port(struct cxl_port *port)
>>   {
>> +	cxl_mask_prot_interrupts(port->uport_dev);
>> +	cxl_mask_prot_interrupts(port->parent_dport->dport_dev);
>> +
>>   	devm_release_action(port->dev.parent, cxl_unlink_parent_dport, port);
>>   	devm_release_action(port->dev.parent, cxl_unlink_uport, port);
>>   	devm_release_action(port->dev.parent, unregister_port, port);
>> @@ -1446,6 +1449,7 @@ static void reap_dports(struct cxl_port *port)
>>   	device_lock_assert(&port->dev);
>>   
>>   	xa_for_each(&port->dports, index, dport) {
>> +		cxl_mask_prot_interrupts(dport->dport_dev);
>>   		devm_release_action(&port->dev, cxl_dport_unlink, dport);
>>   		devm_release_action(&port->dev, cxl_dport_remove, dport);
>>   		devm_kfree(&port->dev, dport);
>> @@ -1476,6 +1480,8 @@ static void cxl_detach_ep(void *data)
>>   {
>>   	struct cxl_memdev *cxlmd = data;
>>   
>> +	cxl_mask_prot_interrupts(cxlmd->cxlds->dev);
>> +
>>   	for (int i = cxlmd->depth - 1; i >= 1; i--) {
>>   		struct cxl_port *port, *parent_port;
>>   		struct detach_ctx ctx = {
>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>> index 2c1c00466a25..2753db3d473e 100644
>> --- a/drivers/cxl/cxl.h
>> +++ b/drivers/cxl/cxl.h
>> @@ -12,6 +12,7 @@
>>   #include <linux/node.h>
>>   #include <linux/io.h>
>>   #include <linux/pci.h>
>> +#include <linux/aer.h>
>>   
>>   extern const struct nvdimm_security_ops *cxl_security_ops;
>>   
>> @@ -771,9 +772,16 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
>>   #ifdef CONFIG_PCIEAER_CXL
>>   void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
>>   void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
>> +static inline void cxl_mask_prot_interrupts(struct device *dev)
>> +{
>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(to_pci_dev(dev));
>> +
>> +	pci_aer_mask_internal_errors(pdev);
>> +}
>>   #else
>>   static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>>   						struct device *host) { }
>> +static inline void cxl_mask_prot_interrupts(struct device *dev) { }
>>   #endif
>>   
>>   struct cxl_decoder *to_cxl_decoder(struct device *dev);
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index 2d202ad1453a..69230cf87d79 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -979,6 +979,27 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
>>   }
>>   EXPORT_SYMBOL_NS_GPL(pci_aer_unmask_internal_errors, "CXL");
>>   
>> +/**
>> + * pci_aer_mask_internal_errors - mask internal errors
>> + * @dev: pointer to the pcie_dev data structure
>> + *
>> + * Masks 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().
>> + */
>> +void pci_aer_mask_internal_errors(struct pci_dev *dev)
>> +{
>> +	int aer = dev->aer_cap;
>> +
>> +	pci_clear_and_set_config_dword(dev, aer + PCI_ERR_UNCOR_MASK,
>> +				       0, PCI_ERR_UNC_INTN);
>> +	pci_clear_and_set_config_dword(dev, aer + PCI_ERR_COR_MASK,
>> +				       0, PCI_ERR_COR_INTERNAL);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(pci_aer_mask_internal_errors, "CXL");
>> +
>>   static bool is_cxl_mem_dev(struct pci_dev *dev)
>>   {
>>   	/*
>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>> index 74600e75705f..41167ad3797a 100644
>> --- a/include/linux/aer.h
>> +++ b/include/linux/aer.h
>> @@ -108,5 +108,6 @@ int cper_severity_to_aer(int cper_severity);
>>   void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
>>   		       int severity, struct aer_capability_regs *aer_regs);
>>   void pci_aer_unmask_internal_errors(struct pci_dev *dev);
>> +void pci_aer_mask_internal_errors(struct pci_dev *dev);
>>   #endif //_AER_H_
>>   


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-06  0:27   ` Dave Jiang
@ 2025-06-06 14:27     ` Bowman, Terry
  2025-06-06 14:36       ` Dave Jiang
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 14:27 UTC (permalink / raw)
  To: Dave Jiang, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/5/2025 7:27 PM, Dave Jiang wrote:
>
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> CXL error handling will soon be moved from the AER driver into the CXL
>> driver. This requires a notification mechanism for the AER driver to share
>> the AER interrupt with the CXL driver. The notification will be used
>> as an indication for the CXL drivers to handle and log the CXL RAS errors.
>>
>> Add a kfifo work queue to be used by the AER driver and CXL driver. The AER
>> driver will be the sole kfifo producer adding work and the cxl_core will be
>> the sole kfifo consumer removing work. Add the boilerplate kfifo support.
>>
>> Add CXL work queue handler registration functions in the AER driver. Export
>> the functions allowing CXL driver to access. Implement registration
>> functions for the CXL driver to assign or clear the work handler function.
>>
>> Introduce function cxl_create_prot_err_info() and 'struct cxl_prot_err_info'.
>> Implement cxl_create_prot_err_info() to populate a 'struct cxl_prot_err_info'
>> instance with the AER severity and the erring device's PCI SBDF. The SBDF
>> details will be used to rediscover the erring device after the CXL driver
>> dequeues the kfifo work. The device rediscovery will be introduced along
>> with the CXL handling in future patches.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/ras.c |  31 +++++++++-
>>  drivers/cxl/cxlpci.h   |   1 +
>>  drivers/pci/pcie/aer.c | 132 ++++++++++++++++++++++++++++-------------
>>  include/linux/aer.h    |  36 +++++++++++
>>  4 files changed, 157 insertions(+), 43 deletions(-)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 485a831695c7..d35525e79e04 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -5,6 +5,7 @@
>>  #include <linux/aer.h>
>>  #include <cxl/event.h>
>>  #include <cxlmem.h>
>> +#include <cxlpci.h>
>>  #include "trace.h"
>>  
>>  static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
>> @@ -107,13 +108,41 @@ 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);
>>  
>> +#ifdef CONFIG_PCIEAER_CXL
>> +
>> +static void cxl_prot_err_work_fn(struct work_struct *work)
>> +{
>> +}
>> +
>> +#else
>> +static void cxl_prot_err_work_fn(struct work_struct *work) { }
>> +#endif /* CONFIG_PCIEAER_CXL */
> I wonder instead of the ifdef block we can just do:
>
> static void cxl_prot_err_work_fn(...)
> {
> 	if (!IS_ENABLED(CONFIG_PCIEAER_CXL))
> 		return;
>
> 	....
> }
I have a TODO request from Jonathan Cameron in the previous series iteration to address the
same #ifdef cleanup. Jonathan recommended introducing drivers/cxl/core/aer.c and moving the
CXL related AER logic to the new file. Are you OK with that solution?

> In general we want to avoid ifdefs in C files. 
>
> Also, where is CONFIG_PCIEAER_CXL defined? I'm having trouble finding the Kconfig that declares it.
>
> $ git grep CONFIG_PCIEAER_CXL
> drivers/cxl/core/pci.c:#ifdef CONFIG_PCIEAER_CXL
> drivers/cxl/core/ras.c:#ifdef CONFIG_PCIEAER_CXL
> drivers/cxl/core/ras.c:#endif /* CONFIG_PCIEAER_CXL */
> drivers/cxl/cxl.h:#ifdef CONFIG_PCIEAER_CXL
> drivers/cxl/port.c:#ifdef CONFIG_PCIEAER_CXL
> drivers/cxl/port.c:#endif /* CONFIG_PCIEAER_CXL */
> drivers/pci/pcie/aer.c:#if defined(CONFIG_PCIEAER_CXL)
> drivers/pci/pcie/aer.c:#ifdef CONFIG_PCIEAER_CXL
> drivers/pci/pcie/aer.c:#if defined(CONFIG_PCIEAER_CXL)
> include/linux/aer.h:#if defined(CONFIG_PCIEAER_CXL)
>
CONFIG_PCIEAER_CXL is a Kconfig dependent on CONFIG_PCIEAER. When enabled the 
#define is found in include/generated/autoconf.h

>> +
>> +static struct work_struct cxl_prot_err_work;
>> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
>> +
>>  int cxl_ras_init(void)
>>  {
>> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>> +	int rc;
>> +
>> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>> +	if (rc)
>> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);
>> +
>> +	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
>> +	if (rc) {
>> +		pr_err("Failed to register native AER kfifo (%x)", rc);
>> +		return rc;
>> +	}
>> +
>> +	return 0;
>>  }
>>  
>>  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_unregister_prot_err_work();
>> +	cancel_work_sync(&cxl_prot_err_work);
>>  }
>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>> index 54e219b0049e..6f1396ef7b77 100644
>> --- a/drivers/cxl/cxlpci.h
>> +++ b/drivers/cxl/cxlpci.h
>> @@ -4,6 +4,7 @@
>>  #define __CXL_PCI_H__
>>  #include <linux/pci.h>
>>  #include "cxl.h"
>> +#include "linux/aer.h"
>>  
>>  #define CXL_MEMORY_PROGIF	0x10
>>  
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index adb4b1123b9b..5350fa5be784 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -114,6 +114,14 @@ struct aer_stats {
>>  static int pcie_aer_disable;
>>  static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
>>  
>> +#if defined(CONFIG_PCIEAER_CXL)
> Would it make sense to move all the CXL bits to a cxl_aer.c instead of all the ifdefs in this C file?
>
> DJ

Yes, this is a good idea. I'll make the AER driver related change to separate the CXL logic.

Terry

>> +#define CXL_ERROR_SOURCES_MAX          128
>> +static DEFINE_KFIFO(cxl_prot_err_fifo, struct cxl_prot_err_work_data,
>> +		    CXL_ERROR_SOURCES_MAX);
>> +static DEFINE_SPINLOCK(cxl_prot_err_fifo_lock);
>> +struct work_struct *cxl_prot_err_work;
>> +#endif
>> +
>>  void pci_no_aer(void)
>>  {
>>  	pcie_aer_disable = 1;
>> @@ -1004,45 +1012,17 @@ static bool is_internal_error(struct aer_err_info *info)
>>  	return info->status & PCI_ERR_UNC_INTN;
>>  }
>>  
>> -static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
>> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
>>  {
>> -	struct aer_err_info *info = (struct aer_err_info *)data;
>> -	const struct pci_error_handlers *err_handler;
>> +	if (!info || !info->is_cxl)
>> +		return false;
>>  
>> -	if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
>> -		return 0;
>> +	/* Only CXL Endpoints are currently supported */
>> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
>> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))
>> +		return false;
>>  
>> -	/* Protect dev->driver */
>> -	device_lock(&dev->dev);
>> -
>> -	err_handler = dev->driver ? dev->driver->err_handler : NULL;
>> -	if (!err_handler)
>> -		goto out;
>> -
>> -	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);
>> -	}
>> -out:
>> -	device_unlock(&dev->dev);
>> -	return 0;
>> -}
>> -
>> -static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_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.
>> -	 */
>> -	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
>> -	    is_internal_error(info))
>> -		pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
>> +	return is_internal_error(info);
>>  }
>>  
>>  static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
>> @@ -1056,13 +1036,17 @@ static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
>>  	return *handles_cxl;
>>  }
>>  
>> -static bool handles_cxl_errors(struct pci_dev *rcec)
>> +static bool handles_cxl_errors(struct pci_dev *dev)
>>  {
>>  	bool handles_cxl = false;
>>  
>> -	if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
>> -	    pcie_aer_is_native(rcec))
>> -		pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
>> +	if (!pcie_aer_is_native(dev))
>> +		return false;
>> +
>> +	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
>> +		pcie_walk_rcec(dev, handles_cxl_error_iter, &handles_cxl);
>> +	else
>> +		handles_cxl = pcie_is_cxl(dev);
>>  
>>  	return handles_cxl;
>>  }
>> @@ -1076,10 +1060,46 @@ static void cxl_rch_enable_rcec(struct pci_dev *rcec)
>>  	pci_info(rcec, "CXL: Internal errors unmasked");
>>  }
>>  
>> +static int cxl_create_prot_error_info(struct pci_dev *pdev,
>> +				      struct aer_err_info *aer_err_info,
>> +				      struct cxl_prot_error_info *cxl_err_info)
>> +{
>> +	cxl_err_info->severity = aer_err_info->severity;
>> +
>> +	cxl_err_info->function = PCI_FUNC(pdev->devfn);
>> +	cxl_err_info->device = PCI_SLOT(pdev->devfn);
>> +	cxl_err_info->bus = pdev->bus->number;
>> +	cxl_err_info->segment = pci_domain_nr(pdev->bus);
>> +
>> +	return 0;
>> +}
>> +
>> +static void forward_cxl_error(struct pci_dev *pdev, struct aer_err_info *aer_err_info)
>> +{
>> +	struct cxl_prot_err_work_data wd;
>> +	struct cxl_prot_error_info *cxl_err_info = &wd.err_info;
>> +
>> +	cxl_create_prot_error_info(pdev, aer_err_info, cxl_err_info);
>> +
>> +	if (!kfifo_put(&cxl_prot_err_fifo, wd)) {
>> +		dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
>> +		return;
>> +	}
>> +
>> +	schedule_work(cxl_prot_err_work);
>> +}
>> +
>>  #else
>>  static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
>>  static inline void cxl_rch_handle_error(struct pci_dev *dev,
>>  					struct aer_err_info *info) { }
>> +static inline void forward_cxl_error(struct pci_dev *dev,
>> +				    struct aer_err_info *info) { }
>> +static inline bool handles_cxl_errors(struct pci_dev *dev)
>> +{
>> +	return false;
>> +}
>> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return 0; };
>>  #endif
>>  
>>  /**
>> @@ -1117,8 +1137,11 @@ 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)
>>  {
>> -	cxl_rch_handle_error(dev, info);
>> -	pci_aer_handle_error(dev, info);
>> +	if (is_cxl_error(dev, info))
>> +		forward_cxl_error(dev, info);
>> +	else
>> +		pci_aer_handle_error(dev, info);
>> +
>>  	pci_dev_put(dev);
>>  }
>>  
>> @@ -1582,6 +1605,31 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
>>  	return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
>>  }
>>  
>> +#if defined(CONFIG_PCIEAER_CXL)
>> +
>> +int cxl_register_prot_err_work(struct work_struct *work)
>> +{
>> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
>> +	cxl_prot_err_work = work;
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_register_prot_err_work, "CXL");
>> +
>> +int cxl_unregister_prot_err_work(void)
>> +{
>> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
>> +	cxl_prot_err_work = NULL;
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_unregister_prot_err_work, "CXL");
>> +
>> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd)
>> +{
>> +	return kfifo_get(&cxl_prot_err_fifo, wd);
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_prot_err_kfifo_get, "CXL");
>> +#endif
>> +
>>  static struct pcie_port_service_driver aerdriver = {
>>  	.name		= "aer",
>>  	.port_type	= PCIE_ANY_PORT,
>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>> index 02940be66324..550407240ab5 100644
>> --- a/include/linux/aer.h
>> +++ b/include/linux/aer.h
>> @@ -10,6 +10,7 @@
>>  
>>  #include <linux/errno.h>
>>  #include <linux/types.h>
>> +#include <linux/workqueue_types.h>
>>  
>>  #define AER_NONFATAL			0
>>  #define AER_FATAL			1
>> @@ -53,6 +54,27 @@ struct aer_capability_regs {
>>  	u16 uncor_err_source;
>>  };
>>  
>> +/**
>> + * struct cxl_prot_err_info - Error information used in CXL error handling
>> + * @severity: AER severity
>> + * @function: Device's PCI function
>> + * @device: Device's PCI device
>> + * @bus: Device's PCI bus
>> + * @segment: Device's PCI segment
>> + */
>> +struct cxl_prot_error_info {
>> +	int severity;
>> +
>> +	u8 function;
>> +	u8 device;
>> +	u8 bus;
>> +	u16 segment;
>> +};
>> +
>> +struct cxl_prot_err_work_data {
>> +	struct cxl_prot_error_info err_info;
>> +};
>> +
>>  #if defined(CONFIG_PCIEAER)
>>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>>  int pcie_aer_is_native(struct pci_dev *dev);
>> @@ -64,6 +86,20 @@ 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; }
>>  #endif
>>  
>> +#if defined(CONFIG_PCIEAER_CXL)
>> +int cxl_register_prot_err_work(struct work_struct *work);
>> +int cxl_unregister_prot_err_work(void);
>> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd);
>> +#else
>> +static inline int
>> +cxl_register_prot_err_work(struct work_struct *work)
>> +{
>> +	return 0;
>> +}
>> +static inline int cxl_unregister_prot_err_work(void) { return 0; }
>> +static inline int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd) { return 0; }
>> +#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);


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-06 14:27     ` Bowman, Terry
@ 2025-06-06 14:36       ` Dave Jiang
  0 siblings, 0 replies; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 14:36 UTC (permalink / raw)
  To: Bowman, Terry, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/25 7:27 AM, Bowman, Terry wrote:
> 
> 
> On 6/5/2025 7:27 PM, Dave Jiang wrote:
>>
>> On 6/3/25 10:22 AM, Terry Bowman wrote:
>>> CXL error handling will soon be moved from the AER driver into the CXL
>>> driver. This requires a notification mechanism for the AER driver to share
>>> the AER interrupt with the CXL driver. The notification will be used
>>> as an indication for the CXL drivers to handle and log the CXL RAS errors.
>>>
>>> Add a kfifo work queue to be used by the AER driver and CXL driver. The AER
>>> driver will be the sole kfifo producer adding work and the cxl_core will be
>>> the sole kfifo consumer removing work. Add the boilerplate kfifo support.
>>>
>>> Add CXL work queue handler registration functions in the AER driver. Export
>>> the functions allowing CXL driver to access. Implement registration
>>> functions for the CXL driver to assign or clear the work handler function.
>>>
>>> Introduce function cxl_create_prot_err_info() and 'struct cxl_prot_err_info'.
>>> Implement cxl_create_prot_err_info() to populate a 'struct cxl_prot_err_info'
>>> instance with the AER severity and the erring device's PCI SBDF. The SBDF
>>> details will be used to rediscover the erring device after the CXL driver
>>> dequeues the kfifo work. The device rediscovery will be introduced along
>>> with the CXL handling in future patches.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>> ---
>>>  drivers/cxl/core/ras.c |  31 +++++++++-
>>>  drivers/cxl/cxlpci.h   |   1 +
>>>  drivers/pci/pcie/aer.c | 132 ++++++++++++++++++++++++++++-------------
>>>  include/linux/aer.h    |  36 +++++++++++
>>>  4 files changed, 157 insertions(+), 43 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>> index 485a831695c7..d35525e79e04 100644
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> @@ -5,6 +5,7 @@
>>>  #include <linux/aer.h>
>>>  #include <cxl/event.h>
>>>  #include <cxlmem.h>
>>> +#include <cxlpci.h>
>>>  #include "trace.h"
>>>  
>>>  static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev,
>>> @@ -107,13 +108,41 @@ 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);
>>>  
>>> +#ifdef CONFIG_PCIEAER_CXL
>>> +
>>> +static void cxl_prot_err_work_fn(struct work_struct *work)
>>> +{
>>> +}
>>> +
>>> +#else
>>> +static void cxl_prot_err_work_fn(struct work_struct *work) { }
>>> +#endif /* CONFIG_PCIEAER_CXL */
>> I wonder instead of the ifdef block we can just do:
>>
>> static void cxl_prot_err_work_fn(...)
>> {
>> 	if (!IS_ENABLED(CONFIG_PCIEAER_CXL))
>> 		return;
>>
>> 	....
>> }
> I have a TODO request from Jonathan Cameron in the previous series iteration to address the
> same #ifdef cleanup. Jonathan recommended introducing drivers/cxl/core/aer.c and moving the
> CXL related AER logic to the new file. Are you OK with that solution?

Yes that works. Thanks!

DJ

> 
>> In general we want to avoid ifdefs in C files. 
>>
>> Also, where is CONFIG_PCIEAER_CXL defined? I'm having trouble finding the Kconfig that declares it.
>>
>> $ git grep CONFIG_PCIEAER_CXL
>> drivers/cxl/core/pci.c:#ifdef CONFIG_PCIEAER_CXL
>> drivers/cxl/core/ras.c:#ifdef CONFIG_PCIEAER_CXL
>> drivers/cxl/core/ras.c:#endif /* CONFIG_PCIEAER_CXL */
>> drivers/cxl/cxl.h:#ifdef CONFIG_PCIEAER_CXL
>> drivers/cxl/port.c:#ifdef CONFIG_PCIEAER_CXL
>> drivers/cxl/port.c:#endif /* CONFIG_PCIEAER_CXL */
>> drivers/pci/pcie/aer.c:#if defined(CONFIG_PCIEAER_CXL)
>> drivers/pci/pcie/aer.c:#ifdef CONFIG_PCIEAER_CXL
>> drivers/pci/pcie/aer.c:#if defined(CONFIG_PCIEAER_CXL)
>> include/linux/aer.h:#if defined(CONFIG_PCIEAER_CXL)
>>
> CONFIG_PCIEAER_CXL is a Kconfig dependent on CONFIG_PCIEAER. When enabled the 
> #define is found in include/generated/autoconf.h
> 
>>> +
>>> +static struct work_struct cxl_prot_err_work;
>>> +static DECLARE_WORK(cxl_prot_err_work, cxl_prot_err_work_fn);
>>> +
>>>  int cxl_ras_init(void)
>>>  {
>>> -	return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>>> +	int rc;
>>> +
>>> +	rc = cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work);
>>> +	if (rc)
>>> +		pr_err("Failed to register CPER AER kfifo (%x)", rc);
>>> +
>>> +	rc = cxl_register_prot_err_work(&cxl_prot_err_work);
>>> +	if (rc) {
>>> +		pr_err("Failed to register native AER kfifo (%x)", rc);
>>> +		return rc;
>>> +	}
>>> +
>>> +	return 0;
>>>  }
>>>  
>>>  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_unregister_prot_err_work();
>>> +	cancel_work_sync(&cxl_prot_err_work);
>>>  }
>>> diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
>>> index 54e219b0049e..6f1396ef7b77 100644
>>> --- a/drivers/cxl/cxlpci.h
>>> +++ b/drivers/cxl/cxlpci.h
>>> @@ -4,6 +4,7 @@
>>>  #define __CXL_PCI_H__
>>>  #include <linux/pci.h>
>>>  #include "cxl.h"
>>> +#include "linux/aer.h"
>>>  
>>>  #define CXL_MEMORY_PROGIF	0x10
>>>  
>>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>>> index adb4b1123b9b..5350fa5be784 100644
>>> --- a/drivers/pci/pcie/aer.c
>>> +++ b/drivers/pci/pcie/aer.c
>>> @@ -114,6 +114,14 @@ struct aer_stats {
>>>  static int pcie_aer_disable;
>>>  static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
>>>  
>>> +#if defined(CONFIG_PCIEAER_CXL)
>> Would it make sense to move all the CXL bits to a cxl_aer.c instead of all the ifdefs in this C file?
>>
>> DJ
> 
> Yes, this is a good idea. I'll make the AER driver related change to separate the CXL logic.
> 
> Terry
> 
>>> +#define CXL_ERROR_SOURCES_MAX          128
>>> +static DEFINE_KFIFO(cxl_prot_err_fifo, struct cxl_prot_err_work_data,
>>> +		    CXL_ERROR_SOURCES_MAX);
>>> +static DEFINE_SPINLOCK(cxl_prot_err_fifo_lock);
>>> +struct work_struct *cxl_prot_err_work;
>>> +#endif
>>> +
>>>  void pci_no_aer(void)
>>>  {
>>>  	pcie_aer_disable = 1;
>>> @@ -1004,45 +1012,17 @@ static bool is_internal_error(struct aer_err_info *info)
>>>  	return info->status & PCI_ERR_UNC_INTN;
>>>  }
>>>  
>>> -static int cxl_rch_handle_error_iter(struct pci_dev *dev, void *data)
>>> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info)
>>>  {
>>> -	struct aer_err_info *info = (struct aer_err_info *)data;
>>> -	const struct pci_error_handlers *err_handler;
>>> +	if (!info || !info->is_cxl)
>>> +		return false;
>>>  
>>> -	if (!is_cxl_mem_dev(dev) || !cxl_error_is_native(dev))
>>> -		return 0;
>>> +	/* Only CXL Endpoints are currently supported */
>>> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
>>> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC))
>>> +		return false;
>>>  
>>> -	/* Protect dev->driver */
>>> -	device_lock(&dev->dev);
>>> -
>>> -	err_handler = dev->driver ? dev->driver->err_handler : NULL;
>>> -	if (!err_handler)
>>> -		goto out;
>>> -
>>> -	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);
>>> -	}
>>> -out:
>>> -	device_unlock(&dev->dev);
>>> -	return 0;
>>> -}
>>> -
>>> -static void cxl_rch_handle_error(struct pci_dev *dev, struct aer_err_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.
>>> -	 */
>>> -	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC &&
>>> -	    is_internal_error(info))
>>> -		pcie_walk_rcec(dev, cxl_rch_handle_error_iter, info);
>>> +	return is_internal_error(info);
>>>  }
>>>  
>>>  static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
>>> @@ -1056,13 +1036,17 @@ static int handles_cxl_error_iter(struct pci_dev *dev, void *data)
>>>  	return *handles_cxl;
>>>  }
>>>  
>>> -static bool handles_cxl_errors(struct pci_dev *rcec)
>>> +static bool handles_cxl_errors(struct pci_dev *dev)
>>>  {
>>>  	bool handles_cxl = false;
>>>  
>>> -	if (pci_pcie_type(rcec) == PCI_EXP_TYPE_RC_EC &&
>>> -	    pcie_aer_is_native(rcec))
>>> -		pcie_walk_rcec(rcec, handles_cxl_error_iter, &handles_cxl);
>>> +	if (!pcie_aer_is_native(dev))
>>> +		return false;
>>> +
>>> +	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
>>> +		pcie_walk_rcec(dev, handles_cxl_error_iter, &handles_cxl);
>>> +	else
>>> +		handles_cxl = pcie_is_cxl(dev);
>>>  
>>>  	return handles_cxl;
>>>  }
>>> @@ -1076,10 +1060,46 @@ static void cxl_rch_enable_rcec(struct pci_dev *rcec)
>>>  	pci_info(rcec, "CXL: Internal errors unmasked");
>>>  }
>>>  
>>> +static int cxl_create_prot_error_info(struct pci_dev *pdev,
>>> +				      struct aer_err_info *aer_err_info,
>>> +				      struct cxl_prot_error_info *cxl_err_info)
>>> +{
>>> +	cxl_err_info->severity = aer_err_info->severity;
>>> +
>>> +	cxl_err_info->function = PCI_FUNC(pdev->devfn);
>>> +	cxl_err_info->device = PCI_SLOT(pdev->devfn);
>>> +	cxl_err_info->bus = pdev->bus->number;
>>> +	cxl_err_info->segment = pci_domain_nr(pdev->bus);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void forward_cxl_error(struct pci_dev *pdev, struct aer_err_info *aer_err_info)
>>> +{
>>> +	struct cxl_prot_err_work_data wd;
>>> +	struct cxl_prot_error_info *cxl_err_info = &wd.err_info;
>>> +
>>> +	cxl_create_prot_error_info(pdev, aer_err_info, cxl_err_info);
>>> +
>>> +	if (!kfifo_put(&cxl_prot_err_fifo, wd)) {
>>> +		dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
>>> +		return;
>>> +	}
>>> +
>>> +	schedule_work(cxl_prot_err_work);
>>> +}
>>> +
>>>  #else
>>>  static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
>>>  static inline void cxl_rch_handle_error(struct pci_dev *dev,
>>>  					struct aer_err_info *info) { }
>>> +static inline void forward_cxl_error(struct pci_dev *dev,
>>> +				    struct aer_err_info *info) { }
>>> +static inline bool handles_cxl_errors(struct pci_dev *dev)
>>> +{
>>> +	return false;
>>> +}
>>> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return 0; };
>>>  #endif
>>>  
>>>  /**
>>> @@ -1117,8 +1137,11 @@ 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)
>>>  {
>>> -	cxl_rch_handle_error(dev, info);
>>> -	pci_aer_handle_error(dev, info);
>>> +	if (is_cxl_error(dev, info))
>>> +		forward_cxl_error(dev, info);
>>> +	else
>>> +		pci_aer_handle_error(dev, info);
>>> +
>>>  	pci_dev_put(dev);
>>>  }
>>>  
>>> @@ -1582,6 +1605,31 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
>>>  	return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
>>>  }
>>>  
>>> +#if defined(CONFIG_PCIEAER_CXL)
>>> +
>>> +int cxl_register_prot_err_work(struct work_struct *work)
>>> +{
>>> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
>>> +	cxl_prot_err_work = work;
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(cxl_register_prot_err_work, "CXL");
>>> +
>>> +int cxl_unregister_prot_err_work(void)
>>> +{
>>> +	guard(spinlock)(&cxl_prot_err_fifo_lock);
>>> +	cxl_prot_err_work = NULL;
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(cxl_unregister_prot_err_work, "CXL");
>>> +
>>> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd)
>>> +{
>>> +	return kfifo_get(&cxl_prot_err_fifo, wd);
>>> +}
>>> +EXPORT_SYMBOL_NS_GPL(cxl_prot_err_kfifo_get, "CXL");
>>> +#endif
>>> +
>>>  static struct pcie_port_service_driver aerdriver = {
>>>  	.name		= "aer",
>>>  	.port_type	= PCIE_ANY_PORT,
>>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>>> index 02940be66324..550407240ab5 100644
>>> --- a/include/linux/aer.h
>>> +++ b/include/linux/aer.h
>>> @@ -10,6 +10,7 @@
>>>  
>>>  #include <linux/errno.h>
>>>  #include <linux/types.h>
>>> +#include <linux/workqueue_types.h>
>>>  
>>>  #define AER_NONFATAL			0
>>>  #define AER_FATAL			1
>>> @@ -53,6 +54,27 @@ struct aer_capability_regs {
>>>  	u16 uncor_err_source;
>>>  };
>>>  
>>> +/**
>>> + * struct cxl_prot_err_info - Error information used in CXL error handling
>>> + * @severity: AER severity
>>> + * @function: Device's PCI function
>>> + * @device: Device's PCI device
>>> + * @bus: Device's PCI bus
>>> + * @segment: Device's PCI segment
>>> + */
>>> +struct cxl_prot_error_info {
>>> +	int severity;
>>> +
>>> +	u8 function;
>>> +	u8 device;
>>> +	u8 bus;
>>> +	u16 segment;
>>> +};
>>> +
>>> +struct cxl_prot_err_work_data {
>>> +	struct cxl_prot_error_info err_info;
>>> +};
>>> +
>>>  #if defined(CONFIG_PCIEAER)
>>>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>>>  int pcie_aer_is_native(struct pci_dev *dev);
>>> @@ -64,6 +86,20 @@ 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; }
>>>  #endif
>>>  
>>> +#if defined(CONFIG_PCIEAER_CXL)
>>> +int cxl_register_prot_err_work(struct work_struct *work);
>>> +int cxl_unregister_prot_err_work(void);
>>> +int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd);
>>> +#else
>>> +static inline int
>>> +cxl_register_prot_err_work(struct work_struct *work)
>>> +{
>>> +	return 0;
>>> +}
>>> +static inline int cxl_unregister_prot_err_work(void) { return 0; }
>>> +static inline int cxl_prot_err_kfifo_get(struct cxl_prot_err_work_data *wd) { return 0; }
>>> +#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);
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
  2025-06-06  9:08   ` Shiju Jose
@ 2025-06-06 14:41     ` Bowman, Terry
  2025-06-06 15:24       ` Bowman, Terry
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 14:41 UTC (permalink / raw)
  To: Shiju Jose, PradeepVineshReddy.Kodamati@amd.com,
	dave@stgolabs.net, Jonathan Cameron, dave.jiang@intel.com,
	alison.schofield@intel.com, vishal.l.verma@intel.com,
	ira.weiny@intel.com, dan.j.williams@intel.com,
	bhelgaas@google.com, bp@alien8.de, ming.li@zohomail.com,
	dan.carpenter@linaro.org, Smita.KoralahalliChannabasappa@amd.com,
	kobayashi.da-06@fujitsu.com, yanfei.xu@intel.com,
	rrichter@amd.com, peterz@infradead.org, colyli@suse.de,
	uaisheng.ye@intel.com, fabio.m.de.francesco@linux.intel.com,
	ilpo.jarvinen@linux.intel.com, yazen.ghannam@amd.com,
	linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org



On 6/6/2025 4:08 AM, Shiju Jose wrote:
>> -----Original Message-----
>> From: Terry Bowman <terry.bowman@amd.com>
>> Sent: 03 June 2025 18:23
>> To: PradeepVineshReddy.Kodamati@amd.com; dave@stgolabs.net; Jonathan
>> Cameron <jonathan.cameron@huawei.com>; dave.jiang@intel.com;
>> alison.schofield@intel.com; vishal.l.verma@intel.com; ira.weiny@intel.com;
>> dan.j.williams@intel.com; bhelgaas@google.com; bp@alien8.de;
>> ming.li@zohomail.com; Shiju Jose <shiju.jose@huawei.com>;
>> dan.carpenter@linaro.org; Smita.KoralahalliChannabasappa@amd.com;
>> kobayashi.da-06@fujitsu.com; terry.bowman@amd.com; yanfei.xu@intel.com;
>> rrichter@amd.com; peterz@infradead.org; colyli@suse.de;
>> uaisheng.ye@intel.com; fabio.m.de.francesco@linux.intel.com;
>> ilpo.jarvinen@linux.intel.com; yazen.ghannam@amd.com; linux-
>> cxl@vger.kernel.org; linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org
>> Subject: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and
>> CXL Ports
>>
>> CXL currently has separate trace routines for CXL Port errors and CXL Endpoint
>> errors. This is inconvenient for the user because they must enable
>> 2 sets of trace routines. Make updates to the trace logging such that a single
>> trace routine logs both CXL Endpoint and CXL Port protocol errors.
>>
>> Rename the 'host' field from the CXL Endpoint trace to 'parent' in the unified
>> trace routines. 'host' does not correctly apply to CXL Port devices. Parent is more
>> general and applies to CXL Port devices and CXL Endpoints.
>>
>> Add serial number parameter to the trace logging. This is used for EPs and 0 is
>> provided for CXL port devices without a serial number.
>>
>> Below is output of correctable and uncorrectable protocol error logging.
>> CXL Root Port and CXL Endpoint examples are included below.
>>
>> Root Port:
>> cxl_aer_correctable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0
>> status='CRC Threshold Hit'
>> cxl_aer_uncorrectable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0
>> status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity
>> Error'
>>
>> Endpoint:
>> cxl_aer_correctable_error: device=mem3 parent=0000:0f:00.0 serial=0
>> status='CRC Threshold Hit'
>> cxl_aer_uncorrectable_error: device=mem3 parent=0000:0f:00.0 serial: 0
>> status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity
>> Error'
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>> drivers/cxl/core/pci.c   | 18 +++++----
>> drivers/cxl/core/ras.c   | 14 ++++---
>> drivers/cxl/core/trace.h | 84 +++++++++-------------------------------
>> 3 files changed, 37 insertions(+), 79 deletions(-)
>>
>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index
>> 186a5a20b951..0f4c07fd64a5 100644
>> --- a/drivers/cxl/core/pci.c
>> +++ b/drivers/cxl/core/pci.c
>> @@ -664,7 +664,7 @@ void read_cdat_data(struct cxl_port *port)  }
>> EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
>>
> [...]
>> static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data
>> *data) diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h index
>> 25ebfbc1616c..8c91b0f3d165 100644
>> --- a/drivers/cxl/core/trace.h
>> +++ b/drivers/cxl/core/trace.h
>> @@ -48,49 +48,22 @@
>> 	{ 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_SIZE_U32)
>> -	),
>> -	TP_fast_assign(
>> -		__assign_str(device);
>> -		__assign_str(host);
>> -		__entry->status = status;
>> -		__entry->first_error = fe;
>> -		/*
>> -		 * Embed the 512B headerlog data for user app retrieval and
>> -		 * parsing, but no need to print this in the trace buffer.
>> -		 */
>> -		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
>> -	),
>> -	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 device *dev, u64 serial, u32 status, u32 fe,
>> +		 u32 *hl),
>> +	TP_ARGS(dev, serial, status, fe, hl),
>> 	TP_STRUCT__entry(
>> -		__string(memdev, dev_name(&cxlmd->dev))
>> -		__string(host, dev_name(cxlmd->dev.parent))
>> +		__string(name, dev_name(dev))
>> +		__string(parent, dev_name(dev->parent))
> Hi Terry,
>
> As we pointed out in v8, renaming the fields "memdev" to "name" and "host" to "parent"
> causes issues and failures in userspace rasdaemon  while parsing the trace event data.
> Additionally, we can't rename these fields in rasdaemon  due to backward compatibility.
Yes, I remember but didn't understand why other SW couldn't be updated to handle. I will
change as you request but many people will be confused why a port device's name is labeled
as a memdev. memdev is only correct for EPs and does not correctly reflect *any* of the
other CXL device types (RP, USP, DSP).

>> 		__field(u64, serial)
>> 		__field(u32, status)
>> 		__field(u32, first_error)
>> 		__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
>> 	),
>> 	TP_fast_assign(
>> -		__assign_str(memdev);
>> -		__assign_str(host);
>> -		__entry->serial = cxlmd->cxlds->serial;
>> +		__assign_str(name);
>> +		__assign_str(parent);
>> +		__entry->serial = serial;
>> 		__entry->status = status;
>> 		__entry->first_error = fe;
>> 		/*
>> @@ -99,8 +72,8 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
>> 		 */
>> 		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
>> 	),
>> -	TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error:
>> '%s'",
>> -		  __get_str(memdev), __get_str(host), __entry->serial,
>> +	TP_printk("device=%s parent=%s serial=%lld status='%s'
>> first_error='%s'",
>> +		  __get_str(name), __get_str(parent), __entry->serial,
>> 		  show_uc_errs(__entry->status),
>> 		  show_uc_errs(__entry->first_error)
>> 	)
>> @@ -124,42 +97,23 @@ 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 device *dev, u64 serial, u32 status),
>> +	TP_ARGS(dev, serial, status),
>> 	TP_STRUCT__entry(
>> -		__string(memdev, dev_name(&cxlmd->dev))
>> -		__string(host, dev_name(cxlmd->dev.parent))
>> +		__string(name, dev_name(dev))
>> +		__string(parent, dev_name(dev->parent))
> Renaming these fields is an issue for userspace as mentioned above 
> in cxl_aer_uncorrectable_error.
I understand, I'll revert as you request.

Terry
>> 		__field(u64, serial)
>> 		__field(u32, status)
>> 	),
>> 	TP_fast_assign(
>> -		__assign_str(memdev);
>> -		__assign_str(host);
>> -		__entry->serial = cxlmd->cxlds->serial;
>> +		__assign_str(name);
>> +		__assign_str(parent);
>> +		__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("device=%s parent=%s serial=%lld status='%s'",
>> +		  __get_str(name), __get_str(parent), __entry->serial,
>> 		  show_ce_errs(__entry->status)
>> 	)
>> );
>> --
>> 2.34.1
>
> Thanks,
> Shiju


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
  2025-06-06 14:41     ` Bowman, Terry
@ 2025-06-06 15:24       ` Bowman, Terry
  2025-06-12 16:25         ` Jonathan Cameron
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 15:24 UTC (permalink / raw)
  To: Shiju Jose, PradeepVineshReddy.Kodamati@amd.com,
	dave@stgolabs.net, Jonathan Cameron, dave.jiang@intel.com,
	alison.schofield@intel.com, vishal.l.verma@intel.com,
	ira.weiny@intel.com, dan.j.williams@intel.com,
	bhelgaas@google.com, bp@alien8.de, ming.li@zohomail.com,
	dan.carpenter@linaro.org, Smita.KoralahalliChannabasappa@amd.com,
	kobayashi.da-06@fujitsu.com, yanfei.xu@intel.com,
	rrichter@amd.com, peterz@infradead.org, colyli@suse.de,
	uaisheng.ye@intel.com, fabio.m.de.francesco@linux.intel.com,
	ilpo.jarvinen@linux.intel.com, yazen.ghannam@amd.com,
	linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org



On 6/6/2025 9:41 AM, Bowman, Terry wrote:
>
> On 6/6/2025 4:08 AM, Shiju Jose wrote:
>>> -----Original Message-----
>>> From: Terry Bowman <terry.bowman@amd.com>
>>> Sent: 03 June 2025 18:23
>>> To: PradeepVineshReddy.Kodamati@amd.com; dave@stgolabs.net; Jonathan
>>> Cameron <jonathan.cameron@huawei.com>; dave.jiang@intel.com;
>>> alison.schofield@intel.com; vishal.l.verma@intel.com; ira.weiny@intel.com;
>>> dan.j.williams@intel.com; bhelgaas@google.com; bp@alien8.de;
>>> ming.li@zohomail.com; Shiju Jose <shiju.jose@huawei.com>;
>>> dan.carpenter@linaro.org; Smita.KoralahalliChannabasappa@amd.com;
>>> kobayashi.da-06@fujitsu.com; terry.bowman@amd.com; yanfei.xu@intel.com;
>>> rrichter@amd.com; peterz@infradead.org; colyli@suse.de;
>>> uaisheng.ye@intel.com; fabio.m.de.francesco@linux.intel.com;
>>> ilpo.jarvinen@linux.intel.com; yazen.ghannam@amd.com; linux-
>>> cxl@vger.kernel.org; linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org
>>> Subject: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and
>>> CXL Ports
>>>
>>> CXL currently has separate trace routines for CXL Port errors and CXL Endpoint
>>> errors. This is inconvenient for the user because they must enable
>>> 2 sets of trace routines. Make updates to the trace logging such that a single
>>> trace routine logs both CXL Endpoint and CXL Port protocol errors.
>>>
>>> Rename the 'host' field from the CXL Endpoint trace to 'parent' in the unified
>>> trace routines. 'host' does not correctly apply to CXL Port devices. Parent is more
>>> general and applies to CXL Port devices and CXL Endpoints.
>>>
>>> Add serial number parameter to the trace logging. This is used for EPs and 0 is
>>> provided for CXL port devices without a serial number.
>>>
>>> Below is output of correctable and uncorrectable protocol error logging.
>>> CXL Root Port and CXL Endpoint examples are included below.
>>>
>>> Root Port:
>>> cxl_aer_correctable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0
>>> status='CRC Threshold Hit'
>>> cxl_aer_uncorrectable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0
>>> status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity
>>> Error'
>>>
>>> Endpoint:
>>> cxl_aer_correctable_error: device=mem3 parent=0000:0f:00.0 serial=0
>>> status='CRC Threshold Hit'
>>> cxl_aer_uncorrectable_error: device=mem3 parent=0000:0f:00.0 serial: 0
>>> status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity
>>> Error'
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>> ---
>>> drivers/cxl/core/pci.c   | 18 +++++----
>>> drivers/cxl/core/ras.c   | 14 ++++---
>>> drivers/cxl/core/trace.h | 84 +++++++++-------------------------------
>>> 3 files changed, 37 insertions(+), 79 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index
>>> 186a5a20b951..0f4c07fd64a5 100644
>>> --- a/drivers/cxl/core/pci.c
>>> +++ b/drivers/cxl/core/pci.c
>>> @@ -664,7 +664,7 @@ void read_cdat_data(struct cxl_port *port)  }
>>> EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
>>>
>> [...]
>>> static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data
>>> *data) diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h index
>>> 25ebfbc1616c..8c91b0f3d165 100644
>>> --- a/drivers/cxl/core/trace.h
>>> +++ b/drivers/cxl/core/trace.h
>>> @@ -48,49 +48,22 @@
>>> 	{ 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_SIZE_U32)
>>> -	),
>>> -	TP_fast_assign(
>>> -		__assign_str(device);
>>> -		__assign_str(host);
>>> -		__entry->status = status;
>>> -		__entry->first_error = fe;
>>> -		/*
>>> -		 * Embed the 512B headerlog data for user app retrieval and
>>> -		 * parsing, but no need to print this in the trace buffer.
>>> -		 */
>>> -		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
>>> -	),
>>> -	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 device *dev, u64 serial, u32 status, u32 fe,
>>> +		 u32 *hl),
>>> +	TP_ARGS(dev, serial, status, fe, hl),
>>> 	TP_STRUCT__entry(
>>> -		__string(memdev, dev_name(&cxlmd->dev))
>>> -		__string(host, dev_name(cxlmd->dev.parent))
>>> +		__string(name, dev_name(dev))
>>> +		__string(parent, dev_name(dev->parent))
>> Hi Terry,
>>
>> As we pointed out in v8, renaming the fields "memdev" to "name" and "host" to "parent"
>> causes issues and failures in userspace rasdaemon  while parsing the trace event data.
>> Additionally, we can't rename these fields in rasdaemon  due to backward compatibility.
> Yes, I remember but didn't understand why other SW couldn't be updated to handle. I will
> change as you request but many people will be confused why a port device's name is labeled
> as a memdev. memdev is only correct for EPs and does not correctly reflect *any* of the
> other CXL device types (RP, USP, DSP).
>
>>> 		__field(u64, serial)
>>> 		__field(u32, status)
>>> 		__field(u32, first_error)
>>> 		__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
>>> 	),
>>> 	TP_fast_assign(
>>> -		__assign_str(memdev);
>>> -		__assign_str(host);
>>> -		__entry->serial = cxlmd->cxlds->serial;
>>> +		__assign_str(name);
>>> +		__assign_str(parent);
>>> +		__entry->serial = serial;
>>> 		__entry->status = status;
>>> 		__entry->first_error = fe;
>>> 		/*
>>> @@ -99,8 +72,8 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
>>> 		 */
>>> 		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
>>> 	),
>>> -	TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error:
>>> '%s'",
>>> -		  __get_str(memdev), __get_str(host), __entry->serial,
>>> +	TP_printk("device=%s parent=%s serial=%lld status='%s'
>>> first_error='%s'",
>>> +		  __get_str(name), __get_str(parent), __entry->serial,
>>> 		  show_uc_errs(__entry->status),
>>> 		  show_uc_errs(__entry->first_error)
>>> 	)
>>> @@ -124,42 +97,23 @@ 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 device *dev, u64 serial, u32 status),
>>> +	TP_ARGS(dev, serial, status),
>>> 	TP_STRUCT__entry(
>>> -		__string(memdev, dev_name(&cxlmd->dev))
>>> -		__string(host, dev_name(cxlmd->dev.parent))
>>> +		__string(name, dev_name(dev))
>>> +		__string(parent, dev_name(dev->parent))
>> Renaming these fields is an issue for userspace as mentioned above 
>> in cxl_aer_uncorrectable_error.
> I understand, I'll revert as you request.
>
> Terry

I'll update the commit message with explanation for leaving as-is.

Terry
>>> 		__field(u64, serial)
>>> 		__field(u32, status)
>>> 	),
>>> 	TP_fast_assign(
>>> -		__assign_str(memdev);
>>> -		__assign_str(host);
>>> -		__entry->serial = cxlmd->cxlds->serial;
>>> +		__assign_str(name);
>>> +		__assign_str(parent);
>>> +		__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("device=%s parent=%s serial=%lld status='%s'",
>>> +		  __get_str(name), __get_str(parent), __entry->serial,
>>> 		  show_ce_errs(__entry->status)
>>> 	)
>>> );
>>> --
>>> 2.34.1
>> Thanks,
>> Shiju


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-03 17:22 ` [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error Terry Bowman
  2025-06-04  6:05   ` Dan Carpenter
  2025-06-04 23:58   ` Sathyanarayanan Kuppuswamy
@ 2025-06-06 15:57   ` Dave Jiang
  2025-06-06 18:14     ` Bowman, Terry
                       ` (2 more replies)
  2025-06-10  4:15   ` Lukas Wunner
  2025-06-12 11:36   ` Jonathan Cameron
  4 siblings, 3 replies; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 15:57 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, coly.li, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> The AER driver is now designed to forward CXL protocol errors to the CXL
> driver. Update the CXL driver with functionality to dequeue the forwarded
> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
> error handling processing using the work received from the FIFO.
> 
> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
> AER service driver. This will begin the CXL protocol error processing
> with a call to cxl_handle_prot_error().
> 
> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
> previously in the AER driver.
> 
> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
> and use in discovering the erring PCI device. Make scope based reference
> increments/decrements for the discovered PCI device and the associated
> CXL device.
> 
> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
> RCH errors will be processed with a call to walk the associated Root
> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
> so the CXL driver can walk the RCEC's downstream bus, searching for
> the RCiEP.
> 
> VH correctable error (CE) processing will call the CXL CE handler. VH
> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
> and pci_clean_device_status() used to clean up AER status after handling.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>  drivers/pci/pci.c       |  1 +
>  drivers/pci/pci.h       |  8 ----
>  drivers/pci/pcie/aer.c  |  1 +
>  drivers/pci/pcie/rcec.c |  1 +
>  include/linux/aer.h     |  2 +
>  include/linux/pci.h     | 10 +++++
>  7 files changed, 107 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index d35525e79e04..9ed5c682e128 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>  
>  #ifdef CONFIG_PCIEAER_CXL
>  
> +static void cxl_do_recovery(struct pci_dev *pdev)
> +{
> +}
> +
> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> +{
> +	struct cxl_prot_error_info *err_info = data;
> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
> +	struct cxl_dev_state *cxlds;
> +
> +	/*
> +	 * The capability, status, and control fields in Device 0,
> +	 * Function 0 DVSEC control the CXL functionality of the
> +	 * entire device (CXL 3.0, 8.1.3).
> +	 */
> +	if (pdev->devfn != PCI_DEVFN(0, 0))
> +		return 0;
> +
> +	/*
> +	 * CXL Memory Devices must have the 502h class code set (CXL
> +	 * 3.0, 8.1.12.1).
> +	 */
> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)

Should use FIELD_GET() to be consistent with the rest of CXL code base

> +		return 0;
> +
> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)

I think you need to hold the pdev->dev lock while checking if the driver exists.

> +		return 0;
> +
> +	cxlds = pci_get_drvdata(pdev);
> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);

Maybe a comment on why cxlmd->dev ref is needed here.

> +
> +	if (err_info->severity == AER_CORRECTABLE)
> +		cxl_cor_error_detected(pdev);
> +	else
> +		cxl_do_recovery(pdev);
> +
> +	return 1;
> +}
> +
> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
> +{
> +	unsigned int devfn = PCI_DEVFN(err_info->device,
> +				       err_info->function);
> +	struct pci_dev *pdev __free(pci_dev_put) =
> +		pci_get_domain_bus_and_slot(err_info->segment,
> +					    err_info->bus,
> +					    devfn);

Looks like DanC already caught that. Maybe have this function return with a ref held. I would also add a comment for the function mention that the caller need to put the device.

> +	return pdev;
> +}
> +
> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
> +{
> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> +
> +	if (!pdev) {
> +		pr_err("Failed to find the CXL device\n");
> +		return;
> +	}
> +
> +	/*
> +	 * 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.
> +	 */
> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
> +

cxl_rch_handle_error_iter() holds the pdev device lock when handling errors. Does the code block below need locking?

DJ

> +	if (err_info->severity == AER_CORRECTABLE) {
> +		int aer = pdev->aer_cap;
> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +
> +		if (aer)
> +			pci_clear_and_set_config_dword(pdev,
> +						       aer + PCI_ERR_COR_STATUS,
> +						       0, PCI_ERR_COR_INTERNAL);
> +
> +		cxl_cor_error_detected(pdev);
> +
> +		pcie_clear_device_status(pdev);
> +	} else {
> +		cxl_do_recovery(pdev);
> +	}
> +}
> +
>  static void cxl_prot_err_work_fn(struct work_struct *work)
>  {
> +	struct cxl_prot_err_work_data wd;
> +
> +	while (cxl_prot_err_kfifo_get(&wd)) {
> +		struct cxl_prot_error_info *err_info = &wd.err_info;
> +
> +		cxl_handle_prot_error(err_info);
> +	}
>  }
>  
>  #else
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index e77d5b53c0ce..524ac32b744a 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
>  	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
>  	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
>  }
> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
>  #endif
>  
>  /**
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index d6296500b004..3c54a5ed803e 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
>  void pci_rcec_init(struct pci_dev *dev);
>  void pci_rcec_exit(struct pci_dev *dev);
>  void pcie_link_rcec(struct pci_dev *rcec);
> -void pcie_walk_rcec(struct pci_dev *rcec,
> -		    int (*cb)(struct pci_dev *, void *),
> -		    void *userdata);
>  #else
>  static inline void pci_rcec_init(struct pci_dev *dev) { }
>  static inline void pci_rcec_exit(struct pci_dev *dev) { }
>  static inline void pcie_link_rcec(struct pci_dev *rcec) { }
> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
> -				  int (*cb)(struct pci_dev *, void *),
> -				  void *userdata) { }
>  #endif
>  
>  #ifdef CONFIG_PCI_ATS
> @@ -967,7 +961,6 @@ void pci_no_aer(void);
>  void pci_aer_init(struct pci_dev *dev);
>  void pci_aer_exit(struct pci_dev *dev);
>  extern const struct attribute_group aer_stats_attr_group;
> -void pci_aer_clear_fatal_status(struct pci_dev *dev);
>  int pci_aer_clear_status(struct pci_dev *dev);
>  int pci_aer_raw_clear_status(struct pci_dev *dev);
>  void pci_save_aer_state(struct pci_dev *dev);
> @@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
>  static inline void pci_no_aer(void) { }
>  static inline void pci_aer_init(struct pci_dev *d) { }
>  static inline void pci_aer_exit(struct pci_dev *d) { }
> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>  static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
>  static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
>  static inline void pci_save_aer_state(struct pci_dev *dev) { }
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 5350fa5be784..6e88331c6303 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
>  	if (status)
>  		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
>  }
> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>  
>  /**
>   * pci_aer_raw_clear_status - Clear AER error registers.
> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
> index d0bcd141ac9c..fb6cf6449a1d 100644
> --- a/drivers/pci/pcie/rcec.c
> +++ b/drivers/pci/pcie/rcec.c
> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>  
>  	walk_rcec(walk_rcec_helper, &rcec_data);
>  }
> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
>  
>  void pci_rcec_init(struct pci_dev *dev)
>  {
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 550407240ab5..c9a18eca16f8 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
>  
>  #if defined(CONFIG_PCIEAER)
>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
>  int pcie_aer_is_native(struct pci_dev *dev);
>  #else
>  static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>  {
>  	return -EINVAL;
>  }
> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>  static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>  #endif
>  
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index bff3009f9ff0..cd53715d53f3 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
>  
>  int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
>  			  bool use_lt);
> +void pcie_walk_rcec(struct pci_dev *rcec,
> +		    int (*cb)(struct pci_dev *, void *),
> +		    void *userdata);
>  #else
>  #define pcie_ports_disabled	true
>  #define pcie_ports_native	false
> @@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
>  {
>  	return -EOPNOTSUPP;
>  }
> +
> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
> +				  int (*cb)(struct pci_dev *, void *),
> +				  void *userdata) { }
> +
>  #endif
>  
> +void pcie_clear_device_status(struct pci_dev *dev);
> +
>  #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
>  #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
>  #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
  2025-06-03 17:22 ` [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
  2025-06-05 15:14   ` Sathyanarayanan Kuppuswamy
@ 2025-06-06 16:45   ` Dave Jiang
  2025-06-06 18:16     ` Bowman, Terry
  2025-06-12 16:06   ` Jonathan Cameron
  2 siblings, 1 reply; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 16:45 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> Create cxl_do_recovery() to provide uncorrectable protocol error (UCE)
> handling. Follow similar design as found in PCIe error driver,
> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
> 
> Copy the PCI error driver's merge_result() and rename as cxl_merge_result().
> Introduce PCI_ERS_RESULT_PANIC and add support in the cxl_merge_result()
> routine.
> 
> Copy pci_walk_bridge() to cxl_walk_bridge(). Make a change to walk the
> first device in all cases.
> 
> Copy the PCI error driver's report_error_detected() to cxl_report_error_detected().
> Note, only CXL Endpoints are currently supported. Add locking for PCI
> device as done in PCI's report_error_detected(). Add reference counting for
> the CXL device responsible for cleanup of the CXL RAS. This is necessary
> to prevent the RAS registers from disappearing before logging is completed.
> 
> Call panic() to halt the system in the case of uncorrectable errors (UCE)
> in cxl_do_recovery(). Export pci_aer_clear_fatal_status() for CXL to use
> if a UCE is not found. In this case the AER status must be cleared and
> uses pci_aer_clear_fatal_status().
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>  drivers/cxl/core/ras.c | 79 ++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci.h    |  3 ++
>  2 files changed, 82 insertions(+)
> 
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 9ed5c682e128..715f7221ea3a 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -110,8 +110,87 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>  
>  #ifdef CONFIG_PCIEAER_CXL
>  
> +static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
> +					 enum pci_ers_result new)
> +{
> +	if (new == PCI_ERS_RESULT_PANIC)
> +		return PCI_ERS_RESULT_PANIC;
> +
> +	if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
> +		return PCI_ERS_RESULT_NO_AER_DRIVER;
> +
> +	if (new == PCI_ERS_RESULT_NONE)
> +		return orig;
> +
> +	switch (orig) {
> +	case PCI_ERS_RESULT_CAN_RECOVER:
> +	case PCI_ERS_RESULT_RECOVERED:
> +		orig = new;
> +		break;
> +	case PCI_ERS_RESULT_DISCONNECT:
> +		if (new == PCI_ERS_RESULT_NEED_RESET)
> +			orig = PCI_ERS_RESULT_NEED_RESET;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return orig;
> +}
> +
> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
> +{
> +	pci_ers_result_t vote, *result = data;
> +	struct cxl_dev_state *cxlds;
> +
> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
> +		return 0;
> +

Lock here before getting driver data instead of later?

guard(device)(&pdev->dev);

> +	cxlds = pci_get_drvdata(pdev);

Add a comment for the ref grab

DJ

> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +
> +	device_lock(&pdev->dev);
> +	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
> +	*result = cxl_merge_result(*result, vote);
> +	device_unlock(&pdev->dev);
> +
> +	return 0;
> +}
> +
> +static void cxl_walk_bridge(struct pci_dev *bridge,
> +			    int (*cb)(struct pci_dev *, void *),
> +			    void *userdata)
> +{
> +	if (cb(bridge, userdata))
> +		return;
> +
> +	if (bridge->subordinate)
> +		pci_walk_bus(bridge->subordinate, cb, userdata);
> +}
> +
>  static void cxl_do_recovery(struct pci_dev *pdev)
>  {
> +	struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
> +	pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
> +
> +	cxl_walk_bridge(pdev, cxl_report_error_detected, &status);
> +	if (status == PCI_ERS_RESULT_PANIC)
> +		panic("CXL cachemem error.");
> +
> +	/*
> +	 * If we have native control of AER, clear error status in the device
> +	 * that detected the error.  If the platform retained control of AER,
> +	 * it is responsible for clearing this status.  In that case, the
> +	 * signaling device may not even be visible to the OS.
> +	 */
> +	if (host->native_aer) {
> +		pcie_clear_device_status(pdev);
> +		pci_aer_clear_nonfatal_status(pdev);
> +		pci_aer_clear_fatal_status(pdev);
> +	}
> +
> +	pci_info(pdev, "CXL uncorrectable error.\n");
>  }
>  
>  static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index cd53715d53f3..b0e7545162de 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -870,6 +870,9 @@ enum pci_ers_result {
>  
>  	/* No AER capabilities registered for the driver */
>  	PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
> +
> +	/* System is unstable, panic  */
> +	PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,
>  };
>  
>  /* PCI bus error event callbacks */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 06/16] cxl/pci: Move RAS initialization to cxl_port driver
  2025-06-03 17:22 ` [PATCH v9 06/16] cxl/pci: Move RAS initialization to cxl_port driver Terry Bowman
@ 2025-06-06 17:04   ` Dave Jiang
  2025-06-06 18:17     ` Bowman, Terry
  0 siblings, 1 reply; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 17:04 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> The cxl_port driver is intended to manage CXL Endpoint Ports and CXL Switch
> Ports. Move existing RAS initialization to the cxl_port driver.
> 
> Restricted CXL Host (RCH) Downstream Port RAS initialization currently
> resides in cxl/core/pci.c. The PCI source file is not otherwise associated
> with CXL Port management.
> 
> Additional CXL Port RAS initialization will be added in future patches to
> support a CXL Port device's CXL errors.

Is this the part that Jonathan recommended moving to cxl/core/ras.c?

DJ

> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>  drivers/cxl/core/pci.c  | 73 --------------------------------------
>  drivers/cxl/core/regs.c |  2 ++
>  drivers/cxl/cxl.h       |  6 ++++
>  drivers/cxl/port.c      | 78 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 86 insertions(+), 73 deletions(-)
> 
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index b50551601c2e..317cd0a91ffe 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -748,79 +748,6 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>  
>  #ifdef CONFIG_PCIEAER_CXL
>  
> -static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
> -{
> -	resource_size_t aer_phys;
> -	struct device *host;
> -	u16 aer_cap;
> -
> -	aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
> -	if (aer_cap) {
> -		host = dport->reg_map.host;
> -		aer_phys = aer_cap + dport->rcrb.base;
> -		dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
> -						sizeof(struct aer_capability_regs));
> -	}
> -}
> -
> -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)
> -		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)))
> -		dev_dbg(dev, "Failed to map RAS capability.\n");
> -}
> -
> -static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
> -{
> -	void __iomem *aer_base = dport->regs.dport_aer;
> -	u32 aer_cmd_mask, aer_cmd;
> -
> -	if (!aer_base)
> -		return;
> -
> -	/*
> -	 * Disable RCH root port command interrupts.
> -	 * CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
> -	 *
> -	 * This sequence may not be necessary. CXL spec states disabling
> -	 * the root cmd register's interrupts is required. But, PCI spec
> -	 * shows these are disabled by default on reset.
> -	 */
> -	aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
> -			PCI_ERR_ROOT_CMD_NONFATAL_EN |
> -			PCI_ERR_ROOT_CMD_FATAL_EN);
> -	aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
> -	aer_cmd &= ~aer_cmd_mask;
> -	writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
> -}
> -
> -/**
> - * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
> - * @dport: the cxl_dport that needs to be initialized
> - * @host: host device for devm operations
> - */
> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
> -{
> -	dport->reg_map.host = host;
> -	cxl_dport_map_ras(dport);
> -
> -	if (dport->rch) {
> -		struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
> -
> -		if (!host_bridge->native_aer)
> -			return;
> -
> -		cxl_dport_map_rch_aer(dport);
> -		cxl_disable_rch_root_ints(dport);
> -	}
> -}
> -EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
> -
>  static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
>  					  struct cxl_dport *dport)
>  {
> diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
> index 5ca7b0eed568..b8e767a9571c 100644
> --- a/drivers/cxl/core/regs.c
> +++ b/drivers/cxl/core/regs.c
> @@ -199,6 +199,7 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
>  
>  	return ret_val;
>  }
> +EXPORT_SYMBOL_NS_GPL(devm_cxl_iomap_block, "CXL");
>  
>  int cxl_map_component_regs(const struct cxl_register_map *map,
>  			   struct cxl_component_regs *regs,
> @@ -517,6 +518,7 @@ u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb)
>  
>  	return offset;
>  }
> +EXPORT_SYMBOL_NS_GPL(cxl_rcrb_to_aer, "CXL");
>  
>  static resource_size_t cxl_rcrb_to_linkcap(struct device *dev, struct cxl_dport *dport)
>  {
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index ba08b77b65da..0dc43bfba76a 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -313,6 +313,12 @@ int cxl_setup_regs(struct cxl_register_map *map);
>  struct cxl_dport;
>  resource_size_t cxl_rcd_component_reg_phys(struct device *dev,
>  					   struct cxl_dport *dport);
> +
> +u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb);
> +
> +void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
> +				   resource_size_t length);
> +
>  int cxl_dport_map_rcd_linkcap(struct pci_dev *pdev, struct cxl_dport *dport);
>  
>  #define CXL_RESOURCE_NONE ((resource_size_t) -1)
> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
> index fe4b593331da..7b61f09347a5 100644
> --- a/drivers/cxl/port.c
> +++ b/drivers/cxl/port.c
> @@ -6,6 +6,7 @@
>  
>  #include "cxlmem.h"
>  #include "cxlpci.h"
> +#include "cxl.h"
>  
>  /**
>   * DOC: cxl port
> @@ -57,6 +58,83 @@ static int discover_region(struct device *dev, void *unused)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_PCIEAER_CXL
> +
> +static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
> +{
> +	resource_size_t aer_phys;
> +	struct device *host;
> +	u16 aer_cap;
> +
> +	aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
> +	if (aer_cap) {
> +		host = dport->reg_map.host;
> +		aer_phys = aer_cap + dport->rcrb.base;
> +		dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
> +						sizeof(struct aer_capability_regs));
> +	}
> +}
> +
> +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)
> +		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)))
> +		dev_dbg(dev, "Failed to map RAS capability.\n");
> +}
> +
> +static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
> +{
> +	void __iomem *aer_base = dport->regs.dport_aer;
> +	u32 aer_cmd_mask, aer_cmd;
> +
> +	if (!aer_base)
> +		return;
> +
> +	/*
> +	 * Disable RCH root port command interrupts.
> +	 * CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
> +	 *
> +	 * This sequence may not be necessary. CXL spec states disabling
> +	 * the root cmd register's interrupts is required. But, PCI spec
> +	 * shows these are disabled by default on reset.
> +	 */
> +	aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
> +			PCI_ERR_ROOT_CMD_NONFATAL_EN |
> +			PCI_ERR_ROOT_CMD_FATAL_EN);
> +	aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
> +	aer_cmd &= ~aer_cmd_mask;
> +	writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
> +}
> +
> +/**
> + * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
> + * @dport: the cxl_dport that needs to be initialized
> + * @host: host device for devm operations
> + */
> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
> +{
> +	dport->reg_map.host = host;
> +	cxl_dport_map_ras(dport);
> +
> +	if (dport->rch) {
> +		struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
> +
> +		if (!host_bridge->native_aer)
> +			return;
> +
> +		cxl_dport_map_rch_aer(dport);
> +		cxl_disable_rch_root_ints(dport);
> +	}
> +}
> +EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
> +
> +#endif /* CONFIG_PCIEAER_CXL */
> +
>  static int cxl_switch_port_probe(struct cxl_port *port)
>  {
>  	struct cxl_hdm *cxlhdm;


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped
  2025-06-03 17:22 ` [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped Terry Bowman
  2025-06-05 16:42   ` Sathyanarayanan Kuppuswamy
@ 2025-06-06 17:27   ` Dave Jiang
  1 sibling, 0 replies; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 17:27 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> The CXL RAS handlers do not currently log if the RAS registers are
> unmapped. This is needed in order to help debug CXL error handling. Update
> the CXL driver to log a warning message if the RAS register block is
> unmapped during RAS error handling.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

Reviewed-by: Dave Jiang <dave.jiang@intel.com>

> ---
>  drivers/cxl/core/pci.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index 78735da7e63d..186a5a20b951 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -670,8 +670,10 @@ static void __cxl_handle_cor_ras(struct device *dev,
>  	void __iomem *addr;
>  	u32 status;
>  
> -	if (!ras_base)
> +	if (!ras_base) {
> +		dev_warn_once(dev, "CXL RAS register block is not mapped");
>  		return;
> +	}
>  
>  	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
>  	status = readl(addr);
> @@ -714,8 +716,10 @@ static bool __cxl_handle_ras(struct device *dev, void __iomem *ras_base)
>  	u32 status;
>  	u32 fe;
>  
> -	if (!ras_base)
> +	if (!ras_base) {
> +		dev_warn_once(dev, "CXL RAS register block is not mapped");
>  		return false;
> +	}
>  
>  	addr = ras_base + CXL_RAS_UNCORRECTABLE_STATUS_OFFSET;
>  	status = readl(addr);


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-06 15:57   ` Dave Jiang
@ 2025-06-06 18:14     ` Bowman, Terry
  2025-06-06 22:43       ` Dave Jiang
  2025-06-06 21:08     ` Bowman, Terry
  2025-06-06 23:15     ` Bowman, Terry
  2 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 18:14 UTC (permalink / raw)
  To: Dave Jiang, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, coly.li, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/2025 10:57 AM, Dave Jiang wrote:
>
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> The AER driver is now designed to forward CXL protocol errors to the CXL
>> driver. Update the CXL driver with functionality to dequeue the forwarded
>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
>> error handling processing using the work received from the FIFO.
>>
>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>> AER service driver. This will begin the CXL protocol error processing
>> with a call to cxl_handle_prot_error().
>>
>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
>> previously in the AER driver.
>>
>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
>> and use in discovering the erring PCI device. Make scope based reference
>> increments/decrements for the discovered PCI device and the associated
>> CXL device.
>>
>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>> RCH errors will be processed with a call to walk the associated Root
>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>> so the CXL driver can walk the RCEC's downstream bus, searching for
>> the RCiEP.
>>
>> VH correctable error (CE) processing will call the CXL CE handler. VH
>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
>> and pci_clean_device_status() used to clean up AER status after handling.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/pci/pci.c       |  1 +
>>  drivers/pci/pci.h       |  8 ----
>>  drivers/pci/pcie/aer.c  |  1 +
>>  drivers/pci/pcie/rcec.c |  1 +
>>  include/linux/aer.h     |  2 +
>>  include/linux/pci.h     | 10 +++++
>>  7 files changed, 107 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index d35525e79e04..9ed5c682e128 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>  
>>  #ifdef CONFIG_PCIEAER_CXL
>>  
>> +static void cxl_do_recovery(struct pci_dev *pdev)
>> +{
>> +}
>> +
>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>> +{
>> +	struct cxl_prot_error_info *err_info = data;
>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>> +	struct cxl_dev_state *cxlds;
>> +
>> +	/*
>> +	 * The capability, status, and control fields in Device 0,
>> +	 * Function 0 DVSEC control the CXL functionality of the
>> +	 * entire device (CXL 3.0, 8.1.3).
>> +	 */
>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>> +		return 0;
>> +
>> +	/*
>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>> +	 * 3.0, 8.1.12.1).
>> +	 */
>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> Should use FIELD_GET() to be consistent with the rest of CXL code base

Ok.

>> +		return 0;
>> +
>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
> I think you need to hold the pdev->dev lock while checking if the driver exists.
Ok.
>> +		return 0;
>> +
>> +	cxlds = pci_get_drvdata(pdev);
>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> Maybe a comment on why cxlmd->dev ref is needed here.
Good point.
>> +
>> +	if (err_info->severity == AER_CORRECTABLE)
>> +		cxl_cor_error_detected(pdev);
>> +	else
>> +		cxl_do_recovery(pdev);
>> +
>> +	return 1;
>> +}
>> +
>> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>> +{
>> +	unsigned int devfn = PCI_DEVFN(err_info->device,
>> +				       err_info->function);
>> +	struct pci_dev *pdev __free(pci_dev_put) =
>> +		pci_get_domain_bus_and_slot(err_info->segment,
>> +					    err_info->bus,
>> +					    devfn);
> Looks like DanC already caught that. Maybe have this function return with a ref held. I would also add a comment for the function mention that the caller need to put the device.
Right. I made the change in v10 source after DanC commented. I'll add a comment that callers must decrement the reference count..
>> +	return pdev;
>> +}
>> +
>> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>> +{
>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
>> +
>> +	if (!pdev) {
>> +		pr_err("Failed to find the CXL device\n");
>> +		return;
>> +	}
>> +
>> +	/*
>> +	 * 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.
>> +	 */
>> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
>> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>> +
> cxl_rch_handle_error_iter() holds the pdev device lock when handling errors. Does the code block below need locking?
>
> DJ
There is a guard_lock() in the EP CXL error handlers (cxl_error_detected()/cxl_cor_error_detected()). I have question about
the same for the non-EP handlers added later: should we add the same guard() for the CXL port handlers? That is in following patch:
[PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers.

Terry
>> +	if (err_info->severity == AER_CORRECTABLE) {
>> +		int aer = pdev->aer_cap;
>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>> +
>> +		if (aer)
>> +			pci_clear_and_set_config_dword(pdev,
>> +						       aer + PCI_ERR_COR_STATUS,
>> +						       0, PCI_ERR_COR_INTERNAL);
>> +
>> +		cxl_cor_error_detected(pdev);
>> +
>> +		pcie_clear_device_status(pdev);
>> +	} else {
>> +		cxl_do_recovery(pdev);
>> +	}
>> +}
>> +
>>  static void cxl_prot_err_work_fn(struct work_struct *work)
>>  {
>> +	struct cxl_prot_err_work_data wd;
>> +
>> +	while (cxl_prot_err_kfifo_get(&wd)) {
>> +		struct cxl_prot_error_info *err_info = &wd.err_info;
>> +
>> +		cxl_handle_prot_error(err_info);
>> +	}
>>  }
>>  
>>  #else
>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>> index e77d5b53c0ce..524ac32b744a 100644
>> --- a/drivers/pci/pci.c
>> +++ b/drivers/pci/pci.c
>> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
>>  	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
>>  	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
>>  }
>> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
>>  #endif
>>  
>>  /**
>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>> index d6296500b004..3c54a5ed803e 100644
>> --- a/drivers/pci/pci.h
>> +++ b/drivers/pci/pci.h
>> @@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
>>  void pci_rcec_init(struct pci_dev *dev);
>>  void pci_rcec_exit(struct pci_dev *dev);
>>  void pcie_link_rcec(struct pci_dev *rcec);
>> -void pcie_walk_rcec(struct pci_dev *rcec,
>> -		    int (*cb)(struct pci_dev *, void *),
>> -		    void *userdata);
>>  #else
>>  static inline void pci_rcec_init(struct pci_dev *dev) { }
>>  static inline void pci_rcec_exit(struct pci_dev *dev) { }
>>  static inline void pcie_link_rcec(struct pci_dev *rcec) { }
>> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
>> -				  int (*cb)(struct pci_dev *, void *),
>> -				  void *userdata) { }
>>  #endif
>>  
>>  #ifdef CONFIG_PCI_ATS
>> @@ -967,7 +961,6 @@ void pci_no_aer(void);
>>  void pci_aer_init(struct pci_dev *dev);
>>  void pci_aer_exit(struct pci_dev *dev);
>>  extern const struct attribute_group aer_stats_attr_group;
>> -void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>  int pci_aer_clear_status(struct pci_dev *dev);
>>  int pci_aer_raw_clear_status(struct pci_dev *dev);
>>  void pci_save_aer_state(struct pci_dev *dev);
>> @@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
>>  static inline void pci_no_aer(void) { }
>>  static inline void pci_aer_init(struct pci_dev *d) { }
>>  static inline void pci_aer_exit(struct pci_dev *d) { }
>> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>  static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>  static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>  static inline void pci_save_aer_state(struct pci_dev *dev) { }
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index 5350fa5be784..6e88331c6303 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
>>  	if (status)
>>  		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
>>  }
>> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>>  
>>  /**
>>   * pci_aer_raw_clear_status - Clear AER error registers.
>> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
>> index d0bcd141ac9c..fb6cf6449a1d 100644
>> --- a/drivers/pci/pcie/rcec.c
>> +++ b/drivers/pci/pcie/rcec.c
>> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>>  
>>  	walk_rcec(walk_rcec_helper, &rcec_data);
>>  }
>> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
>>  
>>  void pci_rcec_init(struct pci_dev *dev)
>>  {
>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>> index 550407240ab5..c9a18eca16f8 100644
>> --- a/include/linux/aer.h
>> +++ b/include/linux/aer.h
>> @@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
>>  
>>  #if defined(CONFIG_PCIEAER)
>>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>  int pcie_aer_is_native(struct pci_dev *dev);
>>  #else
>>  static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>>  {
>>  	return -EINVAL;
>>  }
>> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>  static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>>  #endif
>>  
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index bff3009f9ff0..cd53715d53f3 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
>>  
>>  int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
>>  			  bool use_lt);
>> +void pcie_walk_rcec(struct pci_dev *rcec,
>> +		    int (*cb)(struct pci_dev *, void *),
>> +		    void *userdata);
>>  #else
>>  #define pcie_ports_disabled	true
>>  #define pcie_ports_native	false
>> @@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
>>  {
>>  	return -EOPNOTSUPP;
>>  }
>> +
>> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
>> +				  int (*cb)(struct pci_dev *, void *),
>> +				  void *userdata) { }
>> +
>>  #endif
>>  
>> +void pcie_clear_device_status(struct pci_dev *dev);
>> +
>>  #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
>>  #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
>>  #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
  2025-06-06 16:45   ` Dave Jiang
@ 2025-06-06 18:16     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 18:16 UTC (permalink / raw)
  To: Dave Jiang, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/2025 11:45 AM, Dave Jiang wrote:
>
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> Create cxl_do_recovery() to provide uncorrectable protocol error (UCE)
>> handling. Follow similar design as found in PCIe error driver,
>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>
>> Copy the PCI error driver's merge_result() and rename as cxl_merge_result().
>> Introduce PCI_ERS_RESULT_PANIC and add support in the cxl_merge_result()
>> routine.
>>
>> Copy pci_walk_bridge() to cxl_walk_bridge(). Make a change to walk the
>> first device in all cases.
>>
>> Copy the PCI error driver's report_error_detected() to cxl_report_error_detected().
>> Note, only CXL Endpoints are currently supported. Add locking for PCI
>> device as done in PCI's report_error_detected(). Add reference counting for
>> the CXL device responsible for cleanup of the CXL RAS. This is necessary
>> to prevent the RAS registers from disappearing before logging is completed.
>>
>> Call panic() to halt the system in the case of uncorrectable errors (UCE)
>> in cxl_do_recovery(). Export pci_aer_clear_fatal_status() for CXL to use
>> if a UCE is not found. In this case the AER status must be cleared and
>> uses pci_aer_clear_fatal_status().
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/ras.c | 79 ++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pci.h    |  3 ++
>>  2 files changed, 82 insertions(+)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 9ed5c682e128..715f7221ea3a 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -110,8 +110,87 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>  
>>  #ifdef CONFIG_PCIEAER_CXL
>>  
>> +static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
>> +					 enum pci_ers_result new)
>> +{
>> +	if (new == PCI_ERS_RESULT_PANIC)
>> +		return PCI_ERS_RESULT_PANIC;
>> +
>> +	if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
>> +		return PCI_ERS_RESULT_NO_AER_DRIVER;
>> +
>> +	if (new == PCI_ERS_RESULT_NONE)
>> +		return orig;
>> +
>> +	switch (orig) {
>> +	case PCI_ERS_RESULT_CAN_RECOVER:
>> +	case PCI_ERS_RESULT_RECOVERED:
>> +		orig = new;
>> +		break;
>> +	case PCI_ERS_RESULT_DISCONNECT:
>> +		if (new == PCI_ERS_RESULT_NEED_RESET)
>> +			orig = PCI_ERS_RESULT_NEED_RESET;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return orig;
>> +}
>> +
>> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
>> +{
>> +	pci_ers_result_t vote, *result = data;
>> +	struct cxl_dev_state *cxlds;
>> +
>> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
>> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
>> +		return 0;
>> +
> Lock here before getting driver data instead of later?
>
> guard(device)(&pdev->dev);
Ok.
>> +	cxlds = pci_get_drvdata(pdev);
> Add a comment for the ref grab
Ok.

> DJ
Thanks Dave.

Terry

>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>> +
>> +	device_lock(&pdev->dev);
>> +	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
>> +	*result = cxl_merge_result(*result, vote);
>> +	device_unlock(&pdev->dev);
>> +
>> +	return 0;
>> +}
>> +
>> +static void cxl_walk_bridge(struct pci_dev *bridge,
>> +			    int (*cb)(struct pci_dev *, void *),
>> +			    void *userdata)
>> +{
>> +	if (cb(bridge, userdata))
>> +		return;
>> +
>> +	if (bridge->subordinate)
>> +		pci_walk_bus(bridge->subordinate, cb, userdata);
>> +}
>> +
>>  static void cxl_do_recovery(struct pci_dev *pdev)
>>  {
>> +	struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
>> +	pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
>> +
>> +	cxl_walk_bridge(pdev, cxl_report_error_detected, &status);
>> +	if (status == PCI_ERS_RESULT_PANIC)
>> +		panic("CXL cachemem error.");
>> +
>> +	/*
>> +	 * If we have native control of AER, clear error status in the device
>> +	 * that detected the error.  If the platform retained control of AER,
>> +	 * it is responsible for clearing this status.  In that case, the
>> +	 * signaling device may not even be visible to the OS.
>> +	 */
>> +	if (host->native_aer) {
>> +		pcie_clear_device_status(pdev);
>> +		pci_aer_clear_nonfatal_status(pdev);
>> +		pci_aer_clear_fatal_status(pdev);
>> +	}
>> +
>> +	pci_info(pdev, "CXL uncorrectable error.\n");
>>  }
>>  
>>  static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index cd53715d53f3..b0e7545162de 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -870,6 +870,9 @@ enum pci_ers_result {
>>  
>>  	/* No AER capabilities registered for the driver */
>>  	PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
>> +
>> +	/* System is unstable, panic  */
>> +	PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,
>>  };
>>  
>>  /* PCI bus error event callbacks */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 06/16] cxl/pci: Move RAS initialization to cxl_port driver
  2025-06-06 17:04   ` Dave Jiang
@ 2025-06-06 18:17     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 18:17 UTC (permalink / raw)
  To: Dave Jiang, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/2025 12:04 PM, Dave Jiang wrote:
>
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> The cxl_port driver is intended to manage CXL Endpoint Ports and CXL Switch
>> Ports. Move existing RAS initialization to the cxl_port driver.
>>
>> Restricted CXL Host (RCH) Downstream Port RAS initialization currently
>> resides in cxl/core/pci.c. The PCI source file is not otherwise associated
>> with CXL Port management.
>>
>> Additional CXL Port RAS initialization will be added in future patches to
>> support a CXL Port device's CXL errors.
> Is this the part that Jonathan recommended moving to cxl/core/ras.c?
>
> DJ
Correct.

Terry
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/pci.c  | 73 --------------------------------------
>>  drivers/cxl/core/regs.c |  2 ++
>>  drivers/cxl/cxl.h       |  6 ++++
>>  drivers/cxl/port.c      | 78 +++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 86 insertions(+), 73 deletions(-)
>>
>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
>> index b50551601c2e..317cd0a91ffe 100644
>> --- a/drivers/cxl/core/pci.c
>> +++ b/drivers/cxl/core/pci.c
>> @@ -748,79 +748,6 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>>  
>>  #ifdef CONFIG_PCIEAER_CXL
>>  
>> -static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
>> -{
>> -	resource_size_t aer_phys;
>> -	struct device *host;
>> -	u16 aer_cap;
>> -
>> -	aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
>> -	if (aer_cap) {
>> -		host = dport->reg_map.host;
>> -		aer_phys = aer_cap + dport->rcrb.base;
>> -		dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
>> -						sizeof(struct aer_capability_regs));
>> -	}
>> -}
>> -
>> -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)
>> -		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)))
>> -		dev_dbg(dev, "Failed to map RAS capability.\n");
>> -}
>> -
>> -static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
>> -{
>> -	void __iomem *aer_base = dport->regs.dport_aer;
>> -	u32 aer_cmd_mask, aer_cmd;
>> -
>> -	if (!aer_base)
>> -		return;
>> -
>> -	/*
>> -	 * Disable RCH root port command interrupts.
>> -	 * CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
>> -	 *
>> -	 * This sequence may not be necessary. CXL spec states disabling
>> -	 * the root cmd register's interrupts is required. But, PCI spec
>> -	 * shows these are disabled by default on reset.
>> -	 */
>> -	aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
>> -			PCI_ERR_ROOT_CMD_NONFATAL_EN |
>> -			PCI_ERR_ROOT_CMD_FATAL_EN);
>> -	aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
>> -	aer_cmd &= ~aer_cmd_mask;
>> -	writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
>> -}
>> -
>> -/**
>> - * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
>> - * @dport: the cxl_dport that needs to be initialized
>> - * @host: host device for devm operations
>> - */
>> -void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>> -{
>> -	dport->reg_map.host = host;
>> -	cxl_dport_map_ras(dport);
>> -
>> -	if (dport->rch) {
>> -		struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
>> -
>> -		if (!host_bridge->native_aer)
>> -			return;
>> -
>> -		cxl_dport_map_rch_aer(dport);
>> -		cxl_disable_rch_root_ints(dport);
>> -	}
>> -}
>> -EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>> -
>>  static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
>>  					  struct cxl_dport *dport)
>>  {
>> diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
>> index 5ca7b0eed568..b8e767a9571c 100644
>> --- a/drivers/cxl/core/regs.c
>> +++ b/drivers/cxl/core/regs.c
>> @@ -199,6 +199,7 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
>>  
>>  	return ret_val;
>>  }
>> +EXPORT_SYMBOL_NS_GPL(devm_cxl_iomap_block, "CXL");
>>  
>>  int cxl_map_component_regs(const struct cxl_register_map *map,
>>  			   struct cxl_component_regs *regs,
>> @@ -517,6 +518,7 @@ u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb)
>>  
>>  	return offset;
>>  }
>> +EXPORT_SYMBOL_NS_GPL(cxl_rcrb_to_aer, "CXL");
>>  
>>  static resource_size_t cxl_rcrb_to_linkcap(struct device *dev, struct cxl_dport *dport)
>>  {
>> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
>> index ba08b77b65da..0dc43bfba76a 100644
>> --- a/drivers/cxl/cxl.h
>> +++ b/drivers/cxl/cxl.h
>> @@ -313,6 +313,12 @@ int cxl_setup_regs(struct cxl_register_map *map);
>>  struct cxl_dport;
>>  resource_size_t cxl_rcd_component_reg_phys(struct device *dev,
>>  					   struct cxl_dport *dport);
>> +
>> +u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb);
>> +
>> +void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
>> +				   resource_size_t length);
>> +
>>  int cxl_dport_map_rcd_linkcap(struct pci_dev *pdev, struct cxl_dport *dport);
>>  
>>  #define CXL_RESOURCE_NONE ((resource_size_t) -1)
>> diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
>> index fe4b593331da..7b61f09347a5 100644
>> --- a/drivers/cxl/port.c
>> +++ b/drivers/cxl/port.c
>> @@ -6,6 +6,7 @@
>>  
>>  #include "cxlmem.h"
>>  #include "cxlpci.h"
>> +#include "cxl.h"
>>  
>>  /**
>>   * DOC: cxl port
>> @@ -57,6 +58,83 @@ static int discover_region(struct device *dev, void *unused)
>>  	return 0;
>>  }
>>  
>> +#ifdef CONFIG_PCIEAER_CXL
>> +
>> +static void cxl_dport_map_rch_aer(struct cxl_dport *dport)
>> +{
>> +	resource_size_t aer_phys;
>> +	struct device *host;
>> +	u16 aer_cap;
>> +
>> +	aer_cap = cxl_rcrb_to_aer(dport->dport_dev, dport->rcrb.base);
>> +	if (aer_cap) {
>> +		host = dport->reg_map.host;
>> +		aer_phys = aer_cap + dport->rcrb.base;
>> +		dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys,
>> +						sizeof(struct aer_capability_regs));
>> +	}
>> +}
>> +
>> +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)
>> +		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)))
>> +		dev_dbg(dev, "Failed to map RAS capability.\n");
>> +}
>> +
>> +static void cxl_disable_rch_root_ints(struct cxl_dport *dport)
>> +{
>> +	void __iomem *aer_base = dport->regs.dport_aer;
>> +	u32 aer_cmd_mask, aer_cmd;
>> +
>> +	if (!aer_base)
>> +		return;
>> +
>> +	/*
>> +	 * Disable RCH root port command interrupts.
>> +	 * CXL 3.0 12.2.1.1 - RCH Downstream Port-detected Errors
>> +	 *
>> +	 * This sequence may not be necessary. CXL spec states disabling
>> +	 * the root cmd register's interrupts is required. But, PCI spec
>> +	 * shows these are disabled by default on reset.
>> +	 */
>> +	aer_cmd_mask = (PCI_ERR_ROOT_CMD_COR_EN |
>> +			PCI_ERR_ROOT_CMD_NONFATAL_EN |
>> +			PCI_ERR_ROOT_CMD_FATAL_EN);
>> +	aer_cmd = readl(aer_base + PCI_ERR_ROOT_COMMAND);
>> +	aer_cmd &= ~aer_cmd_mask;
>> +	writel(aer_cmd, aer_base + PCI_ERR_ROOT_COMMAND);
>> +}
>> +
>> +/**
>> + * cxl_dport_init_ras_reporting - Setup CXL RAS report on this dport
>> + * @dport: the cxl_dport that needs to be initialized
>> + * @host: host device for devm operations
>> + */
>> +void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host)
>> +{
>> +	dport->reg_map.host = host;
>> +	cxl_dport_map_ras(dport);
>> +
>> +	if (dport->rch) {
>> +		struct pci_host_bridge *host_bridge = to_pci_host_bridge(dport->dport_dev);
>> +
>> +		if (!host_bridge->native_aer)
>> +			return;
>> +
>> +		cxl_dport_map_rch_aer(dport);
>> +		cxl_disable_rch_root_ints(dport);
>> +	}
>> +}
>> +EXPORT_SYMBOL_NS_GPL(cxl_dport_init_ras_reporting, "CXL");
>> +
>> +#endif /* CONFIG_PCIEAER_CXL */
>> +
>>  static int cxl_switch_port_probe(struct cxl_port *port)
>>  {
>>  	struct cxl_hdm *cxlhdm;


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors
  2025-06-03 17:22 ` [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
  2025-06-05 18:37   ` Sathyanarayanan Kuppuswamy
@ 2025-06-06 20:30   ` Dave Jiang
  2025-06-06 20:55     ` Bowman, Terry
  2025-06-12 16:46   ` Jonathan Cameron
  2 siblings, 1 reply; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 20:30 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> __cxl_handle_cor_ras() is missing logic to leave the function early in the
> case there is no RAS error. Update __cxl_handle_cor_ras() to exit early in
> the case there is no RAS errors detected after applying the mask.

This change is small enough that I would just fold it into the patch that introduces this function.

DJ

> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>  drivers/cxl/core/pci.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index 0f4c07fd64a5..f5f87c2c3fd5 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -677,10 +677,11 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>  
>  	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
>  	status = readl(addr);
> -	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
> -		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
> -		trace_cxl_aer_correctable_error(dev, serial, status);
> -	}
> +	if (!(status & CXL_RAS_CORRECTABLE_STATUS_MASK))
> +		return;
> +	writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
> +
> +	trace_cxl_aer_correctable_error(dev, serial, status);
>  }
>  
>  static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors
  2025-06-06 20:30   ` Dave Jiang
@ 2025-06-06 20:55     ` Bowman, Terry
  2025-06-06 22:38       ` Dave Jiang
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 20:55 UTC (permalink / raw)
  To: Dave Jiang, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/2025 3:30 PM, Dave Jiang wrote:
>
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> __cxl_handle_cor_ras() is missing logic to leave the function early in the
>> case there is no RAS error. Update __cxl_handle_cor_ras() to exit early in
>> the case there is no RAS errors detected after applying the mask.
> This change is small enough that I would just fold it into the patch that introduces this function.
>
> DJ
I agree. The problem is it was already present before this series. This is a 'fix'. I had this change in:
[PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped
but was asked to move out because it appeared as an unrelated miscellaneous patch.

Terry
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/pci.c | 9 +++++----
>>  1 file changed, 5 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
>> index 0f4c07fd64a5..f5f87c2c3fd5 100644
>> --- a/drivers/cxl/core/pci.c
>> +++ b/drivers/cxl/core/pci.c
>> @@ -677,10 +677,11 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>>  
>>  	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
>>  	status = readl(addr);
>> -	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
>> -		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
>> -		trace_cxl_aer_correctable_error(dev, serial, status);
>> -	}
>> +	if (!(status & CXL_RAS_CORRECTABLE_STATUS_MASK))
>> +		return;
>> +	writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
>> +
>> +	trace_cxl_aer_correctable_error(dev, serial, status);
>>  }
>>  
>>  static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-06 15:57   ` Dave Jiang
  2025-06-06 18:14     ` Bowman, Terry
@ 2025-06-06 21:08     ` Bowman, Terry
  2025-06-06 23:15     ` Bowman, Terry
  2 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 21:08 UTC (permalink / raw)
  To: Dave Jiang, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, coly.li, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/2025 10:57 AM, Dave Jiang wrote:
>
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> The AER driver is now designed to forward CXL protocol errors to the CXL
>> driver. Update the CXL driver with functionality to dequeue the forwarded
>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
>> error handling processing using the work received from the FIFO.
>>
>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>> AER service driver. This will begin the CXL protocol error processing
>> with a call to cxl_handle_prot_error().
>>
>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
>> previously in the AER driver.
>>
>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
>> and use in discovering the erring PCI device. Make scope based reference
>> increments/decrements for the discovered PCI device and the associated
>> CXL device.
>>
>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>> RCH errors will be processed with a call to walk the associated Root
>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>> so the CXL driver can walk the RCEC's downstream bus, searching for
>> the RCiEP.
>>
>> VH correctable error (CE) processing will call the CXL CE handler. VH
>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
>> and pci_clean_device_status() used to clean up AER status after handling.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/pci/pci.c       |  1 +
>>  drivers/pci/pci.h       |  8 ----
>>  drivers/pci/pcie/aer.c  |  1 +
>>  drivers/pci/pcie/rcec.c |  1 +
>>  include/linux/aer.h     |  2 +
>>  include/linux/pci.h     | 10 +++++
>>  7 files changed, 107 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index d35525e79e04..9ed5c682e128 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>  
>>  #ifdef CONFIG_PCIEAER_CXL
>>  
>> +static void cxl_do_recovery(struct pci_dev *pdev)
>> +{
>> +}
>> +
>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>> +{
>> +	struct cxl_prot_error_info *err_info = data;
>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>> +	struct cxl_dev_state *cxlds;
>> +
>> +	/*
>> +	 * The capability, status, and control fields in Device 0,
>> +	 * Function 0 DVSEC control the CXL functionality of the
>> +	 * entire device (CXL 3.0, 8.1.3).
>> +	 */
>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>> +		return 0;
>> +
>> +	/*
>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>> +	 * 3.0, 8.1.12.1).
>> +	 */
>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> Should use FIELD_GET() to be consistent with the rest of CXL code base
>
>> +		return 0;
>> +
>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
> I think you need to hold the pdev->dev lock while checking if the driver exists.
>
>> +		return 0;
>> +
>> +	cxlds = pci_get_drvdata(pdev);
>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> Maybe a comment on why cxlmd->dev ref is needed here.
Ooof. This is coded incorrectly. This should have been using the pdev/cxlds device (pdev->dev/cxlds->dev)
instead of cxlmd->dev. CXL EP RAS is mapped using the PCI device dev (same as cxlds->dev) as the host.
The pdev ref count further above works making it functionally ok but this line is not doing anything to help with the
reference counting, is misleading, and just needs to be fixed. Unfortunately, this broken EP reference counting
is found later in the driver to protect accesses to EP mapped RAS.

Terry
>> +
>> +	if (err_info->severity == AER_CORRECTABLE)
>> +		cxl_cor_error_detected(pdev);
>> +	else
>> +		cxl_do_recovery(pdev);
>> +
>> +	return 1;
>> +}
>> +
>> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>> +{
>> +	unsigned int devfn = PCI_DEVFN(err_info->device,
>> +				       err_info->function);
>> +	struct pci_dev *pdev __free(pci_dev_put) =
>> +		pci_get_domain_bus_and_slot(err_info->segment,
>> +					    err_info->bus,
>> +					    devfn);
> Looks like DanC already caught that. Maybe have this function return with a ref held. I would also add a comment for the function mention that the caller need to put the device.
>
>> +	return pdev;
>> +}
>> +
>> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>> +{
>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
>> +
>> +	if (!pdev) {
>> +		pr_err("Failed to find the CXL device\n");
>> +		return;
>> +	}
>> +
>> +	/*
>> +	 * 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.
>> +	 */
>> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
>> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>> +
> cxl_rch_handle_error_iter() holds the pdev device lock when handling errors. Does the code block below need locking?
>
> DJ
>
>> +	if (err_info->severity == AER_CORRECTABLE) {
>> +		int aer = pdev->aer_cap;
>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>> +
>> +		if (aer)
>> +			pci_clear_and_set_config_dword(pdev,
>> +						       aer + PCI_ERR_COR_STATUS,
>> +						       0, PCI_ERR_COR_INTERNAL);
>> +
>> +		cxl_cor_error_detected(pdev);
>> +
>> +		pcie_clear_device_status(pdev);
>> +	} else {
>> +		cxl_do_recovery(pdev);
>> +	}
>> +}
>> +
>>  static void cxl_prot_err_work_fn(struct work_struct *work)
>>  {
>> +	struct cxl_prot_err_work_data wd;
>> +
>> +	while (cxl_prot_err_kfifo_get(&wd)) {
>> +		struct cxl_prot_error_info *err_info = &wd.err_info;
>> +
>> +		cxl_handle_prot_error(err_info);
>> +	}
>>  }
>>  
>>  #else
>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>> index e77d5b53c0ce..524ac32b744a 100644
>> --- a/drivers/pci/pci.c
>> +++ b/drivers/pci/pci.c
>> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
>>  	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
>>  	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
>>  }
>> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
>>  #endif
>>  
>>  /**
>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>> index d6296500b004..3c54a5ed803e 100644
>> --- a/drivers/pci/pci.h
>> +++ b/drivers/pci/pci.h
>> @@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
>>  void pci_rcec_init(struct pci_dev *dev);
>>  void pci_rcec_exit(struct pci_dev *dev);
>>  void pcie_link_rcec(struct pci_dev *rcec);
>> -void pcie_walk_rcec(struct pci_dev *rcec,
>> -		    int (*cb)(struct pci_dev *, void *),
>> -		    void *userdata);
>>  #else
>>  static inline void pci_rcec_init(struct pci_dev *dev) { }
>>  static inline void pci_rcec_exit(struct pci_dev *dev) { }
>>  static inline void pcie_link_rcec(struct pci_dev *rcec) { }
>> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
>> -				  int (*cb)(struct pci_dev *, void *),
>> -				  void *userdata) { }
>>  #endif
>>  
>>  #ifdef CONFIG_PCI_ATS
>> @@ -967,7 +961,6 @@ void pci_no_aer(void);
>>  void pci_aer_init(struct pci_dev *dev);
>>  void pci_aer_exit(struct pci_dev *dev);
>>  extern const struct attribute_group aer_stats_attr_group;
>> -void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>  int pci_aer_clear_status(struct pci_dev *dev);
>>  int pci_aer_raw_clear_status(struct pci_dev *dev);
>>  void pci_save_aer_state(struct pci_dev *dev);
>> @@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
>>  static inline void pci_no_aer(void) { }
>>  static inline void pci_aer_init(struct pci_dev *d) { }
>>  static inline void pci_aer_exit(struct pci_dev *d) { }
>> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>  static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>  static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>  static inline void pci_save_aer_state(struct pci_dev *dev) { }
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index 5350fa5be784..6e88331c6303 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
>>  	if (status)
>>  		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
>>  }
>> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>>  
>>  /**
>>   * pci_aer_raw_clear_status - Clear AER error registers.
>> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
>> index d0bcd141ac9c..fb6cf6449a1d 100644
>> --- a/drivers/pci/pcie/rcec.c
>> +++ b/drivers/pci/pcie/rcec.c
>> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>>  
>>  	walk_rcec(walk_rcec_helper, &rcec_data);
>>  }
>> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
>>  
>>  void pci_rcec_init(struct pci_dev *dev)
>>  {
>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>> index 550407240ab5..c9a18eca16f8 100644
>> --- a/include/linux/aer.h
>> +++ b/include/linux/aer.h
>> @@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
>>  
>>  #if defined(CONFIG_PCIEAER)
>>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>  int pcie_aer_is_native(struct pci_dev *dev);
>>  #else
>>  static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>>  {
>>  	return -EINVAL;
>>  }
>> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>  static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>>  #endif
>>  
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index bff3009f9ff0..cd53715d53f3 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
>>  
>>  int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
>>  			  bool use_lt);
>> +void pcie_walk_rcec(struct pci_dev *rcec,
>> +		    int (*cb)(struct pci_dev *, void *),
>> +		    void *userdata);
>>  #else
>>  #define pcie_ports_disabled	true
>>  #define pcie_ports_native	false
>> @@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
>>  {
>>  	return -EOPNOTSUPP;
>>  }
>> +
>> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
>> +				  int (*cb)(struct pci_dev *, void *),
>> +				  void *userdata) { }
>> +
>>  #endif
>>  
>> +void pcie_clear_device_status(struct pci_dev *dev);
>> +
>>  #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
>>  #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
>>  #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors
  2025-06-06 20:55     ` Bowman, Terry
@ 2025-06-06 22:38       ` Dave Jiang
  0 siblings, 0 replies; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 22:38 UTC (permalink / raw)
  To: Bowman, Terry, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/25 1:55 PM, Bowman, Terry wrote:
> 
> 
> On 6/6/2025 3:30 PM, Dave Jiang wrote:
>>
>> On 6/3/25 10:22 AM, Terry Bowman wrote:
>>> __cxl_handle_cor_ras() is missing logic to leave the function early in the
>>> case there is no RAS error. Update __cxl_handle_cor_ras() to exit early in
>>> the case there is no RAS errors detected after applying the mask.
>> This change is small enough that I would just fold it into the patch that introduces this function.
>>
>> DJ
> I agree. The problem is it was already present before this series. This is a 'fix'. I had this change in:
> [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped
> but was asked to move out because it appeared as an unrelated miscellaneous patch.

Ok. Then

Reviewed-by: Dave Jiang <dave.jiang@intel.com>

> 
> Terry
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>> ---
>>>  drivers/cxl/core/pci.c | 9 +++++----
>>>  1 file changed, 5 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
>>> index 0f4c07fd64a5..f5f87c2c3fd5 100644
>>> --- a/drivers/cxl/core/pci.c
>>> +++ b/drivers/cxl/core/pci.c
>>> @@ -677,10 +677,11 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>>>  
>>>  	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
>>>  	status = readl(addr);
>>> -	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
>>> -		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
>>> -		trace_cxl_aer_correctable_error(dev, serial, status);
>>> -	}
>>> +	if (!(status & CXL_RAS_CORRECTABLE_STATUS_MASK))
>>> +		return;
>>> +	writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
>>> +
>>> +	trace_cxl_aer_correctable_error(dev, serial, status);
>>>  }
>>>  
>>>  static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-06 18:14     ` Bowman, Terry
@ 2025-06-06 22:43       ` Dave Jiang
  2025-06-09 19:57         ` Bowman, Terry
  0 siblings, 1 reply; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 22:43 UTC (permalink / raw)
  To: Bowman, Terry, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, coly.li, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/25 11:14 AM, Bowman, Terry wrote:
> 
> 
> On 6/6/2025 10:57 AM, Dave Jiang wrote:
>>
>> On 6/3/25 10:22 AM, Terry Bowman wrote:
>>> The AER driver is now designed to forward CXL protocol errors to the CXL
>>> driver. Update the CXL driver with functionality to dequeue the forwarded
>>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
>>> error handling processing using the work received from the FIFO.
>>>
>>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>>> AER service driver. This will begin the CXL protocol error processing
>>> with a call to cxl_handle_prot_error().
>>>
>>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
>>> previously in the AER driver.
>>>
>>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
>>> and use in discovering the erring PCI device. Make scope based reference
>>> increments/decrements for the discovered PCI device and the associated
>>> CXL device.
>>>
>>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
>>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>>> RCH errors will be processed with a call to walk the associated Root
>>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>>> so the CXL driver can walk the RCEC's downstream bus, searching for
>>> the RCiEP.
>>>
>>> VH correctable error (CE) processing will call the CXL CE handler. VH
>>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
>>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
>>> and pci_clean_device_status() used to clean up AER status after handling.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>> ---
>>>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>>>  drivers/pci/pci.c       |  1 +
>>>  drivers/pci/pci.h       |  8 ----
>>>  drivers/pci/pcie/aer.c  |  1 +
>>>  drivers/pci/pcie/rcec.c |  1 +
>>>  include/linux/aer.h     |  2 +
>>>  include/linux/pci.h     | 10 +++++
>>>  7 files changed, 107 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>> index d35525e79e04..9ed5c682e128 100644
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>>  
>>>  #ifdef CONFIG_PCIEAER_CXL
>>>  
>>> +static void cxl_do_recovery(struct pci_dev *pdev)
>>> +{
>>> +}
>>> +
>>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>>> +{
>>> +	struct cxl_prot_error_info *err_info = data;
>>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>>> +	struct cxl_dev_state *cxlds;
>>> +
>>> +	/*
>>> +	 * The capability, status, and control fields in Device 0,
>>> +	 * Function 0 DVSEC control the CXL functionality of the
>>> +	 * entire device (CXL 3.0, 8.1.3).
>>> +	 */
>>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>>> +		return 0;
>>> +
>>> +	/*
>>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>>> +	 * 3.0, 8.1.12.1).
>>> +	 */
>>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>> Should use FIELD_GET() to be consistent with the rest of CXL code base
> 
> Ok.
> 
>>> +		return 0;
>>> +
>>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
>> I think you need to hold the pdev->dev lock while checking if the driver exists.
> Ok.
>>> +		return 0;
>>> +
>>> +	cxlds = pci_get_drvdata(pdev);
>>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>> Maybe a comment on why cxlmd->dev ref is needed here.
> Good point.
>>> +
>>> +	if (err_info->severity == AER_CORRECTABLE)
>>> +		cxl_cor_error_detected(pdev);
>>> +	else
>>> +		cxl_do_recovery(pdev);
>>> +
>>> +	return 1;
>>> +}
>>> +
>>> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>>> +{
>>> +	unsigned int devfn = PCI_DEVFN(err_info->device,
>>> +				       err_info->function);
>>> +	struct pci_dev *pdev __free(pci_dev_put) =
>>> +		pci_get_domain_bus_and_slot(err_info->segment,
>>> +					    err_info->bus,
>>> +					    devfn);
>> Looks like DanC already caught that. Maybe have this function return with a ref held. I would also add a comment for the function mention that the caller need to put the device.
> Right. I made the change in v10 source after DanC commented. I'll add a comment that callers must decrement the reference count..
>>> +	return pdev;
>>> +}
>>> +
>>> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>>> +{
>>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
>>> +
>>> +	if (!pdev) {
>>> +		pr_err("Failed to find the CXL device\n");
>>> +		return;
>>> +	}
>>> +
>>> +	/*
>>> +	 * 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.
>>> +	 */
>>> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
>>> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>>> +
>> cxl_rch_handle_error_iter() holds the pdev device lock when handling errors. Does the code block below need locking?
>>
>> DJ
> There is a guard_lock() in the EP CXL error handlers (cxl_error_detected()/cxl_cor_error_detected()). I have question about
> the same for the non-EP handlers added later: should we add the same guard() for the CXL port handlers? That is in following patch:
> [PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers.

I would think so....

DJ

> 
> Terry
>>> +	if (err_info->severity == AER_CORRECTABLE) {
>>> +		int aer = pdev->aer_cap;
>>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>>> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>>> +
>>> +		if (aer)
>>> +			pci_clear_and_set_config_dword(pdev,
>>> +						       aer + PCI_ERR_COR_STATUS,
>>> +						       0, PCI_ERR_COR_INTERNAL);
>>> +
>>> +		cxl_cor_error_detected(pdev);
>>> +
>>> +		pcie_clear_device_status(pdev);
>>> +	} else {
>>> +		cxl_do_recovery(pdev);
>>> +	}
>>> +}
>>> +
>>>  static void cxl_prot_err_work_fn(struct work_struct *work)
>>>  {
>>> +	struct cxl_prot_err_work_data wd;
>>> +
>>> +	while (cxl_prot_err_kfifo_get(&wd)) {
>>> +		struct cxl_prot_error_info *err_info = &wd.err_info;
>>> +
>>> +		cxl_handle_prot_error(err_info);
>>> +	}
>>>  }
>>>  
>>>  #else
>>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>>> index e77d5b53c0ce..524ac32b744a 100644
>>> --- a/drivers/pci/pci.c
>>> +++ b/drivers/pci/pci.c
>>> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
>>>  	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
>>>  	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
>>>  }
>>> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
>>>  #endif
>>>  
>>>  /**
>>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>>> index d6296500b004..3c54a5ed803e 100644
>>> --- a/drivers/pci/pci.h
>>> +++ b/drivers/pci/pci.h
>>> @@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
>>>  void pci_rcec_init(struct pci_dev *dev);
>>>  void pci_rcec_exit(struct pci_dev *dev);
>>>  void pcie_link_rcec(struct pci_dev *rcec);
>>> -void pcie_walk_rcec(struct pci_dev *rcec,
>>> -		    int (*cb)(struct pci_dev *, void *),
>>> -		    void *userdata);
>>>  #else
>>>  static inline void pci_rcec_init(struct pci_dev *dev) { }
>>>  static inline void pci_rcec_exit(struct pci_dev *dev) { }
>>>  static inline void pcie_link_rcec(struct pci_dev *rcec) { }
>>> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
>>> -				  int (*cb)(struct pci_dev *, void *),
>>> -				  void *userdata) { }
>>>  #endif
>>>  
>>>  #ifdef CONFIG_PCI_ATS
>>> @@ -967,7 +961,6 @@ void pci_no_aer(void);
>>>  void pci_aer_init(struct pci_dev *dev);
>>>  void pci_aer_exit(struct pci_dev *dev);
>>>  extern const struct attribute_group aer_stats_attr_group;
>>> -void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>>  int pci_aer_clear_status(struct pci_dev *dev);
>>>  int pci_aer_raw_clear_status(struct pci_dev *dev);
>>>  void pci_save_aer_state(struct pci_dev *dev);
>>> @@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
>>>  static inline void pci_no_aer(void) { }
>>>  static inline void pci_aer_init(struct pci_dev *d) { }
>>>  static inline void pci_aer_exit(struct pci_dev *d) { }
>>> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>>  static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>>  static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>>  static inline void pci_save_aer_state(struct pci_dev *dev) { }
>>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>>> index 5350fa5be784..6e88331c6303 100644
>>> --- a/drivers/pci/pcie/aer.c
>>> +++ b/drivers/pci/pcie/aer.c
>>> @@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
>>>  	if (status)
>>>  		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
>>>  }
>>> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>>>  
>>>  /**
>>>   * pci_aer_raw_clear_status - Clear AER error registers.
>>> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
>>> index d0bcd141ac9c..fb6cf6449a1d 100644
>>> --- a/drivers/pci/pcie/rcec.c
>>> +++ b/drivers/pci/pcie/rcec.c
>>> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>>>  
>>>  	walk_rcec(walk_rcec_helper, &rcec_data);
>>>  }
>>> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
>>>  
>>>  void pci_rcec_init(struct pci_dev *dev)
>>>  {
>>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>>> index 550407240ab5..c9a18eca16f8 100644
>>> --- a/include/linux/aer.h
>>> +++ b/include/linux/aer.h
>>> @@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
>>>  
>>>  #if defined(CONFIG_PCIEAER)
>>>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>>> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>>  int pcie_aer_is_native(struct pci_dev *dev);
>>>  #else
>>>  static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>>>  {
>>>  	return -EINVAL;
>>>  }
>>> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>>  static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>>>  #endif
>>>  
>>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>>> index bff3009f9ff0..cd53715d53f3 100644
>>> --- a/include/linux/pci.h
>>> +++ b/include/linux/pci.h
>>> @@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
>>>  
>>>  int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
>>>  			  bool use_lt);
>>> +void pcie_walk_rcec(struct pci_dev *rcec,
>>> +		    int (*cb)(struct pci_dev *, void *),
>>> +		    void *userdata);
>>>  #else
>>>  #define pcie_ports_disabled	true
>>>  #define pcie_ports_native	false
>>> @@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
>>>  {
>>>  	return -EOPNOTSUPP;
>>>  }
>>> +
>>> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
>>> +				  int (*cb)(struct pci_dev *, void *),
>>> +				  void *userdata) { }
>>> +
>>>  #endif
>>>  
>>> +void pcie_clear_device_status(struct pci_dev *dev);
>>> +
>>>  #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
>>>  #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
>>>  #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */
> 
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
  2025-06-03 17:22 ` [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
  2025-06-06  0:52   ` Sathyanarayanan Kuppuswamy
@ 2025-06-06 22:59   ` Dave Jiang
  2025-06-12 17:19   ` Jonathan Cameron
  2 siblings, 0 replies; 90+ messages in thread
From: Dave Jiang @ 2025-06-06 22:59 UTC (permalink / raw)
  To: Terry Bowman, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/3/25 10:22 AM, Terry Bowman wrote:
> During CXL device cleanup the CXL PCIe Port device interrupts remain
> enabled. This potentially allows unnecessary interrupt processing on
> behalf of the CXL errors while the device is destroyed.
> 
> Disable CXL protocol errors by setting the CXL devices' AER mask register.
> 
> Introduce pci_aer_mask_internal_errors() similar to pci_aer_unmask_internal_errors().
> 
> Introduce cxl_mask_prot_interrupts() to call pci_aer_mask_internal_errors().
> Add calls to cxl_mask_prot_interrupts() within CXL Port teardown for CXL
> Root Ports, CXL Downstream Switch Ports, CXL Upstream Switch Ports, and CXL
> Endpoints. Follow the same "bottom-up" approach used during CXL Port
> teardown.
> 
> Implement cxl_mask_prot_interrupts() in a header file to avoid introducing
> Kconfig ifdefs in cxl/core/port.c.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> ---
>  drivers/cxl/core/port.c |  6 ++++++
>  drivers/cxl/cxl.h       |  8 ++++++++
>  drivers/pci/pcie/aer.c  | 21 +++++++++++++++++++++
>  include/linux/aer.h     |  1 +
>  4 files changed, 36 insertions(+)
> 
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 07b9bb0f601f..6aaaad002a7f 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -1433,6 +1433,9 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_autoremove, "CXL");
>   */
>  static void delete_switch_port(struct cxl_port *port)
>  {
> +	cxl_mask_prot_interrupts(port->uport_dev);
> +	cxl_mask_prot_interrupts(port->parent_dport->dport_dev);
> +
>  	devm_release_action(port->dev.parent, cxl_unlink_parent_dport, port);
>  	devm_release_action(port->dev.parent, cxl_unlink_uport, port);
>  	devm_release_action(port->dev.parent, unregister_port, port);
> @@ -1446,6 +1449,7 @@ static void reap_dports(struct cxl_port *port)
>  	device_lock_assert(&port->dev);
>  
>  	xa_for_each(&port->dports, index, dport) {
> +		cxl_mask_prot_interrupts(dport->dport_dev);
>  		devm_release_action(&port->dev, cxl_dport_unlink, dport);
>  		devm_release_action(&port->dev, cxl_dport_remove, dport);
>  		devm_kfree(&port->dev, dport);
> @@ -1476,6 +1480,8 @@ static void cxl_detach_ep(void *data)
>  {
>  	struct cxl_memdev *cxlmd = data;
>  
> +	cxl_mask_prot_interrupts(cxlmd->cxlds->dev);
> +
>  	for (int i = cxlmd->depth - 1; i >= 1; i--) {
>  		struct cxl_port *port, *parent_port;
>  		struct detach_ctx ctx = {
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 2c1c00466a25..2753db3d473e 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -12,6 +12,7 @@
>  #include <linux/node.h>
>  #include <linux/io.h>
>  #include <linux/pci.h>
> +#include <linux/aer.h>
>  
>  extern const struct nvdimm_security_ops *cxl_security_ops;
>  
> @@ -771,9 +772,16 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
>  #ifdef CONFIG_PCIEAER_CXL
>  void cxl_setup_parent_dport(struct device *host, struct cxl_dport *dport);
>  void cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device *host);
> +static inline void cxl_mask_prot_interrupts(struct device *dev)
> +{
> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(to_pci_dev(dev));
> +
> +	pci_aer_mask_internal_errors(pdev);
> +}
>  #else
>  static inline void cxl_dport_init_ras_reporting(struct cxl_dport *dport,
>  						struct device *host) { }
> +static inline void cxl_mask_prot_interrupts(struct device *dev) { }
>  #endif
>  
>  struct cxl_decoder *to_cxl_decoder(struct device *dev);
> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index 2d202ad1453a..69230cf87d79 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c
> @@ -979,6 +979,27 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
>  }
>  EXPORT_SYMBOL_NS_GPL(pci_aer_unmask_internal_errors, "CXL");
>  
> +/**
> + * pci_aer_mask_internal_errors - mask internal errors
> + * @dev: pointer to the pcie_dev data structure
> + *
> + * Masks 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().
> + */
> +void pci_aer_mask_internal_errors(struct pci_dev *dev)
> +{
> +	int aer = dev->aer_cap;
> +
> +	pci_clear_and_set_config_dword(dev, aer + PCI_ERR_UNCOR_MASK,
> +				       0, PCI_ERR_UNC_INTN);
> +	pci_clear_and_set_config_dword(dev, aer + PCI_ERR_COR_MASK,
> +				       0, PCI_ERR_COR_INTERNAL);
> +}
> +EXPORT_SYMBOL_NS_GPL(pci_aer_mask_internal_errors, "CXL");
> +
>  static bool is_cxl_mem_dev(struct pci_dev *dev)
>  {
>  	/*
> diff --git a/include/linux/aer.h b/include/linux/aer.h
> index 74600e75705f..41167ad3797a 100644
> --- a/include/linux/aer.h
> +++ b/include/linux/aer.h
> @@ -108,5 +108,6 @@ int cper_severity_to_aer(int cper_severity);
>  void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
>  		       int severity, struct aer_capability_regs *aer_regs);
>  void pci_aer_unmask_internal_errors(struct pci_dev *dev);
> +void pci_aer_mask_internal_errors(struct pci_dev *dev);
>  #endif //_AER_H_
>  


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-06 15:57   ` Dave Jiang
  2025-06-06 18:14     ` Bowman, Terry
  2025-06-06 21:08     ` Bowman, Terry
@ 2025-06-06 23:15     ` Bowman, Terry
  2025-06-09 20:17       ` Dave Jiang
  2 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-06 23:15 UTC (permalink / raw)
  To: Dave Jiang, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, coly.li, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/2025 10:57 AM, Dave Jiang wrote:
>
> On 6/3/25 10:22 AM, Terry Bowman wrote:
>> The AER driver is now designed to forward CXL protocol errors to the CXL
>> driver. Update the CXL driver with functionality to dequeue the forwarded
>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
>> error handling processing using the work received from the FIFO.
>>
>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>> AER service driver. This will begin the CXL protocol error processing
>> with a call to cxl_handle_prot_error().
>>
>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
>> previously in the AER driver.
>>
>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
>> and use in discovering the erring PCI device. Make scope based reference
>> increments/decrements for the discovered PCI device and the associated
>> CXL device.
>>
>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>> RCH errors will be processed with a call to walk the associated Root
>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>> so the CXL driver can walk the RCEC's downstream bus, searching for
>> the RCiEP.
>>
>> VH correctable error (CE) processing will call the CXL CE handler. VH
>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
>> and pci_clean_device_status() used to clean up AER status after handling.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>>  drivers/pci/pci.c       |  1 +
>>  drivers/pci/pci.h       |  8 ----
>>  drivers/pci/pcie/aer.c  |  1 +
>>  drivers/pci/pcie/rcec.c |  1 +
>>  include/linux/aer.h     |  2 +
>>  include/linux/pci.h     | 10 +++++
>>  7 files changed, 107 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index d35525e79e04..9ed5c682e128 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>  
>>  #ifdef CONFIG_PCIEAER_CXL
>>  
>> +static void cxl_do_recovery(struct pci_dev *pdev)
>> +{
>> +}
>> +
>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>> +{
>> +	struct cxl_prot_error_info *err_info = data;
>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>> +	struct cxl_dev_state *cxlds;
>> +
>> +	/*
>> +	 * The capability, status, and control fields in Device 0,
>> +	 * Function 0 DVSEC control the CXL functionality of the
>> +	 * entire device (CXL 3.0, 8.1.3).
>> +	 */
>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>> +		return 0;
>> +
>> +	/*
>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>> +	 * 3.0, 8.1.12.1).
>> +	 */
>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> Should use FIELD_GET() to be consistent with the rest of CXL code base
>
>> +		return 0;
>> +
>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
> I think you need to hold the pdev->dev lock while checking if the driver exists.
Hi Dave,

Wouldn't a reference count increment prevent the driver from being unbound and thus
make this access here to the driver safe (given the pci_dev_get() above)? And a lock
would prevent concurrent access with a busy wait when the driver executes the next
lock take?

Terry

[snip]

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-06 22:43       ` Dave Jiang
@ 2025-06-09 19:57         ` Bowman, Terry
  2025-06-09 20:34           ` Dave Jiang
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-09 19:57 UTC (permalink / raw)
  To: Dave Jiang, PradeepVineshReddy.Kodamati, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, rrichter, peterz,
	linux-cxl, linux-kernel, linux-pci



On 6/6/2025 5:43 PM, Dave Jiang wrote:
>
> On 6/6/25 11:14 AM, Bowman, Terry wrote:
>>
>> On 6/6/2025 10:57 AM, Dave Jiang wrote:
>>> On 6/3/25 10:22 AM, Terry Bowman wrote:
>>>> The AER driver is now designed to forward CXL protocol errors to the CXL
>>>> driver. Update the CXL driver with functionality to dequeue the forwarded
>>>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
>>>> error handling processing using the work received from the FIFO.
>>>>
>>>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>>>> AER service driver. This will begin the CXL protocol error processing
>>>> with a call to cxl_handle_prot_error().
>>>>
>>>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
>>>> previously in the AER driver.
>>>>
>>>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
>>>> and use in discovering the erring PCI device. Make scope based reference
>>>> increments/decrements for the discovered PCI device and the associated
>>>> CXL device.
>>>>
>>>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
>>>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>>>> RCH errors will be processed with a call to walk the associated Root
>>>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>>>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>>>> so the CXL driver can walk the RCEC's downstream bus, searching for
>>>> the RCiEP.
>>>>
>>>> VH correctable error (CE) processing will call the CXL CE handler. VH
>>>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
>>>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
>>>> and pci_clean_device_status() used to clean up AER status after handling.
>>>>
>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>> ---
>>>>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>>>>  drivers/pci/pci.c       |  1 +
>>>>  drivers/pci/pci.h       |  8 ----
>>>>  drivers/pci/pcie/aer.c  |  1 +
>>>>  drivers/pci/pcie/rcec.c |  1 +
>>>>  include/linux/aer.h     |  2 +
>>>>  include/linux/pci.h     | 10 +++++
>>>>  7 files changed, 107 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>>> index d35525e79e04..9ed5c682e128 100644
>>>> --- a/drivers/cxl/core/ras.c
>>>> +++ b/drivers/cxl/core/ras.c
>>>> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>>>  
>>>>  #ifdef CONFIG_PCIEAER_CXL
>>>>  
>>>> +static void cxl_do_recovery(struct pci_dev *pdev)
>>>> +{
>>>> +}
>>>> +
>>>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>>>> +{
>>>> +	struct cxl_prot_error_info *err_info = data;
>>>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>>>> +	struct cxl_dev_state *cxlds;
>>>> +
>>>> +	/*
>>>> +	 * The capability, status, and control fields in Device 0,
>>>> +	 * Function 0 DVSEC control the CXL functionality of the
>>>> +	 * entire device (CXL 3.0, 8.1.3).
>>>> +	 */
>>>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>>>> +		return 0;
>>>> +
>>>> +	/*
>>>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>>>> +	 * 3.0, 8.1.12.1).
>>>> +	 */
>>>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>>> Should use FIELD_GET() to be consistent with the rest of CXL code base
>> Ok.

Hi Dave,

I have a question. I found I need to do the same you recommended for is_cxl_mem_dev() in
drivers/pci/pcie/cxl_aer.c. Looks like I need to define:

#define PCI_CLASS_CODE_MASK         GENMASK(23, 8)

to be used as:

FIELD_GET(PCI_CLASS_CODE_MASK, pdev->class)

What header file can I add the PCI_CLASS_CODE_MASK #define so that it can be used in CXL
and PCI drivers?

Terry


>>>> +		return 0;
>>>> +
>>>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
>>> I think you need to hold the pdev->dev lock while checking if the driver exists.
>> Ok.
>>>> +		return 0;
>>>> +
>>>> +	cxlds = pci_get_drvdata(pdev);
>>>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>>> Maybe a comment on why cxlmd->dev ref is needed here.
>> Good point.
>>>> +
>>>> +	if (err_info->severity == AER_CORRECTABLE)
>>>> +		cxl_cor_error_detected(pdev);
>>>> +	else
>>>> +		cxl_do_recovery(pdev);
>>>> +
>>>> +	return 1;
>>>> +}
>>>> +
>>>> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>>>> +{
>>>> +	unsigned int devfn = PCI_DEVFN(err_info->device,
>>>> +				       err_info->function);
>>>> +	struct pci_dev *pdev __free(pci_dev_put) =
>>>> +		pci_get_domain_bus_and_slot(err_info->segment,
>>>> +					    err_info->bus,
>>>> +					    devfn);
>>> Looks like DanC already caught that. Maybe have this function return with a ref held. I would also add a comment for the function mention that the caller need to put the device.
>> Right. I made the change in v10 source after DanC commented. I'll add a comment that callers must decrement the reference count..
>>>> +	return pdev;
>>>> +}
>>>> +
>>>> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>>>> +{
>>>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
>>>> +
>>>> +	if (!pdev) {
>>>> +		pr_err("Failed to find the CXL device\n");
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	/*
>>>> +	 * 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.
>>>> +	 */
>>>> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
>>>> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>>>> +
>>> cxl_rch_handle_error_iter() holds the pdev device lock when handling errors. Does the code block below need locking?
>>>
>>> DJ
>> There is a guard_lock() in the EP CXL error handlers (cxl_error_detected()/cxl_cor_error_detected()). I have question about
>> the same for the non-EP handlers added later: should we add the same guard() for the CXL port handlers? That is in following patch:
>> [PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers.
> I would think so....
>
> DJ
>
>> Terry
>>>> +	if (err_info->severity == AER_CORRECTABLE) {
>>>> +		int aer = pdev->aer_cap;
>>>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>>>> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>>>> +
>>>> +		if (aer)
>>>> +			pci_clear_and_set_config_dword(pdev,
>>>> +						       aer + PCI_ERR_COR_STATUS,
>>>> +						       0, PCI_ERR_COR_INTERNAL);
>>>> +
>>>> +		cxl_cor_error_detected(pdev);
>>>> +
>>>> +		pcie_clear_device_status(pdev);
>>>> +	} else {
>>>> +		cxl_do_recovery(pdev);
>>>> +	}
>>>> +}
>>>> +
>>>>  static void cxl_prot_err_work_fn(struct work_struct *work)
>>>>  {
>>>> +	struct cxl_prot_err_work_data wd;
>>>> +
>>>> +	while (cxl_prot_err_kfifo_get(&wd)) {
>>>> +		struct cxl_prot_error_info *err_info = &wd.err_info;
>>>> +
>>>> +		cxl_handle_prot_error(err_info);
>>>> +	}
>>>>  }
>>>>  
>>>>  #else
>>>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>>>> index e77d5b53c0ce..524ac32b744a 100644
>>>> --- a/drivers/pci/pci.c
>>>> +++ b/drivers/pci/pci.c
>>>> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
>>>>  	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
>>>>  	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
>>>>  }
>>>> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
>>>>  #endif
>>>>  
>>>>  /**
>>>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>>>> index d6296500b004..3c54a5ed803e 100644
>>>> --- a/drivers/pci/pci.h
>>>> +++ b/drivers/pci/pci.h
>>>> @@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
>>>>  void pci_rcec_init(struct pci_dev *dev);
>>>>  void pci_rcec_exit(struct pci_dev *dev);
>>>>  void pcie_link_rcec(struct pci_dev *rcec);
>>>> -void pcie_walk_rcec(struct pci_dev *rcec,
>>>> -		    int (*cb)(struct pci_dev *, void *),
>>>> -		    void *userdata);
>>>>  #else
>>>>  static inline void pci_rcec_init(struct pci_dev *dev) { }
>>>>  static inline void pci_rcec_exit(struct pci_dev *dev) { }
>>>>  static inline void pcie_link_rcec(struct pci_dev *rcec) { }
>>>> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
>>>> -				  int (*cb)(struct pci_dev *, void *),
>>>> -				  void *userdata) { }
>>>>  #endif
>>>>  
>>>>  #ifdef CONFIG_PCI_ATS
>>>> @@ -967,7 +961,6 @@ void pci_no_aer(void);
>>>>  void pci_aer_init(struct pci_dev *dev);
>>>>  void pci_aer_exit(struct pci_dev *dev);
>>>>  extern const struct attribute_group aer_stats_attr_group;
>>>> -void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>>>  int pci_aer_clear_status(struct pci_dev *dev);
>>>>  int pci_aer_raw_clear_status(struct pci_dev *dev);
>>>>  void pci_save_aer_state(struct pci_dev *dev);
>>>> @@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
>>>>  static inline void pci_no_aer(void) { }
>>>>  static inline void pci_aer_init(struct pci_dev *d) { }
>>>>  static inline void pci_aer_exit(struct pci_dev *d) { }
>>>> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>>>  static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>>>  static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>>>  static inline void pci_save_aer_state(struct pci_dev *dev) { }
>>>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>>>> index 5350fa5be784..6e88331c6303 100644
>>>> --- a/drivers/pci/pcie/aer.c
>>>> +++ b/drivers/pci/pcie/aer.c
>>>> @@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
>>>>  	if (status)
>>>>  		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
>>>>  }
>>>> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>>>>  
>>>>  /**
>>>>   * pci_aer_raw_clear_status - Clear AER error registers.
>>>> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
>>>> index d0bcd141ac9c..fb6cf6449a1d 100644
>>>> --- a/drivers/pci/pcie/rcec.c
>>>> +++ b/drivers/pci/pcie/rcec.c
>>>> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>>>>  
>>>>  	walk_rcec(walk_rcec_helper, &rcec_data);
>>>>  }
>>>> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
>>>>  
>>>>  void pci_rcec_init(struct pci_dev *dev)
>>>>  {
>>>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>>>> index 550407240ab5..c9a18eca16f8 100644
>>>> --- a/include/linux/aer.h
>>>> +++ b/include/linux/aer.h
>>>> @@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
>>>>  
>>>>  #if defined(CONFIG_PCIEAER)
>>>>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>>>> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>>>  int pcie_aer_is_native(struct pci_dev *dev);
>>>>  #else
>>>>  static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>>>>  {
>>>>  	return -EINVAL;
>>>>  }
>>>> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>>>  static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>>>>  #endif
>>>>  
>>>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>>>> index bff3009f9ff0..cd53715d53f3 100644
>>>> --- a/include/linux/pci.h
>>>> +++ b/include/linux/pci.h
>>>> @@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
>>>>  
>>>>  int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
>>>>  			  bool use_lt);
>>>> +void pcie_walk_rcec(struct pci_dev *rcec,
>>>> +		    int (*cb)(struct pci_dev *, void *),
>>>> +		    void *userdata);
>>>>  #else
>>>>  #define pcie_ports_disabled	true
>>>>  #define pcie_ports_native	false
>>>> @@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
>>>>  {
>>>>  	return -EOPNOTSUPP;
>>>>  }
>>>> +
>>>> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
>>>> +				  int (*cb)(struct pci_dev *, void *),
>>>> +				  void *userdata) { }
>>>> +
>>>>  #endif
>>>>  
>>>> +void pcie_clear_device_status(struct pci_dev *dev);
>>>> +
>>>>  #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
>>>>  #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
>>>>  #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */
>>


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-06 23:15     ` Bowman, Terry
@ 2025-06-09 20:17       ` Dave Jiang
  0 siblings, 0 replies; 90+ messages in thread
From: Dave Jiang @ 2025-06-09 20:17 UTC (permalink / raw)
  To: Bowman, Terry, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, coly.li, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/6/25 4:15 PM, Bowman, Terry wrote:
> 
> 
> On 6/6/2025 10:57 AM, Dave Jiang wrote:
>>
>> On 6/3/25 10:22 AM, Terry Bowman wrote:
>>> The AER driver is now designed to forward CXL protocol errors to the CXL
>>> driver. Update the CXL driver with functionality to dequeue the forwarded
>>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
>>> error handling processing using the work received from the FIFO.
>>>
>>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>>> AER service driver. This will begin the CXL protocol error processing
>>> with a call to cxl_handle_prot_error().
>>>
>>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
>>> previously in the AER driver.
>>>
>>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
>>> and use in discovering the erring PCI device. Make scope based reference
>>> increments/decrements for the discovered PCI device and the associated
>>> CXL device.
>>>
>>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
>>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>>> RCH errors will be processed with a call to walk the associated Root
>>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>>> so the CXL driver can walk the RCEC's downstream bus, searching for
>>> the RCiEP.
>>>
>>> VH correctable error (CE) processing will call the CXL CE handler. VH
>>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
>>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
>>> and pci_clean_device_status() used to clean up AER status after handling.
>>>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>> ---
>>>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>>>  drivers/pci/pci.c       |  1 +
>>>  drivers/pci/pci.h       |  8 ----
>>>  drivers/pci/pcie/aer.c  |  1 +
>>>  drivers/pci/pcie/rcec.c |  1 +
>>>  include/linux/aer.h     |  2 +
>>>  include/linux/pci.h     | 10 +++++
>>>  7 files changed, 107 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>> index d35525e79e04..9ed5c682e128 100644
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>>  
>>>  #ifdef CONFIG_PCIEAER_CXL
>>>  
>>> +static void cxl_do_recovery(struct pci_dev *pdev)
>>> +{
>>> +}
>>> +
>>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>>> +{
>>> +	struct cxl_prot_error_info *err_info = data;
>>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>>> +	struct cxl_dev_state *cxlds;
>>> +
>>> +	/*
>>> +	 * The capability, status, and control fields in Device 0,
>>> +	 * Function 0 DVSEC control the CXL functionality of the
>>> +	 * entire device (CXL 3.0, 8.1.3).
>>> +	 */
>>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>>> +		return 0;
>>> +
>>> +	/*
>>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>>> +	 * 3.0, 8.1.12.1).
>>> +	 */
>>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>> Should use FIELD_GET() to be consistent with the rest of CXL code base
>>
>>> +		return 0;
>>> +
>>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
>> I think you need to hold the pdev->dev lock while checking if the driver exists.
> Hi Dave,
> 
> Wouldn't a reference count increment prevent the driver from being unbound and thus
> make this access here to the driver safe (given the pci_dev_get() above)? And a lock
> would prevent concurrent access with a busy wait when the driver executes the next
> lock take?

Actually nothing prevents a driver from being unbound unless you are holding the device lock. Because device core needs the device lock in order to call driver removal [1]. So if you acquire the lock, either the driver is still bound and you are ok, or the driver is gone and there's nothing to do. The incremented refcount prevents ->release() of the device and the memory allocated for the device from being freed based on kref behavior [2].

[1]: https://elixir.bootlin.com/linux/v6.15.1/source/drivers/base/dd.c#L1292
[2]: https://elixir.bootlin.com/linux/v6.15.1/source/include/linux/kref.h#L48

DJ

> 
> Terry
> 
> [snip]
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-09 19:57         ` Bowman, Terry
@ 2025-06-09 20:34           ` Dave Jiang
  2025-06-12 11:17             ` Jonathan Cameron
  0 siblings, 1 reply; 90+ messages in thread
From: Dave Jiang @ 2025-06-09 20:34 UTC (permalink / raw)
  To: Bowman, Terry, PradeepVineshReddy.Kodamati, dave,
	jonathan.cameron, alison.schofield, vishal.l.verma, ira.weiny,
	dan.j.williams, bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, rrichter, peterz,
	linux-cxl, linux-kernel, linux-pci



On 6/9/25 12:57 PM, Bowman, Terry wrote:
> 
> 
> On 6/6/2025 5:43 PM, Dave Jiang wrote:
>>
>> On 6/6/25 11:14 AM, Bowman, Terry wrote:
>>>
>>> On 6/6/2025 10:57 AM, Dave Jiang wrote:
>>>> On 6/3/25 10:22 AM, Terry Bowman wrote:
>>>>> The AER driver is now designed to forward CXL protocol errors to the CXL
>>>>> driver. Update the CXL driver with functionality to dequeue the forwarded
>>>>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
>>>>> error handling processing using the work received from the FIFO.
>>>>>
>>>>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>>>>> AER service driver. This will begin the CXL protocol error processing
>>>>> with a call to cxl_handle_prot_error().
>>>>>
>>>>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
>>>>> previously in the AER driver.
>>>>>
>>>>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
>>>>> and use in discovering the erring PCI device. Make scope based reference
>>>>> increments/decrements for the discovered PCI device and the associated
>>>>> CXL device.
>>>>>
>>>>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
>>>>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>>>>> RCH errors will be processed with a call to walk the associated Root
>>>>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>>>>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>>>>> so the CXL driver can walk the RCEC's downstream bus, searching for
>>>>> the RCiEP.
>>>>>
>>>>> VH correctable error (CE) processing will call the CXL CE handler. VH
>>>>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
>>>>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
>>>>> and pci_clean_device_status() used to clean up AER status after handling.
>>>>>
>>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>>>> ---
>>>>>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
>>>>>  drivers/pci/pci.c       |  1 +
>>>>>  drivers/pci/pci.h       |  8 ----
>>>>>  drivers/pci/pcie/aer.c  |  1 +
>>>>>  drivers/pci/pcie/rcec.c |  1 +
>>>>>  include/linux/aer.h     |  2 +
>>>>>  include/linux/pci.h     | 10 +++++
>>>>>  7 files changed, 107 insertions(+), 8 deletions(-)
>>>>>
>>>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>>>> index d35525e79e04..9ed5c682e128 100644
>>>>> --- a/drivers/cxl/core/ras.c
>>>>> +++ b/drivers/cxl/core/ras.c
>>>>> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>>>>  
>>>>>  #ifdef CONFIG_PCIEAER_CXL
>>>>>  
>>>>> +static void cxl_do_recovery(struct pci_dev *pdev)
>>>>> +{
>>>>> +}
>>>>> +
>>>>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>>>>> +{
>>>>> +	struct cxl_prot_error_info *err_info = data;
>>>>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>>>>> +	struct cxl_dev_state *cxlds;
>>>>> +
>>>>> +	/*
>>>>> +	 * The capability, status, and control fields in Device 0,
>>>>> +	 * Function 0 DVSEC control the CXL functionality of the
>>>>> +	 * entire device (CXL 3.0, 8.1.3).
>>>>> +	 */
>>>>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>>>>> +		return 0;
>>>>> +
>>>>> +	/*
>>>>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>>>>> +	 * 3.0, 8.1.12.1).
>>>>> +	 */
>>>>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>>>> Should use FIELD_GET() to be consistent with the rest of CXL code base
>>> Ok.
> 
> Hi Dave,
> 
> I have a question. I found I need to do the same you recommended for is_cxl_mem_dev() in
> drivers/pci/pcie/cxl_aer.c. Looks like I need to define:
> 
> #define PCI_CLASS_CODE_MASK         GENMASK(23, 8)
> 
> to be used as:
> 
> FIELD_GET(PCI_CLASS_CODE_MASK, pdev->class)
> 
> What header file can I add the PCI_CLASS_CODE_MASK #define so that it can be used in CXL
> and PCI drivers?

Perhaps include/uapi/linux/pci_regs.h? Although you may need to define the raw mask instead of using GENMASK due to the header being exported to user as well.

DJ

> 
> Terry
> 
> 
>>>>> +		return 0;
>>>>> +
>>>>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
>>>> I think you need to hold the pdev->dev lock while checking if the driver exists.
>>> Ok.
>>>>> +		return 0;
>>>>> +
>>>>> +	cxlds = pci_get_drvdata(pdev);
>>>>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>>>> Maybe a comment on why cxlmd->dev ref is needed here.
>>> Good point.
>>>>> +
>>>>> +	if (err_info->severity == AER_CORRECTABLE)
>>>>> +		cxl_cor_error_detected(pdev);
>>>>> +	else
>>>>> +		cxl_do_recovery(pdev);
>>>>> +
>>>>> +	return 1;
>>>>> +}
>>>>> +
>>>>> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>>>>> +{
>>>>> +	unsigned int devfn = PCI_DEVFN(err_info->device,
>>>>> +				       err_info->function);
>>>>> +	struct pci_dev *pdev __free(pci_dev_put) =
>>>>> +		pci_get_domain_bus_and_slot(err_info->segment,
>>>>> +					    err_info->bus,
>>>>> +					    devfn);
>>>> Looks like DanC already caught that. Maybe have this function return with a ref held. I would also add a comment for the function mention that the caller need to put the device.
>>> Right. I made the change in v10 source after DanC commented. I'll add a comment that callers must decrement the reference count..
>>>>> +	return pdev;
>>>>> +}
>>>>> +
>>>>> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>>>>> +{
>>>>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
>>>>> +
>>>>> +	if (!pdev) {
>>>>> +		pr_err("Failed to find the CXL device\n");
>>>>> +		return;
>>>>> +	}
>>>>> +
>>>>> +	/*
>>>>> +	 * 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.
>>>>> +	 */
>>>>> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
>>>>> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>>>>> +
>>>> cxl_rch_handle_error_iter() holds the pdev device lock when handling errors. Does the code block below need locking?
>>>>
>>>> DJ
>>> There is a guard_lock() in the EP CXL error handlers (cxl_error_detected()/cxl_cor_error_detected()). I have question about
>>> the same for the non-EP handlers added later: should we add the same guard() for the CXL port handlers? That is in following patch:
>>> [PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers.
>> I would think so....
>>
>> DJ
>>
>>> Terry
>>>>> +	if (err_info->severity == AER_CORRECTABLE) {
>>>>> +		int aer = pdev->aer_cap;
>>>>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>>>>> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>>>>> +
>>>>> +		if (aer)
>>>>> +			pci_clear_and_set_config_dword(pdev,
>>>>> +						       aer + PCI_ERR_COR_STATUS,
>>>>> +						       0, PCI_ERR_COR_INTERNAL);
>>>>> +
>>>>> +		cxl_cor_error_detected(pdev);
>>>>> +
>>>>> +		pcie_clear_device_status(pdev);
>>>>> +	} else {
>>>>> +		cxl_do_recovery(pdev);
>>>>> +	}
>>>>> +}
>>>>> +
>>>>>  static void cxl_prot_err_work_fn(struct work_struct *work)
>>>>>  {
>>>>> +	struct cxl_prot_err_work_data wd;
>>>>> +
>>>>> +	while (cxl_prot_err_kfifo_get(&wd)) {
>>>>> +		struct cxl_prot_error_info *err_info = &wd.err_info;
>>>>> +
>>>>> +		cxl_handle_prot_error(err_info);
>>>>> +	}
>>>>>  }
>>>>>  
>>>>>  #else
>>>>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
>>>>> index e77d5b53c0ce..524ac32b744a 100644
>>>>> --- a/drivers/pci/pci.c
>>>>> +++ b/drivers/pci/pci.c
>>>>> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
>>>>>  	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
>>>>>  	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
>>>>>  }
>>>>> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
>>>>>  #endif
>>>>>  
>>>>>  /**
>>>>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
>>>>> index d6296500b004..3c54a5ed803e 100644
>>>>> --- a/drivers/pci/pci.h
>>>>> +++ b/drivers/pci/pci.h
>>>>> @@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
>>>>>  void pci_rcec_init(struct pci_dev *dev);
>>>>>  void pci_rcec_exit(struct pci_dev *dev);
>>>>>  void pcie_link_rcec(struct pci_dev *rcec);
>>>>> -void pcie_walk_rcec(struct pci_dev *rcec,
>>>>> -		    int (*cb)(struct pci_dev *, void *),
>>>>> -		    void *userdata);
>>>>>  #else
>>>>>  static inline void pci_rcec_init(struct pci_dev *dev) { }
>>>>>  static inline void pci_rcec_exit(struct pci_dev *dev) { }
>>>>>  static inline void pcie_link_rcec(struct pci_dev *rcec) { }
>>>>> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
>>>>> -				  int (*cb)(struct pci_dev *, void *),
>>>>> -				  void *userdata) { }
>>>>>  #endif
>>>>>  
>>>>>  #ifdef CONFIG_PCI_ATS
>>>>> @@ -967,7 +961,6 @@ void pci_no_aer(void);
>>>>>  void pci_aer_init(struct pci_dev *dev);
>>>>>  void pci_aer_exit(struct pci_dev *dev);
>>>>>  extern const struct attribute_group aer_stats_attr_group;
>>>>> -void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>>>>  int pci_aer_clear_status(struct pci_dev *dev);
>>>>>  int pci_aer_raw_clear_status(struct pci_dev *dev);
>>>>>  void pci_save_aer_state(struct pci_dev *dev);
>>>>> @@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
>>>>>  static inline void pci_no_aer(void) { }
>>>>>  static inline void pci_aer_init(struct pci_dev *d) { }
>>>>>  static inline void pci_aer_exit(struct pci_dev *d) { }
>>>>> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>>>>  static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>>>>  static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
>>>>>  static inline void pci_save_aer_state(struct pci_dev *dev) { }
>>>>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>>>>> index 5350fa5be784..6e88331c6303 100644
>>>>> --- a/drivers/pci/pcie/aer.c
>>>>> +++ b/drivers/pci/pcie/aer.c
>>>>> @@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
>>>>>  	if (status)
>>>>>  		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
>>>>>  }
>>>>> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
>>>>>  
>>>>>  /**
>>>>>   * pci_aer_raw_clear_status - Clear AER error registers.
>>>>> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
>>>>> index d0bcd141ac9c..fb6cf6449a1d 100644
>>>>> --- a/drivers/pci/pcie/rcec.c
>>>>> +++ b/drivers/pci/pcie/rcec.c
>>>>> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
>>>>>  
>>>>>  	walk_rcec(walk_rcec_helper, &rcec_data);
>>>>>  }
>>>>> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
>>>>>  
>>>>>  void pci_rcec_init(struct pci_dev *dev)
>>>>>  {
>>>>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>>>>> index 550407240ab5..c9a18eca16f8 100644
>>>>> --- a/include/linux/aer.h
>>>>> +++ b/include/linux/aer.h
>>>>> @@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
>>>>>  
>>>>>  #if defined(CONFIG_PCIEAER)
>>>>>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>>>>> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>>>>  int pcie_aer_is_native(struct pci_dev *dev);
>>>>>  #else
>>>>>  static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>>>>>  {
>>>>>  	return -EINVAL;
>>>>>  }
>>>>> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>>>>  static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>>>>>  #endif
>>>>>  
>>>>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>>>>> index bff3009f9ff0..cd53715d53f3 100644
>>>>> --- a/include/linux/pci.h
>>>>> +++ b/include/linux/pci.h
>>>>> @@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
>>>>>  
>>>>>  int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
>>>>>  			  bool use_lt);
>>>>> +void pcie_walk_rcec(struct pci_dev *rcec,
>>>>> +		    int (*cb)(struct pci_dev *, void *),
>>>>> +		    void *userdata);
>>>>>  #else
>>>>>  #define pcie_ports_disabled	true
>>>>>  #define pcie_ports_native	false
>>>>> @@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
>>>>>  {
>>>>>  	return -EOPNOTSUPP;
>>>>>  }
>>>>> +
>>>>> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
>>>>> +				  int (*cb)(struct pci_dev *, void *),
>>>>> +				  void *userdata) { }
>>>>> +
>>>>>  #endif
>>>>>  
>>>>> +void pcie_clear_device_status(struct pci_dev *dev);
>>>>> +
>>>>>  #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
>>>>>  #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
>>>>>  #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */
>>>
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-03 17:22 ` [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error Terry Bowman
                     ` (2 preceding siblings ...)
  2025-06-06 15:57   ` Dave Jiang
@ 2025-06-10  4:15   ` Lukas Wunner
  2025-06-10 18:07     ` Bowman, Terry
  2025-06-12 11:36   ` Jonathan Cameron
  4 siblings, 1 reply; 90+ messages in thread
From: Lukas Wunner @ 2025-06-10  4:15 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, jonathan.cameron, dave.jiang,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, yanfei.xu,
	rrichter, peterz, colyli, uaisheng.ye, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci

On Tue, Jun 03, 2025 at 12:22:27PM -0500, Terry Bowman wrote:
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> +{
> +	struct cxl_prot_error_info *err_info = data;
> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
> +	struct cxl_dev_state *cxlds;
> +
> +	/*
> +	 * The capability, status, and control fields in Device 0,
> +	 * Function 0 DVSEC control the CXL functionality of the
> +	 * entire device (CXL 3.0, 8.1.3).
> +	 */
> +	if (pdev->devfn != PCI_DEVFN(0, 0))
> +		return 0;
> +
> +	/*
> +	 * CXL Memory Devices must have the 502h class code set (CXL
> +	 * 3.0, 8.1.12.1).
> +	 */
> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> +		return 0;
> +
> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
> +		return 0;

Is the point of the "!pdev->dev.driver" check to ascertain that
pdev is bound to cxl_pci_driver?

If so, you need to check "if (pdev->driver != &cxl_pci_driver)"
directly (like cxl_handle_cper_event() does).

That's because there are drivers which may bind to *any* PCI device,
e.g. vfio_pci_driver.

Thanks,

Lukas

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-10  4:15   ` Lukas Wunner
@ 2025-06-10 18:07     ` Bowman, Terry
  2025-06-10 21:20       ` Bowman, Terry
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-10 18:07 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: dave, jonathan.cameron, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, rrichter, peterz, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/9/2025 11:15 PM, Lukas Wunner wrote:
> On Tue, Jun 03, 2025 at 12:22:27PM -0500, Terry Bowman wrote:
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>> +{
>> +	struct cxl_prot_error_info *err_info = data;
>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>> +	struct cxl_dev_state *cxlds;
>> +
>> +	/*
>> +	 * The capability, status, and control fields in Device 0,
>> +	 * Function 0 DVSEC control the CXL functionality of the
>> +	 * entire device (CXL 3.0, 8.1.3).
>> +	 */
>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>> +		return 0;
>> +
>> +	/*
>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>> +	 * 3.0, 8.1.12.1).
>> +	 */
>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>> +		return 0;
>> +
>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
>> +		return 0;
> Is the point of the "!pdev->dev.driver" check to ascertain that
> pdev is bound to cxl_pci_driver?
>
> If so, you need to check "if (pdev->driver != &cxl_pci_driver)"
> directly (like cxl_handle_cper_event() does).
>
> That's because there are drivers which may bind to *any* PCI device,
> e.g. vfio_pci_driver.
>
> Thanks,
>
> Lukas

Good point. I'm adding this change. Thanks Lukas.

-Terry



^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-10 18:07     ` Bowman, Terry
@ 2025-06-10 21:20       ` Bowman, Terry
  2025-06-11  4:38         ` Lukas Wunner
  0 siblings, 1 reply; 90+ messages in thread
From: Bowman, Terry @ 2025-06-10 21:20 UTC (permalink / raw)
  To: Lukas Wunner
  Cc: dave, jonathan.cameron, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, rrichter, peterz, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/10/2025 1:07 PM, Bowman, Terry wrote:
>
> On 6/9/2025 11:15 PM, Lukas Wunner wrote:
>> On Tue, Jun 03, 2025 at 12:22:27PM -0500, Terry Bowman wrote:
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>>> +{
>>> +	struct cxl_prot_error_info *err_info = data;
>>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>>> +	struct cxl_dev_state *cxlds;
>>> +
>>> +	/*
>>> +	 * The capability, status, and control fields in Device 0,
>>> +	 * Function 0 DVSEC control the CXL functionality of the
>>> +	 * entire device (CXL 3.0, 8.1.3).
>>> +	 */
>>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>>> +		return 0;
>>> +
>>> +	/*
>>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>>> +	 * 3.0, 8.1.12.1).
>>> +	 */
>>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>>> +		return 0;
>>> +
>>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
>>> +		return 0;
>> Is the point of the "!pdev->dev.driver" check to ascertain that
>> pdev is bound to cxl_pci_driver?
>>
>> If so, you need to check "if (pdev->driver != &cxl_pci_driver)"
>> directly (like cxl_handle_cper_event() does).
>>
>> That's because there are drivers which may bind to *any* PCI device,
>> e.g. vfio_pci_driver.
>>
>> Thanks,
>>
>> Lukas
> Good point. I'm adding this change. Thanks Lukas.
>
> -Terry
Hi Lukas,

Looking closer to implement this change I find the cxl_pci_driver is defined static in cxl/pci.c and
is unavailable to reference in cxl/core/ras.c as-is. Would you like me to export cxl_pci_driver to
make available for this check? The existing class code check guarantees it is a CXL EP. Is it not
safe to expect it is bound to a the CXL driver?

-Terry



^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-10 21:20       ` Bowman, Terry
@ 2025-06-11  4:38         ` Lukas Wunner
  2025-06-17 16:08           ` Dave Jiang
  0 siblings, 1 reply; 90+ messages in thread
From: Lukas Wunner @ 2025-06-11  4:38 UTC (permalink / raw)
  To: Bowman, Terry
  Cc: dave, jonathan.cameron, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, rrichter, peterz, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci

On Tue, Jun 10, 2025 at 04:20:53PM -0500, Bowman, Terry wrote:
> On 6/10/2025 1:07 PM, Bowman, Terry wrote:
> > On 6/9/2025 11:15 PM, Lukas Wunner wrote:
> >> On Tue, Jun 03, 2025 at 12:22:27PM -0500, Terry Bowman wrote:
> >>> --- a/drivers/cxl/core/ras.c
> >>> +++ b/drivers/cxl/core/ras.c
> >>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> >>> +{
> >>> +	struct cxl_prot_error_info *err_info = data;
> >>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
> >>> +	struct cxl_dev_state *cxlds;
> >>> +
> >>> +	/*
> >>> +	 * The capability, status, and control fields in Device 0,
> >>> +	 * Function 0 DVSEC control the CXL functionality of the
> >>> +	 * entire device (CXL 3.0, 8.1.3).
> >>> +	 */
> >>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
> >>> +		return 0;
> >>> +
> >>> +	/*
> >>> +	 * CXL Memory Devices must have the 502h class code set (CXL
> >>> +	 * 3.0, 8.1.12.1).
> >>> +	 */
> >>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> >>> +		return 0;
> >>> +
> >>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
> >>> +		return 0;
> >>
> >> Is the point of the "!pdev->dev.driver" check to ascertain that
> >> pdev is bound to cxl_pci_driver?
> >>
> >> If so, you need to check "if (pdev->driver != &cxl_pci_driver)"
> >> directly (like cxl_handle_cper_event() does).
> >>
> >> That's because there are drivers which may bind to *any* PCI device,
> >> e.g. vfio_pci_driver.
> 
> Looking closer to implement this change I find the cxl_pci_driver is
> defined static in cxl/pci.c and is unavailable to reference in
> cxl/core/ras.c as-is. Would you like me to export cxl_pci_driver to
> make available for this check?

I'm not sure you need an export.  The consumer you're introducing
is located in core/ras.c, which is always built-in, never modular,
hence just making it non-static and adding a declaration to cxlpci.h
may be sufficient.

An alternative would be to keep it static, but add a non-static helper
cxl_pci_drv_bound() or something like that.

I'm passing the buck to CXL maintainers for this. :)

> The existing class code check guarantees it is a CXL EP. Is it not
> safe to expect it is bound to a the CXL driver?

Just checking for the pci_dev being bound seems insufficient to me
because of the vfio_pci_driver case and potentially others.

HTH,

Lukas

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-03 17:22 ` [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors Terry Bowman
                     ` (2 preceding siblings ...)
  2025-06-06  0:27   ` Dave Jiang
@ 2025-06-12 11:04   ` Jonathan Cameron
  2025-06-12 14:29     ` Bowman, Terry
  3 siblings, 1 reply; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 11:04 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, 3 Jun 2025 12:22:26 -0500
Terry Bowman <terry.bowman@amd.com> wrote:

> CXL error handling will soon be moved from the AER driver into the CXL
> driver. This requires a notification mechanism for the AER driver to share
> the AER interrupt with the CXL driver. The notification will be used
> as an indication for the CXL drivers to handle and log the CXL RAS errors.
> 
> Add a kfifo work queue to be used by the AER driver and CXL driver. The AER
> driver will be the sole kfifo producer adding work and the cxl_core will be
> the sole kfifo consumer removing work. Add the boilerplate kfifo support.
> 
> Add CXL work queue handler registration functions in the AER driver. Export
> the functions allowing CXL driver to access. Implement registration
> functions for the CXL driver to assign or clear the work handler function.
> 
> Introduce function cxl_create_prot_err_info() and 'struct cxl_prot_err_info'.
> Implement cxl_create_prot_err_info() to populate a 'struct cxl_prot_err_info'
> instance with the AER severity and the erring device's PCI SBDF. The SBDF
> details will be used to rediscover the erring device after the CXL driver
> dequeues the kfifo work. The device rediscovery will be introduced along
> with the CXL handling in future patches.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Hi Terry,

A few trivial bits of feedback.  I didn't find anything substantial that
hasn't already been covered by others.

Jonathan

> ---
>  drivers/cxl/core/ras.c |  31 +++++++++-
>  drivers/cxl/cxlpci.h   |   1 +
>  drivers/pci/pcie/aer.c | 132 ++++++++++++++++++++++++++++-------------
>  include/linux/aer.h    |  36 +++++++++++
>  4 files changed, 157 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 485a831695c7..d35525e79e04 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -5,6 +5,7 @@

>  
>  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_unregister_prot_err_work();
> +	cancel_work_sync(&cxl_prot_err_work);
>  }

> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> index adb4b1123b9b..5350fa5be784 100644
> --- a/drivers/pci/pcie/aer.c
> +++ b/drivers/pci/pcie/aer.c

> +static int cxl_create_prot_error_info(struct pci_dev *pdev,
> +				      struct aer_err_info *aer_err_info,
> +				      struct cxl_prot_error_info *cxl_err_info)
> +{
> +	cxl_err_info->severity = aer_err_info->severity;
> +
> +	cxl_err_info->function = PCI_FUNC(pdev->devfn);
> +	cxl_err_info->device = PCI_SLOT(pdev->devfn);
> +	cxl_err_info->bus = pdev->bus->number;
> +	cxl_err_info->segment = pci_domain_nr(pdev->bus);
Maybe 
	*cxl_err_info = (struct cxl_prot_error_info) {
		.severity = aer_err_info->severity,
		.function = PCI_FUNC(pdev->devfn),
		.device = PCI_SLOT(pdev->devfn),
		.bus = pdev->bus_number,
		.segment = pci_domain_nr(dev->nbus),
	};

Or if it isn't going to get more use later, just put that assignment in
forward_cxl_error as this helper doesn't seem to add a huge amount of
value wrt to code reability.


> +
> +	return 0;
> +}
> +
> +static void forward_cxl_error(struct pci_dev *pdev, struct aer_err_info *aer_err_info)
> +{
> +	struct cxl_prot_err_work_data wd;
> +	struct cxl_prot_error_info *cxl_err_info = &wd.err_info;
> +
> +	cxl_create_prot_error_info(pdev, aer_err_info, cxl_err_info);

	cxl_create_prot_error_info(pdev, aer_err_info, &wd.err_info);

Ignore if this gets more complicated in a later patch but for now I don't
see the local variable adding any value. If anything it slightly obscures
how this gets used via wd in the next line.  However given the code is short
that is fairly obvious either way.

Or as above
	wd.error_info = (struct cxl_prot_error_info) {
		.severity = ...
	};

> +
> +	if (!kfifo_put(&cxl_prot_err_fifo, wd)) {
> +		dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
> +		return;
> +	}
> +
> +	schedule_work(cxl_prot_err_work);
> +}
> +
>  #else
>  static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
>  static inline void cxl_rch_handle_error(struct pci_dev *dev,
>  					struct aer_err_info *info) { }
> +static inline void forward_cxl_error(struct pci_dev *dev,
> +				    struct aer_err_info *info) { }

Is this aligned right - looks one space short?

> +static inline bool handles_cxl_errors(struct pci_dev *dev)
> +{
> +	return false;
> +}
> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return 0; };

wrap choices for the two stubs are a bit odd.   The first one is actually shorter
if not wrapped than the second one is that you chose not to wrap.
My slightly preference would be to wrap them both as the fist one.


>  #endif



^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-09 20:34           ` Dave Jiang
@ 2025-06-12 11:17             ` Jonathan Cameron
  0 siblings, 0 replies; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 11:17 UTC (permalink / raw)
  To: Dave Jiang
  Cc: Bowman, Terry, PradeepVineshReddy.Kodamati, dave,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, rrichter, peterz,
	linux-cxl, linux-kernel, linux-pci

On Mon, 9 Jun 2025 13:34:31 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> On 6/9/25 12:57 PM, Bowman, Terry wrote:
> > 
> > 
> > On 6/6/2025 5:43 PM, Dave Jiang wrote:  
> >>
> >> On 6/6/25 11:14 AM, Bowman, Terry wrote:  
> >>>
> >>> On 6/6/2025 10:57 AM, Dave Jiang wrote:  
> >>>> On 6/3/25 10:22 AM, Terry Bowman wrote:  
> >>>>> The AER driver is now designed to forward CXL protocol errors to the CXL
> >>>>> driver. Update the CXL driver with functionality to dequeue the forwarded
> >>>>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
> >>>>> error handling processing using the work received from the FIFO.
> >>>>>
> >>>>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
> >>>>> AER service driver. This will begin the CXL protocol error processing
> >>>>> with a call to cxl_handle_prot_error().
> >>>>>
> >>>>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
> >>>>> previously in the AER driver.
> >>>>>
> >>>>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
> >>>>> and use in discovering the erring PCI device. Make scope based reference
> >>>>> increments/decrements for the discovered PCI device and the associated
> >>>>> CXL device.
> >>>>>
> >>>>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
> >>>>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
> >>>>> RCH errors will be processed with a call to walk the associated Root
> >>>>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
> >>>>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
> >>>>> so the CXL driver can walk the RCEC's downstream bus, searching for
> >>>>> the RCiEP.
> >>>>>
> >>>>> VH correctable error (CE) processing will call the CXL CE handler. VH
> >>>>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
> >>>>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
> >>>>> and pci_clean_device_status() used to clean up AER status after handling.
> >>>>>
> >>>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> >>>>> ---
> >>>>>  drivers/cxl/core/ras.c  | 92 +++++++++++++++++++++++++++++++++++++++++
> >>>>>  drivers/pci/pci.c       |  1 +
> >>>>>  drivers/pci/pci.h       |  8 ----
> >>>>>  drivers/pci/pcie/aer.c  |  1 +
> >>>>>  drivers/pci/pcie/rcec.c |  1 +
> >>>>>  include/linux/aer.h     |  2 +
> >>>>>  include/linux/pci.h     | 10 +++++
> >>>>>  7 files changed, 107 insertions(+), 8 deletions(-)
> >>>>>
> >>>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> >>>>> index d35525e79e04..9ed5c682e128 100644
> >>>>> --- a/drivers/cxl/core/ras.c
> >>>>> +++ b/drivers/cxl/core/ras.c
> >>>>> @@ -110,8 +110,100 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
> >>>>>  
> >>>>>  #ifdef CONFIG_PCIEAER_CXL
> >>>>>  
> >>>>> +static void cxl_do_recovery(struct pci_dev *pdev)
> >>>>> +{
> >>>>> +}
> >>>>> +
> >>>>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> >>>>> +{
> >>>>> +	struct cxl_prot_error_info *err_info = data;
> >>>>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
> >>>>> +	struct cxl_dev_state *cxlds;
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * The capability, status, and control fields in Device 0,
> >>>>> +	 * Function 0 DVSEC control the CXL functionality of the
> >>>>> +	 * entire device (CXL 3.0, 8.1.3).
> >>>>> +	 */
> >>>>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
> >>>>> +		return 0;
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * CXL Memory Devices must have the 502h class code set (CXL
> >>>>> +	 * 3.0, 8.1.12.1).
> >>>>> +	 */
> >>>>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)  
> >>>> Should use FIELD_GET() to be consistent with the rest of CXL code base  
> >>> Ok.  
> > 
> > Hi Dave,
> > 
> > I have a question. I found I need to do the same you recommended for is_cxl_mem_dev() in
> > drivers/pci/pcie/cxl_aer.c. Looks like I need to define:
> > 
> > #define PCI_CLASS_CODE_MASK         GENMASK(23, 8)
> > 
> > to be used as:
> > 
> > FIELD_GET(PCI_CLASS_CODE_MASK, pdev->class)
> > 
> > What header file can I add the PCI_CLASS_CODE_MASK #define so that it can be used in CXL
> > and PCI drivers?  
> 
> Perhaps include/uapi/linux/pci_regs.h? Although you may need to define the raw mask instead of using GENMASK due to the header being exported to user as well.
> 
It's messy because that register has 3 fields (at least it does by 6.2 - not sure about earlier)
and we are matching on combination of "sub class code" and "base class code" but not the programming
interface which is the bottom 8 bits.

Whilst I'd kind like this cleaned up naming a mask might be a pain...
Maybe we can get away with PCI_CLASS_CODE_MASK given how we name the 
specific IDs but perhaps making it kernel internal via include/linux/pci_ids.h
is safer than an include in uapi?

I'd also like to see such a macro used through out the kernel and not
just in this one place.

Jonathan

> DJ
> 
> > 
> > Terry
> > 
> >   
> >>>>> +		return 0;
> >>>>> +
> >>>>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)  
> >>>> I think you need to hold the pdev->dev lock while checking if the driver exists.  
> >>> Ok.  
> >>>>> +		return 0;
> >>>>> +
> >>>>> +	cxlds = pci_get_drvdata(pdev);
> >>>>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);  
> >>>> Maybe a comment on why cxlmd->dev ref is needed here.  
> >>> Good point.  
> >>>>> +
> >>>>> +	if (err_info->severity == AER_CORRECTABLE)
> >>>>> +		cxl_cor_error_detected(pdev);
> >>>>> +	else
> >>>>> +		cxl_do_recovery(pdev);
> >>>>> +
> >>>>> +	return 1;
> >>>>> +}
> >>>>> +
> >>>>> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
> >>>>> +{
> >>>>> +	unsigned int devfn = PCI_DEVFN(err_info->device,
> >>>>> +				       err_info->function);
> >>>>> +	struct pci_dev *pdev __free(pci_dev_put) =
> >>>>> +		pci_get_domain_bus_and_slot(err_info->segment,
> >>>>> +					    err_info->bus,
> >>>>> +					    devfn);  
> >>>> Looks like DanC already caught that. Maybe have this function return with a ref held. I would also add a comment for the function mention that the caller need to put the device.  
> >>> Right. I made the change in v10 source after DanC commented. I'll add a comment that callers must decrement the reference count..  
> >>>>> +	return pdev;
> >>>>> +}
> >>>>> +
> >>>>> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
> >>>>> +{
> >>>>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> >>>>> +
> >>>>> +	if (!pdev) {
> >>>>> +		pr_err("Failed to find the CXL device\n");
> >>>>> +		return;
> >>>>> +	}
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * 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.
> >>>>> +	 */
> >>>>> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
> >>>>> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
> >>>>> +  
> >>>> cxl_rch_handle_error_iter() holds the pdev device lock when handling errors. Does the code block below need locking?
> >>>>
> >>>> DJ  
> >>> There is a guard_lock() in the EP CXL error handlers (cxl_error_detected()/cxl_cor_error_detected()). I have question about
> >>> the same for the non-EP handlers added later: should we add the same guard() for the CXL port handlers? That is in following patch:
> >>> [PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers.  
> >> I would think so....
> >>
> >> DJ
> >>  
> >>> Terry  
> >>>>> +	if (err_info->severity == AER_CORRECTABLE) {
> >>>>> +		int aer = pdev->aer_cap;
> >>>>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> >>>>> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> >>>>> +
> >>>>> +		if (aer)
> >>>>> +			pci_clear_and_set_config_dword(pdev,
> >>>>> +						       aer + PCI_ERR_COR_STATUS,
> >>>>> +						       0, PCI_ERR_COR_INTERNAL);
> >>>>> +
> >>>>> +		cxl_cor_error_detected(pdev);
> >>>>> +
> >>>>> +		pcie_clear_device_status(pdev);
> >>>>> +	} else {
> >>>>> +		cxl_do_recovery(pdev);
> >>>>> +	}
> >>>>> +}
> >>>>> +
> >>>>>  static void cxl_prot_err_work_fn(struct work_struct *work)
> >>>>>  {
> >>>>> +	struct cxl_prot_err_work_data wd;
> >>>>> +
> >>>>> +	while (cxl_prot_err_kfifo_get(&wd)) {
> >>>>> +		struct cxl_prot_error_info *err_info = &wd.err_info;
> >>>>> +
> >>>>> +		cxl_handle_prot_error(err_info);
> >>>>> +	}
> >>>>>  }
> >>>>>  
> >>>>>  #else
> >>>>> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> >>>>> index e77d5b53c0ce..524ac32b744a 100644
> >>>>> --- a/drivers/pci/pci.c
> >>>>> +++ b/drivers/pci/pci.c
> >>>>> @@ -2328,6 +2328,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
> >>>>>  	pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
> >>>>>  	pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
> >>>>>  }
> >>>>> +EXPORT_SYMBOL_NS_GPL(pcie_clear_device_status, "CXL");
> >>>>>  #endif
> >>>>>  
> >>>>>  /**
> >>>>> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> >>>>> index d6296500b004..3c54a5ed803e 100644
> >>>>> --- a/drivers/pci/pci.h
> >>>>> +++ b/drivers/pci/pci.h
> >>>>> @@ -649,16 +649,10 @@ static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
> >>>>>  void pci_rcec_init(struct pci_dev *dev);
> >>>>>  void pci_rcec_exit(struct pci_dev *dev);
> >>>>>  void pcie_link_rcec(struct pci_dev *rcec);
> >>>>> -void pcie_walk_rcec(struct pci_dev *rcec,
> >>>>> -		    int (*cb)(struct pci_dev *, void *),
> >>>>> -		    void *userdata);
> >>>>>  #else
> >>>>>  static inline void pci_rcec_init(struct pci_dev *dev) { }
> >>>>>  static inline void pci_rcec_exit(struct pci_dev *dev) { }
> >>>>>  static inline void pcie_link_rcec(struct pci_dev *rcec) { }
> >>>>> -static inline void pcie_walk_rcec(struct pci_dev *rcec,
> >>>>> -				  int (*cb)(struct pci_dev *, void *),
> >>>>> -				  void *userdata) { }
> >>>>>  #endif
> >>>>>  
> >>>>>  #ifdef CONFIG_PCI_ATS
> >>>>> @@ -967,7 +961,6 @@ void pci_no_aer(void);
> >>>>>  void pci_aer_init(struct pci_dev *dev);
> >>>>>  void pci_aer_exit(struct pci_dev *dev);
> >>>>>  extern const struct attribute_group aer_stats_attr_group;
> >>>>> -void pci_aer_clear_fatal_status(struct pci_dev *dev);
> >>>>>  int pci_aer_clear_status(struct pci_dev *dev);
> >>>>>  int pci_aer_raw_clear_status(struct pci_dev *dev);
> >>>>>  void pci_save_aer_state(struct pci_dev *dev);
> >>>>> @@ -976,7 +969,6 @@ void pci_restore_aer_state(struct pci_dev *dev);
> >>>>>  static inline void pci_no_aer(void) { }
> >>>>>  static inline void pci_aer_init(struct pci_dev *d) { }
> >>>>>  static inline void pci_aer_exit(struct pci_dev *d) { }
> >>>>> -static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
> >>>>>  static inline int pci_aer_clear_status(struct pci_dev *dev) { return -EINVAL; }
> >>>>>  static inline int pci_aer_raw_clear_status(struct pci_dev *dev) { return -EINVAL; }
> >>>>>  static inline void pci_save_aer_state(struct pci_dev *dev) { }
> >>>>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
> >>>>> index 5350fa5be784..6e88331c6303 100644
> >>>>> --- a/drivers/pci/pcie/aer.c
> >>>>> +++ b/drivers/pci/pcie/aer.c
> >>>>> @@ -290,6 +290,7 @@ void pci_aer_clear_fatal_status(struct pci_dev *dev)
> >>>>>  	if (status)
> >>>>>  		pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_STATUS, status);
> >>>>>  }
> >>>>> +EXPORT_SYMBOL_GPL(pci_aer_clear_fatal_status);
> >>>>>  
> >>>>>  /**
> >>>>>   * pci_aer_raw_clear_status - Clear AER error registers.
> >>>>> diff --git a/drivers/pci/pcie/rcec.c b/drivers/pci/pcie/rcec.c
> >>>>> index d0bcd141ac9c..fb6cf6449a1d 100644
> >>>>> --- a/drivers/pci/pcie/rcec.c
> >>>>> +++ b/drivers/pci/pcie/rcec.c
> >>>>> @@ -145,6 +145,7 @@ void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
> >>>>>  
> >>>>>  	walk_rcec(walk_rcec_helper, &rcec_data);
> >>>>>  }
> >>>>> +EXPORT_SYMBOL_NS_GPL(pcie_walk_rcec, "CXL");
> >>>>>  
> >>>>>  void pci_rcec_init(struct pci_dev *dev)
> >>>>>  {
> >>>>> diff --git a/include/linux/aer.h b/include/linux/aer.h
> >>>>> index 550407240ab5..c9a18eca16f8 100644
> >>>>> --- a/include/linux/aer.h
> >>>>> +++ b/include/linux/aer.h
> >>>>> @@ -77,12 +77,14 @@ struct cxl_prot_err_work_data {
> >>>>>  
> >>>>>  #if defined(CONFIG_PCIEAER)
> >>>>>  int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
> >>>>> +void pci_aer_clear_fatal_status(struct pci_dev *dev);
> >>>>>  int pcie_aer_is_native(struct pci_dev *dev);
> >>>>>  #else
> >>>>>  static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
> >>>>>  {
> >>>>>  	return -EINVAL;
> >>>>>  }
> >>>>> +static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
> >>>>>  static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
> >>>>>  #endif
> >>>>>  
> >>>>> diff --git a/include/linux/pci.h b/include/linux/pci.h
> >>>>> index bff3009f9ff0..cd53715d53f3 100644
> >>>>> --- a/include/linux/pci.h
> >>>>> +++ b/include/linux/pci.h
> >>>>> @@ -1806,6 +1806,9 @@ extern bool pcie_ports_native;
> >>>>>  
> >>>>>  int pcie_set_target_speed(struct pci_dev *port, enum pci_bus_speed speed_req,
> >>>>>  			  bool use_lt);
> >>>>> +void pcie_walk_rcec(struct pci_dev *rcec,
> >>>>> +		    int (*cb)(struct pci_dev *, void *),
> >>>>> +		    void *userdata);
> >>>>>  #else
> >>>>>  #define pcie_ports_disabled	true
> >>>>>  #define pcie_ports_native	false
> >>>>> @@ -1816,8 +1819,15 @@ static inline int pcie_set_target_speed(struct pci_dev *port,
> >>>>>  {
> >>>>>  	return -EOPNOTSUPP;
> >>>>>  }
> >>>>> +
> >>>>> +static inline void pcie_walk_rcec(struct pci_dev *rcec,
> >>>>> +				  int (*cb)(struct pci_dev *, void *),
> >>>>> +				  void *userdata) { }
> >>>>> +
> >>>>>  #endif
> >>>>>  
> >>>>> +void pcie_clear_device_status(struct pci_dev *dev);
> >>>>> +
> >>>>>  #define PCIE_LINK_STATE_L0S		(BIT(0) | BIT(1)) /* Upstr/dwnstr L0s */
> >>>>>  #define PCIE_LINK_STATE_L1		BIT(2)	/* L1 state */
> >>>>>  #define PCIE_LINK_STATE_L1_1		BIT(3)	/* ASPM L1.1 state */  
> >>>  
> >   
> 
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-03 17:22 ` [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error Terry Bowman
                     ` (3 preceding siblings ...)
  2025-06-10  4:15   ` Lukas Wunner
@ 2025-06-12 11:36   ` Jonathan Cameron
  2025-06-12 18:35     ` Bowman, Terry
  4 siblings, 1 reply; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 11:36 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, 3 Jun 2025 12:22:27 -0500
Terry Bowman <terry.bowman@amd.com> wrote:

> The AER driver is now designed to forward CXL protocol errors to the CXL
> driver. Update the CXL driver with functionality to dequeue the forwarded
> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
> error handling processing using the work received from the FIFO.
> 
> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
> AER service driver. This will begin the CXL protocol error processing
> with a call to cxl_handle_prot_error().
> 
> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
> previously in the AER driver.
> 
> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
> and use in discovering the erring PCI device. Make scope based reference
> increments/decrements for the discovered PCI device and the associated
> CXL device.
> 
> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
> RCH errors will be processed with a call to walk the associated Root
> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
> so the CXL driver can walk the RCEC's downstream bus, searching for
> the RCiEP.
> 
> VH correctable error (CE) processing will call the CXL CE handler. VH
> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
> and pci_clean_device_status() used to clean up AER status after handling.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>

Hopefully I haven't duplicated existing feedback. A few more minor things
inline.

> +
> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)

That's an odd function name as the sbdf is buried.
Unless it's going to get a lot of use, I'd just put the lookup
inline and not have a 'hard to name' function.  With other suggested
changes you only need (at where this is currently called)
	struct pci_dev *pdev __free(pci_dev_put) =
		pci_get_domain_bus_and_slot(err_info->segment, err_info->bus,
					    err_info->devfn);

> +{
> +	unsigned int devfn = PCI_DEVFN(err_info->device,
> +				       err_info->function);

This makes me wonder if you should have just use devfn inside the err_info.
Is there a good reason to split them up before storing them?

IIRC ARI makes a mess anyway of their meaning when separate.

> +	struct pci_dev *pdev __free(pci_dev_put) =
> +		pci_get_domain_bus_and_slot(err_info->segment,
> +					    err_info->bus,
> +					    devfn);
> +	return pdev;
> +}
> +
> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
> +{
> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> +
> +	if (!pdev) {
> +		pr_err("Failed to find the CXL device\n");
> +		return;
> +	}
> +
> +	/*
> +	 * 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.
> +	 */
> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
> +
> +	if (err_info->severity == AER_CORRECTABLE) {
> +		int aer = pdev->aer_cap;
> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +
> +		if (aer)
> +			pci_clear_and_set_config_dword(pdev,
> +						       aer + PCI_ERR_COR_STATUS,
> +						       0, PCI_ERR_COR_INTERNAL);
> +
> +		cxl_cor_error_detected(pdev);
> +
> +		pcie_clear_device_status(pdev);
> +	} else {
> +		cxl_do_recovery(pdev);
> +	}
> +}
> +
>  static void cxl_prot_err_work_fn(struct work_struct *work)
>  {
> +	struct cxl_prot_err_work_data wd;
> +
> +	while (cxl_prot_err_kfifo_get(&wd)) {
> +		struct cxl_prot_error_info *err_info = &wd.err_info;
> +
> +		cxl_handle_prot_error(err_info);

I'm not seeing value in the local variable.
Ignore if this code changes later and that makes more sense!

> +	}
>  }
>  
>  #else


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors
  2025-06-12 11:04   ` Jonathan Cameron
@ 2025-06-12 14:29     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-12 14:29 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, rrichter, peterz, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/12/2025 6:04 AM, Jonathan Cameron wrote:
> On Tue, 3 Jun 2025 12:22:26 -0500
> Terry Bowman <terry.bowman@amd.com> wrote:
>
>> CXL error handling will soon be moved from the AER driver into the CXL
>> driver. This requires a notification mechanism for the AER driver to share
>> the AER interrupt with the CXL driver. The notification will be used
>> as an indication for the CXL drivers to handle and log the CXL RAS errors.
>>
>> Add a kfifo work queue to be used by the AER driver and CXL driver. The AER
>> driver will be the sole kfifo producer adding work and the cxl_core will be
>> the sole kfifo consumer removing work. Add the boilerplate kfifo support.
>>
>> Add CXL work queue handler registration functions in the AER driver. Export
>> the functions allowing CXL driver to access. Implement registration
>> functions for the CXL driver to assign or clear the work handler function.
>>
>> Introduce function cxl_create_prot_err_info() and 'struct cxl_prot_err_info'.
>> Implement cxl_create_prot_err_info() to populate a 'struct cxl_prot_err_info'
>> instance with the AER severity and the erring device's PCI SBDF. The SBDF
>> details will be used to rediscover the erring device after the CXL driver
>> dequeues the kfifo work. The device rediscovery will be introduced along
>> with the CXL handling in future patches.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Hi Terry,
>
> A few trivial bits of feedback.  I didn't find anything substantial that
> hasn't already been covered by others.
>
> Jonathan
>
>> ---
>>  drivers/cxl/core/ras.c |  31 +++++++++-
>>  drivers/cxl/cxlpci.h   |   1 +
>>  drivers/pci/pcie/aer.c | 132 ++++++++++++++++++++++++++++-------------
>>  include/linux/aer.h    |  36 +++++++++++
>>  4 files changed, 157 insertions(+), 43 deletions(-)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 485a831695c7..d35525e79e04 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -5,6 +5,7 @@
>>  
>>  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_unregister_prot_err_work();
>> +	cancel_work_sync(&cxl_prot_err_work);
>>  }
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index adb4b1123b9b..5350fa5be784 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> +static int cxl_create_prot_error_info(struct pci_dev *pdev,
>> +				      struct aer_err_info *aer_err_info,
>> +				      struct cxl_prot_error_info *cxl_err_info)
>> +{
>> +	cxl_err_info->severity = aer_err_info->severity;
>> +
>> +	cxl_err_info->function = PCI_FUNC(pdev->devfn);
>> +	cxl_err_info->device = PCI_SLOT(pdev->devfn);
>> +	cxl_err_info->bus = pdev->bus->number;
>> +	cxl_err_info->segment = pci_domain_nr(pdev->bus);
> Maybe 
> 	*cxl_err_info = (struct cxl_prot_error_info) {
> 		.severity = aer_err_info->severity,
> 		.function = PCI_FUNC(pdev->devfn),
> 		.device = PCI_SLOT(pdev->devfn),
> 		.bus = pdev->bus_number,
> 		.segment = pci_domain_nr(dev->nbus),
> 	};
>
Ok. And I'll take your other recommendation from patch [4/16] to not split devfn.
> Or if it isn't going to get more use later, just put that assignment in
> forward_cxl_error as this helper doesn't seem to add a huge amount of
> value wrt to code reability.
>
Good idea. This function started out doing more work but has been simplified that
it no longer needs be in a helper function.

>> +
>> +	return 0;
>> +}
>> +
>> +static void forward_cxl_error(struct pci_dev *pdev, struct aer_err_info *aer_err_info)
>> +{
>> +	struct cxl_prot_err_work_data wd;
>> +	struct cxl_prot_error_info *cxl_err_info = &wd.err_info;
>> +
>> +	cxl_create_prot_error_info(pdev, aer_err_info, cxl_err_info);
> 	cxl_create_prot_error_info(pdev, aer_err_info, &wd.err_info);
>
> Ignore if this gets more complicated in a later patch but for now I don't
> see the local variable adding any value. If anything it slightly obscures
> how this gets used via wd in the next line.  However given the code is short
> that is fairly obvious either way.
>
> Or as above
> 	wd.error_info = (struct cxl_prot_error_info) {
> 		.severity = ...
> 	};
Ok. I'll let you know if it doesn't work. ;)
>> +
>> +	if (!kfifo_put(&cxl_prot_err_fifo, wd)) {
>> +		dev_err_ratelimited(&pdev->dev, "CXL kfifo overflow\n");
>> +		return;
>> +	}
>> +
>> +	schedule_work(cxl_prot_err_work);
>> +}
>> +
>>  #else
>>  static inline void cxl_rch_enable_rcec(struct pci_dev *dev) { }
>>  static inline void cxl_rch_handle_error(struct pci_dev *dev,
>>  					struct aer_err_info *info) { }
>> +static inline void forward_cxl_error(struct pci_dev *dev,
>> +				    struct aer_err_info *info) { }
> Is this aligned right - looks one space short?
>
>> +static inline bool handles_cxl_errors(struct pci_dev *dev)
>> +{
>> +	return false;
>> +}
>> +static bool is_cxl_error(struct pci_dev *pdev, struct aer_err_info *info) { return 0; };
> wrap choices for the two stubs are a bit odd.   The first one is actually shorter
> if not wrapped than the second one is that you chose not to wrap.
> My slightly preference would be to wrap them both as the fist one.
>
Thanks for pointing out. Fortunately, this (and above alignment note) is moved into a new file
pci/pcie/cxl_aer.c in the next revision and no longer requires this source file #ifdef.

-Terry

>>  #endif
>


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
  2025-06-03 17:22 ` [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
  2025-06-05 15:14   ` Sathyanarayanan Kuppuswamy
  2025-06-06 16:45   ` Dave Jiang
@ 2025-06-12 16:06   ` Jonathan Cameron
  2025-06-12 16:29     ` Bowman, Terry
  2 siblings, 1 reply; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 16:06 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, 3 Jun 2025 12:22:28 -0500
Terry Bowman <terry.bowman@amd.com> wrote:

> Create cxl_do_recovery() to provide uncorrectable protocol error (UCE)
> handling. Follow similar design as found in PCIe error driver,
> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
> 
> Copy the PCI error driver's merge_result() and rename as cxl_merge_result().
> Introduce PCI_ERS_RESULT_PANIC and add support in the cxl_merge_result()
> routine.

Do we need a separate version?  PCI won't ever set PCI_ERS_RESULT_PANIC
so new != PCI_ERS_RESULT_PANIC and the first condition would only do
something on CXL.

> 
> Copy pci_walk_bridge() to cxl_walk_bridge(). Make a change to walk the
> first device in all cases.
> 
> Copy the PCI error driver's report_error_detected() to cxl_report_error_detected().
> Note, only CXL Endpoints are currently supported. Add locking for PCI
> device as done in PCI's report_error_detected(). Add reference counting for
> the CXL device responsible for cleanup of the CXL RAS. This is necessary
> to prevent the RAS registers from disappearing before logging is completed.
> 
> Call panic() to halt the system in the case of uncorrectable errors (UCE)
> in cxl_do_recovery(). Export pci_aer_clear_fatal_status() for CXL to use
> if a UCE is not found. In this case the AER status must be cleared and
> uses pci_aer_clear_fatal_status().
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>  drivers/cxl/core/ras.c | 79 ++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci.h    |  3 ++
>  2 files changed, 82 insertions(+)
> 
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 9ed5c682e128..715f7221ea3a 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c
> @@ -110,8 +110,87 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>  
>  #ifdef CONFIG_PCIEAER_CXL
>  
> +static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
> +					 enum pci_ers_result new)
> +{
> +	if (new == PCI_ERS_RESULT_PANIC)
> +		return PCI_ERS_RESULT_PANIC;
> +
> +	if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
> +		return PCI_ERS_RESULT_NO_AER_DRIVER;
> +
> +	if (new == PCI_ERS_RESULT_NONE)
> +		return orig;
> +
> +	switch (orig) {
> +	case PCI_ERS_RESULT_CAN_RECOVER:
> +	case PCI_ERS_RESULT_RECOVERED:
> +		orig = new;
> +		break;
> +	case PCI_ERS_RESULT_DISCONNECT:
> +		if (new == PCI_ERS_RESULT_NEED_RESET)
> +			orig = PCI_ERS_RESULT_NEED_RESET;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return orig;
> +}
> +
> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
> +{
> +	pci_ers_result_t vote, *result = data;
> +	struct cxl_dev_state *cxlds;
> +
> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
> +		return 0;
> +
> +	cxlds = pci_get_drvdata(pdev);
> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
> +
> +	device_lock(&pdev->dev);
> +	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
> +	*result = cxl_merge_result(*result, vote);
> +	device_unlock(&pdev->dev);
> +
> +	return 0;
> +}
> +
> +static void cxl_walk_bridge(struct pci_dev *bridge,
> +			    int (*cb)(struct pci_dev *, void *),
> +			    void *userdata)
> +{
> +	if (cb(bridge, userdata))
> +		return;
> +
> +	if (bridge->subordinate)
> +		pci_walk_bus(bridge->subordinate, cb, userdata);
> +}
> +
>  static void cxl_do_recovery(struct pci_dev *pdev)
>  {
> +	struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
> +	pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
> +
> +	cxl_walk_bridge(pdev, cxl_report_error_detected, &status);
> +	if (status == PCI_ERS_RESULT_PANIC)
> +		panic("CXL cachemem error.");
> +
> +	/*
> +	 * If we have native control of AER, clear error status in the device
> +	 * that detected the error.  If the platform retained control of AER,
> +	 * it is responsible for clearing this status.  In that case, the
> +	 * signaling device may not even be visible to the OS.
> +	 */
> +	if (host->native_aer) {
> +		pcie_clear_device_status(pdev);
> +		pci_aer_clear_nonfatal_status(pdev);
> +		pci_aer_clear_fatal_status(pdev);
> +	}
> +
> +	pci_info(pdev, "CXL uncorrectable error.\n");
>  }
>  
>  static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index cd53715d53f3..b0e7545162de 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -870,6 +870,9 @@ enum pci_ers_result {
>  
>  	/* No AER capabilities registered for the driver */
>  	PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
> +
> +	/* System is unstable, panic  */
> +	PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,
>  };
>  
>  /* PCI bus error event callbacks */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports
  2025-06-06 15:24       ` Bowman, Terry
@ 2025-06-12 16:25         ` Jonathan Cameron
  0 siblings, 0 replies; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 16:25 UTC (permalink / raw)
  To: Bowman, Terry
  Cc: Shiju Jose, PradeepVineshReddy.Kodamati@amd.com,
	dave@stgolabs.net, dave.jiang@intel.com,
	alison.schofield@intel.com, vishal.l.verma@intel.com,
	ira.weiny@intel.com, dan.j.williams@intel.com,
	bhelgaas@google.com, bp@alien8.de, ming.li@zohomail.com,
	dan.carpenter@linaro.org, Smita.KoralahalliChannabasappa@amd.com,
	kobayashi.da-06@fujitsu.com, yanfei.xu@intel.com,
	rrichter@amd.com, peterz@infradead.org, colyli@suse.de,
	uaisheng.ye@intel.com, fabio.m.de.francesco@linux.intel.com,
	ilpo.jarvinen@linux.intel.com, yazen.ghannam@amd.com,
	linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-pci@vger.kernel.org, Mauro Carvalho Chehab

On Fri, 6 Jun 2025 10:24:25 -0500
"Bowman, Terry" <terry.bowman@amd.com> wrote:

> On 6/6/2025 9:41 AM, Bowman, Terry wrote:
> >
> > On 6/6/2025 4:08 AM, Shiju Jose wrote:  
> >>> -----Original Message-----
> >>> From: Terry Bowman <terry.bowman@amd.com>
> >>> Sent: 03 June 2025 18:23
> >>> To: PradeepVineshReddy.Kodamati@amd.com; dave@stgolabs.net; Jonathan
> >>> Cameron <jonathan.cameron@huawei.com>; dave.jiang@intel.com;
> >>> alison.schofield@intel.com; vishal.l.verma@intel.com; ira.weiny@intel.com;
> >>> dan.j.williams@intel.com; bhelgaas@google.com; bp@alien8.de;
> >>> ming.li@zohomail.com; Shiju Jose <shiju.jose@huawei.com>;
> >>> dan.carpenter@linaro.org; Smita.KoralahalliChannabasappa@amd.com;
> >>> kobayashi.da-06@fujitsu.com; terry.bowman@amd.com; yanfei.xu@intel.com;
> >>> rrichter@amd.com; peterz@infradead.org; colyli@suse.de;
> >>> uaisheng.ye@intel.com; fabio.m.de.francesco@linux.intel.com;
> >>> ilpo.jarvinen@linux.intel.com; yazen.ghannam@amd.com; linux-
> >>> cxl@vger.kernel.org; linux-kernel@vger.kernel.org; linux-pci@vger.kernel.org
> >>> Subject: [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and
> >>> CXL Ports
> >>>
> >>> CXL currently has separate trace routines for CXL Port errors and CXL Endpoint
> >>> errors. This is inconvenient for the user because they must enable
> >>> 2 sets of trace routines. Make updates to the trace logging such that a single
> >>> trace routine logs both CXL Endpoint and CXL Port protocol errors.
> >>>
> >>> Rename the 'host' field from the CXL Endpoint trace to 'parent' in the unified
> >>> trace routines. 'host' does not correctly apply to CXL Port devices. Parent is more
> >>> general and applies to CXL Port devices and CXL Endpoints.
> >>>
> >>> Add serial number parameter to the trace logging. This is used for EPs and 0 is
> >>> provided for CXL port devices without a serial number.
> >>>
> >>> Below is output of correctable and uncorrectable protocol error logging.
> >>> CXL Root Port and CXL Endpoint examples are included below.
> >>>
> >>> Root Port:
> >>> cxl_aer_correctable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0
> >>> status='CRC Threshold Hit'
> >>> cxl_aer_uncorrectable_error: device=0000:0c:00.0 parent=pci0000:0c serial: 0
> >>> status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity
> >>> Error'
> >>>
> >>> Endpoint:
> >>> cxl_aer_correctable_error: device=mem3 parent=0000:0f:00.0 serial=0
> >>> status='CRC Threshold Hit'
> >>> cxl_aer_uncorrectable_error: device=mem3 parent=0000:0f:00.0 serial: 0
> >>> status: 'Cache Byte Enable Parity Error' first_error: 'Cache Byte Enable Parity
> >>> Error'
> >>>
> >>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> >>> ---
> >>> drivers/cxl/core/pci.c   | 18 +++++----
> >>> drivers/cxl/core/ras.c   | 14 ++++---
> >>> drivers/cxl/core/trace.h | 84 +++++++++-------------------------------
> >>> 3 files changed, 37 insertions(+), 79 deletions(-)
> >>>
> >>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index
> >>> 186a5a20b951..0f4c07fd64a5 100644
> >>> --- a/drivers/cxl/core/pci.c
> >>> +++ b/drivers/cxl/core/pci.c
> >>> @@ -664,7 +664,7 @@ void read_cdat_data(struct cxl_port *port)  }
> >>> EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
> >>>  
> >> [...]  
> >>> static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data
> >>> *data) diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h index
> >>> 25ebfbc1616c..8c91b0f3d165 100644
> >>> --- a/drivers/cxl/core/trace.h
> >>> +++ b/drivers/cxl/core/trace.h
> >>> @@ -48,49 +48,22 @@
> >>> 	{ 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_SIZE_U32)
> >>> -	),
> >>> -	TP_fast_assign(
> >>> -		__assign_str(device);
> >>> -		__assign_str(host);
> >>> -		__entry->status = status;
> >>> -		__entry->first_error = fe;
> >>> -		/*
> >>> -		 * Embed the 512B headerlog data for user app retrieval and
> >>> -		 * parsing, but no need to print this in the trace buffer.
> >>> -		 */
> >>> -		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
> >>> -	),
> >>> -	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 device *dev, u64 serial, u32 status, u32 fe,
> >>> +		 u32 *hl),
> >>> +	TP_ARGS(dev, serial, status, fe, hl),
> >>> 	TP_STRUCT__entry(
> >>> -		__string(memdev, dev_name(&cxlmd->dev))
> >>> -		__string(host, dev_name(cxlmd->dev.parent))
> >>> +		__string(name, dev_name(dev))
> >>> +		__string(parent, dev_name(dev->parent))  
> >> Hi Terry,
> >>
> >> As we pointed out in v8, renaming the fields "memdev" to "name" and "host" to "parent"
> >> causes issues and failures in userspace rasdaemon  while parsing the trace event data.
> >> Additionally, we can't rename these fields in rasdaemon  due to backward compatibility.  
> > Yes, I remember but didn't understand why other SW couldn't be updated to handle. I will
> > change as you request but many people will be confused why a port device's name is labeled
> > as a memdev. memdev is only correct for EPs and does not correctly reflect *any* of the
> > other CXL device types (RP, USP, DSP).

RAS trace points are ABI so you can introduce whatever you like that is new, but you can't
remove or rename existing elements. If userspace breaks (which Shiju is confirming it will)
and anyone reports the regression, then you get grumpy Linus.

Test this stuff against upstream rasdaemon. It's easy and means things
like this don't sneak in - various cloud vendors have stated it's what their
stacks are based on, so they will see this in production if they get a mismatch.

https://github.com/mchehab/rasdaemon/blob/master/ras-cxl-handler.c#L354

It think this will error out if an AER UE does not contain the memdev field.

So your options are a new tracepoint, or leave those fields in place and just
let them contain whatever is most useful. If you go with new tracepoint you
still should generate the old one as well if it is enabled.  Note that
even adding fields can be a bit painful as it requires some DB restructuring
on an upgrade of rasdaemon (or dumping existing logs and starting from scratch).

+CC Mauro in case I've missed any other ways to deal with this change.


> >  
> >>> 		__field(u64, serial)
> >>> 		__field(u32, status)
> >>> 		__field(u32, first_error)
> >>> 		__array(u32, header_log, CXL_HEADERLOG_SIZE_U32)
> >>> 	),
> >>> 	TP_fast_assign(
> >>> -		__assign_str(memdev);
> >>> -		__assign_str(host);
> >>> -		__entry->serial = cxlmd->cxlds->serial;
> >>> +		__assign_str(name);
> >>> +		__assign_str(parent);
> >>> +		__entry->serial = serial;
> >>> 		__entry->status = status;
> >>> 		__entry->first_error = fe;
> >>> 		/*
> >>> @@ -99,8 +72,8 @@ TRACE_EVENT(cxl_aer_uncorrectable_error,
> >>> 		 */
> >>> 		memcpy(__entry->header_log, hl, CXL_HEADERLOG_SIZE);
> >>> 	),
> >>> -	TP_printk("memdev=%s host=%s serial=%lld: status: '%s' first_error:
> >>> '%s'",
> >>> -		  __get_str(memdev), __get_str(host), __entry->serial,
> >>> +	TP_printk("device=%s parent=%s serial=%lld status='%s'
> >>> first_error='%s'",
> >>> +		  __get_str(name), __get_str(parent), __entry->serial,
> >>> 		  show_uc_errs(__entry->status),
> >>> 		  show_uc_errs(__entry->first_error)
> >>> 	)
> >>> @@ -124,42 +97,23 @@ 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 device *dev, u64 serial, u32 status),
> >>> +	TP_ARGS(dev, serial, status),
> >>> 	TP_STRUCT__entry(
> >>> -		__string(memdev, dev_name(&cxlmd->dev))
> >>> -		__string(host, dev_name(cxlmd->dev.parent))
> >>> +		__string(name, dev_name(dev))
> >>> +		__string(parent, dev_name(dev->parent))  
> >> Renaming these fields is an issue for userspace as mentioned above 
> >> in cxl_aer_uncorrectable_error.  
> > I understand, I'll revert as you request.
> >
> > Terry  
> 
> I'll update the commit message with explanation for leaving as-is.
> 
> Terry
> >>> 		__field(u64, serial)
> >>> 		__field(u32, status)
> >>> 	),
> >>> 	TP_fast_assign(
> >>> -		__assign_str(memdev);
> >>> -		__assign_str(host);
> >>> -		__entry->serial = cxlmd->cxlds->serial;
> >>> +		__assign_str(name);
> >>> +		__assign_str(parent);
> >>> +		__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("device=%s parent=%s serial=%lld status='%s'",
> >>> +		  __get_str(name), __get_str(parent), __entry->serial,
> >>> 		  show_ce_errs(__entry->status)
> >>> 	)
> >>> );
> >>> --
> >>> 2.34.1  
> >> Thanks,
> >> Shiju  
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery
  2025-06-12 16:06   ` Jonathan Cameron
@ 2025-06-12 16:29     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-12 16:29 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci



On 6/12/2025 11:06 AM, Jonathan Cameron wrote:
> On Tue, 3 Jun 2025 12:22:28 -0500
> Terry Bowman <terry.bowman@amd.com> wrote:
>
>> Create cxl_do_recovery() to provide uncorrectable protocol error (UCE)
>> handling. Follow similar design as found in PCIe error driver,
>> pcie_do_recovery(). One difference is cxl_do_recovery() will treat all UCEs
>> as fatal with a kernel panic. This is to prevent corruption on CXL memory.
>>
>> Copy the PCI error driver's merge_result() and rename as cxl_merge_result().
>> Introduce PCI_ERS_RESULT_PANIC and add support in the cxl_merge_result()
>> routine.
> Do we need a separate version?  PCI won't ever set PCI_ERS_RESULT_PANIC
> so new != PCI_ERS_RESULT_PANIC and the first condition would only do
> something on CXL.
Correct. A common merge_result() can be used. I'll change it.

- Terry
>> Copy pci_walk_bridge() to cxl_walk_bridge(). Make a change to walk the
>> first device in all cases.
>>
>> Copy the PCI error driver's report_error_detected() to cxl_report_error_detected().
>> Note, only CXL Endpoints are currently supported. Add locking for PCI
>> device as done in PCI's report_error_detected(). Add reference counting for
>> the CXL device responsible for cleanup of the CXL RAS. This is necessary
>> to prevent the RAS registers from disappearing before logging is completed.
>>
>> Call panic() to halt the system in the case of uncorrectable errors (UCE)
>> in cxl_do_recovery(). Export pci_aer_clear_fatal_status() for CXL to use
>> if a UCE is not found. In this case the AER status must be cleared and
>> uses pci_aer_clear_fatal_status().
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/ras.c | 79 ++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/pci.h    |  3 ++
>>  2 files changed, 82 insertions(+)
>>
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 9ed5c682e128..715f7221ea3a 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -110,8 +110,87 @@ static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>  
>>  #ifdef CONFIG_PCIEAER_CXL
>>  
>> +static pci_ers_result_t cxl_merge_result(enum pci_ers_result orig,
>> +					 enum pci_ers_result new)
>> +{
>> +	if (new == PCI_ERS_RESULT_PANIC)
>> +		return PCI_ERS_RESULT_PANIC;
>> +
>> +	if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
>> +		return PCI_ERS_RESULT_NO_AER_DRIVER;
>> +
>> +	if (new == PCI_ERS_RESULT_NONE)
>> +		return orig;
>> +
>> +	switch (orig) {
>> +	case PCI_ERS_RESULT_CAN_RECOVER:
>> +	case PCI_ERS_RESULT_RECOVERED:
>> +		orig = new;
>> +		break;
>> +	case PCI_ERS_RESULT_DISCONNECT:
>> +		if (new == PCI_ERS_RESULT_NEED_RESET)
>> +			orig = PCI_ERS_RESULT_NEED_RESET;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return orig;
>> +}
>> +
>> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
>> +{
>> +	pci_ers_result_t vote, *result = data;
>> +	struct cxl_dev_state *cxlds;
>> +
>> +	if ((pci_pcie_type(pdev) != PCI_EXP_TYPE_ENDPOINT) &&
>> +	    (pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_END))
>> +		return 0;
>> +
>> +	cxlds = pci_get_drvdata(pdev);
>> +	struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>> +
>> +	device_lock(&pdev->dev);
>> +	vote = cxl_error_detected(pdev, pci_channel_io_frozen);
>> +	*result = cxl_merge_result(*result, vote);
>> +	device_unlock(&pdev->dev);
>> +
>> +	return 0;
>> +}
>> +
>> +static void cxl_walk_bridge(struct pci_dev *bridge,
>> +			    int (*cb)(struct pci_dev *, void *),
>> +			    void *userdata)
>> +{
>> +	if (cb(bridge, userdata))
>> +		return;
>> +
>> +	if (bridge->subordinate)
>> +		pci_walk_bus(bridge->subordinate, cb, userdata);
>> +}
>> +
>>  static void cxl_do_recovery(struct pci_dev *pdev)
>>  {
>> +	struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
>> +	pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
>> +
>> +	cxl_walk_bridge(pdev, cxl_report_error_detected, &status);
>> +	if (status == PCI_ERS_RESULT_PANIC)
>> +		panic("CXL cachemem error.");
>> +
>> +	/*
>> +	 * If we have native control of AER, clear error status in the device
>> +	 * that detected the error.  If the platform retained control of AER,
>> +	 * it is responsible for clearing this status.  In that case, the
>> +	 * signaling device may not even be visible to the OS.
>> +	 */
>> +	if (host->native_aer) {
>> +		pcie_clear_device_status(pdev);
>> +		pci_aer_clear_nonfatal_status(pdev);
>> +		pci_aer_clear_fatal_status(pdev);
>> +	}
>> +
>> +	pci_info(pdev, "CXL uncorrectable error.\n");
>>  }
>>  
>>  static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>> diff --git a/include/linux/pci.h b/include/linux/pci.h
>> index cd53715d53f3..b0e7545162de 100644
>> --- a/include/linux/pci.h
>> +++ b/include/linux/pci.h
>> @@ -870,6 +870,9 @@ enum pci_ers_result {
>>  
>>  	/* No AER capabilities registered for the driver */
>>  	PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6,
>> +
>> +	/* System is unstable, panic  */
>> +	PCI_ERS_RESULT_PANIC = (__force pci_ers_result_t) 7,
>>  };
>>  
>>  /* PCI bus error event callbacks */


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors
  2025-06-03 17:22 ` [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
  2025-06-05 18:37   ` Sathyanarayanan Kuppuswamy
  2025-06-06 20:30   ` Dave Jiang
@ 2025-06-12 16:46   ` Jonathan Cameron
  2025-06-16 20:30     ` Bowman, Terry
  2 siblings, 1 reply; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 16:46 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, 3 Jun 2025 12:22:34 -0500
Terry Bowman <terry.bowman@amd.com> wrote:

> __cxl_handle_cor_ras() is missing logic to leave the function early in the
> case there is no RAS error. Update __cxl_handle_cor_ras() to exit early in
> the case there is no RAS errors detected after applying the mask.

I'm all for this as sensible cleanup, but the 'missing' kind
of suggest a bug to me whereas I don't see one.
Perhaps reword?

> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> ---
>  drivers/cxl/core/pci.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index 0f4c07fd64a5..f5f87c2c3fd5 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -677,10 +677,11 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>  
>  	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
>  	status = readl(addr);
> -	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
> -		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
> -		trace_cxl_aer_correctable_error(dev, serial, status);
> -	}
> +	if (!(status & CXL_RAS_CORRECTABLE_STATUS_MASK))
> +		return;
> +	writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
> +
> +	trace_cxl_aer_correctable_error(dev, serial, status);
>  }
>  
>  static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 12/16] cxl/pci: Introduce CXL Endpoint protocol error handlers
  2025-06-03 17:22 ` [PATCH v9 12/16] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
  2025-06-06  0:22   ` Sathyanarayanan Kuppuswamy
@ 2025-06-12 16:55   ` Jonathan Cameron
  1 sibling, 0 replies; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 16:55 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, 3 Jun 2025 12:22:35 -0500
Terry Bowman <terry.bowman@amd.com> wrote:

> CXL Endpoint protocol errors are currently handled using PCI error
> handlers. The CXL Endpoint requires CXL specific handling in the case of
> uncorrectable error handling not provided by the PCI handlers.
> 
> Add CXL specific handlers for CXL Endpoints. Rename the existing
> cxl_error_handlers to be pci_error_handlers to more correctly indicate
> the error type and follow naming consistency.

I wonder if a rename precursor patch would be better here than doing it
all in one go?

Having not read the patch description thoroughly this had me confused ;)

> 
> Keep the existing PCI Endpoint handlers. PCI handlers can be called if the
> CXL device is not trained for alternate protocol (CXL). Update the CXL
> Endpoint PCI handlers to call the CXL handler. If the CXL uncorrectable
> handler returns PCI_ERS_RESULT_PANIC then the PCI handler invokes panic().
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>


>  
>  static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>  {
> -

So this snuck in somewhere between upstream and here.  If it is in this
set let's push the removal back to where it came from.

>  	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
>  }
>  
> @@ -844,14 +843,15 @@ static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds)
>  static void cxl_handle_rdport_errors(struct cxl_dev_state *cxlds) { }
>  #endif
>
> +pci_ers_result_t cxl_error_detected(struct device *dev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +	struct device *cxlmd_dev = &cxlds->cxlmd->dev;
> +	pci_ers_result_t ue;
> +
> +	scoped_guard(device, cxlmd_dev) {
>  		if (!dev->driver) {
>  			dev_warn(&pdev->dev,
>  				 "%s: memdev disabled, abort error handling\n",
>  				 dev_name(dev));
> -			return PCI_ERS_RESULT_DISCONNECT;
> +			return PCI_ERS_RESULT_PANIC;
>  		}
>  
>  		if (cxlds->rcd)
> @@ -892,29 +900,25 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
>  		ue = cxl_handle_endpoint_ras(cxlds);
>  	}
>  
> -

Maybe something more in the patch description on why this chunk isn't relevant?
I guess we don't need the more complex handling as these are all panic :)

> -	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);
> -		return PCI_ERS_RESULT_NEED_RESET;
> -	case pci_channel_io_perm_failure:
> -		dev_warn(&pdev->dev,
> -			 "failure state error detected, request disconnect\n");
> -		return PCI_ERS_RESULT_DISCONNECT;
> -	}
> -	return PCI_ERS_RESULT_NEED_RESET;
> +	return ue;
>  }
>  EXPORT_SYMBOL_NS_GPL(cxl_error_detected, "CXL");

>  static int cxl_flit_size(struct pci_dev *pdev)
>  {
>  	if (cxl_pci_flit_256(pdev))
> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 0ef8c2068c0c..664f532cc838 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c

> @@ -244,6 +244,8 @@ static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>  static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>  {
>  	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> +	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>  
>  	if (!pdev) {
>  		pr_err("Failed to find the CXL device\n");
> @@ -260,15 +262,13 @@ static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>  
>  	if (err_info->severity == AER_CORRECTABLE) {
>  		int aer = pdev->aer_cap;
> -		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> -		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);

This code move seems somewhat unrelated?  Maybe it's in the wrong patch and
becomes necessary later?

>  
>  		if (aer)
>  			pci_clear_and_set_config_dword(pdev,
>  						       aer + PCI_ERR_COR_STATUS,
>  						       0, PCI_ERR_COR_INTERNAL);
>  
> -		cxl_cor_error_detected(pdev);
> +		cxl_cor_error_detected(&pdev->dev);
>  
>  		pcie_clear_device_status(pdev);
>  	} else {




^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers
  2025-06-03 17:22 ` [PATCH v9 13/16] cxl/pci: Introduce CXL Port " Terry Bowman
  2025-06-06  0:50   ` Sathyanarayanan Kuppuswamy
@ 2025-06-12 17:14   ` Jonathan Cameron
  2025-06-16 22:17     ` Bowman, Terry
  1 sibling, 1 reply; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 17:14 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, 3 Jun 2025 12:22:36 -0500
Terry Bowman <terry.bowman@amd.com> wrote:

> Introduce CXL error handlers for CXL Port devices.
> 
> Add functions cxl_port_cor_error_detected() and cxl_port_error_detected().
> These will serve as the handlers for all CXL Port devices. Introduce
> cxl_get_ras_base() to provide the RAS base address needed by the handlers.
> 
> Update cxl_handle_prot_error() to call the CXL Port or CXL Endpoint handler
> depending on which CXL device reports the error.
> 
> Implement pci_get_ras_base() to return the cached RAS register address of a
> CXL Root Port, CXL Downstream Port, or CXL Upstream Port.
> 
> Update the AER driver's is_cxl_error() to remove the filter PCI type check
> because CXL Port devices are now supported.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

A few minor things on a fresh read.

>  size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index e094ef518e0a..b6836825e8df 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -753,6 +753,67 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>  
>  #ifdef CONFIG_PCIEAER_CXL
>  
> +static void __iomem *cxl_get_ras_base(struct device *dev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	void __iomem *ras_base;
> +
> +	switch (pci_pcie_type(pdev)) {
> +	case PCI_EXP_TYPE_ROOT_PORT:
> +	case PCI_EXP_TYPE_DOWNSTREAM:
> +	{
> +		struct cxl_dport *dport = NULL;
> +		struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
> +
> +		if (!dport || !dport->dport_dev) {
> +			pci_err(pdev, "Failed to find the CXL device");
> +			return NULL;
> +		}
> +
> +		ras_base = dport ? dport->regs.ras : NULL;
As below - perhaps a sanity check for error and early return makes sense here.

> +		break;
> +	}
> +	case PCI_EXP_TYPE_UPSTREAM:
> +	{
> +		struct cxl_port *port;
> +		struct device *dev __free(put_device) = bus_find_device(&cxl_bus_type, NULL,
> +									&pdev->dev, match_uport);
> +
> +		if (!dev || !is_cxl_port(dev)) {
> +			pci_err(pdev, "Failed to find the CXL device");
> +			return NULL;
> +		}
> +
> +		port = to_cxl_port(dev);
> +		ras_base = port ? port->uport_regs.ras : NULL;

I'd be tempted to return here to keep the flows simple.  Maybe avoiding the ternary
		if (!port)
			return NULL;

		return port->uport_regs.ras;


> +		break;
> +	}
> +	default:
> +	{
> +		pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> +		return NULL;

Better not to introduce scope {} when not needed.

> +	}
> +	}
> +
> +	return ras_base;
> +}

> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
> index 664f532cc838..6093e70ece37 100644
> --- a/drivers/cxl/core/ras.c
> +++ b/drivers/cxl/core/ras.c

> +
> +/* Return 'struct device*' responsible for freeing pdev's CXL resources */
> +static struct device *get_pci_cxl_host_dev(struct pci_dev *pdev)
> +{
> +	struct device *host_dev;
> +
> +	switch (pci_pcie_type(pdev)) {
> +	case PCI_EXP_TYPE_ROOT_PORT:
> +	case PCI_EXP_TYPE_DOWNSTREAM:
> +	{
> +		struct cxl_dport *dport = NULL;
> +		struct cxl_port *port = find_cxl_port(&pdev->dev, &dport);
> +
> +		if (!dport || !dport->dport_dev)

What does !dport->dprot_dev mean?  I.e. how does that happen?
I can only find places where we set it just after allocating a dport.
Perhaps a comment?



> +			return NULL;
> +
> +		host_dev = &port->dev;
> +		break;
> +	}
> +	case PCI_EXP_TYPE_UPSTREAM:
> +	{
> +		struct cxl_port *port;
> +		struct device *cxl_dev = bus_find_device(&cxl_bus_type, NULL,
> +							 &pdev->dev, match_uport);

Doesn't his leave you holding a reference to a device different form
the one you return? Hence wrong one gets put in caller.

> +
> +		if (!cxl_dev || !is_cxl_port(cxl_dev))
> +			return NULL;
> +
> +		port = to_cxl_port(cxl_dev);
> +		host_dev = &port->dev;
Actually no. Isn't this a circle that lands you on cxl_dev again?

		container_of(dev, struct cxl_port, dev)->dev

> +		break;
> +	}
> +	case PCI_EXP_TYPE_ENDPOINT:
> +	case PCI_EXP_TYPE_RC_END:
> +	{
> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> +
> +		if (!cxlds)
> +			return NULL;
> +
> +		host_dev = get_device(&cxlds->cxlmd->dev);
> +		break;

Maybe just return it here? Similar for other cases.
Saves a reader keeping track of references if we get them roughly where
we return them.

> +	}
> +	default:
> +	{
No need for scope on this one (or at least some of the others) so drop the {}

> +		pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
> +		return NULL;
> +	}
> +	}
> +
> +	return host_dev;
> +}
> +
> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device *host_dev __free(put_device) = get_pci_cxl_host_dev(pdev);
> +	pci_ers_result_t vote, *result = data;
>  
>  	device_lock(&pdev->dev);
> -	vote = cxl_error_detected(&pdev->dev);
> +	if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
> +	    (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
> +		vote = cxl_error_detected(dev);
> +	} else {
> +		vote = cxl_port_error_detected(dev);
> +	}
>  	*result = cxl_merge_result(*result, vote);
>  	device_unlock(&pdev->dev);
>  
> @@ -244,14 +309,18 @@ static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>  static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>  {
>  	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
> -	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
> -	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>  
>  	if (!pdev) {
>  		pr_err("Failed to find the CXL device\n");
>  		return;
>  	}
>  
> +	struct device *host_dev __free(put_device) = get_pci_cxl_host_dev(pdev);
> +	if (!host_dev) {
> +		pr_err("Failed to find the CXL device's host\n");
> +		return;
> +	}
> +


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 14/16] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions
  2025-06-03 17:22 ` [PATCH v9 14/16] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions Terry Bowman
  2025-06-06  0:50   ` Sathyanarayanan Kuppuswamy
@ 2025-06-12 17:16   ` Jonathan Cameron
  1 sibling, 0 replies; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 17:16 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, 3 Jun 2025 12:22:37 -0500
Terry Bowman <terry.bowman@amd.com> wrote:

> The CXL driver's cxl_handle_endpoint_cor_ras()/cxl_handle_endpoint_ras()
> are unnecessary helper functions used only for Endpoints. Remove these
> functions as they are not common for all CXL devices and do not provide
> value for EP handling.
> 
> Rename __cxl_handle_ras to cxl_handle_ras() and __cxl_handle_cor_ras()
> to cxl_handle_cor_ras().
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>

If it looks like we are going to need a few more versions, maybe
drag this to front so Dave can pick it up and reduce size of the
patch set? This one is a good cleanup on it's own.

> ---
>  drivers/cxl/core/pci.c | 32 ++++++++++++--------------------
>  1 file changed, 12 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index b6836825e8df..b36a58607041 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -664,8 +664,8 @@ void read_cdat_data(struct cxl_port *port)
>  }
>  EXPORT_SYMBOL_NS_GPL(read_cdat_data, "CXL");
>  
> -static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
> -				 void __iomem *ras_base)
> +static void cxl_handle_cor_ras(struct device *dev, u64 serial,
> +			       void __iomem *ras_base)
>  {
>  	void __iomem *addr;
>  	u32 status;
> @@ -684,11 +684,6 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>  	trace_cxl_aer_correctable_error(dev, serial, status);
>  }
>  
> -static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
> -{
> -	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> -}
> -
>  /* CXL spec rev3.0 8.2.4.16.1 */
>  static void header_log_copy(void __iomem *ras_base, u32 *log)
>  {
> @@ -710,8 +705,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.
>   */
> -static pci_ers_result_t __cxl_handle_ras(struct device *dev, u64 serial,
> -					 void __iomem *ras_base)
> +static pci_ers_result_t cxl_handle_ras(struct device *dev, u64 serial,
> +				       void __iomem *ras_base)
>  {
>  	u32 hl[CXL_HEADERLOG_SIZE_U32];
>  	void __iomem *addr;
> @@ -746,11 +741,6 @@ static pci_ers_result_t __cxl_handle_ras(struct device *dev, u64 serial,
>  	return PCI_ERS_RESULT_PANIC;
>  }
>  
> -static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
> -{
> -	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, cxlds->regs.ras);
> -}
> -
>  #ifdef CONFIG_PCIEAER_CXL
>  
>  static void __iomem *cxl_get_ras_base(struct device *dev)
> @@ -802,7 +792,7 @@ void cxl_port_cor_error_detected(struct device *dev)
>  {
>  	void __iomem *ras_base = cxl_get_ras_base(dev);
>  
> -	__cxl_handle_cor_ras(dev, 0, ras_base);
> +	cxl_handle_cor_ras(dev, 0, ras_base);
>  }
>  EXPORT_SYMBOL_NS_GPL(cxl_port_cor_error_detected, "CXL");
>  
> @@ -810,20 +800,20 @@ pci_ers_result_t cxl_port_error_detected(struct device *dev)
>  {
>  	void __iomem *ras_base = cxl_get_ras_base(dev);
>  
> -	return  __cxl_handle_ras(dev, 0, ras_base);
> +	return  cxl_handle_ras(dev, 0, ras_base);
>  }
>  EXPORT_SYMBOL_NS_GPL(cxl_port_error_detected, "CXL");
>  
>  static void cxl_handle_rdport_cor_ras(struct cxl_dev_state *cxlds,
>  					  struct cxl_dport *dport)
>  {
> -	return __cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
> +	return cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
>  }
>  
>  static bool cxl_handle_rdport_ras(struct cxl_dev_state *cxlds,
>  				       struct cxl_dport *dport)
>  {
> -	return __cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
> +	return cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial, dport->regs.ras);
>  }
>  
>  /*
> @@ -921,7 +911,8 @@ void cxl_cor_error_detected(struct device *dev)
>  		if (cxlds->rcd)
>  			cxl_handle_rdport_errors(cxlds);
>  
> -		cxl_handle_endpoint_cor_ras(cxlds);
> +		cxl_handle_cor_ras(&cxlds->cxlmd->dev, cxlds->serial,
> +				   cxlds->regs.ras);
>  	}
>  }
>  EXPORT_SYMBOL_NS_GPL(cxl_cor_error_detected, "CXL");
> @@ -958,7 +949,8 @@ pci_ers_result_t cxl_error_detected(struct device *dev)
>  		 * chance the situation is recoverable dump the status of the RAS
>  		 * capability registers and bounce the active state of the memdev.
>  		 */
> -		ue = cxl_handle_endpoint_ras(cxlds);
> +		ue = cxl_handle_ras(&cxlds->cxlmd->dev, cxlds->serial,
> +				    cxlds->regs.ras);
>  	}
>  
>  	return ue;


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup
  2025-06-03 17:22 ` [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
  2025-06-06  0:52   ` Sathyanarayanan Kuppuswamy
  2025-06-06 22:59   ` Dave Jiang
@ 2025-06-12 17:19   ` Jonathan Cameron
  2 siblings, 0 replies; 90+ messages in thread
From: Jonathan Cameron @ 2025-06-12 17:19 UTC (permalink / raw)
  To: Terry Bowman
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, yanfei.xu, rrichter, peterz, colyli, uaisheng.ye,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On Tue, 3 Jun 2025 12:22:39 -0500
Terry Bowman <terry.bowman@amd.com> wrote:

> During CXL device cleanup the CXL PCIe Port device interrupts remain
> enabled. This potentially allows unnecessary interrupt processing on
> behalf of the CXL errors while the device is destroyed.
> 
> Disable CXL protocol errors by setting the CXL devices' AER mask register.
> 
> Introduce pci_aer_mask_internal_errors() similar to pci_aer_unmask_internal_errors().
> 
> Introduce cxl_mask_prot_interrupts() to call pci_aer_mask_internal_errors().
> Add calls to cxl_mask_prot_interrupts() within CXL Port teardown for CXL
> Root Ports, CXL Downstream Switch Ports, CXL Upstream Switch Ports, and CXL
> Endpoints. Follow the same "bottom-up" approach used during CXL Port
> teardown.
> 
> Implement cxl_mask_prot_interrupts() in a header file to avoid introducing
> Kconfig ifdefs in cxl/core/port.c.
> 
> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-12 11:36   ` Jonathan Cameron
@ 2025-06-12 18:35     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-12 18:35 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, rrichter, peterz, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/12/2025 6:36 AM, Jonathan Cameron wrote:
> On Tue, 3 Jun 2025 12:22:27 -0500
> Terry Bowman <terry.bowman@amd.com> wrote:
>
>> The AER driver is now designed to forward CXL protocol errors to the CXL
>> driver. Update the CXL driver with functionality to dequeue the forwarded
>> CXL error from the kfifo. Also, update the CXL driver to begin the protocol
>> error handling processing using the work received from the FIFO.
>>
>> Introduce function cxl_prot_err_work_fn() to dequeue work forwarded by the
>> AER service driver. This will begin the CXL protocol error processing
>> with a call to cxl_handle_prot_error().
>>
>> Update cxl/core/ras.c by adding cxl_rch_handle_error_iter() that was
>> previously in the AER driver.
>>
>> Introduce sbdf_to_pci() to take the SBDF values from 'struct cxl_prot_error_info'
>> and use in discovering the erring PCI device. Make scope based reference
>> increments/decrements for the discovered PCI device and the associated
>> CXL device.
>>
>> Implement cxl_handle_prot_error() to differentiate between Restricted CXL
>> Host (RCH) protocol errors and CXL virtual host (VH) protocol errors.
>> RCH errors will be processed with a call to walk the associated Root
>> Complex Event Collector's (RCEC) secondary bus looking for the Root Complex
>> Integrated Endpoint (RCiEP) to handle the RCH error. Export pcie_walk_rcec()
>> so the CXL driver can walk the RCEC's downstream bus, searching for
>> the RCiEP.
>>
>> VH correctable error (CE) processing will call the CXL CE handler. VH
>> uncorrectable errors (UCE) will call cxl_do_recovery(), implemented as a
>> stub for now and to be updated in future patch. Export pci_aer_clean_fatal_status()
>> and pci_clean_device_status() used to clean up AER status after handling.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
> Hopefully I haven't duplicated existing feedback. A few more minor things
> inline.
>
>> +
>> +static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
> That's an odd function name as the sbdf is buried.
> Unless it's going to get a lot of use, I'd just put the lookup
> inline and not have a 'hard to name' function.  With other suggested
> changes you only need (at where this is currently called)
> 	struct pci_dev *pdev __free(pci_dev_put) =
> 		pci_get_domain_bus_and_slot(err_info->segment, err_info->bus,
> 					    err_info->devfn);
Ok. I'll remove the helper and add inline.
>> +{
>> +	unsigned int devfn = PCI_DEVFN(err_info->device,
>> +				       err_info->function);
> This makes me wonder if you should have just use devfn inside the err_info.
> Is there a good reason to split them up before storing them?
>
> IIRC ARI makes a mess anyway of their meaning when separate.
Agreed. I'll keep devfn together.
>> +	struct pci_dev *pdev __free(pci_dev_put) =
>> +		pci_get_domain_bus_and_slot(err_info->segment,
>> +					    err_info->bus,
>> +					    devfn);
>> +	return pdev;
>> +}
>> +
>> +static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>> +{
>> +	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
>> +
>> +	if (!pdev) {
>> +		pr_err("Failed to find the CXL device\n");
>> +		return;
>> +	}
>> +
>> +	/*
>> +	 * 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.
>> +	 */
>> +	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_EC)
>> +		return pcie_walk_rcec(pdev, cxl_rch_handle_error_iter, err_info);
>> +
>> +	if (err_info->severity == AER_CORRECTABLE) {
>> +		int aer = pdev->aer_cap;
>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>> +		struct device *dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>> +
>> +		if (aer)
>> +			pci_clear_and_set_config_dword(pdev,
>> +						       aer + PCI_ERR_COR_STATUS,
>> +						       0, PCI_ERR_COR_INTERNAL);
>> +
>> +		cxl_cor_error_detected(pdev);
>> +
>> +		pcie_clear_device_status(pdev);
>> +	} else {
>> +		cxl_do_recovery(pdev);
>> +	}
>> +}
>> +
>>  static void cxl_prot_err_work_fn(struct work_struct *work)
>>  {
>> +	struct cxl_prot_err_work_data wd;
>> +
>> +	while (cxl_prot_err_kfifo_get(&wd)) {
>> +		struct cxl_prot_error_info *err_info = &wd.err_info;
>> +
>> +		cxl_handle_prot_error(err_info);
> I'm not seeing value in the local variable.
> Ignore if this code changes later and that makes more sense!
It can be removed and simplified.

Thanks for reviewing.

-Terry
>> +	}
>>  }
>>  
>>  #else


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors
  2025-06-12 16:46   ` Jonathan Cameron
@ 2025-06-16 20:30     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-16 20:30 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, rrichter, peterz, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci

On 6/12/2025 11:46 AM, Jonathan Cameron wrote:
> On Tue, 3 Jun 2025 12:22:34 -0500
> Terry Bowman <terry.bowman@amd.com> wrote:
> 
>> __cxl_handle_cor_ras() is missing logic to leave the function early in the
>> case there is no RAS error. Update __cxl_handle_cor_ras() to exit early in
>> the case there is no RAS errors detected after applying the mask.
> 
> I'm all for this as sensible cleanup, but the 'missing' kind
> of suggest a bug to me whereas I don't see one.
> Perhaps reword?
> 

Yes, I will reword the commit message.

-Terry

>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> ---
>>  drivers/cxl/core/pci.c | 9 +++++----
>>  1 file changed, 5 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
>> index 0f4c07fd64a5..f5f87c2c3fd5 100644
>> --- a/drivers/cxl/core/pci.c
>> +++ b/drivers/cxl/core/pci.c
>> @@ -677,10 +677,11 @@ static void __cxl_handle_cor_ras(struct device *dev, u64 serial,
>>  
>>  	addr = ras_base + CXL_RAS_CORRECTABLE_STATUS_OFFSET;
>>  	status = readl(addr);
>> -	if (status & CXL_RAS_CORRECTABLE_STATUS_MASK) {
>> -		writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
>> -		trace_cxl_aer_correctable_error(dev, serial, status);
>> -	}
>> +	if (!(status & CXL_RAS_CORRECTABLE_STATUS_MASK))
>> +		return;
>> +	writel(status & CXL_RAS_CORRECTABLE_STATUS_MASK, addr);
>> +
>> +	trace_cxl_aer_correctable_error(dev, serial, status);
>>  }
>>  
>>  static void cxl_handle_endpoint_cor_ras(struct cxl_dev_state *cxlds)
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 13/16] cxl/pci: Introduce CXL Port protocol error handlers
  2025-06-12 17:14   ` Jonathan Cameron
@ 2025-06-16 22:17     ` Bowman, Terry
  0 siblings, 0 replies; 90+ messages in thread
From: Bowman, Terry @ 2025-06-16 22:17 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: PradeepVineshReddy.Kodamati, dave, dave.jiang, alison.schofield,
	vishal.l.verma, ira.weiny, dan.j.williams, bhelgaas, bp, ming.li,
	shiju.jose, dan.carpenter, Smita.KoralahalliChannabasappa,
	kobayashi.da-06, rrichter, peterz, colyli, fabio.m.de.francesco,
	ilpo.jarvinen, yazen.ghannam, linux-cxl, linux-kernel, linux-pci

On 6/12/2025 12:14 PM, Jonathan Cameron wrote:
> On Tue, 3 Jun 2025 12:22:36 -0500
> Terry Bowman <terry.bowman@amd.com> wrote:
> 
>> Introduce CXL error handlers for CXL Port devices.
>>
>> Add functions cxl_port_cor_error_detected() and cxl_port_error_detected().
>> These will serve as the handlers for all CXL Port devices. Introduce
>> cxl_get_ras_base() to provide the RAS base address needed by the handlers.
>>
>> Update cxl_handle_prot_error() to call the CXL Port or CXL Endpoint handler
>> depending on which CXL device reports the error.
>>
>> Implement pci_get_ras_base() to return the cached RAS register address of a
>> CXL Root Port, CXL Downstream Port, or CXL Upstream Port.
>>
>> Update the AER driver's is_cxl_error() to remove the filter PCI type check
>> because CXL Port devices are now supported.
>>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> 
> A few minor things on a fresh read.
> 
>>  size_t cxl_get_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid,
>> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
>> index e094ef518e0a..b6836825e8df 100644
>> --- a/drivers/cxl/core/pci.c
>> +++ b/drivers/cxl/core/pci.c
>> @@ -753,6 +753,67 @@ static bool cxl_handle_endpoint_ras(struct cxl_dev_state *cxlds)
>>  
>>  #ifdef CONFIG_PCIEAER_CXL
>>  
>> +static void __iomem *cxl_get_ras_base(struct device *dev)
>> +{
>> +	struct pci_dev *pdev = to_pci_dev(dev);
>> +	void __iomem *ras_base;
>> +
>> +	switch (pci_pcie_type(pdev)) {
>> +	case PCI_EXP_TYPE_ROOT_PORT:
>> +	case PCI_EXP_TYPE_DOWNSTREAM:
>> +	{
>> +		struct cxl_dport *dport = NULL;
>> +		struct cxl_port *port __free(put_cxl_port) = find_cxl_port(&pdev->dev, &dport);
>> +
>> +		if (!dport || !dport->dport_dev) {
>> +			pci_err(pdev, "Failed to find the CXL device");
>> +			return NULL;
>> +		}
>> +
>> +		ras_base = dport ? dport->regs.ras : NULL;
> As below - perhaps a sanity check for error and early return makes sense here.
> 

Good idea.

>> +		break;
>> +	}
>> +	case PCI_EXP_TYPE_UPSTREAM:
>> +	{
>> +		struct cxl_port *port;
>> +		struct device *dev __free(put_device) = bus_find_device(&cxl_bus_type, NULL,
>> +									&pdev->dev, match_uport);
>> +
>> +		if (!dev || !is_cxl_port(dev)) {
>> +			pci_err(pdev, "Failed to find the CXL device");
>> +			return NULL;
>> +		}
>> +
>> +		port = to_cxl_port(dev);
>> +		ras_base = port ? port->uport_regs.ras : NULL;
> 
> I'd be tempted to return here to keep the flows simple.  Maybe avoiding the ternary
> 		if (!port)
> 			return NULL;
> 
> 		return port->uport_regs.ras;
> 
> 

Ok.

>> +		break;
>> +	}
>> +	default:
>> +	{
>> +		pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
>> +		return NULL;
> 
> Better not to introduce scope {} when not needed.
> 

Ok.

>> +	}
>> +	}
>> +
>> +	return ras_base;
>> +}
> 
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index 664f532cc838..6093e70ece37 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
> 
>> +
>> +/* Return 'struct device*' responsible for freeing pdev's CXL resources */
>> +static struct device *get_pci_cxl_host_dev(struct pci_dev *pdev)
>> +{
>> +	struct device *host_dev;
>> +
>> +	switch (pci_pcie_type(pdev)) {
>> +	case PCI_EXP_TYPE_ROOT_PORT:
>> +	case PCI_EXP_TYPE_DOWNSTREAM:
>> +	{
>> +		struct cxl_dport *dport = NULL;
>> +		struct cxl_port *port = find_cxl_port(&pdev->dev, &dport);
>> +
>> +		if (!dport || !dport->dport_dev)
> 
> What does !dport->dprot_dev mean?  I.e. how does that happen?
> I can only find places where we set it just after allocating a dport.
> Perhaps a comment?
> 
> 
I'll remove the check for !dport->dport_dev.

> 
>> +			return NULL;
>> +
>> +		host_dev = &port->dev;
>> +		break;
>> +	}
>> +	case PCI_EXP_TYPE_UPSTREAM:
>> +	{
>> +		struct cxl_port *port;
>> +		struct device *cxl_dev = bus_find_device(&cxl_bus_type, NULL,
>> +							 &pdev->dev, match_uport);
> 
> Doesn't his leave you holding a reference to a device different form
> the one you return? Hence wrong one gets put in caller.
> 



>> +
>> +		if (!cxl_dev || !is_cxl_port(cxl_dev))
>> +			return NULL;
>> +
>> +		port = to_cxl_port(cxl_dev);
>> +		host_dev = &port->dev;
> Actually no. Isn't this a circle that lands you on cxl_dev again?
> 
> 		container_of(dev, struct cxl_port, dev)->dev
> 

You're right, it is circular. I'll simplify it. Thanks.

>> +		break;
>> +	}
>> +	case PCI_EXP_TYPE_ENDPOINT:
>> +	case PCI_EXP_TYPE_RC_END:
>> +	{
>> +		struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>> +
>> +		if (!cxlds)
>> +			return NULL;
>> +
>> +		host_dev = get_device(&cxlds->cxlmd->dev);
>> +		break;
> 
> Maybe just return it here? Similar for other cases.
> Saves a reader keeping track of references if we get them roughly where
> we return them.
> 

Ok.

>> +	}
>> +	default:
>> +	{
> No need for scope on this one (or at least some of the others) so drop the {}
> 

Ok.

-Terry

>> +		pci_warn_once(pdev, "Error: Unsupported device type (%X)", pci_pcie_type(pdev));
>> +		return NULL;
>> +	}
>> +	}
>> +
>> +	return host_dev;
>> +}
>> +
>> +static int cxl_report_error_detected(struct pci_dev *pdev, void *data)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct device *host_dev __free(put_device) = get_pci_cxl_host_dev(pdev);
>> +	pci_ers_result_t vote, *result = data;
>>  
>>  	device_lock(&pdev->dev);
>> -	vote = cxl_error_detected(&pdev->dev);
>> +	if ((pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT) ||
>> +	    (pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END)) {
>> +		vote = cxl_error_detected(dev);
>> +	} else {
>> +		vote = cxl_port_error_detected(dev);
>> +	}
>>  	*result = cxl_merge_result(*result, vote);
>>  	device_unlock(&pdev->dev);
>>  
>> @@ -244,14 +309,18 @@ static struct pci_dev *sbdf_to_pci(struct cxl_prot_error_info *err_info)
>>  static void cxl_handle_prot_error(struct cxl_prot_error_info *err_info)
>>  {
>>  	struct pci_dev *pdev __free(pci_dev_put) = pci_dev_get(sbdf_to_pci(err_info));
>> -	struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
>> -	struct device *cxlmd_dev __free(put_device) = get_device(&cxlds->cxlmd->dev);
>>  
>>  	if (!pdev) {
>>  		pr_err("Failed to find the CXL device\n");
>>  		return;
>>  	}
>>  
>> +	struct device *host_dev __free(put_device) = get_pci_cxl_host_dev(pdev);
>> +	if (!host_dev) {
>> +		pr_err("Failed to find the CXL device's host\n");
>> +		return;
>> +	}
>> +
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-11  4:38         ` Lukas Wunner
@ 2025-06-17 16:08           ` Dave Jiang
  2025-06-17 18:20             ` Robert Richter
  0 siblings, 1 reply; 90+ messages in thread
From: Dave Jiang @ 2025-06-17 16:08 UTC (permalink / raw)
  To: Lukas Wunner, Bowman, Terry
  Cc: dave, jonathan.cameron, alison.schofield, vishal.l.verma,
	ira.weiny, dan.j.williams, bhelgaas, bp, ming.li, shiju.jose,
	dan.carpenter, Smita.KoralahalliChannabasappa, kobayashi.da-06,
	rrichter, peterz, fabio.m.de.francesco, ilpo.jarvinen,
	yazen.ghannam, linux-cxl, linux-kernel, linux-pci



On 6/10/25 9:38 PM, Lukas Wunner wrote:
> On Tue, Jun 10, 2025 at 04:20:53PM -0500, Bowman, Terry wrote:
>> On 6/10/2025 1:07 PM, Bowman, Terry wrote:
>>> On 6/9/2025 11:15 PM, Lukas Wunner wrote:
>>>> On Tue, Jun 03, 2025 at 12:22:27PM -0500, Terry Bowman wrote:
>>>>> --- a/drivers/cxl/core/ras.c
>>>>> +++ b/drivers/cxl/core/ras.c
>>>>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
>>>>> +{
>>>>> +	struct cxl_prot_error_info *err_info = data;
>>>>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
>>>>> +	struct cxl_dev_state *cxlds;
>>>>> +
>>>>> +	/*
>>>>> +	 * The capability, status, and control fields in Device 0,
>>>>> +	 * Function 0 DVSEC control the CXL functionality of the
>>>>> +	 * entire device (CXL 3.0, 8.1.3).
>>>>> +	 */
>>>>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
>>>>> +		return 0;
>>>>> +
>>>>> +	/*
>>>>> +	 * CXL Memory Devices must have the 502h class code set (CXL
>>>>> +	 * 3.0, 8.1.12.1).
>>>>> +	 */
>>>>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
>>>>> +		return 0;
>>>>> +
>>>>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
>>>>> +		return 0;
>>>>
>>>> Is the point of the "!pdev->dev.driver" check to ascertain that
>>>> pdev is bound to cxl_pci_driver?
>>>>
>>>> If so, you need to check "if (pdev->driver != &cxl_pci_driver)"
>>>> directly (like cxl_handle_cper_event() does).
>>>>
>>>> That's because there are drivers which may bind to *any* PCI device,
>>>> e.g. vfio_pci_driver.
>>
>> Looking closer to implement this change I find the cxl_pci_driver is
>> defined static in cxl/pci.c and is unavailable to reference in
>> cxl/core/ras.c as-is. Would you like me to export cxl_pci_driver to
>> make available for this check?
> 
> I'm not sure you need an export.  The consumer you're introducing
> is located in core/ras.c, which is always built-in, never modular,
> hence just making it non-static and adding a declaration to cxlpci.h
> may be sufficient.
> 
> An alternative would be to keep it static, but add a non-static helper
> cxl_pci_drv_bound() or something like that.
> 
> I'm passing the buck to CXL maintainers for this. :)

I don't have a good solution to this. Moving the declaration of cxl_pci driver to core would be pretty messy. Perhaps doing the dance of calling try_module_get() is less messy? Or maybe Dan has a better idea....

DJ

> 
>> The existing class code check guarantees it is a CXL EP. Is it not
>> safe to expect it is bound to a the CXL driver?
> 
> Just checking for the pci_dev being bound seems insufficient to me
> because of the vfio_pci_driver case and potentially others.
> 
> HTH,
> 
> Lukas
> 


^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error
  2025-06-17 16:08           ` Dave Jiang
@ 2025-06-17 18:20             ` Robert Richter
  0 siblings, 0 replies; 90+ messages in thread
From: Robert Richter @ 2025-06-17 18:20 UTC (permalink / raw)
  To: Dave Jiang
  Cc: Lukas Wunner, Bowman, Terry, dave, jonathan.cameron,
	alison.schofield, vishal.l.verma, ira.weiny, dan.j.williams,
	bhelgaas, bp, ming.li, shiju.jose, dan.carpenter,
	Smita.KoralahalliChannabasappa, kobayashi.da-06, peterz,
	fabio.m.de.francesco, ilpo.jarvinen, yazen.ghannam, linux-cxl,
	linux-kernel, linux-pci

On 17.06.25 09:08:27, Dave Jiang wrote:
> 
> 
> On 6/10/25 9:38 PM, Lukas Wunner wrote:
> > On Tue, Jun 10, 2025 at 04:20:53PM -0500, Bowman, Terry wrote:
> >> On 6/10/2025 1:07 PM, Bowman, Terry wrote:
> >>> On 6/9/2025 11:15 PM, Lukas Wunner wrote:
> >>>> On Tue, Jun 03, 2025 at 12:22:27PM -0500, Terry Bowman wrote:
> >>>>> --- a/drivers/cxl/core/ras.c
> >>>>> +++ b/drivers/cxl/core/ras.c
> >>>>> +static int cxl_rch_handle_error_iter(struct pci_dev *pdev, void *data)
> >>>>> +{
> >>>>> +	struct cxl_prot_error_info *err_info = data;
> >>>>> +	struct pci_dev *pdev_ref __free(pci_dev_put) = pci_dev_get(pdev);
> >>>>> +	struct cxl_dev_state *cxlds;
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * The capability, status, and control fields in Device 0,
> >>>>> +	 * Function 0 DVSEC control the CXL functionality of the
> >>>>> +	 * entire device (CXL 3.0, 8.1.3).
> >>>>> +	 */
> >>>>> +	if (pdev->devfn != PCI_DEVFN(0, 0))
> >>>>> +		return 0;
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * CXL Memory Devices must have the 502h class code set (CXL
> >>>>> +	 * 3.0, 8.1.12.1).
> >>>>> +	 */
> >>>>> +	if ((pdev->class >> 8) != PCI_CLASS_MEMORY_CXL)
> >>>>> +		return 0;
> >>>>> +
> >>>>> +	if (!is_cxl_memdev(&pdev->dev) || !pdev->dev.driver)
> >>>>> +		return 0;
> >>>>
> >>>> Is the point of the "!pdev->dev.driver" check to ascertain that
> >>>> pdev is bound to cxl_pci_driver?
> >>>>
> >>>> If so, you need to check "if (pdev->driver != &cxl_pci_driver)"
> >>>> directly (like cxl_handle_cper_event() does).
> >>>>
> >>>> That's because there are drivers which may bind to *any* PCI device,
> >>>> e.g. vfio_pci_driver.
> >>
> >> Looking closer to implement this change I find the cxl_pci_driver is
> >> defined static in cxl/pci.c and is unavailable to reference in
> >> cxl/core/ras.c as-is. Would you like me to export cxl_pci_driver to
> >> make available for this check?
> > 
> > I'm not sure you need an export.  The consumer you're introducing
> > is located in core/ras.c, which is always built-in, never modular,
> > hence just making it non-static and adding a declaration to cxlpci.h
> > may be sufficient.
> > 
> > An alternative would be to keep it static, but add a non-static helper
> > cxl_pci_drv_bound() or something like that.
> > 
> > I'm passing the buck to CXL maintainers for this. :)
> 

> I don't have a good solution to this. Moving the declaration of
> cxl_pci driver to core would be pretty messy. Perhaps doing the
> dance of calling try_module_get() is less messy? Or maybe Dan has a
> better idea....

That check originally was to ensure the pci driver can connect to the
cxl driver to handle errors. So the cxl driver exposes something here
that can be used to check the binding.

-Robert

^ permalink raw reply	[flat|nested] 90+ messages in thread

end of thread, other threads:[~2025-06-17 18:20 UTC | newest]

Thread overview: 90+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-03 17:22 [PATCH v9 00/16] Enable CXL PCIe port protocol error handling and logging Terry Bowman
2025-06-03 17:22 ` [PATCH v9 01/16] PCI/CXL: Add pcie_is_cxl() Terry Bowman
2025-06-04 19:06   ` Sathyanarayanan Kuppuswamy
2025-06-04 19:18     ` Bowman, Terry
2025-06-05 23:24   ` Dave Jiang
2025-06-03 17:22 ` [PATCH v9 02/16] PCI/AER: Report CXL or PCIe bus error type in trace logging Terry Bowman
2025-06-03 22:02   ` Sathyanarayanan Kuppuswamy
2025-06-04 14:32     ` Bowman, Terry
2025-06-04 19:24       ` Sathyanarayanan Kuppuswamy
2025-06-04 21:30         ` Bowman, Terry
2025-06-05 23:28   ` Dave Jiang
2025-06-03 17:22 ` [PATCH v9 03/16] CXL/AER: Introduce kfifo for forwarding CXL errors Terry Bowman
2025-06-04  6:01   ` Dan Carpenter
2025-06-04 14:37     ` Bowman, Terry
2025-06-04 17:24       ` Dan Carpenter
2025-06-04 19:21         ` Bowman, Terry
2025-06-04 22:50   ` Sathyanarayanan Kuppuswamy
2025-06-05 14:04     ` Bowman, Terry
2025-06-06  0:27   ` Dave Jiang
2025-06-06 14:27     ` Bowman, Terry
2025-06-06 14:36       ` Dave Jiang
2025-06-12 11:04   ` Jonathan Cameron
2025-06-12 14:29     ` Bowman, Terry
2025-06-03 17:22 ` [PATCH v9 04/16] PCI/AER: Dequeue forwarded CXL error Terry Bowman
2025-06-04  6:05   ` Dan Carpenter
2025-06-04 14:38     ` Bowman, Terry
2025-06-04 23:58   ` Sathyanarayanan Kuppuswamy
2025-06-06 15:57   ` Dave Jiang
2025-06-06 18:14     ` Bowman, Terry
2025-06-06 22:43       ` Dave Jiang
2025-06-09 19:57         ` Bowman, Terry
2025-06-09 20:34           ` Dave Jiang
2025-06-12 11:17             ` Jonathan Cameron
2025-06-06 21:08     ` Bowman, Terry
2025-06-06 23:15     ` Bowman, Terry
2025-06-09 20:17       ` Dave Jiang
2025-06-10  4:15   ` Lukas Wunner
2025-06-10 18:07     ` Bowman, Terry
2025-06-10 21:20       ` Bowman, Terry
2025-06-11  4:38         ` Lukas Wunner
2025-06-17 16:08           ` Dave Jiang
2025-06-17 18:20             ` Robert Richter
2025-06-12 11:36   ` Jonathan Cameron
2025-06-12 18:35     ` Bowman, Terry
2025-06-03 17:22 ` [PATCH v9 05/16] CXL/PCI: Introduce CXL uncorrectable protocol error recovery Terry Bowman
2025-06-05 15:14   ` Sathyanarayanan Kuppuswamy
2025-06-05 16:01     ` Bowman, Terry
2025-06-06 16:45   ` Dave Jiang
2025-06-06 18:16     ` Bowman, Terry
2025-06-12 16:06   ` Jonathan Cameron
2025-06-12 16:29     ` Bowman, Terry
2025-06-03 17:22 ` [PATCH v9 06/16] cxl/pci: Move RAS initialization to cxl_port driver Terry Bowman
2025-06-06 17:04   ` Dave Jiang
2025-06-06 18:17     ` Bowman, Terry
2025-06-03 17:22 ` [PATCH v9 07/16] cxl/pci: Map CXL Endpoint Port and CXL Switch Port RAS registers Terry Bowman
2025-06-03 17:22 ` [PATCH v9 08/16] cxl/pci: Update RAS handler interfaces to also support CXL Ports Terry Bowman
2025-06-05 16:42   ` Sathyanarayanan Kuppuswamy
2025-06-03 17:22 ` [PATCH v9 09/16] cxl/pci: Log message if RAS registers are unmapped Terry Bowman
2025-06-05 16:42   ` Sathyanarayanan Kuppuswamy
2025-06-06 17:27   ` Dave Jiang
2025-06-03 17:22 ` [PATCH v9 10/16] cxl/pci: Unify CXL trace logging for CXL Endpoints and CXL Ports Terry Bowman
2025-06-05 16:49   ` Sathyanarayanan Kuppuswamy
2025-06-06  9:08   ` Shiju Jose
2025-06-06 14:41     ` Bowman, Terry
2025-06-06 15:24       ` Bowman, Terry
2025-06-12 16:25         ` Jonathan Cameron
2025-06-03 17:22 ` [PATCH v9 11/16] cxl/pci: Update __cxl_handle_cor_ras() to return early if no RAS errors Terry Bowman
2025-06-05 18:37   ` Sathyanarayanan Kuppuswamy
2025-06-06 20:30   ` Dave Jiang
2025-06-06 20:55     ` Bowman, Terry
2025-06-06 22:38       ` Dave Jiang
2025-06-12 16:46   ` Jonathan Cameron
2025-06-16 20:30     ` Bowman, Terry
2025-06-03 17:22 ` [PATCH v9 12/16] cxl/pci: Introduce CXL Endpoint protocol error handlers Terry Bowman
2025-06-06  0:22   ` Sathyanarayanan Kuppuswamy
2025-06-12 16:55   ` Jonathan Cameron
2025-06-03 17:22 ` [PATCH v9 13/16] cxl/pci: Introduce CXL Port " Terry Bowman
2025-06-06  0:50   ` Sathyanarayanan Kuppuswamy
2025-06-12 17:14   ` Jonathan Cameron
2025-06-16 22:17     ` Bowman, Terry
2025-06-03 17:22 ` [PATCH v9 14/16] cxl/pci: Remove unnecessary CXL Endpoint handling helper functions Terry Bowman
2025-06-06  0:50   ` Sathyanarayanan Kuppuswamy
2025-06-12 17:16   ` Jonathan Cameron
2025-06-03 17:22 ` [PATCH v9 15/16] CXL/PCI: Enable CXL protocol errors during CXL Port probe Terry Bowman
2025-06-06  0:51   ` Sathyanarayanan Kuppuswamy
2025-06-03 17:22 ` [PATCH v9 16/16] CXL/PCI: Disable CXL protocol error interrupts during CXL Port cleanup Terry Bowman
2025-06-06  0:52   ` Sathyanarayanan Kuppuswamy
2025-06-06 13:51     ` Bowman, Terry
2025-06-06 22:59   ` Dave Jiang
2025-06-12 17:19   ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).