Skip to content

Commit f69767a

Browse files
weihuang-amdbjorn-helgaas
authored andcommitted
PCI: Add TLP Processing Hints (TPH) support
Add support for PCIe TLP Processing Hints (TPH) support (see PCIe r6.2, sec 6.17). Add TPH register definitions in pci_regs.h, including the TPH Requester capability register, TPH Requester control register, TPH Completer capability, and the ST fields of MSI-X entry. Introduce pcie_enable_tph() and pcie_disable_tph(), enabling drivers to toggle TPH support and configure specific ST mode as needed. Also add a new kernel parameter, "pci=notph", allowing users to disable TPH support across the entire system. Link: https://lore.kernel.org/r/20241002165954.128085-2-wei.huang2@amd.com Co-developed-by: Jing Liu <jing2.liu@intel.com> Co-developed-by: Paul Luse <paul.e.luse@linux.intel.com> Co-developed-by: Eric Van Tassell <Eric.VanTassell@amd.com> Signed-off-by: Jing Liu <jing2.liu@intel.com> Signed-off-by: Paul Luse <paul.e.luse@linux.intel.com> Signed-off-by: Eric Van Tassell <Eric.VanTassell@amd.com> Signed-off-by: Wei Huang <wei.huang2@amd.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com> Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com> Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Lukas Wunner <lukas@wunner.de>
1 parent 9852d85 commit f69767a

File tree

10 files changed

+285
-8
lines changed

10 files changed

+285
-8
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4678,6 +4678,10 @@
46784678
nomio [S390] Do not use MIO instructions.
46794679
norid [S390] ignore the RID field and force use of
46804680
one PCI domain per PCI function
4681+
notph [PCIE] If the PCIE_TPH kernel config parameter
4682+
is enabled, this kernel boot option can be used
4683+
to disable PCIe TLP Processing Hints support
4684+
system-wide.
46814685

46824686
pcie_aspm= [PCIE] Forcibly enable or ignore PCIe Active State Power
46834687
Management.

drivers/pci/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,15 @@ config PCI_PASID
173173

174174
If unsure, say N.
175175

176+
config PCIE_TPH
177+
bool "TLP Processing Hints"
178+
help
179+
This option adds support for PCIe TLP Processing Hints (TPH).
180+
TPH allows endpoint devices to provide optimization hints, such as
181+
desired caching behavior, for requests that target memory space.
182+
These hints, called Steering Tags, can empower the system hardware
183+
to optimize the utilization of platform resources.
184+
176185
config PCI_P2PDMA
177186
bool "PCI peer-to-peer transfer support"
178187
depends on ZONE_DEVICE

drivers/pci/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ obj-$(CONFIG_VGA_ARB) += vgaarb.o
3636
obj-$(CONFIG_PCI_DOE) += doe.o
3737
obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o
3838
obj-$(CONFIG_PCI_NPEM) += npem.o
39+
obj-$(CONFIG_PCIE_TPH) += tph.o
3940

4041
# Endpoint library must be initialized before its users
4142
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/

drivers/pci/pci.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,6 +1828,7 @@ int pci_save_state(struct pci_dev *dev)
18281828
pci_save_dpc_state(dev);
18291829
pci_save_aer_state(dev);
18301830
pci_save_ptm_state(dev);
1831+
pci_save_tph_state(dev);
18311832
return pci_save_vc_state(dev);
18321833
}
18331834
EXPORT_SYMBOL(pci_save_state);
@@ -1933,6 +1934,7 @@ void pci_restore_state(struct pci_dev *dev)
19331934
pci_restore_rebar_state(dev);
19341935
pci_restore_dpc_state(dev);
19351936
pci_restore_ptm_state(dev);
1937+
pci_restore_tph_state(dev);
19361938

