History

PCI: Add TLP Prefix reading to pcie_read_tlp_log()

pcie_read_tlp_log() handles only 4 Header Log DWORDs but TLP Prefix Log (PCIe r6.1 secs 7.8.4.12 & 7.9.14.13) may also be present. Generalize pcie_read_tlp_log() and struct pcie_tlp_log to also handle TLP Prefix Log. The relevant registers are formatted identically in AER and DPC Capability, but has these variations: a) The offsets of TLP Prefix Log registers vary. b) DPC RP PIO TLP Prefix Log register can be < 4 DWORDs. c) AER TLP Prefix Log Present (PCIe r6.1 sec 7.8.4.7) can indicate Prefix Log is not present. Therefore callers must pass the offset of the TLP Prefix Log register and the entire length to pcie_read_tlp_log() to be able to read the correct number of TLP Prefix DWORDs from the correct offset.

Ilpo Järvinen committed 1 year ago

Commit ad41dde1 parent e5321ae6 files · +68 −18Browse files

Unified · Split

6 files
  1. drivers/pci/pci.h +4 −1
  2. drivers/pci/pcie/aer.c +4 −1
  3. drivers/pci/pcie/dpc.c +6 −7
  4. drivers/pci/pcie/tlp.c +47 −5
  5. include/linux/aer.h +1 −0
  6. include/uapi/linux/pci_regs.h +6 −4
