1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * PCIe TLP Log handling 4 * 5 * Copyright (C) 2024 Intel Corporation 6 */ 7 8 #include <linux/aer.h> 9 #include <linux/array_size.h> 10 #include <linux/pci.h> 11 #include <linux/string.h> 12 13 #include "../pci.h" 14 15 /** 16 * aer_tlp_log_len - Calculate AER Capability TLP Header/Prefix Log length 17 * @dev: PCIe device 18 * @aercc: AER Capabilities and Control register value 19 * 20 * Return: TLP Header/Prefix Log length 21 */ 22 unsigned int aer_tlp_log_len(struct pci_dev *dev, u32 aercc) 23 { 24 return PCIE_STD_NUM_TLP_HEADERLOG + 25 ((aercc & PCI_ERR_CAP_PREFIX_LOG_PRESENT) ? 26 dev->eetlp_prefix_max : 0); 27 } 28 29 #ifdef CONFIG_PCIE_DPC 30 /** 31 * dpc_tlp_log_len - Calculate DPC RP PIO TLP Header/Prefix Log length 32 * @dev: PCIe device 33 * 34 * Return: TLP Header/Prefix Log length 35 */ 36 unsigned int dpc_tlp_log_len(struct pci_dev *dev) 37 { 38 /* Remove ImpSpec Log register from the count */ 39 if (dev->dpc_rp_log_size >= PCIE_STD_NUM_TLP_HEADERLOG + 1) 40 return dev->dpc_rp_log_size - 1; 41 42 return dev->dpc_rp_log_size; 43 } 44 #endif 45 46 /** 47 * pcie_read_tlp_log - read TLP Header Log 48 * @dev: PCIe device 49 * @where: PCI Config offset of TLP Header Log 50 * @where2: PCI Config offset of TLP Prefix Log 51 * @tlp_len: TLP Log length (Header Log + TLP Prefix Log in DWORDs) 52 * @log: TLP Log structure to fill 53 * 54 * Fill @log from TLP Header Log registers, e.g., AER or DPC. 55 * 56 * Return: 0 on success and filled TLP Log structure, <0 on error. 57 */ 58 int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2, 59 unsigned int tlp_len, struct pcie_tlp_log *log) 60 { 61 unsigned int i; 62 int off, ret; 63 u32 *to; 64 65 memset(log, 0, sizeof(*log)); 66 67 for (i = 0; i < tlp_len; i++) { 68 if (i < PCIE_STD_NUM_TLP_HEADERLOG) { 69 off = where + i * 4; 70 to = &log->dw[i]; 71 } else { 72 off = where2 + (i - PCIE_STD_NUM_TLP_HEADERLOG) * 4; 73 to = &log->prefix[i - PCIE_STD_NUM_TLP_HEADERLOG]; 74 } 75 76 ret = pci_read_config_dword(dev, off, to); 77 if (ret) 78 return pcibios_err_to_errno(ret); 79 } 80 81 return 0; 82 } 83 84 #define EE_PREFIX_STR " E-E Prefixes:" 85 86 /** 87 * pcie_print_tlp_log - Print TLP Header / Prefix Log contents 88 * @dev: PCIe device 89 * @log: TLP Log structure 90 * @pfx: String prefix 91 * 92 * Prints TLP Header and Prefix Log information held by @log. 93 */ 94 void pcie_print_tlp_log(const struct pci_dev *dev, 95 const struct pcie_tlp_log *log, const char *pfx) 96 { 97 char buf[11 * (PCIE_STD_NUM_TLP_HEADERLOG + ARRAY_SIZE(log->prefix)) + 98 sizeof(EE_PREFIX_STR)]; 99 unsigned int i; 100 int len; 101 102 len = scnprintf(buf, sizeof(buf), "%#010x %#010x %#010x %#010x", 103 log->dw[0], log->dw[1], log->dw[2], log->dw[3]); 104 105 if (log->prefix[0]) 106 len += scnprintf(buf + len, sizeof(buf) - len, EE_PREFIX_STR); 107 for (i = 0; i < ARRAY_SIZE(log->prefix); i++) { 108 if (!log->prefix[i]) 109 break; 110 len += scnprintf(buf + len, sizeof(buf) - len, 111 " %#010x", log->prefix[i]); 112 } 113 114 pci_err(dev, "%sTLP Header: %s\n", pfx, buf); 115 } 116