19371939
pci_aer_clear_status(dev);
19381940
pci_restore_aer_state(dev);
@@ -6896,6 +6898,8 @@ static int __init pci_setup(char *str)
68966898
pci_no_domains();
68976899
} else if (!strncmp(str, "noari", 5)) {
68986900
pcie_ari_disabled = true;
6901+
} else if (!strncmp(str, "notph", 5)) {
6902+
pci_no_tph();
68996903
} else if (!strncmp(str, "cbiosize=", 9)) {
69006904
pci_cardbus_io_size = memparse(str + 9, &str);
69016905
} else if (!strncmp(str, "cbmemsize=", 10)) {

drivers/pci/pci.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,18 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
597597

598598
#endif /* CONFIG_PCI_IOV */
599599

600+
#ifdef CONFIG_PCIE_TPH
601+
void pci_restore_tph_state(struct pci_dev *dev);
602+
void pci_save_tph_state(struct pci_dev *dev);
603+
void pci_no_tph(void);
604+
void pci_tph_init(struct pci_dev *dev);
605+
#else
606+
static inline void pci_restore_tph_state(struct pci_dev *dev) { }
607+
static inline void pci_save_tph_state(struct pci_dev *dev) { }
608+
static inline void pci_no_tph(void) { }
609+
static inline void pci_tph_init(struct pci_dev *dev) { }
610+
#endif
611+
600612
#ifdef CONFIG_PCIE_PTM
601613
void pci_ptm_init(struct pci_dev *dev);
602614
void pci_save_ptm_state(struct pci_dev *dev);

drivers/pci/probe.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2495,6 +2495,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
24952495
pci_dpc_init(dev); /* Downstream Port Containment */
24962496
pci_rcec_init(dev); /* Root Complex Event Collector */
24972497
pci_doe_init(dev); /* Data Object Exchange */
2498+
pci_tph_init(dev); /* TLP Processing Hints */
24982499

24992500
pcie_report_downtraining(dev);
25002501
pci_init_reset_methods(dev);

drivers/pci/tph.c

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* TPH (TLP Processing Hints) support
4+
*
5+
* Copyright (C) 2024 Advanced Micro Devices, Inc.
6+
* Eric Van Tassell <Eric.VanTassell@amd.com>
7+
* Wei Huang <wei.huang2@amd.com>
8+
*/
9+
#include <linux/pci.h>
10+
#include <linux/bitfield.h>
11+
#include <linux/pci-tph.h>
12+
13+
#include "pci.h"
14+
15+
/* System-wide TPH disabled */
16+
static bool pci_tph_disabled;
17+
18+
static u8 get_st_modes(struct pci_dev *pdev)
19+
{
20+
u32 reg;
21+
22+
pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CAP, &reg);
23+
reg &= PCI_TPH_CAP_ST_NS | PCI_TPH_CAP_ST_IV | PCI_TPH_CAP_ST_DS;
24+
25+
return reg;
26+
}
27+
28+
/* Return device's Root Port completer capability */
29+
static u8 get_rp_completer_type(struct pci_dev *pdev)
30+
{
31+
struct pci_dev *rp;
32+
u32 reg;
33+
int ret;
34+
35+
rp = pcie_find_root_port(pdev);
36+
if (!rp)
37+
return 0;
38+
39+
ret = pcie_capability_read_dword(rp, PCI_EXP_DEVCAP2, &reg);
40+
if (ret)
41+
return 0;
42+
43+
return FIELD_GET(PCI_EXP_DEVCAP2_TPH_COMP_MASK, reg);
44+
}
45+
46+
/**
47+
* pcie_disable_tph - Turn off TPH support for device
48+
* @pdev: PCI device
49+
*
50+
* Return: none
51+
*/
52+
void pcie_disable_tph(struct pci_dev *pdev)
53+
{
54+
if (!pdev->tph_cap)
55+
return;
56+
57+
if (!pdev->tph_enabled)
58+
return;
59+
60+
pci_write_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, 0);
61+
62+
pdev->tph_mode = 0;
63+
pdev->tph_req_type = 0;
64+
pdev->tph_enabled = 0;
65+
}
66+
EXPORT_SYMBOL(pcie_disable_tph);
67+
68+
/**
69+
* pcie_enable_tph - Enable TPH support for device using a specific ST mode
70+
* @pdev: PCI device
71+
* @mode: ST mode to enable. Current supported modes include:
72+
*
73+
* - PCI_TPH_ST_NS_MODE: NO ST Mode
74+
* - PCI_TPH_ST_IV_MODE: Interrupt Vector Mode
75+
* - PCI_TPH_ST_DS_MODE: Device Specific Mode
76+
*
77+
* Check whether the mode is actually supported by the device before enabling
78+
* and return an error if not. Additionally determine what types of requests,
79+
* TPH or extended TPH, can be issued by the device based on its TPH requester
80+
* capability and the Root Port's completer capability.
81+
*
82+
* Return: 0 on success, otherwise negative value (-errno)
83+
*/
84+
int pcie_enable_tph(struct pci_dev *pdev, int mode)
85+
{
86+
u32 reg;
87+
u8 dev_modes;
88+
u8 rp_req_type;
89+
90+
/* Honor "notph" kernel parameter */
91+
if (pci_tph_disabled)
92+
return -EINVAL;
93+
94+
if (!pdev->tph_cap)
95+
return -EINVAL;
96+
97+
if (pdev->tph_enabled)
98+
return -EBUSY;
99+
100+
/* Sanitize and check ST mode compatibility */
101+
mode &= PCI_TPH_CTRL_MODE_SEL_MASK;
102+
dev_modes = get_st_modes(pdev);
103+
if (!((1 << mode) & dev_modes))
104+
return -EINVAL;
105+
106+
pdev->tph_mode = mode;
107+
108+
/* Get req_type supported by device and its Root Port */
109+
pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CAP, &reg);
110+
if (FIELD_GET(PCI_TPH_CAP_EXT_TPH, reg))
111+
pdev->tph_req_type = PCI_TPH_REQ_EXT_TPH;
112+
else
113+
pdev->tph_req_type = PCI_TPH_REQ_TPH_ONLY;
114+
115+
rp_req_type = get_rp_completer_type(pdev);
116+
117+
/* Final req_type is the smallest value of two */
118+
pdev->tph_req_type = min(pdev->tph_req_type, rp_req_type);
119+
120+
if (pdev->tph_req_type == PCI_TPH_REQ_DISABLE)
121+
return -EINVAL;
122+
123+
/* Write them into TPH control register */
124+
pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, &reg);
125+
126+
reg &= ~PCI_TPH_CTRL_MODE_SEL_MASK;
127+
reg |= FIELD_PREP(PCI_TPH_CTRL_MODE_SEL_MASK, pdev->tph_mode);
128+
129+
reg &= ~PCI_TPH_CTRL_REQ_EN_MASK;
130+
reg |= FIELD_PREP(PCI_TPH_CTRL_REQ_EN_MASK, pdev->tph_req_type);
131+
132+
pci_write_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, reg);
133+
134+
pdev->tph_enabled = 1;
135+
136+
return 0;
137+
}
138+
EXPORT_SYMBOL(pcie_enable_tph);
139+
140+
void pci_restore_tph_state(struct pci_dev *pdev)
141+
{
142+
struct pci_cap_saved_state *save_state;
143+
u32 *cap;
144+
145+
if (!pdev->tph_cap)
146+
return;
147+
148+
if (!pdev->tph_enabled)
149+
return;
150+
151+
save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_TPH);
152+
if (!save_state)
153+
return;
154+
155+
/* Restore control register and all ST entries */
156+
cap = &save_state->cap.data[0];
157+
pci_write_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, *cap++);
158+
}
159+
160+
void pci_save_tph_state(struct pci_dev *pdev)
161+
{
162+
struct pci_cap_saved_state *save_state;
163+
u32 *cap;
164+
165+
if (!pdev->tph_cap)
166+
return;
167+
168+
if (!pdev->tph_enabled)
169+
return;
170+
171+
save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_TPH);
172+
if (!save_state)
173+
return;
174+
175+
/* Save control register */
176+
cap = &save_state->cap.data[0];
177+
pci_read_config_dword(pdev, pdev->tph_cap + PCI_TPH_CTRL, cap++);
178+
}
179+
180+
void pci_no_tph(void)
181+
{
182+
pci_tph_disabled = true;
183+
184+
pr_info("PCIe TPH is disabled\n");
185+
}
186+
187+
void pci_tph_init(struct pci_dev *pdev)
188+
{
189+
u32 save_size;
190+
191+
pdev->tph_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_TPH);
192+
if (!pdev->tph_cap)
193+
return;
194+
195+
save_size = sizeof(u32);
196+
pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_TPH, save_size);
197+
}

