Skip to content

Commit f4a0927

Browse files
committed
Merge branch 'pci/err'
- Unexport pcie_read_tlp_log() to encourage drivers to use PCI core logging rather than building their own (Ilpo Järvinen) - Move TLP Log handling to its own file (Ilpo Järvinen) - Add #defines for TLP Header/Prefix log sizes (Ilpo Järvinen) - Store number of supported End-End TLP Prefixes always so we can read the correct number of DWORDs from the TLP Prefix Log (Ilpo Järvinen) - Read TLP Prefixes in addition to the Header Log in pcie_read_tlp_log() (Ilpo Järvinen) - Add pcie_print_tlp_log() to consolidate printing of TLP Header and Prefix Log (Ilpo Järvinen) * pci/err: PCI: Add pcie_print_tlp_log() to print TLP Header and Prefix Log PCI: Add TLP Prefix reading to pcie_read_tlp_log() PCI: Store number of supported End-End TLP Prefixes PCI: Use unsigned int i in pcie_read_tlp_log() PCI: Use same names in pcie_read_tlp_log() prototype and definition PCI: Add defines for TLP Header/Prefix log sizes PCI: Move TLP Log handling to its own file PCI: Don't expose pcie_read_tlp_log() outside PCI subsystem
2 parents 5a1d568 + f68ea77 commit f4a0927

File tree

12 files changed

+172
-66
lines changed

12 files changed

+172
-66
lines changed

drivers/pci/ats.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ int pci_enable_pasid(struct pci_dev *pdev, int features)
410410
if (WARN_ON(pdev->pasid_enabled))
411411
return -EBUSY;
412412

413-
if (!pdev->eetlp_prefix_path && !pdev->pasid_no_tlp)
413+
if (!pdev->eetlp_prefix_max && !pdev->pasid_no_tlp)
414414
return -EINVAL;
415415

416416
if (!pasid)

drivers/pci/pci.c

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,34 +1099,6 @@ static void pci_enable_acs(struct pci_dev *dev)
10991099
pci_write_config_word(dev, pos + PCI_ACS_CTRL, caps.ctrl);
11001100
}
11011101

1102-
/**
1103-
* pcie_read_tlp_log - read TLP Header Log
1104-
* @dev: PCIe device
1105-
* @where: PCI Config offset of TLP Header Log
1106-
* @tlp_log: TLP Log structure to fill
1107-
*
1108-
* Fill @tlp_log from TLP Header Log registers, e.g., AER or DPC.
1109-
*
1110-
* Return: 0 on success and filled TLP Log structure, <0 on error.
1111-
*/
1112-
int pcie_read_tlp_log(struct pci_dev *dev, int where,
1113-
struct pcie_tlp_log *tlp_log)
1114-
{
1115-
int i, ret;
1116-
1117-
memset(tlp_log, 0, sizeof(*tlp_log));
1118-
1119-
for (i = 0; i < 4; i++) {
1120-
ret = pci_read_config_dword(dev, where + i * 4,
1121-
&tlp_log->dw[i]);
1122-
if (ret)
1123-
return pcibios_err_to_errno(ret);
1124-
}
1125-
1126-
return 0;
1127-
}
1128-
EXPORT_SYMBOL_GPL(pcie_read_tlp_log);
1129-
11301102
/**
11311103
* pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
11321104
* @dev: PCI device to have its BARs restored

drivers/pci/pci.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include <linux/pci.h>
66

7+
struct pcie_tlp_log;
8+
79
/* Number of possible devfns: 0.0 to 1f.7 inclusive */
810
#define MAX_NR_DEVFNS 256
911

@@ -549,6 +551,12 @@ struct aer_err_info {
549551

550552
int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
551553
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
554+
555+
int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2,
556+
unsigned int tlp_len, struct pcie_tlp_log *log);
557+
unsigned int aer_tlp_log_len(struct pci_dev *dev, u32 aercc);
558+
void pcie_print_tlp_log(const struct pci_dev *dev,
559+
const struct pcie_tlp_log *log, const char *pfx);
552560
#endif /* CONFIG_PCIEAER */
553561

