Skip to content

Commit ab02baf

Browse files
committed
Merge branch 'pci/tph'
- Add and document TLP Processing Hints (TPH) support so drivers can enable and disable TPH and the kernel can save/restore TPH configuration (Wei Huang) - Add TPH Steering Tag support so drivers can retrieve Steering Tag values associated with specific CPUs via an ACPI _DSM to direct DMA writes closer to their consumers (Wei Huang) * pci/tph: PCI/TPH: Add TPH documentation PCI/TPH: Add Steering Tag support PCI: Add TLP Processing Hints (TPH) support
2 parents efcbd9d + 48d0fd2 commit ab02baf

File tree

13 files changed

+794
-8
lines changed

13 files changed

+794
-8
lines changed

Documentation/PCI/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ PCI Bus Subsystem
1818
pcieaer-howto
1919
endpoint/index
2020
boot-interrupts
21+
tph

Documentation/PCI/tph.rst

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
4+
===========
5+
TPH Support
6+
===========
7+
8+
:Copyright: 2024 Advanced Micro Devices, Inc.
9+
:Authors: - Eric van Tassell <eric.vantassell@amd.com>
10+
- Wei Huang <wei.huang2@amd.com>
11+
12+
13+
Overview
14+
========
15+
16+
TPH (TLP Processing Hints) is a PCIe feature that allows endpoint devices
17+
to provide optimization hints for requests that target memory space.
18+
These hints, in a format called Steering Tags (STs), are embedded in the
19+
requester's TLP headers, enabling the system hardware, such as the Root
20+
Complex, to better manage platform resources for these requests.
21+
22+
For example, on platforms with TPH-based direct data cache injection
23+
support, an endpoint device can include appropriate STs in its DMA
24+
traffic to specify which cache the data should be written to. This allows
25+
the CPU core to have a higher probability of getting data from cache,
26+
potentially improving performance and reducing latency in data
27+
processing.
28+
29+
30+
How to Use TPH
31+
==============
32+
33+
TPH is presented as an optional extended capability in PCIe. The Linux
34+
kernel handles TPH discovery during boot, but it is up to the device
35+
driver to request TPH enablement if it is to be utilized. Once enabled,
36+
the driver uses the provided API to obtain the Steering Tag for the
37+
target memory and to program the ST into the device's ST table.
38+
39+
Enable TPH support in Linux
40+
---------------------------
41+
42+
To support TPH, the kernel must be built with the CONFIG_PCIE_TPH option
43+
enabled.
44+
45+
Manage TPH
46+
----------
47+
48+
To enable TPH for a device, use the following function::
49+
50+
int pcie_enable_tph(struct pci_dev *pdev, int mode);
51+
52+
This function enables TPH support for device with a specific ST mode.
53+
Current supported modes include:
54+
55+
* PCI_TPH_ST_NS_MODE - NO ST Mode
56+
* PCI_TPH_ST_IV_MODE - Interrupt Vector Mode
57+
* PCI_TPH_ST_DS_MODE - Device Specific Mode
58+
59+
`pcie_enable_tph()` checks whether the requested mode is actually
60+
supported by the device before enabling. The device driver can figure out
61+
which TPH mode is supported and can be properly enabled based on the
62+
return value of `pcie_enable_tph()`.
63+
64+
To disable TPH, use the following function::
65+
66+
void pcie_disable_tph(struct pci_dev *pdev);
67+
68+
Manage ST
69+
---------
70+
71+
Steering Tags are platform specific. PCIe spec does not specify where STs
72+
are from. Instead PCI Firmware Specification defines an ACPI _DSM method
73+
(see the `Revised _DSM for Cache Locality TPH Features ECN
74+
<https://members.pcisig.com/wg/PCI-SIG/document/15470>`_) for retrieving
75+
STs for a target memory of various properties. This method is what is
76+
supported in this implementation.
77+
78+
To retrieve a Steering Tag for a target memory associated with a specific
79+
CPU, use the following function::
80+
81+
int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type type,
82+
unsigned int cpu_uid, u16 *tag);
83+
84+
The `type` argument is used to specify the memory type, either volatile
85+
or persistent, of the target memory. The `cpu_uid` argument specifies the
86+
CPU where the memory is associated to.
87+
88+
After the ST value is retrieved, the device driver can use the following
89+
function to write the ST into the device::
90+
91+
int pcie_tph_set_st_entry(struct pci_dev *pdev, unsigned int index,
92+
u16 tag);
93+
94+
The `index` argument is the ST table entry index the ST tag will be
95+
written into. `pcie_tph_set_st_entry()` will figure out the proper
96+
location of ST table, either in the MSI-X table or in the TPH Extended
97+
Capability space, and write the Steering Tag into the ST entry pointed by
98+
the `index` argument.
99+
100+
It is completely up to the driver to decide how to use these TPH
101+
functions. For example a network device driver can use the TPH APIs above
102+
to update the Steering Tag when interrupt affinity of a RX/TX queue has
103+
been changed. Here is a sample code for IRQ affinity notifier:
104+
105+
.. code-block:: c
106+
107+
static void irq_affinity_notified(struct irq_affinity_notify *notify,
108+
const cpumask_t *mask)
109+
{
110+
struct drv_irq *irq;
111+
unsigned int cpu_id;
112+
u16 tag;
113+
114+
irq = container_of(notify, struct drv_irq, affinity_notify);
115+
cpumask_copy(irq->cpu_mask, mask);
116+
117+
/* Pick a right CPU as the target - here is just an example */
118+
cpu_id = cpumask_first(irq->cpu_mask);
119+
120+
if (pcie_tph_get_cpu_st(irq->pdev, TPH_MEM_TYPE_VM, cpu_id,
121+
&tag))
122+
return;
123+
124+
if (pcie_tph_set_st_entry(irq->pdev, irq->msix_nr, tag))
125+
return;
126+
}
127+
128+
Disable TPH system-wide
129+
-----------------------
130+
131+
There is a kernel command line option available to control TPH feature:
132+
* "notph": TPH will be disabled for all endpoint devices.

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.

