Merge tag 'sh-for-v6.6-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/glaubit...
[platform/kernel/linux-rpi.git] / drivers / firmware / efi / cper_cxl.c
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 header_log[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(pfx, "", DUMP_PREFIX_OFFSET, 16, 4,
149                                        prot_err->capability,
150                                        sizeof(prot_err->capability), 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(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, (prot_err + 1),
162                                prot_err->dvsec_len, 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(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, cxl_ras->header_log,
187                                sizeof(cxl_ras->header_log), 0);
188         }
189 }