554562
#ifdef CONFIG_PCIEPORTBUS
@@ -567,6 +575,7 @@ void pci_dpc_init(struct pci_dev *pdev);
567575
void dpc_process_error(struct pci_dev *pdev);
568576
pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);
569577
bool pci_dpc_recovered(struct pci_dev *pdev);
578+
unsigned int dpc_tlp_log_len(struct pci_dev *dev);
570579
#else
571580
static inline void pci_save_dpc_state(struct pci_dev *dev) { }
572581
static inline void pci_restore_dpc_state(struct pci_dev *dev) { }

drivers/pci/pcie/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pcieportdrv-y := portdrv.o rcec.o
77
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o bwctrl.o
88

99
obj-y += aspm.o
10-
obj-$(CONFIG_PCIEAER) += aer.o err.o
10+
obj-$(CONFIG_PCIEAER) += aer.o err.o tlp.o
1111
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
1212
obj-$(CONFIG_PCIE_PME) += pme.o
1313
obj-$(CONFIG_PCIE_DPC) += dpc.o

drivers/pci/pcie/aer.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -665,12 +665,6 @@ static void pci_rootport_aer_stats_incr(struct pci_dev *pdev,
665665
}
666666
}
667667

668-
static void __print_tlp_header(struct pci_dev *dev, struct pcie_tlp_log *t)
669-
{
670-
pci_err(dev, " TLP Header: %08x %08x %08x %08x\n",
671-
t->dw[0], t->dw[1], t->dw[2], t->dw[3]);
672-
}
673-
674668
static void __aer_print_error(struct pci_dev *dev,
675669
struct aer_err_info *info)
676670
{
@@ -725,7 +719,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
725719
__aer_print_error(dev, info);
726720

727721
if (info->tlp_header_valid)
728-
__print_tlp_header(dev, &info->tlp);
722+
pcie_print_tlp_log(dev, &info->tlp, dev_fmt(" "));
729723

730724
out:
731725
if (info->id && info->error_dev_num > 1 && info->id == id)
@@ -797,7 +791,7 @@ void pci_print_aer(struct pci_dev *dev, int aer_severity,
797791
aer->uncor_severity);
798792

799793
if (tlp_header_valid)
800-
__print_tlp_header(dev, &aer->header_log);
794+
pcie_print_tlp_log(dev, &aer->header_log, dev_fmt(" "));
801795

802796
trace_aer_event(dev_name(&dev->dev), (status & ~mask),
803797
aer_severity, tlp_header_valid, &aer->header_log);
@@ -1248,7 +1242,10 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
12481242

12491243
if (info->status & AER_LOG_TLP_MASKS) {
12501244
info->tlp_header_valid = 1;
1251-
pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG, &info->tlp);
1245+
pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG,
1246+
aer + PCI_ERR_PREFIX_LOG,
1247+
aer_tlp_log_len(dev, aercc),
1248+
&info->tlp);
12521249
}
12531250
}
12541251

drivers/pci/pcie/dpc.c

Lines changed: 10 additions & 12 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

@@ -215,22 +215,18 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
215215
first_error == i ? " (First)" : "");
216216
}
217217

218-
if (pdev->dpc_rp_log_size < 4)
218+
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);
221-
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]);
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);
223+
pcie_print_tlp_log(pdev, &tlp_log, dev_fmt(""));
223224

224-
if (pdev->dpc_rp_log_size < 5)
225+
if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG + 1)
225226
goto clear_status;
226227
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_IMPSPEC_LOG, &log);
227228
pci_err(pdev, "RP PIO ImpSpec Log %#010x\n", log);
228229