include/linux/pci-tph.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* TPH (TLP Processing Hints)
4+
*
5+
* Copyright (C) 2024 Advanced Micro Devices, Inc.
6+
* Eric Van Tassell <Eric.VanTassell@amd.com>
7+
* Wei Huang <wei.huang2@amd.com>
8+
*/
9+
#ifndef LINUX_PCI_TPH_H
10+
#define LINUX_PCI_TPH_H
11+
12+
#ifdef CONFIG_PCIE_TPH
13+
void pcie_disable_tph(struct pci_dev *pdev);
14+
int pcie_enable_tph(struct pci_dev *pdev, int mode);
15+
#else
16+
static inline void pcie_disable_tph(struct pci_dev *pdev) { }
17+
static inline int pcie_enable_tph(struct pci_dev *pdev, int mode)
18+
{ return -EINVAL; }
19+
#endif
20+
21+
#endif /* LINUX_PCI_TPH_H */

include/linux/pci.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ struct pci_dev {
434434
unsigned int ats_enabled:1; /* Address Translation Svc */
435435
unsigned int pasid_enabled:1; /* Process Address Space ID */
436436
unsigned int pri_enabled:1; /* Page Request Interface */
437+
unsigned int tph_enabled:1; /* TLP Processing Hints */
437438
unsigned int is_managed:1; /* Managed via devres */
438439
unsigned int is_msi_managed:1; /* MSI release via devres installed */
439440
unsigned int needs_freset:1; /* Requires fundamental reset */
@@ -534,6 +535,12 @@ struct pci_dev {
534535

535536
/* These methods index pci_reset_fn_methods[] */
536537
u8 reset_methods[PCI_NUM_RESET_METHODS]; /* In priority order */
538+
539+
#ifdef CONFIG_PCIE_TPH
540+
u16 tph_cap; /* TPH capability offset */
541+
u8 tph_mode; /* TPH mode */
542+
u8 tph_req_type; /* TPH requester type */
543+
#endif
537544
};
538545

539546
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)