drivers/pci/pci.h+4−1
@@ -550,7 +550,9 @@ struct aer_err_info { · 549 unmodified lines
550int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);550int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
551void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);551void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
552 552
553int pcie_read_tlp_log(struct pci_dev *dev, int where, struct pcie_tlp_log *log);553int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
554 unsigned int tlp_len, struct pcie_tlp_log *log);
555unsigned int aer_tlp_log_len(struct pci_dev *dev, u32 aercc);
554#endif /* CONFIG_PCIEAER */556#endif /* CONFIG_PCIEAER */
555 557
556#ifdef CONFIG_PCIEPORTBUS558#ifdef CONFIG_PCIEPORTBUS
@@ -569,6 +571,7 @@ void pci_dpc_init(struct pci_dev *pdev); · 12 unmodified lines
569void dpc_process_error(struct pci_dev *pdev);571void dpc_process_error(struct pci_dev *pdev);
570pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);572pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);
571bool pci_dpc_recovered(struct pci_dev *pdev);573bool pci_dpc_recovered(struct pci_dev *pdev);
574unsigned int dpc_tlp_log_len(struct pci_dev *dev);
572#else575#else
573static inline void pci_save_dpc_state(struct pci_dev *dev) { }576static inline void pci_save_dpc_state(struct pci_dev *dev) { }
574static inline void pci_restore_dpc_state(struct pci_dev *dev) { }577static inline void pci_restore_dpc_state(struct pci_dev *dev) { }
drivers/pci/pcie/aer.c+4−1
@@ -1248,7 +1248,10 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) · 1247 unmodified lines
1248 1248
1249 if (info->status & AER_LOG_TLP_MASKS) {1249 if (info->status & AER_LOG_TLP_MASKS) {
1250 info->tlp_header_valid = 1;1250 info->tlp_header_valid = 1;
1251 pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG, &info->tlp);1251 pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG,
1252 aer + PCI_ERR_PREFIX_LOG,
1253 aer_tlp_log_len(dev, aercc),
1254 &info->tlp);
1252 }1255 }
1253 }1256 }
1254 1257
drivers/pci/pcie/dpc.c+6−7
@@ -190,7 +190,7 @@ out: · 189 unmodified lines
190static void dpc_process_rp_pio_error(struct pci_dev *pdev)190static void dpc_process_rp_pio_error(struct pci_dev *pdev)
191{191{
192 u16 cap = pdev->dpc_cap, dpc_status, first_error;192 u16 cap = pdev->dpc_cap, dpc_status, first_error;
193 u32 status, mask, sev, syserr, exc, log, prefix;193 u32 status, mask, sev, syserr, exc, log;
194 struct pcie_tlp_log tlp_log;194 struct pcie_tlp_log tlp_log;
195 int i;195 int i;
196 196
@@ -217,20 +217,19 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev) · 20 unmodified lines
217 217
218 if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG)218 if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG)
219 goto clear_status;219 goto clear_status;
220 pcie_read_tlp_log(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG, &tlp_log);220 pcie_read_tlp_log(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG,
221 cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG,
222 dpc_tlp_log_len(pdev), &tlp_log);
221 pci_err(pdev, "TLP Header: %#010x %#010x %#010x %#010x\n",223 pci_err(pdev, "TLP Header: %#010x %#010x %#010x %#010x\n",
222 tlp_log.dw[0], tlp_log.dw[1], tlp_log.dw[2], tlp_log.dw[3]);224 tlp_log.dw[0], tlp_log.dw[1], tlp_log.dw[2], tlp_log.dw[3]);
225 for (i = 0; i < pdev->dpc_rp_log_size - PCIE_STD_NUM_TLP_HEADERLOG - 1; i++)
226 pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, tlp_log.prefix[i]);
223 227
224 if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG + 1)228 if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG + 1)
225 goto clear_status;229 goto clear_status;
226 pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log);230 pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log);
227 pci_err(pdev, "RP PIO ImpSpec Log %#010x\n", log);231 pci_err(pdev, "RP PIO ImpSpec Log %#010x\n", log);
228 232
229 for (i = 0; i < pdev->dpc_rp_log_size - PCIE_STD_NUM_TLP_HEADERLOG - 1; i++) {
230 pci_read_config_dword(pdev,
231 cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG + i * 4, &prefix);
232 pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix);
233 }
234 clear_status:233 clear_status:
235 pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, status);234 pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, status);
236}235}
drivers/pci/pcie/tlp.c+47−5
@@ -11,26 +11,68 @@ · 10 unmodified lines
11 11
12#include "../pci.h"12#include "../pci.h"
13 13
14/**
15 * aer_tlp_log_len - Calculate AER Capability TLP Header/Prefix Log length
16 * @dev: PCIe device
17 * @aercc: AER Capabilities and Control register value
18 *
19 * Return: TLP Header/Prefix Log length
20 */
21unsigned int aer_tlp_log_len(struct pci_dev *dev, u32 aercc)
22{
23 return PCIE_STD_NUM_TLP_HEADERLOG +
24 ((aercc & PCI_ERR_CAP_PREFIX_LOG_PRESENT) ?
25 dev->eetlp_prefix_max : 0);
26}
27
28#ifdef CONFIG_PCIE_DPC
29/**
30 * dpc_tlp_log_len - Calculate DPC RP PIO TLP Header/Prefix Log length
31 * @dev: PCIe device
32 *
33 * Return: TLP Header/Prefix Log length
34 */
35unsigned int dpc_tlp_log_len(struct pci_dev *dev)
36{
37 /* Remove ImpSpec Log register from the count */
38 if (dev->dpc_rp_log_size >= PCIE_STD_NUM_TLP_HEADERLOG + 1)
39 return dev->dpc_rp_log_size - 1;
40
41 return dev->dpc_rp_log_size;
42}
43#endif
44
14/**45/**
15 * pcie_read_tlp_log - read TLP Header Log46 * pcie_read_tlp_log - read TLP Header Log
16 * @dev: PCIe device47 * @dev: PCIe device
17 * @where: PCI Config offset of TLP Header Log48 * @where: PCI Config offset of TLP Header Log
49 * @where2: PCI Config offset of TLP Prefix Log
50 * @tlp_len: TLP Log length (Header Log + TLP Prefix Log in DWORDs)
18 * @log: TLP Log structure to fill51 * @log: TLP Log structure to fill
19 *52 *
20 * Fill @log from TLP Header Log registers, e.g., AER or DPC.53 * Fill @log from TLP Header Log registers, e.g., AER or DPC.
21 *54 *
22 * Return: 0 on success and filled TLP Log structure, <0 on error.55 * Return: 0 on success and filled TLP Log structure, <0 on error.
23 */56 */
24int pcie_read_tlp_log(struct pci_dev *dev, int where,57int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
25 struct pcie_tlp_log *log)58 unsigned int tlp_len, struct pcie_tlp_log *log)
26{59{
27 unsigned int i;60 unsigned int i;
28 int ret;61 int off, ret;
62 u32 *to;
29 63
30 memset(log, 0, sizeof(*log));64 memset(log, 0, sizeof(*log));
31 65
32 for (i = 0; i < PCIE_STD_NUM_TLP_HEADERLOG; i++) {66 for (i = 0; i < tlp_len; i++) {
33 ret = pci_read_config_dword(dev, where + i * 4, &log->dw[i]);67 if (i < PCIE_STD_NUM_TLP_HEADERLOG) {
68 off = where + i * 4;
69 to = &log->dw[i];
70 } else {
71 off = where2 + (i - PCIE_STD_NUM_TLP_HEADERLOG) * 4;
72 to = &log->prefix[i - PCIE_STD_NUM_TLP_HEADERLOG];
73 }
74
75 ret = pci_read_config_dword(dev, off, to);
34 if (ret)76 if (ret)
35 return pcibios_err_to_errno(ret);77 return pcibios_err_to_errno(ret);
36 }78 }
include/linux/aer.h+1−0
@@ -27,6 +27,7 @@ struct pci_dev; · 26 unmodified lines
27 27
28struct pcie_tlp_log {28struct pcie_tlp_log {
29 u32 dw[PCIE_STD_NUM_TLP_HEADERLOG];29 u32 dw[PCIE_STD_NUM_TLP_HEADERLOG];
30 u32 prefix[PCIE_STD_MAX_TLP_PREFIXLOG];
30};31};
31 32
32struct aer_capability_regs {33struct aer_capability_regs {
include/uapi/linux/pci_regs.h+6−4
@@ -790,10 +790,11 @@ · 789 unmodified lines
790 /* Same bits as above */790 /* Same bits as above */
791#define PCI_ERR_CAP 0x18 /* Advanced Error Capabilities & Ctrl*/791#define PCI_ERR_CAP 0x18 /* Advanced Error Capabilities & Ctrl*/
792#define PCI_ERR_CAP_FEP(x) ((x) & 0x1f) /* First Error Pointer */792#define PCI_ERR_CAP_FEP(x) ((x) & 0x1f) /* First Error Pointer */
793#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */793#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */
794#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */794#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */
795#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */795#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
796#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */796#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
797#define PCI_ERR_CAP_PREFIX_LOG_PRESENT 0x00000800 /* TLP Prefix Log Present */
797#define PCI_ERR_HEADER_LOG 0x1c /* Header Log Register (16 bytes) */798#define PCI_ERR_HEADER_LOG 0x1c /* Header Log Register (16 bytes) */
798#define PCI_ERR_ROOT_COMMAND 0x2c /* Root Error Command */799#define PCI_ERR_ROOT_COMMAND 0x2c /* Root Error Command */
799#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 /* Correctable Err Reporting Enable */800#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 /* Correctable Err Reporting Enable */
@@ -809,6 +810,7 @@ · 9 unmodified lines
809#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */810#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */
810#define PCI_ERR_ROOT_AER_IRQ 0xf8000000 /* Advanced Error Interrupt Message Number */811#define PCI_ERR_ROOT_AER_IRQ 0xf8000000 /* Advanced Error Interrupt Message Number */
811#define PCI_ERR_ROOT_ERR_SRC 0x34 /* Error Source Identification */812#define PCI_ERR_ROOT_ERR_SRC 0x34 /* Error Source Identification */
813#define PCI_ERR_PREFIX_LOG 0x38 /* TLP Prefix LOG Register (up to 16 bytes) */
812 814
813/* Virtual Channel */815/* Virtual Channel */
814#define PCI_VC_PORT_CAP1 0x04816#define PCI_VC_PORT_CAP1 0x04