229-
for (i = 0; i < pdev->dpc_rp_log_size - 5; 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-
}
234230
clear_status:
235231
pci_write_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, status);
236232
}
@@ -404,7 +400,9 @@ void pci_dpc_init(struct pci_dev *pdev)
404400
if (!pdev->dpc_rp_log_size) {
405401
pdev->dpc_rp_log_size =
406402
FIELD_GET(PCI_EXP_DPC_RP_PIO_LOG_SIZE, cap);
407-
if (pdev->dpc_rp_log_size < 4 || pdev->dpc_rp_log_size > 9) {
403+
if (pdev->dpc_rp_log_size < PCIE_STD_NUM_TLP_HEADERLOG ||
404+
pdev->dpc_rp_log_size > PCIE_STD_NUM_TLP_HEADERLOG + 1 +
405+
PCIE_STD_MAX_TLP_PREFIXLOG) {
408406
pci_err(pdev, "RP PIO log size %u is invalid\n",
409407
pdev->dpc_rp_log_size);
410408
pdev->dpc_rp_log_size = 0;

drivers/pci/pcie/tlp.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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+
}

drivers/pci/probe.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,8 +2294,8 @@ static void pci_configure_relaxed_ordering(struct pci_dev *dev)
22942294

22952295
static void pci_configure_eetlp_prefix(struct pci_dev *dev)
22962296
{
2297-
#ifdef CONFIG_PCI_PASID
22982297
struct pci_dev *bridge;
2298+
unsigned int eetlp_max;
22992299
int pcie_type;
23002300
u32 cap;
23012301

@@ -2307,15 +2307,19 @@ static void pci_configure_eetlp_prefix(struct pci_dev *dev)
23072307
return;
23082308

23092309
pcie_type = pci_pcie_type(dev);
2310+
2311+
eetlp_max = FIELD_GET(PCI_EXP_DEVCAP2_EE_PREFIX_MAX, cap);
2312+
/* 00b means 4 */
2313+
eetlp_max = eetlp_max ?: 4;
2314+
23102315
if (pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
23112316
pcie_type == PCI_EXP_TYPE_RC_END)
2312-
dev->eetlp_prefix_path = 1;
2317+
dev->eetlp_prefix_max = eetlp_max;
23132318
else {
23142319
bridge = pci_upstream_bridge(dev);
2315-
if (bridge && bridge->eetlp_prefix_path)
2316-
dev->eetlp_prefix_path = 1;
2320+
if (bridge && bridge->eetlp_prefix_max)
2321+
dev->eetlp_prefix_max = eetlp_max;
23172322
}
2318-
#endif
23192323
}
23202324

23212325
static void pci_configure_serr(struct pci_dev *dev)

drivers/pci/quirks.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* file, where their drivers can use them.
1313
*/
1414

15+
#include <linux/aer.h>
1516
#include <linux/align.h>
1617
#include <linux/bitfield.h>
1718
#include <linux/types.h>
@@ -6233,8 +6234,9 @@ static void dpc_log_size(struct pci_dev *dev)
62336234
return;
62346235

62356236
if (FIELD_GET(PCI_EXP_DPC_RP_PIO_LOG_SIZE, val) == 0) {
6236-
pci_info(dev, "Overriding RP PIO Log Size to 4\n");
6237-
dev->dpc_rp_log_size = 4;
6237+
pci_info(dev, "Overriding RP PIO Log Size to %d\n",
6238+
PCIE_STD_NUM_TLP_HEADERLOG);
6239+
dev->dpc_rp_log_size = PCIE_STD_NUM_TLP_HEADERLOG;
62386240
}
62396241
}
62406242
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x461f, dpc_log_size);

include/linux/aer.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,18 @@
1616
#define AER_CORRECTABLE 2
1717
#define DPC_FATAL 3
1818

19+
/*
20+
* AER and DPC capabilities TLP Logging register sizes (PCIe r6.2, sec 7.8.4
21+
* & 7.9.14).
22+
*/
23+
#define PCIE_STD_NUM_TLP_HEADERLOG 4
24+
#define PCIE_STD_MAX_TLP_PREFIXLOG 4
25+
1926
struct pci_dev;
2027

2128
struct pcie_tlp_log {
22-
u32 dw[4];
29+
u32 dw[PCIE_STD_NUM_TLP_HEADERLOG];
30+
u32 prefix[PCIE_STD_MAX_TLP_PREFIXLOG];
2331
};
2432

2533
struct aer_capability_regs {
@@ -37,8 +45,6 @@ struct aer_capability_regs {
3745
u16 uncor_err_source;
3846
};
3947

40-
int pcie_read_tlp_log(struct pci_dev *dev, int where, struct pcie_tlp_log *log);
41-
4248
#if defined(CONFIG_PCIEAER)
4349
int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
4450
int pcie_aer_is_native(struct pci_dev *dev);

0 commit comments

Comments
 (0)