1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * UEFI Common Platform Error Record (CPER) support for CXL Section. |
4 | * |
5 | * Copyright (C) 2022 Advanced Micro Devices, Inc. |
6 | * |
7 | * Author: Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com> |
8 | */ |
9 | |
10 | #include <linux/cper.h> |
11 | #include "cper_cxl.h" |
12 | |
13 | #define PROT_ERR_VALID_AGENT_TYPE BIT_ULL(0) |
14 | #define PROT_ERR_VALID_AGENT_ADDRESS BIT_ULL(1) |
15 | #define PROT_ERR_VALID_DEVICE_ID BIT_ULL(2) |
16 | #define PROT_ERR_VALID_SERIAL_NUMBER BIT_ULL(3) |
17 | #define PROT_ERR_VALID_CAPABILITY BIT_ULL(4) |
18 | #define PROT_ERR_VALID_DVSEC BIT_ULL(5) |
19 | #define PROT_ERR_VALID_ERROR_LOG BIT_ULL(6) |
20 | |
21 | /* CXL RAS Capability Structure, CXL v3.0 sec 8.2.4.16 */ |
22 | struct cxl_ras_capability_regs { |
23 | u32 uncor_status; |
24 | u32 uncor_mask; |
25 | u32 uncor_severity; |
26 | u32 cor_status; |
27 | u32 cor_mask; |
28 | u32 cap_control; |
29 | u32 [16]; |
30 | }; |
31 | |
32 | static const char * const prot_err_agent_type_strs[] = { |
33 | "Restricted CXL Device" , |
34 | "Restricted CXL Host Downstream Port" , |
35 | "CXL Device" , |
36 | "CXL Logical Device" , |
37 | "CXL Fabric Manager managed Logical Device" , |
38 | "CXL Root Port" , |
39 | "CXL Downstream Switch Port" , |
40 | "CXL Upstream Switch Port" , |
41 | }; |
42 | |
43 | /* |
44 | * The layout of the enumeration and the values matches CXL Agent Type |
45 | * field in the UEFI 2.10 Section N.2.13, |
46 | */ |
47 | enum { |
48 | RCD, /* Restricted CXL Device */ |
49 | RCH_DP, /* Restricted CXL Host Downstream Port */ |
50 | DEVICE, /* CXL Device */ |
51 | LD, /* CXL Logical Device */ |
52 | FMLD, /* CXL Fabric Manager managed Logical Device */ |
53 | RP, /* CXL Root Port */ |
54 | DSP, /* CXL Downstream Switch Port */ |
55 | USP, /* CXL Upstream Switch Port */ |
56 | }; |
57 | |
58 | void cper_print_prot_err(const char *pfx, const struct cper_sec_prot_err *prot_err) |
59 | { |
60 | if (prot_err->valid_bits & PROT_ERR_VALID_AGENT_TYPE) |
61 | pr_info("%s agent_type: %d, %s\n" , pfx, prot_err->agent_type, |
62 | prot_err->agent_type < ARRAY_SIZE(prot_err_agent_type_strs) |
63 | ? prot_err_agent_type_strs[prot_err->agent_type] |
64 | : "unknown" ); |
65 | |
66 | if (prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS) { |
67 | switch (prot_err->agent_type) { |
68 | /* |
69 | * According to UEFI 2.10 Section N.2.13, the term CXL Device |
70 | * is used to refer to Restricted CXL Device, CXL Device, CXL |
71 | * Logical Device or a CXL Fabric Manager Managed Logical |
72 | * Device. |
73 | */ |
74 | case RCD: |
75 | case DEVICE: |
76 | case LD: |
77 | case FMLD: |
78 | case RP: |
79 | case DSP: |
80 | case USP: |
81 | pr_info("%s agent_address: %04x:%02x:%02x.%x\n" , |
82 | pfx, prot_err->agent_addr.segment, |
83 | prot_err->agent_addr.bus, |
84 | prot_err->agent_addr.device, |
85 | prot_err->agent_addr.function); |
86 | break; |
87 | case RCH_DP: |
88 | pr_info("%s rcrb_base_address: 0x%016llx\n" , pfx, |
89 | prot_err->agent_addr.rcrb_base_addr); |
90 | break; |
91 | default: |
92 | break; |
93 | } |
94 | } |
95 | |
96 | if (prot_err->valid_bits & PROT_ERR_VALID_DEVICE_ID) { |
97 | const __u8 *class_code; |
98 | |
99 | switch (prot_err->agent_type) { |
100 | case RCD: |
101 | case DEVICE: |
102 | case LD: |
103 | case FMLD: |
104 | case RP: |
105 | case DSP: |
106 | case USP: |
107 | pr_info("%s slot: %d\n" , pfx, |
108 | prot_err->device_id.slot >> CPER_PCIE_SLOT_SHIFT); |
109 | pr_info("%s vendor_id: 0x%04x, device_id: 0x%04x\n" , |
110 | pfx, prot_err->device_id.vendor_id, |
111 | prot_err->device_id.device_id); |
112 | pr_info("%s sub_vendor_id: 0x%04x, sub_device_id: 0x%04x\n" , |
113 | pfx, prot_err->device_id.subsystem_vendor_id, |
114 | prot_err->device_id.subsystem_id); |
115 | class_code = prot_err->device_id.class_code; |
116 | pr_info("%s class_code: %02x%02x\n" , pfx, |
117 | class_code[1], class_code[0]); |
118 | break; |
119 | default: |
120 | break; |
121 | } |
122 | } |
123 | |
124 | if (prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER) { |
125 | switch (prot_err->agent_type) { |
126 | case RCD: |
127 | case DEVICE: |
128 | case LD: |
129 | case FMLD: |
130 | pr_info("%s lower_dw: 0x%08x, upper_dw: 0x%08x\n" , pfx, |
131 | prot_err->dev_serial_num.lower_dw, |
132 | prot_err->dev_serial_num.upper_dw); |
133 | break; |
134 | default: |
135 | break; |
136 | } |
137 | } |
138 | |
139 | if (prot_err->valid_bits & PROT_ERR_VALID_CAPABILITY) { |
140 | switch (prot_err->agent_type) { |
141 | case RCD: |
142 | case DEVICE: |
143 | case LD: |
144 | case FMLD: |
145 | case RP: |
146 | case DSP: |
147 | case USP: |
148 | print_hex_dump(level: pfx, prefix_str: "" , prefix_type: DUMP_PREFIX_OFFSET, rowsize: 16, groupsize: 4, |
149 | buf: prot_err->capability, |
150 | len: sizeof(prot_err->capability), ascii: 0); |
151 | break; |
152 | default: |
153 | break; |
154 | } |
155 | } |
156 | |
157 | if (prot_err->valid_bits & PROT_ERR_VALID_DVSEC) { |
158 | pr_info("%s DVSEC length: 0x%04x\n" , pfx, prot_err->dvsec_len); |
159 | |
160 | pr_info("%s CXL DVSEC:\n" , pfx); |
161 | print_hex_dump(level: pfx, prefix_str: "" , prefix_type: DUMP_PREFIX_OFFSET, rowsize: 16, groupsize: 4, buf: (prot_err + 1), |
162 | len: prot_err->dvsec_len, ascii: 0); |
163 | } |
164 | |
165 | if (prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG) { |
166 | size_t size = sizeof(*prot_err) + prot_err->dvsec_len; |
167 | struct cxl_ras_capability_regs *cxl_ras; |
168 | |
169 | pr_info("%s Error log length: 0x%04x\n" , pfx, prot_err->err_len); |
170 | |
171 | pr_info("%s CXL Error Log:\n" , pfx); |
172 | cxl_ras = (struct cxl_ras_capability_regs *)((long)prot_err + size); |
173 | pr_info("%s cxl_ras_uncor_status: 0x%08x" , pfx, |
174 | cxl_ras->uncor_status); |
175 | pr_info("%s cxl_ras_uncor_mask: 0x%08x\n" , pfx, |
176 | cxl_ras->uncor_mask); |
177 | pr_info("%s cxl_ras_uncor_severity: 0x%08x\n" , pfx, |
178 | cxl_ras->uncor_severity); |
179 | pr_info("%s cxl_ras_cor_status: 0x%08x" , pfx, |
180 | cxl_ras->cor_status); |
181 | pr_info("%s cxl_ras_cor_mask: 0x%08x\n" , pfx, |
182 | cxl_ras->cor_mask); |
183 | pr_info("%s cap_control: 0x%08x\n" , pfx, |
184 | cxl_ras->cap_control); |
185 | pr_info("%s Header Log Registers:\n" , pfx); |
186 | print_hex_dump(level: pfx, prefix_str: "" , prefix_type: DUMP_PREFIX_OFFSET, rowsize: 16, groupsize: 4, buf: cxl_ras->header_log, |
187 | len: sizeof(cxl_ras->header_log), ascii: 0); |
188 | } |
189 | } |
190 | |