xref: /openbmc/linux/drivers/firmware/efi/cper_cxl.c (revision b0048092)
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 
cper_print_prot_err(const char * pfx,const struct cper_sec_prot_err * prot_err)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 }
190