Documentation/driver-api/pci/pci.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ PCI Support Library
4646
.. kernel-doc:: drivers/pci/pci-sysfs.c
4747
:internal:
4848

49+
.. kernel-doc:: drivers/pci/tph.c
50+
:export:
51+
4952
PCI Hotplug Support Library
5053
---------------------------
5154

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);
@@ -6925,6 +6927,8 @@ static int __init pci_setup(char *str)
69256927
pci_no_domains();
69266928
} else if (!strncmp(str, "noari", 5)) {
69276929
pcie_ari_disabled = true;
6930+
} else if (!strncmp(str, "notph", 5)) {
6931+
pci_no_tph();
69286932
} else if (!strncmp(str, "cbiosize=", 9)) {
69296933
pci_cardbus_io_size = memparse(str + 9, &str);
69306934
} else if (!strncmp(str, "cbmemsize=", 10)) {

drivers/pci/pci.h

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

639639
#endif /* CONFIG_PCI_IOV */
640640

641+
#ifdef CONFIG_PCIE_TPH
642+
void pci_restore_tph_state(struct pci_dev *dev);
643+
void pci_save_tph_state(struct pci_dev *dev);
644+
void pci_no_tph(void);
645+
void pci_tph_init(struct pci_dev *dev);
646+
#else
647+
static inline void pci_restore_tph_state(struct pci_dev *dev) { }
648+
static inline void pci_save_tph_state(struct pci_dev *dev) { }
649+
static inline void pci_no_tph(void) { }
650+
static inline void pci_tph_init(struct pci_dev *dev) { }
651+
#endif
652+
641653
#ifdef CONFIG_PCIE_PTM
642654
void pci_ptm_init(struct pci_dev *dev);
643655
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
@@ -2516,6 +2516,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
25162516
pci_dpc_init(dev); /* Downstream Port Containment */
25172517
pci_rcec_init(dev); /* Root Complex Event Collector */
25182518
pci_doe_init(dev); /* Data Object Exchange */
2519+
pci_tph_init(dev); /* TLP Processing Hints */
25192520

25202521
pcie_report_downtraining(dev);
25212522
pci_init_reset_methods(dev);

0 commit comments

Comments
 (0)