Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Wei Huang and committed by
Bjorn Helgaas
f69767a1 9852d85e

+285 -8
+4
Documentation/admin-guide/kernel-parameters.txt
··· 4678 4678 nomio [S390] Do not use MIO instructions. 4679 4679 norid [S390] ignore the RID field and force use of 4680 4680 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. 4681 4685 4682 4686 pcie_aspm= [PCIE] Forcibly enable or ignore PCIe Active State Power 4683 4687 Management.
+9
drivers/pci/Kconfig
··· 173 173 174 174 If unsure, say N. 175 175 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 + 176 185 config PCI_P2PDMA 177 186 bool "PCI peer-to-peer transfer support" 178 187 depends on ZONE_DEVICE
+1
drivers/pci/Makefile
··· 36 36 obj-$(CONFIG_PCI_DOE) += doe.o 37 37 obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o 38 38 obj-$(CONFIG_PCI_NPEM) += npem.o 39 + obj-$(CONFIG_PCIE_TPH) += tph.o 39 40 40 41 # Endpoint library must be initialized before its users 41 42 obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
+4
drivers/pci/pci.c
··· 1828 1828 pci_save_dpc_state(dev); 1829 1829 pci_save_aer_state(dev); 1830 1830 pci_save_ptm_state(dev); 1831 + pci_save_tph_state(dev); 1831 1832 return pci_save_vc_state(dev); 1832 1833 } 1833 1834 EXPORT_SYMBOL(pci_save_state); ··· 1934 1933 pci_restore_rebar_state(dev); 1935 1934 pci_restore_dpc_state(dev); 1936 1935 pci_restore_ptm_state(dev); 1936 + pci_restore_tph_state(dev); 1937 1937 1938 1938 pci_aer_clear_status(dev); 1939 1939 pci_restore_aer_state(dev); ··· 6898 6896 pci_no_domains(); 6899 6897 } else if (!strncmp(str, "noari", 5)) { 6900 6898 pcie_ari_disabled = true; 6899 + } else if (!strncmp(str, "notph", 5)) { 6900 + pci_no_tph(); 6901 6901 } else if (!strncmp(str, "cbiosize=", 9)) { 6902 6902 pci_cardbus_io_size = memparse(str + 9, &str); 6903 6903 } else if (!strncmp(str, "cbmemsize=", 10)) {
+12
drivers/pci/pci.h
··· 597 597 598 598 #endif /* CONFIG_PCI_IOV */ 599 599 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 + 600 612 #ifdef CONFIG_PCIE_PTM 601 613 void pci_ptm_init(struct pci_dev *dev); 602 614 void pci_save_ptm_state(struct pci_dev *dev);
+1
drivers/pci/probe.c
··· 2495 2495 pci_dpc_init(dev); /* Downstream Port Containment */ 2496 2496 pci_rcec_init(dev); /* Root Complex Event Collector */ 2497 2497 pci_doe_init(dev); /* Data Object Exchange */ 2498 + pci_tph_init(dev); /* TLP Processing Hints */ 2498 2499 2499 2500 pcie_report_downtraining(dev); 2500 2501 pci_init_reset_methods(dev);
+197
drivers/pci/tph.c
··· 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 + }
+21
include/linux/pci-tph.h
··· 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 */
+7
include/linux/pci.h
··· 434 434 unsigned int ats_enabled:1; /* Address Translation Svc */ 435 435 unsigned int pasid_enabled:1; /* Process Address Space ID */ 436 436 unsigned int pri_enabled:1; /* Page Request Interface */ 437 + unsigned int tph_enabled:1; /* TLP Processing Hints */ 437 438 unsigned int is_managed:1; /* Managed via devres */ 438 439 unsigned int is_msi_managed:1; /* MSI release via devres installed */ 439 440 unsigned int needs_freset:1; /* Requires fundamental reset */ ··· 535 534 536 535 /* These methods index pci_reset_fn_methods[] */ 537 536 u8 reset_methods[PCI_NUM_RESET_METHODS]; /* In priority order */ 537 + 538 + #ifdef CONFIG_PCIE_TPH 539 + u16 tph_cap; /* TPH capability offset */ 540 + u8 tph_mode; /* TPH mode */ 541 + u8 tph_req_type; /* TPH requester type */ 542 + #endif 538 543 }; 539 544 540 545 static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
+29 -8
include/uapi/linux/pci_regs.h
··· 340 340 #define PCI_MSIX_ENTRY_UPPER_ADDR 0x4 /* Message Upper Address */ 341 341 #define PCI_MSIX_ENTRY_DATA 0x8 /* Message Data */ 342 342 #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 */ 344 345 345 346 /* CompactPCI Hotswap Register */ 346 347 ··· 660 659 #define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* 64b AtomicOp completion */ 661 660 #define PCI_EXP_DEVCAP2_ATOMIC_COMP128 0x00000200 /* 128b AtomicOp completion */ 662 661 #define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */ 662 + #define PCI_EXP_DEVCAP2_TPH_COMP_MASK 0x00003000 /* TPH completer support */ 663 663 #define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */ 664 664 #define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */ 665 665 #define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */ ··· 1025 1023 #define PCI_DPA_CAP_SUBSTATE_MASK 0x1F /* # substates - 1 */ 1026 1024 #define PCI_DPA_BASE_SIZEOF 16 /* size with 0 substates */ 1027 1025 1026 + /* TPH Completer Support */ 1027 + #define PCI_EXP_DEVCAP2_TPH_COMP_NONE 0x0 /* None */ 1028 + #define PCI_EXP_DEVCAP2_TPH_COMP_TPH_ONLY 0x1 /* TPH only */ 1029 + #define PCI_EXP_DEVCAP2_TPH_COMP_EXT_TPH 0x3 /* TPH and Extended TPH */ 1030 + 1028 1031 /* TPH Requester */ 1029 1032 #define PCI_TPH_CAP 4 /* capability register */ 1030 - #define PCI_TPH_CAP_LOC_MASK 0x600 /* location mask */ 1031 - #define PCI_TPH_LOC_NONE 0x000 /* no location */ 1032 - #define PCI_TPH_LOC_CAP 0x200 /* in capability */ 1033 - #define PCI_TPH_LOC_MSIX 0x400 /* in MSI-X */ 1034 - #define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* ST table mask */ 1035 - #define PCI_TPH_CAP_ST_SHIFT 16 /* ST table shift */ 1036 - #define PCI_TPH_BASE_SIZEOF 0xc /* size with no ST table */ 1033 + #define PCI_TPH_CAP_ST_NS 0x00000001 /* No ST Mode Supported */ 1034 + #define PCI_TPH_CAP_ST_IV 0x00000002 /* Interrupt Vector Mode Supported */ 1035 + #define PCI_TPH_CAP_ST_DS 0x00000004 /* Device Specific Mode Supported */ 1036 + #define PCI_TPH_CAP_EXT_TPH 0x00000100 /* Ext TPH Requester Supported */ 1037 + #define PCI_TPH_CAP_LOC_MASK 0x00000600 /* ST Table Location */ 1038 + #define PCI_TPH_LOC_NONE 0x00000000 /* Not present */ 1039 + #define PCI_TPH_LOC_CAP 0x00000200 /* In capability */ 1040 + #define PCI_TPH_LOC_MSIX 0x00000400 /* In MSI-X */ 1041 + #define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* ST Table Size */ 1042 + #define PCI_TPH_CAP_ST_SHIFT 16 /* ST Table Size shift */ 1043 + #define PCI_TPH_BASE_SIZEOF 0xc /* Size with no ST table */ 1044 + 1045 + #define PCI_TPH_CTRL 8 /* control register */ 1046 + #define PCI_TPH_CTRL_MODE_SEL_MASK 0x00000007 /* ST Mode Select */ 1047 + #define PCI_TPH_ST_NS_MODE 0x0 /* No ST Mode */ 1048 + #define PCI_TPH_ST_IV_MODE 0x1 /* Interrupt Vector Mode */ 1049 + #define PCI_TPH_ST_DS_MODE 0x2 /* Device Specific Mode */ 1050 + #define PCI_TPH_CTRL_REQ_EN_MASK 0x00000300 /* TPH Requester Enable */ 1051 + #define PCI_TPH_REQ_DISABLE 0x0 /* No TPH requests allowed */ 1052 + #define PCI_TPH_REQ_TPH_ONLY 0x1 /* TPH only requests allowed */ 1053 + #define PCI_TPH_REQ_EXT_TPH 0x3 /* Extended TPH requests allowed */ 1037 1054 1038 1055 /* Downstream Port Containment */ 1039 1056 #define PCI_EXP_DPC_CAP 0x04 /* DPC Capability */