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