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