162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * UEFI Common Platform Error Record (CPER) support for CXL Section. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022 Advanced Micro Devices, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/cper.h> 1162306a36Sopenharmony_ci#include "cper_cxl.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define PROT_ERR_VALID_AGENT_TYPE BIT_ULL(0) 1462306a36Sopenharmony_ci#define PROT_ERR_VALID_AGENT_ADDRESS BIT_ULL(1) 1562306a36Sopenharmony_ci#define PROT_ERR_VALID_DEVICE_ID BIT_ULL(2) 1662306a36Sopenharmony_ci#define PROT_ERR_VALID_SERIAL_NUMBER BIT_ULL(3) 1762306a36Sopenharmony_ci#define PROT_ERR_VALID_CAPABILITY BIT_ULL(4) 1862306a36Sopenharmony_ci#define PROT_ERR_VALID_DVSEC BIT_ULL(5) 1962306a36Sopenharmony_ci#define PROT_ERR_VALID_ERROR_LOG BIT_ULL(6) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* CXL RAS Capability Structure, CXL v3.0 sec 8.2.4.16 */ 2262306a36Sopenharmony_cistruct cxl_ras_capability_regs { 2362306a36Sopenharmony_ci u32 uncor_status; 2462306a36Sopenharmony_ci u32 uncor_mask; 2562306a36Sopenharmony_ci u32 uncor_severity; 2662306a36Sopenharmony_ci u32 cor_status; 2762306a36Sopenharmony_ci u32 cor_mask; 2862306a36Sopenharmony_ci u32 cap_control; 2962306a36Sopenharmony_ci u32 header_log[16]; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic const char * const prot_err_agent_type_strs[] = { 3362306a36Sopenharmony_ci "Restricted CXL Device", 3462306a36Sopenharmony_ci "Restricted CXL Host Downstream Port", 3562306a36Sopenharmony_ci "CXL Device", 3662306a36Sopenharmony_ci "CXL Logical Device", 3762306a36Sopenharmony_ci "CXL Fabric Manager managed Logical Device", 3862306a36Sopenharmony_ci "CXL Root Port", 3962306a36Sopenharmony_ci "CXL Downstream Switch Port", 4062306a36Sopenharmony_ci "CXL Upstream Switch Port", 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* 4462306a36Sopenharmony_ci * The layout of the enumeration and the values matches CXL Agent Type 4562306a36Sopenharmony_ci * field in the UEFI 2.10 Section N.2.13, 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cienum { 4862306a36Sopenharmony_ci RCD, /* Restricted CXL Device */ 4962306a36Sopenharmony_ci RCH_DP, /* Restricted CXL Host Downstream Port */ 5062306a36Sopenharmony_ci DEVICE, /* CXL Device */ 5162306a36Sopenharmony_ci LD, /* CXL Logical Device */ 5262306a36Sopenharmony_ci FMLD, /* CXL Fabric Manager managed Logical Device */ 5362306a36Sopenharmony_ci RP, /* CXL Root Port */ 5462306a36Sopenharmony_ci DSP, /* CXL Downstream Switch Port */ 5562306a36Sopenharmony_ci USP, /* CXL Upstream Switch Port */ 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_civoid cper_print_prot_err(const char *pfx, const struct cper_sec_prot_err *prot_err) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci if (prot_err->valid_bits & PROT_ERR_VALID_AGENT_TYPE) 6162306a36Sopenharmony_ci pr_info("%s agent_type: %d, %s\n", pfx, prot_err->agent_type, 6262306a36Sopenharmony_ci prot_err->agent_type < ARRAY_SIZE(prot_err_agent_type_strs) 6362306a36Sopenharmony_ci ? prot_err_agent_type_strs[prot_err->agent_type] 6462306a36Sopenharmony_ci : "unknown"); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS) { 6762306a36Sopenharmony_ci switch (prot_err->agent_type) { 6862306a36Sopenharmony_ci /* 6962306a36Sopenharmony_ci * According to UEFI 2.10 Section N.2.13, the term CXL Device 7062306a36Sopenharmony_ci * is used to refer to Restricted CXL Device, CXL Device, CXL 7162306a36Sopenharmony_ci * Logical Device or a CXL Fabric Manager Managed Logical 7262306a36Sopenharmony_ci * Device. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci case RCD: 7562306a36Sopenharmony_ci case DEVICE: 7662306a36Sopenharmony_ci case LD: 7762306a36Sopenharmony_ci case FMLD: 7862306a36Sopenharmony_ci case RP: 7962306a36Sopenharmony_ci case DSP: 8062306a36Sopenharmony_ci case USP: 8162306a36Sopenharmony_ci pr_info("%s agent_address: %04x:%02x:%02x.%x\n", 8262306a36Sopenharmony_ci pfx, prot_err->agent_addr.segment, 8362306a36Sopenharmony_ci prot_err->agent_addr.bus, 8462306a36Sopenharmony_ci prot_err->agent_addr.device, 8562306a36Sopenharmony_ci prot_err->agent_addr.function); 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci case RCH_DP: 8862306a36Sopenharmony_ci pr_info("%s rcrb_base_address: 0x%016llx\n", pfx, 8962306a36Sopenharmony_ci prot_err->agent_addr.rcrb_base_addr); 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci default: 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (prot_err->valid_bits & PROT_ERR_VALID_DEVICE_ID) { 9762306a36Sopenharmony_ci const __u8 *class_code; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci switch (prot_err->agent_type) { 10062306a36Sopenharmony_ci case RCD: 10162306a36Sopenharmony_ci case DEVICE: 10262306a36Sopenharmony_ci case LD: 10362306a36Sopenharmony_ci case FMLD: 10462306a36Sopenharmony_ci case RP: 10562306a36Sopenharmony_ci case DSP: 10662306a36Sopenharmony_ci case USP: 10762306a36Sopenharmony_ci pr_info("%s slot: %d\n", pfx, 10862306a36Sopenharmony_ci prot_err->device_id.slot >> CPER_PCIE_SLOT_SHIFT); 10962306a36Sopenharmony_ci pr_info("%s vendor_id: 0x%04x, device_id: 0x%04x\n", 11062306a36Sopenharmony_ci pfx, prot_err->device_id.vendor_id, 11162306a36Sopenharmony_ci prot_err->device_id.device_id); 11262306a36Sopenharmony_ci pr_info("%s sub_vendor_id: 0x%04x, sub_device_id: 0x%04x\n", 11362306a36Sopenharmony_ci pfx, prot_err->device_id.subsystem_vendor_id, 11462306a36Sopenharmony_ci prot_err->device_id.subsystem_id); 11562306a36Sopenharmony_ci class_code = prot_err->device_id.class_code; 11662306a36Sopenharmony_ci pr_info("%s class_code: %02x%02x\n", pfx, 11762306a36Sopenharmony_ci class_code[1], class_code[0]); 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci default: 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER) { 12562306a36Sopenharmony_ci switch (prot_err->agent_type) { 12662306a36Sopenharmony_ci case RCD: 12762306a36Sopenharmony_ci case DEVICE: 12862306a36Sopenharmony_ci case LD: 12962306a36Sopenharmony_ci case FMLD: 13062306a36Sopenharmony_ci pr_info("%s lower_dw: 0x%08x, upper_dw: 0x%08x\n", pfx, 13162306a36Sopenharmony_ci prot_err->dev_serial_num.lower_dw, 13262306a36Sopenharmony_ci prot_err->dev_serial_num.upper_dw); 13362306a36Sopenharmony_ci break; 13462306a36Sopenharmony_ci default: 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (prot_err->valid_bits & PROT_ERR_VALID_CAPABILITY) { 14062306a36Sopenharmony_ci switch (prot_err->agent_type) { 14162306a36Sopenharmony_ci case RCD: 14262306a36Sopenharmony_ci case DEVICE: 14362306a36Sopenharmony_ci case LD: 14462306a36Sopenharmony_ci case FMLD: 14562306a36Sopenharmony_ci case RP: 14662306a36Sopenharmony_ci case DSP: 14762306a36Sopenharmony_ci case USP: 14862306a36Sopenharmony_ci print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, 14962306a36Sopenharmony_ci prot_err->capability, 15062306a36Sopenharmony_ci sizeof(prot_err->capability), 0); 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci default: 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (prot_err->valid_bits & PROT_ERR_VALID_DVSEC) { 15862306a36Sopenharmony_ci pr_info("%s DVSEC length: 0x%04x\n", pfx, prot_err->dvsec_len); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci pr_info("%s CXL DVSEC:\n", pfx); 16162306a36Sopenharmony_ci print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, (prot_err + 1), 16262306a36Sopenharmony_ci prot_err->dvsec_len, 0); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG) { 16662306a36Sopenharmony_ci size_t size = sizeof(*prot_err) + prot_err->dvsec_len; 16762306a36Sopenharmony_ci struct cxl_ras_capability_regs *cxl_ras; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci pr_info("%s Error log length: 0x%04x\n", pfx, prot_err->err_len); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci pr_info("%s CXL Error Log:\n", pfx); 17262306a36Sopenharmony_ci cxl_ras = (struct cxl_ras_capability_regs *)((long)prot_err + size); 17362306a36Sopenharmony_ci pr_info("%s cxl_ras_uncor_status: 0x%08x", pfx, 17462306a36Sopenharmony_ci cxl_ras->uncor_status); 17562306a36Sopenharmony_ci pr_info("%s cxl_ras_uncor_mask: 0x%08x\n", pfx, 17662306a36Sopenharmony_ci cxl_ras->uncor_mask); 17762306a36Sopenharmony_ci pr_info("%s cxl_ras_uncor_severity: 0x%08x\n", pfx, 17862306a36Sopenharmony_ci cxl_ras->uncor_severity); 17962306a36Sopenharmony_ci pr_info("%s cxl_ras_cor_status: 0x%08x", pfx, 18062306a36Sopenharmony_ci cxl_ras->cor_status); 18162306a36Sopenharmony_ci pr_info("%s cxl_ras_cor_mask: 0x%08x\n", pfx, 18262306a36Sopenharmony_ci cxl_ras->cor_mask); 18362306a36Sopenharmony_ci pr_info("%s cap_control: 0x%08x\n", pfx, 18462306a36Sopenharmony_ci cxl_ras->cap_control); 18562306a36Sopenharmony_ci pr_info("%s Header Log Registers:\n", pfx); 18662306a36Sopenharmony_ci print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, cxl_ras->header_log, 18762306a36Sopenharmony_ci sizeof(cxl_ras->header_log), 0); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci} 190