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