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