12. TPH 支持

版权所有:

2024 Advanced Micro Devices, Inc.

作者:

12.1. 概述

TPH (TLP 处理提示) 是一种 PCIe 功能,它允许端点设备为面向内存空间的请求提供优化提示。这些提示以转向标签 (Steering Tags, STs) 的格式嵌入在请求者的 TLP 报头中,使系统硬件(例如根联合体)能够更好地管理这些请求的平台资源。

例如,在支持基于 TPH 的直接数据缓存注入的平台上,端点设备可以在其 DMA 流量中包含适当的 ST,以指定数据应写入哪个缓存。这使得 CPU 核心从缓存中获取数据的可能性更高,从而可能提高性能并减少数据处理中的延迟。

12.2. 如何使用 TPH

TPH 在 PCIe 中作为可选的扩展功能呈现。Linux 内核在启动期间处理 TPH 的发现,但如果需要利用 TPH,则由设备驱动程序请求启用 TPH。一旦启用,驱动程序使用提供的 API 获取目标内存的转向标签,并将 ST 编程到设备的 ST 表中。

12.2.1. 在 Linux 中启用 TPH 支持

要支持 TPH,内核必须在启用 CONFIG_PCIE_TPH 选项的情况下构建。

12.2.2. 管理 TPH

要为设备启用 TPH,请使用以下函数

int pcie_enable_tph(struct pci_dev *pdev, int mode);

此函数为具有特定 ST 模式的设备启用 TPH 支持。当前支持的模式包括

  • PCI_TPH_ST_NS_MODE - 无 ST 模式

  • PCI_TPH_ST_IV_MODE - 中断向量模式

  • PCI_TPH_ST_DS_MODE - 设备特定模式

pcie_enable_tph() 在启用前会检查所请求的模式是否实际受设备支持。设备驱动程序可以根据 pcie_enable_tph() 的返回值判断支持哪种 TPH 模式并正确启用。

要禁用 TPH,请使用以下函数

void pcie_disable_tph(struct pci_dev *pdev);

12.2.3. 管理 ST

转向标签是平台特定的。PCIe 规范没有明确指定 ST 的来源。相反,PCI 固件规范定义了一个 ACPI _DSM 方法(参见 《针对缓存局部性 TPH 功能修订的 _DSM ECN》),用于检索具有各种属性的目标内存的 ST。此实现支持的就是这种方法。

要检索与特定 CPU 关联的目标内存的转向标签,请使用以下函数

int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type type,
                        unsigned int cpu_uid, u16 *tag);

参数 type 用于指定目标内存的类型,即易失性或持久性。参数 cpu_uid 指定内存关联的 CPU。

检索到 ST 值后,设备驱动程序可以使用以下函数将 ST 写入设备

int pcie_tph_set_st_entry(struct pci_dev *pdev, unsigned int index,
                          u16 tag);

参数 index 是要写入 ST 标签的 ST 表条目索引。pcie_tph_set_st_entry() 将确定 ST 表的正确位置(无论是在 MSI-X 表中还是在 TPH 扩展功能空间中),并将转向标签写入 index 参数指向的 ST 条目。

如何使用这些 TPH 函数完全由驱动程序决定。例如,当 RX/TX 队列的中断亲和性发生变化时,网络设备驱动程序可以使用上述 TPH API 更新转向标签。这是一个 IRQ 亲和性通知器的示例代码

static void irq_affinity_notified(struct irq_affinity_notify *notify,
                                  const cpumask_t *mask)
{
     struct drv_irq *irq;
     unsigned int cpu_id;
     u16 tag;

     irq = container_of(notify, struct drv_irq, affinity_notify);
     cpumask_copy(irq->cpu_mask, mask);

     /* Pick a right CPU as the target - here is just an example */
     cpu_id = cpumask_first(irq->cpu_mask);

     if (pcie_tph_get_cpu_st(irq->pdev, TPH_MEM_TYPE_VM, cpu_id,
                             &tag))
         return;

     if (pcie_tph_set_st_entry(irq->pdev, irq->msix_nr, tag))
         return;
}

12.2.4. 系统范围禁用 TPH

有一个内核命令行选项可用于控制 TPH 功能
  • “notph”:TPH 将对所有端点设备禁用。