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 */
22struct 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
32static 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 */
47enum {
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
58void 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