# PCI/PCIe(7): TLP processing hints(TPH)
## Overview
TLP processing hints(TPH) 是由 [PCI-SIG](https://en.wikipedia.org/wiki/PCI-SIG) 所規範,一種可用於最佳化 PCIe 效能的可選機制。其允許 Requester 為記憶體空間的存取提供提示,告知其將要進行的記憶體存取之 pattern。則 Completer 可以根據提示更佳的管理系統資源。例如,Requester 可以指定資料應寫入哪個 cache,使得 host 更容易從 cache 中獲取資料,進而能提高效能並降低延遲。
TPH 旨在應用於以記憶體空間為目標的 transaction,適用於 device to host、device to deivce 和 host to device 的傳輸類型。在任何情況下,要支援 TPH,Requester、Completer 和所有中間的 Router 都必須支援相關的 TPH 功能。
對於 TPH 的詳細說明,可參考 PCIe 規格書 6.17 TLP Processing Hints (TPH)。
## Processing Hint(PH)
### TH
TLP header 的第一個 DWORD 中,TH bit 用於表示是否封包中是否存在 TPH 資訊。
* TH: 等於 1 表示存在 TPH

### Processing Hint(PH)
對於 Completer 無法準確推斷存取方式,只有 Requester 了解即將發生的請求之 pattern 的狀況,通過 TPH 讓 Requester 向 Root Complex 提示預期如何使用資料,可以優化效能。需要此類提示的情況包括:
* DWHR:device 寫入後 host 很快就會讀取
* HWDR:device 將讀取 host 最近寫入的數據
* DWDW、DWDR、DRDW、DRDR:device 寫入/讀取後,device 很快又進行了後續讀取/寫入
* 雙向(Bi-Directional): 資料結構由 host 和 device 共用且雙方具有同等讀取/寫入存取權限
這些資訊被編碼在 Processing Hint(PH) 欄位中。當 TH=1 時,PH 可以生效。
| PH[1:0] | Processing Hint | Usage Model |
|:------- |:----------------------------- |:------------------------------------------------ |
| 00 | Bi-directional data structure | Host 和 device 雙方頻繁對資料讀寫 |
| 01 | Requester | device 頻繁對資料讀寫(D\*D\*) |
| 10 | Target | host 頻繁對資料讀寫(DWHR/HWDR) |
| 11 | Target with Priority | host 頻繁對資料讀寫 +所訪問資料具有高度 temporal locality |
PH 在 TLP header 中的位置如下表所示。

## Steering Tag(ST)
為了讓 Request 能連結到特定的處理資源(例如 host processor 或 cache),Requester 會需要在封包中嵌入一個特定於系統的值,用以指示系統(如 Root Complex)將資料存放在特定的 Cache Hierarchy 中,從而提升 Cache 利用率,最佳化數據存取效率。這個值稱為「Steering Tag」。
### Steering Tag Table
軟體將 Steering Tag 儲存在 Steering Tag table(後簡稱 ST 表)中,該表的位置有兩種可能性: 一種是位於 TPH Requester Extended Capability 結構中,另一種是結合 MSI-X 表使用。但一個 Function 只能二擇一,不能同時使用。當 ST 表與 MSI-X 表組合使用時,每個 MSI-X entry 的 Vector Control register 之兩個最高 bytes 用於儲存 Steering Tag 值。
ST 表的位置的取決於具體實作,並且可以透過軟體搜尋。
* 實現 MSI-X 的 Function 之 ST 表可以採用上述的任一方案
* 同時實現 MSI 和 MSI-X 的 Function,即便在 MSI-X disabled 的情況下,也可以將 ST 表與 MSI-X 表合併使用
每個 ST 表的 entry 使用 2 個 byte 表示,而 ST 表的大小在 TPH Requester Extended Capability 中指定。
### ST Table Location
TPH Requester Capability Regsiter(詳閱PCIe 7.9.13.2 節) 中的 「ST Table Location」欄位指示 Function 是否以及在何處實作了 ST 表。

* ST Table Location
* 00: ST table 不存在
* 01: ST table 在 TPH Requester Extended Capability
* 10: ST table 在 MSI-X Table
如果實現了 ST 表,軟體可以使用系統特定的 Steering tag 對其進行 program。
### ST Mode
而 TPH Requester Control Regsiter 中的 ST Mode Select 可以決定 ST 的使用方式:
| ST Mode Select[2:0] | ST Mode Name | Description |
| -------- | -------- | -------- |
| 000 | No ST Mode | Steering Tags 必須使用全零值 |
| 001 | Interrupt Vector Mode | 每個 Steering Tags 都由一個 MSI/MSI-X interrupt vector number 表示。Function 所使用來的 ST 表 entry 中的 Steering Tag,必須可以透過有效的 MSI/MSI-X interrupt vector number 進行索引。 |
| 010 | Device Specific Mode | 建議 Function 使用 ST 表 entry 中的 Steering Tag,但非必要。 |
| 其他 | Reserved | 保留 |

* 在 No ST Mode 下,Function 使用的 Steering Tag 只能是全零值,以允許在不使用 ST 的狀況下使用 PH
* 在 Interrupt Vector Mode 下,使用 MSI/MSI-X interrupt vector number 從 ST 表中選擇 Steering Tag
* 對於啟用了 MSI 的 Function,其必須在 MSI Capability 中的 "Multiple Message Enable" 欄位指定的範圍內選擇 ST
* 對於啟用了 MSI-X 的 Function,其必須在 MSI-X table 大小的範圍內選擇 ST
* 如果 ST 表大小比啟用的 interrupt vector numbers 範圍還小,則允許該 Function 在某些 transaction 中不使用 TPH/使用 ST 為 0 的 TPH/使用特定 Function 的機制從 ST 表中選擇 ST
* 如果 ST 表大小比啟用的 interrupt vector numbers 範圍還大,則 Function 將忽略超出 ST 表的 entry
* 在 Device Specific Mode 下,Steering Tag 的分配特定於裝置。Function 使用的 Steering Tag 數量可以與分配給其的 interrupt vector 數量不同,可以忽略 ST Table location 的欄位,甚至 request 中使用的 ST 也不需要來自規範的 ST table
能夠產生 TPH request 的 Function 必須支援 No ST Mode,其他模式則為可選。一次只能選擇一種 ST mode 運行,而這可透過對 ST mode 進行改寫來做選擇。
## TPH Capability
TPH Capability 是可選的 PCIe capability。每個能夠產生帶有 TPH 的 TLP request 的 Function 都必須實作 TPH Requester Extended Capability;而支援接收帶有 TPH 的 TLP 的 Completer 必須透過 Device Capabilities 2 register 指示 TPH Completer 的支援。
* TPH Requester Extended Capability

* Device Capabilities 2 register

## TPH Support on Linux
在 Linux kernel 中,TPH 的支援從 6.13 版本開始,需透過開啟 `CONFIG_PCIE_TPH` config 去啟用。
Linux kernel 會在 booting 期間識別 TPH 的支援,但裝置驅動程式需要主動啟用 TPH 以使用之。啟用後,驅動程式會使用提供的 API 取得目標記憶體的 Steering Tag,並將其寫入裝置的 ST table 中。
## Reference
- [Turning PCIe Hints into Cache Hits: Enabling Smart Data Cache Injection in Linux - Wei Huang](https://www.youtube.com/watch?v=SUzeEH5SlwY)
- [Linux Doc: TPH Support](https://docs.kernel.org/PCI/tph.html)
- [pcisig - TLP Processing Hints](https://pcisig.com/PCIExpress/ECN/Base/TLPProcessingHints)