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 } 190