Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.16-rc7 126 lines 3.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* Copyright(c) 2025 AMD Corporation. All rights reserved. */ 3 4#include <linux/pci.h> 5#include <linux/aer.h> 6#include <cxl/event.h> 7#include <cxlmem.h> 8#include "trace.h" 9 10static void cxl_cper_trace_corr_port_prot_err(struct pci_dev *pdev, 11 struct cxl_ras_capability_regs ras_cap) 12{ 13 u32 status = ras_cap.cor_status & ~ras_cap.cor_mask; 14 15 trace_cxl_port_aer_correctable_error(&pdev->dev, status); 16} 17 18static void cxl_cper_trace_uncorr_port_prot_err(struct pci_dev *pdev, 19 struct cxl_ras_capability_regs ras_cap) 20{ 21 u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask; 22 u32 fe; 23 24 if (hweight32(status) > 1) 25 fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, 26 ras_cap.cap_control)); 27 else 28 fe = status; 29 30 trace_cxl_port_aer_uncorrectable_error(&pdev->dev, status, fe, 31 ras_cap.header_log); 32} 33 34static void cxl_cper_trace_corr_prot_err(struct cxl_memdev *cxlmd, 35 struct cxl_ras_capability_regs ras_cap) 36{ 37 u32 status = ras_cap.cor_status & ~ras_cap.cor_mask; 38 39 trace_cxl_aer_correctable_error(cxlmd, status); 40} 41 42static void 43cxl_cper_trace_uncorr_prot_err(struct cxl_memdev *cxlmd, 44 struct cxl_ras_capability_regs ras_cap) 45{ 46 u32 status = ras_cap.uncor_status & ~ras_cap.uncor_mask; 47 u32 fe; 48 49 if (hweight32(status) > 1) 50 fe = BIT(FIELD_GET(CXL_RAS_CAP_CONTROL_FE_MASK, 51 ras_cap.cap_control)); 52 else 53 fe = status; 54 55 trace_cxl_aer_uncorrectable_error(cxlmd, status, fe, 56 ras_cap.header_log); 57} 58 59static int match_memdev_by_parent(struct device *dev, const void *uport) 60{ 61 if (is_cxl_memdev(dev) && dev->parent == uport) 62 return 1; 63 return 0; 64} 65 66static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data) 67{ 68 unsigned int devfn = PCI_DEVFN(data->prot_err.agent_addr.device, 69 data->prot_err.agent_addr.function); 70 struct pci_dev *pdev __free(pci_dev_put) = 71 pci_get_domain_bus_and_slot(data->prot_err.agent_addr.segment, 72 data->prot_err.agent_addr.bus, 73 devfn); 74 struct cxl_memdev *cxlmd; 75 int port_type; 76 77 if (!pdev) 78 return; 79 80 port_type = pci_pcie_type(pdev); 81 if (port_type == PCI_EXP_TYPE_ROOT_PORT || 82 port_type == PCI_EXP_TYPE_DOWNSTREAM || 83 port_type == PCI_EXP_TYPE_UPSTREAM) { 84 if (data->severity == AER_CORRECTABLE) 85 cxl_cper_trace_corr_port_prot_err(pdev, data->ras_cap); 86 else 87 cxl_cper_trace_uncorr_port_prot_err(pdev, data->ras_cap); 88 89 return; 90 } 91 92 guard(device)(&pdev->dev); 93 if (!pdev->dev.driver) 94 return; 95 96 struct device *mem_dev __free(put_device) = bus_find_device( 97 &cxl_bus_type, NULL, pdev, match_memdev_by_parent); 98 if (!mem_dev) 99 return; 100 101 cxlmd = to_cxl_memdev(mem_dev); 102 if (data->severity == AER_CORRECTABLE) 103 cxl_cper_trace_corr_prot_err(cxlmd, data->ras_cap); 104 else 105 cxl_cper_trace_uncorr_prot_err(cxlmd, data->ras_cap); 106} 107 108static void cxl_cper_prot_err_work_fn(struct work_struct *work) 109{ 110 struct cxl_cper_prot_err_work_data wd; 111 112 while (cxl_cper_prot_err_kfifo_get(&wd)) 113 cxl_cper_handle_prot_err(&wd); 114} 115static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn); 116 117int cxl_ras_init(void) 118{ 119 return cxl_cper_register_prot_err_work(&cxl_cper_prot_err_work); 120} 121 122void cxl_ras_exit(void) 123{ 124 cxl_cper_unregister_prot_err_work(&cxl_cper_prot_err_work); 125 cancel_work_sync(&cxl_cper_prot_err_work); 126}