include/uapi/linux/pci_regs.h

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,8 @@
340340
#define PCI_MSIX_ENTRY_UPPER_ADDR 0x4 /* Message Upper Address */
341341
#define PCI_MSIX_ENTRY_DATA 0x8 /* Message Data */
342342
#define PCI_MSIX_ENTRY_VECTOR_CTRL 0xc /* Vector Control */
343-
#define PCI_MSIX_ENTRY_CTRL_MASKBIT 0x00000001
343+
#define PCI_MSIX_ENTRY_CTRL_MASKBIT 0x00000001 /* Mask Bit */
344+
#define PCI_MSIX_ENTRY_CTRL_ST 0xffff0000 /* Steering Tag */
344345

345346
/* CompactPCI Hotswap Register */
346347

@@ -659,6 +660,7 @@
659660
#define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* 64b AtomicOp completion */
660661
#define PCI_EXP_DEVCAP2_ATOMIC_COMP128 0x00000200 /* 128b AtomicOp completion */
661662
#define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */
663+
#define PCI_EXP_DEVCAP2_TPH_COMP_MASK 0x00003000 /* TPH completer support */
662664
#define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */
663665
#define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */
664666
#define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */
@@ -1023,15 +1025,34 @@
10231025
#define PCI_DPA_CAP_SUBSTATE_MASK 0x1F /* # substates - 1 */
10241026
#define PCI_DPA_BASE_SIZEOF 16 /* size with 0 substates */
10251027

