Skip to content

Commit ad41dde

Browse files
ij-intelbjorn-helgaas
authored andcommitted
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. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ilpo Järvinen <[email protected]> [bhelgaas: squash ternary fix from https://lore.kernel.org/r/[email protected]] Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]>
1 parent e5321ae commit ad41dde

File tree

6 files changed

+68
-18
lines changed

6 files changed

+68
-18
lines changed

drivers/pci/pci.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,9 @@ struct aer_err_info {
550550
int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
551551
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
552552

553-
int pcie_read_tlp_log(struct pci_dev *dev, int where, struct pcie_tlp_log *log);
553+
int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
554+
unsigned int tlp_len, struct pcie_tlp_log *log);
555+
unsigned int aer_tlp_log_len(struct pci_dev *dev, u32 aercc);
554556
#endif /* CONFIG_PCIEAER */
555557

556558
#ifdef CONFIG_PCIEPORTBUS
@@ -569,6 +571,7 @@ void pci_dpc_init(struct pci_dev *pdev);
569571
void dpc_process_error(struct pci_dev *pdev);
570572
pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);
571573
bool pci_dpc_recovered(struct pci_dev *pdev);
574+
unsigned int dpc_tlp_log_len(struct pci_dev *dev);
572575
#else
573576
static inline void pci_save_dpc_state(struct pci_dev *dev) { }
574577
static inline void pci_restore_dpc_state(struct pci_dev *dev) { }

drivers/pci/pcie/aer.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1248,7 +1248,10 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
12481248

12491249
if (info->status & AER_LOG_TLP_MASKS) {
12501250
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);
12521255
}
12531256
}
12541257

drivers/pci/pcie/dpc.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
190190
static void dpc_process_rp_pio_error(struct pci_dev *pdev)
191191
{
192192
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;
194194
struct pcie_tlp_log tlp_log;
195195
int i;
196196

@@ -217,20 +217,19 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
217217

218218
if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG)
219219
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);
221223
pci_err(pdev, "TLP Header: %#010x %#010x %#010x %#010x\n",
222224
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]);
223227

224228
if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG + 1)
225229
goto clear_status;
226230
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log);
227231
pci_err(pdev, "RP PIO ImpSpec Log %#010x\n", log);
228232

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-
}
234233
clear_status:
235234
pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, status);
236235
}

drivers/pci/pcie/tlp.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,68 @@
1111

1212
#include "../pci.h"
1313

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+
*/
21+
unsigned 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+
*/
35+
unsigned 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+
1445
/**
1546
* pcie_read_tlp_log - read TLP Header Log
1647
* @dev: PCIe device
1748
* @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)
1851
* @log: TLP Log structure to fill
1952
*
2053
* Fill @log from TLP Header Log registers, e.g., AER or DPC.
2154
*
2255
* Return: 0 on success and filled TLP Log structure, <0 on error.
2356
*/
24-
int pcie_read_tlp_log(struct pci_dev *dev, int where,
25-
struct pcie_tlp_log *log)
57+
int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
58+
unsigned int tlp_len, struct pcie_tlp_log *log)
2659
{
2760
unsigned int i;
28-
int ret;
61+
int off, ret;
62+
u32 *to;
2963

3064
memset(log, 0, sizeof(*log));
3165

32-
for (i = 0; i < PCIE_STD_NUM_TLP_HEADERLOG; i++) {
33-
ret = pci_read_config_dword(dev, where + i * 4, &log->dw[i]);
66+
for (i = 0; i < tlp_len; 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);
3476
if (ret)
3577
return pcibios_err_to_errno(ret);
3678
}

include/linux/aer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct pci_dev;
2727

2828
struct pcie_tlp_log {
2929
u32 dw[PCIE_STD_NUM_TLP_HEADERLOG];
30+
u32 prefix[PCIE_STD_MAX_TLP_PREFIXLOG];
3031
};
3132

3233
struct aer_capability_regs {

include/uapi/linux/pci_regs.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -790,10 +790,11 @@
790790
/* Same bits as above */
791791
#define PCI_ERR_CAP 0x18 /* Advanced Error Capabilities & Ctrl*/
792792
#define PCI_ERR_CAP_FEP(x) ((x) & 0x1f) /* First Error Pointer */
793-
#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */
794-
#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */
795-
#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
796-
#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
793+
#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */
794+
#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */
795+
#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */
796+
#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */
797+
#define PCI_ERR_CAP_PREFIX_LOG_PRESENT 0x00000800 /* TLP Prefix Log Present */
797798
#define PCI_ERR_HEADER_LOG 0x1c /* Header Log Register (16 bytes) */
798799
#define PCI_ERR_ROOT_COMMAND 0x2c /* Root Error Command */
799800
#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 /* Correctable Err Reporting Enable */
@@ -809,6 +810,7 @@
809810
#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */
810811
#define PCI_ERR_ROOT_AER_IRQ 0xf8000000 /* Advanced Error Interrupt Message Number */
811812
#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) */
812814

813815
/* Virtual Channel */
814816
#define PCI_VC_PORT_CAP1 0x04

0 commit comments

Comments
 (0)