本文件是使用 PCI 端點框架(PCI Endpoint Framework)建立端點控制器驅動、端點功能驅動以及使用 configfs 介面將功能驅動繫結到控制器驅動的指南。
9.1. 簡介¶
Linux 擁有一個全面的 PCI 子系統,以支援在 Root Complex 模式下執行的 PCI 控制器。該子系統能夠掃描 PCI 匯流排、分配記憶體資源和 IRQ 資源、載入 PCI 驅動(基於供應商 ID、裝置 ID)、支援熱插拔、電源管理、高階錯誤報告和虛擬通道等其他服務。
然而,某些 SoC 中整合的 PCI 控制器 IP 能夠以 Root Complex 模式或 Endpoint 模式執行。PCI 端點框架將在 Linux 中新增端點模式支援。這將有助於在 EP 系統中執行 Linux,該系統可用於從測試或驗證到協處理器加速等各種用例。
9.2. PCI 端點核心¶
PCI 端點核心層包含 3 個元件:端點控制器庫、端點功能庫以及用於將端點功能與端點控制器繫結的 configfs 層。
9.2.1. PCI 端點控制器 (EPC) 庫¶
EPC 庫提供了供可在端點模式下執行的控制器使用的 API。它還提供了供功能驅動/庫使用的 API,以實現特定的端點功能。
9.2.1.1. PCI 控制器驅動的 API¶
本節列出了 PCI 端點核心提供給 PCI 控制器驅動使用的 API。
devm_pci_epc_create()/pci_epc_create()
PCI 控制器驅動應實現以下操作:
write_header: 填充配置空間頭部的操作
set_bar: 配置 BAR 的操作
clear_bar: 重置 BAR 的操作
alloc_addr_space: 在 PCI 控制器地址空間中分配的操作
free_addr_space: 釋放已分配地址空間的操作
raise_irq: 觸發傳統、MSI 或 MSI-X 中斷的操作
start: 啟動 PCI 連結的操作
stop: 停止 PCI 連結的操作
PCI 控制器驅動可以透過呼叫 devm_pci_epc_create()/pci_epc_create() 建立新的 EPC 裝置。
pci_epc_destroy()
PCI 控制器驅動可以使用 pci_epc_destroy() 銷燬由 pci_epc_create() 建立的 EPC 裝置。
pci_epc_linkup()
為了通知所有功能裝置,它們所連結的 EPC 裝置已與主機建立連線,PCI 控制器驅動應呼叫 pci_epc_linkup()。
pci_epc_mem_init()
初始化用於分配 EPC 地址空間的 pci_epc_mem 結構。
pci_epc_mem_exit()
清除在 pci_epc_mem_init() 期間分配的 pci_epc_mem 結構。
9.2.1.2. PCI 端點功能驅動的 EPC API¶
本節列出了 PCI 端點核心提供給 PCI 端點功能驅動使用的 API。
pci_epc_write_header()
PCI 端點功能驅動應使用 pci_epc_write_header() 將標準配置頭部寫入端點控制器。
pci_epc_set_bar()
PCI 端點功能驅動應使用 pci_epc_set_bar() 配置基地址暫存器 (Base Address Register),以便主機分配 PCI 地址空間。功能驅動的暫存器空間通常使用此 API 進行配置。
pci_epc_clear_bar()
PCI 端點功能驅動應使用 pci_epc_clear_bar() 重置 BAR。
pci_epc_raise_irq()
PCI 端點功能驅動應使用 pci_epc_raise_irq() 觸發傳統中斷、MSI 或 MSI-X 中斷。
pci_epc_mem_alloc_addr()
PCI 端點功能驅動應使用 pci_epc_mem_alloc_addr(),從 EPC 地址空間分配訪問 RC 緩衝區所需的記憶體地址。
pci_epc_mem_free_addr()
PCI 端點功能驅動應使用 pci_epc_mem_free_addr() 釋放使用 pci_epc_mem_alloc_addr() 分配的記憶體空間。
pci_epc_map_addr()
PCI 端點功能驅動應使用 pci_epc_map_addr() 將透過 pci_epc_mem_alloc_addr() 獲取的本地記憶體的 CPU 地址對映到 RC PCI 地址。
pci_epc_unmap_addr()
PCI 端點功能驅動應使用 pci_epc_unmap_addr() 解除透過 pci_epc_map_addr() 對映到 RC 地址的本地記憶體的 CPU 地址。
pci_epc_mem_map()
PCI 端點控制器可能會對可對映的 RC PCI 地址施加限制。pci_epc_mem_map() 函式允許端點功能驅動在處理此類限制的同時分配和對映控制器記憶體。此函式將確定必須使用 pci_epc_mem_alloc_addr() 分配的記憶體大小,以成功對映 RC PCI 地址範圍。此函式還將指示實際對映的 PCI 地址範圍大小(可能小於請求的大小),以及在分配記憶體中用於訪問對映的 RC PCI 地址範圍的偏移量。
pci_epc_mem_unmap()
PCI 端點功能驅動可以使用 pci_epc_mem_unmap() 解除對映並釋放使用 pci_epc_mem_map() 分配和對映的控制器記憶體。
9.2.1.3. 其他 EPC API¶
EPC 庫還提供了其他 API。這些 API 用於將 EPF 裝置與 EPC 裝置繫結。pci-ep-cfs.c 可用作使用這些 API 的參考。
pci_epc_get()
根據控制器的裝置名稱獲取 PCI 端點控制器的引用。
pci_epc_put()
釋放使用 pci_epc_get() 獲取的 PCI 端點控制器的引用
pci_epc_add_epf()
將 PCI 端點功能新增到 PCI 端點控制器。根據規範,一個 PCIe 裝置最多可以有 8 個功能。
pci_epc_remove_epf()
從 PCI 端點控制器中移除 PCI 端點功能。
pci_epc_start()
PCI 端點功能驅動在配置完端點功能並希望啟動 PCI 連結後,應呼叫 pci_epc_start()。
pci_epc_stop()
PCI 端點功能驅動應呼叫 pci_epc_stop() 來停止 PCI 連結。
9.2.2. PCI 端點功能 (EPF) 庫¶
EPF 庫提供了供功能驅動和 EPC 庫用於提供端點模式功能的 API。
9.2.2.1. PCI 端點功能驅動的 EPF API¶
本節列出了 PCI 端點核心提供給 PCI 端點功能驅動使用的 API。
pci_epf_register_driver()
- PCI 端點功能驅動應實現以下操作:
bind: 當 EPC 裝置繫結到 EPF 裝置時執行的操作
unbind: 當 EPC 裝置和 EPF 裝置之間的繫結丟失時執行的操作
add_cfs: 可選操作,用於建立功能特定的 configfs 屬性
PCI 功能驅動可以使用 pci_epf_register_driver() 註冊 PCI EPF 驅動。
pci_epf_unregister_driver()
PCI 功能驅動可以使用 pci_epf_unregister_driver() 登出 PCI EPF 驅動。
pci_epf_alloc_space()
PCI 功能驅動可以使用 pci_epf_alloc_space() 為特定 BAR 分配空間。
pci_epf_free_space()
PCI 功能驅動可以透過呼叫 pci_epf_free_space() 釋放已分配的空間(使用 pci_epf_alloc_space 分配)。
9.2.2.2. PCI 端點控制器庫的 API¶
本節列出了 PCI 端點核心提供給 PCI 端點控制器庫使用的 API。
pci_epf_linkup()
當 EPC 裝置與主機建立連線時,PCI 端點控制器庫會呼叫 pci_epf_linkup()。
9.2.2.3. 其他 EPF API¶
EPF 庫還提供了其他 API。這些 API 用於在 EPF 裝置繫結到 EPC 裝置時通知功能驅動。pci-ep-cfs.c 可用作使用這些 API 的參考。
pci_epf_create()
透過傳遞 PCI EPF 裝置的名稱來建立新的 PCI EPF 裝置。此名稱將用於將 EPF 裝置繫結到 EPF 驅動。
pci_epf_destroy()
銷燬已建立的 PCI EPF 裝置。
pci_epf_bind()
當 EPF 裝置繫結到 EPC 裝置時,應呼叫 pci_epf_bind()。
pci_epf_unbind()
當 EPC 裝置和 EPF 裝置之間的繫結丟失時,應呼叫 pci_epf_unbind()。