1028+
/* TPH Completer Support */
1029+
#define PCI_EXP_DEVCAP2_TPH_COMP_NONE 0x0 /* None */
1030+
#define PCI_EXP_DEVCAP2_TPH_COMP_TPH_ONLY 0x1 /* TPH only */
1031+
#define PCI_EXP_DEVCAP2_TPH_COMP_EXT_TPH 0x3 /* TPH and Extended TPH */
1032+
10261033
/* TPH Requester */
10271034
#define PCI_TPH_CAP 4 /* capability register */
1028-
#define PCI_TPH_CAP_LOC_MASK 0x600 /* location mask */
1029-
#define PCI_TPH_LOC_NONE 0x000 /* no location */
1030-
#define PCI_TPH_LOC_CAP 0x200 /* in capability */
1031-
#define PCI_TPH_LOC_MSIX 0x400 /* in MSI-X */
1032-
#define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* ST table mask */
1033-
#define PCI_TPH_CAP_ST_SHIFT 16 /* ST table shift */
1034-
#define PCI_TPH_BASE_SIZEOF 0xc /* size with no ST table */
1035+
#define PCI_TPH_CAP_ST_NS 0x00000001 /* No ST Mode Supported */
1036+
#define PCI_TPH_CAP_ST_IV 0x00000002 /* Interrupt Vector Mode Supported */
1037+
#define PCI_TPH_CAP_ST_DS 0x00000004 /* Device Specific Mode Supported */
1038+
#define PCI_TPH_CAP_EXT_TPH 0x00000100 /* Ext TPH Requester Supported */
1039+
#define PCI_TPH_CAP_LOC_MASK 0x00000600 /* ST Table Location */
1040+
#define PCI_TPH_LOC_NONE 0x00000000 /* Not present */
1041+
#define PCI_TPH_LOC_CAP 0x00000200 /* In capability */
1042+
#define PCI_TPH_LOC_MSIX 0x00000400 /* In MSI-X */
1043+
#define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* ST Table Size */
1044+
#define PCI_TPH_CAP_ST_SHIFT 16 /* ST Table Size shift */
1045+
#define PCI_TPH_BASE_SIZEOF 0xc /* Size with no ST table */
1046+
1047+
#define PCI_TPH_CTRL 8 /* control register */
1048+
#define PCI_TPH_CTRL_MODE_SEL_MASK 0x00000007 /* ST Mode Select */
1049+
#define PCI_TPH_ST_NS_MODE 0x0 /* No ST Mode */
1050+
#define PCI_TPH_ST_IV_MODE 0x1 /* Interrupt Vector Mode */
1051+
#define PCI_TPH_ST_DS_MODE 0x2 /* Device Specific Mode */
1052+
#define PCI_TPH_CTRL_REQ_EN_MASK 0x00000300 /* TPH Requester Enable */
1053+
#define PCI_TPH_REQ_DISABLE 0x0 /* No TPH requests allowed */
1054+
#define PCI_TPH_REQ_TPH_ONLY 0x1 /* TPH only requests allowed */
1055+
#define PCI_TPH_REQ_EXT_TPH 0x3 /* Extended TPH requests allowed */
10351056

10361057
/* Downstream Port Containment */
10371058
#define PCI_EXP_DPC_CAP 0x04 /* DPC Capability */

0 commit comments

Comments
 (0)