Linux 内核 PCI NTB 端点功能详解:pci_epf_ntb 的 configfs 绑定字段与源码实现

Linux 内核 PCI NTB 端点功能详解:pci_epf_ntb 的 configfs 绑定字段与源码实现
Linux 内核 PCI NTB 端点功能详解pci_epf_ntb 的 configfs 绑定字段与源码实现【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文以 Linux 内核文档 pci-ntb.rst 为主体完整讲解 PCI NTBNon-Transparent Bridge非透明桥端点功能pci_epf_ntb在 configfs 中的绑定流程标准 EPF 可配置字段vendorid/deviceid/baseclass_code 等与 NTB 专有字段db_count、mw1~mw4、num_mws、spad_count的取值约束与默认值并结合 pci-epf-ntb.c 源码剖析这些字段在驱动内部的解析、校验与生效路径帮助读者掌握在双主机、多 EP 控制器平台上配置 NTB 端点的完整实操方案与底层原理。1. 背景PCI NTB 端点功能在 Linux 中的定位PCI NTB 允许两个主机系统把彼此暴露为设备进行通信NTB 设备通常支持在远端机器上产生中断、把内存区间以 BAR 形式暴露给对端、执行 DMA并提供双方都可访问的 scratchpad暂存寄存器区。在 Linux 的可配置 PCI 端点框架PCI Endpoint framework中这一功能由端点功能驱动 pci-epf-ntb.c 实现它把 SoC 上的多个 PCI EndpointEP控制器实例配置成一台主机的事务被路由到另一个 EP 控制器从而让 HOST1 与 HOST2 以 SoC 作为桥互相通信。从源码文件头部的注释框图pci-epf-ntb.c#L9-L35可以看到该拓扑------------- ------------- | HOST1 | | HOST2 | ------^------ ------^------ | | ------|-------------------------------------------------|--------- | ---v------ ------v------ | | | EP | | EP | | | |CONTROLLER1|-----------------------------------CONTROLLER2 | | | ----------- SoC With Multiple EP Instances ------------- | -------------------------------------------------------------------完整的 NTB 硬件建模Config Region、Self/Peer Scratchpad、Doorbell、Memory Window 五大构件及其 BAR 布局见配套文档 pci-ntb-function.rst本文聚焦的 pci-ntb.rst 则回答一个更具体的问题在 configfs 中创建pci_epf_ntb功能设备时有哪些字段必须/可以配置各自的取值要求是什么。1.1 编译前提根据 drivers/pci/endpoint/functions/Kconfig 与 drivers/pci/endpoint/Kconfig需要开启CONFIG_PCI_ENDPOINTPCI Endpoint Support平台具有可工作在端点模式的 PCI 控制器时需要CONFIG_PCI_EPF_NTBPCI Endpoint NTB driver依赖PCI_ENDPOINT并自动select CONFIGFS_FSCONFIG_PCI_ENDPOINT_CONFIGFSPCI Endpoint Configfs Support开启 configfs 入口用于配置端点功能设备并将其与端点控制器绑定。对应的构建规则见 drivers/pci/endpoint/Makefile 与 drivers/pci/endpoint/functions/Makefile# drivers/pci/endpoint/Makefile obj-$(CONFIG_PCI_ENDPOINT_CONFIGFS) pci-ep-cfs.o # drivers/pci/endpoint/functions/Makefile obj-$(CONFIG_PCI_EPF_NTB) pci-epf-ntb.o2. 第一步在 configfs 中创建 pci_epf_ntb 设备文档给出的第一步是在pci_epf_ntb目录下创建一个子目录。按 pci-ntb-howto.rst 的完整操作前提系统中至少有两个 EP 控制器设备且功能驱动已注册# 挂载 configfs 并确认设备/驱动就绪 mount -t configfs none /sys/kernel/config ls /sys/kernel/config/pci_ep/controllers # 2900000.pcie-ep 2910000.pcie-ep ls /sys/kernel/config/pci_ep/functions # pci_epf_ntb pci_epf_ntb # 创建功能设备目录名可自定如 func1 cd /sys/kernel/config/pci_ep/ mkdir functions/pci_epf_ntb/func1mkdir func1创建的正是会被pci_epf_ntb驱动 probe 的功能设备。PCI 端点框架随后会在该目录下填充标准 EPF 可配置字段例如# ls functions/pci_epf_ntb/func1 baseclass_code deviceid msi_interrupts pci-epf-ntb.0 progif_code secondary subsys_id vendorid cache_line_size interrupt_pin msix_interrupts primary revid subclass_code subsys_vendor_id2.1 标准 EPF 可配置字段文档原始表格pci-ntb.rst 规定了对 NTB 功能的字段取值要求字段要求vendorid应为 0x104cdeviceid对 TI 的 J721E SoC 应为 0xb00drevid无要求dont careprogif_code无要求subclass_code应为 0x00baseclass_code应为 0x5cache_line_size无要求subsys_vendor_id无要求subsys_id无要求interrupt_pin无要求msi_interrupts无要求msix_interrupts无要求其中几个硬要求在源码中有对应物baseclass_code 0x5PCI 基类 0x05 内存控制器类与subclass_code 0x00对应驱动默认 PCI 头epf_ntb_header见 pci-epf-ntb.c#L124-L129static struct pci_epf_header epf_ntb_header { .vendorid PCI_ANY_ID, .deviceid PCI_ANY_ID, .baseclass_code PCI_BASE_CLASS_MEMORY, .interrupt_pin PCI_INTERRUPT_INTA, };按 pci-ntb-howto.rst 的说法功能设备绑定驱动后框架会用默认值填充条目pci-epf-ntb驱动则把 vendorid 填为 0xffff、interrupt_pin 填为 0x0001。因此要让主机侧按预期识别设备需要显式写入# echo 0x104c functions/pci_epf_ntb/func1/vendorid # echo 0xb00d functions/pci_epf_ntb/func1/deviceid这一步写入的值最终会体现在主机侧的lspci输出中见第 6 节Texas Instruments Device b00d即 vendorid0x104c、deviceid0xb00d 的结果。3. 第二步配置 NTB 专有字段3.1 文档规定的 NTB 专有字段表框架会自动在功能属性目录下再建一个与功能设备同名的子目录即pci_epf_ntb.0其中填充 NTB 专有属性。pci-ntb.rst 给出的字段说明如下字段说明db_count门铃doorbell数量默认 4mw1内存窗口 1 的大小mw2内存窗口 2 的大小mw3内存窗口 3 的大小mw4内存窗口 4 的大小num_mws内存窗口数量最大 4spad_count暂存寄存器scratchpad数量默认 64这些属性的注册与默认值可以直接在 pci-epf-ntb.c 中逐一印证#define SPAD_COUNT 64 #define DB_COUNT 4 #define NTB_MW_OFFSET 2 #define DB_COUNT_MASK GENMASK(15, 0) #define MSIX_ENABLE BIT(16) #define MAX_DB_COUNT 32 #define MAX_MW 4db_count默认 4驱动初始化时校验ntb-db_count必须落在 1..MAX_DB_COUNT(32) 区间否则报 Invalid db_count 错误见 pci-epf-ntb.c#L1301-L1310。该值同时决定 MSI/MSI-X 向量的数量pci_epc_set_msi(epc, func_no, vfunc_no, ntb-db_count)或pci_epc_set_msix(...)即每个门铃对应一个中断向量。spad_count默认 64暂存区大小按spad_size spad_count * 4计算每个寄存器 32 位见 pci-epf-ntb.c#L1030-L1037并写入控制区的SPAD OFFSET/SPAD COUNT供主机侧读取。num_mws最大 4store 函数直接拒绝大于MAX_MW(4) 的写入见 pci-epf-ntb.c#L1947-L1963static ssize_t epf_ntb_num_mws_store(struct config_item *item, const char *page, size_t len) { ... if (kstrtou32(page, 0, val) 0) return -EINVAL; if (val MAX_MW) return -EINVAL; ntb-num_mws val; return len; }mw1~mw4分别表示 4 个内存窗口的大小。注意写入mwN前必须先保证num_mws N否则 store 路径会打印 Invalid num_nws: %d value 并返回 -EINVALpci-epf-ntb.c#L1937-L1940。窗口大小在主机下发CMD_CONFIGURE_MW时还会再校验一次请求映射尺寸不能超过ntb-mws_size[mw]否则返回 -EINVALpci-epf-ntb.c#L262-L269。这 7 个属性通过CONFIGFS_ATTR宏注册进ntb_group_type并在epf_ntb_add_cfs()中挂到功能设备的 configfs 目录下pci-epf-ntb.c#L1979-L2022因此设备 bind 到驱动后才会出现pci_epf_ntb.0/子目录。3.2 一个可复制的示例配置来自 pci-ntb-howto.rst 的示例注意先设num_mws再设mwN# echo 4 functions/pci_epf_ntb/func1/pci_epf_ntb.0/db_count # echo 128 functions/pci_epf_ntb/func1/pci_epf_ntb.0/spad_count # echo 2 functions/pci_epf_ntb/func1/pci_epf_ntb.0/num_mws # echo 0x100000 functions/pci_epf_ntb/func1/pci_epf_ntb.0/mw1 # echo 0x100000 functions/pci_epf_ntb/func1/pci_epf_ntb.0/mw2即4 个门铃、128 个暂存寄存器、2 个内存窗口、每个窗口 0x100000 字节。3.3 字段如何决定 BAR 分配这些字段不是写了就生效的孤立参数——它们直接决定 BAR 布局。从struct epf_ntbpci-epf-ntb.c#L76-L84可见num_mws、db_count、spad_count与mws_size[MAX_MW]都保存在功能结构体中在 BAR 分配逻辑里pci-epf-ntb.c#L1437-L1462 附近BAR_DB_MW1的大小由db_count * 对齐值 mws_size[0]决定其余窗口依次占用后续 BAR。这与 pci-ntb-function.rst 给出的打包 BAR 方案一致BAR承载构件BAR0Config Region Self ScratchpadBAR1Peer ScratchpadBAR2Doorbell Memory Window 1BAR3Memory Window 2BAR4Memory Window 3BAR5Memory Window 4对应源码中的 BAR 枚举为enum epf_ntb_bar { BAR_CONFIG, BAR_PEER_SPAD, BAR_DB_MW1, BAR_MW2, BAR_MW3, BAR_MW4, };pci-epf-ntb.c#L67-L74。文档同时说明对仅支持 64 位 BAR 的平台每个构件单独占用一个 BAR 会不够用所以 EPF NTB 采用上述打包方式基础 NTB 功能只需 3 个 BAR。MW1 与 Doorbell 挤在同一个 BAR 内因此控制区专门有MEMORY WINDOW1 OFFSET字段记录 MW1 在其中的偏移同理SPAD OFFSET记录 self scratchpad 在 BAR0 中的偏移。4. 第三步绑定 EP 控制器并启动链路NTB 功能设备需要同时挂到两个 EP 控制器分别连接两台主机使用功能设备下的primary和secondary条目pci-ntb-howto.rst# ln -s controllers/2900000.pcie-ep/ functions/pci_epf_ntb/func1/primary # ln -s controllers/2910000.pcie-ep/ functions/pci_epf_ntb/func1/secondary随后两个控制器各自与主机建立链路# echo 1 controllers/2900000.pcie-ep/start # echo 1 controllers/2910000.pcie-ep/start两个控制器都建链后功能设备即处于就绪状态。从源码看epf_ntb结构体中epc[2]数组pci-epf-ntb.c#L83正是保存 primary/secondary 两个epf_ntb_epc实例命令处理逻辑会遍历PRIMARY_INTERFACE与SECONDARY_INTERFACE两类接口如epf_ntb_link_up()pci-epf-ntb.c#L140-L173。5. 底层机制主机与端点之间的命令协议上述字段最终服务于主机RC 侧与端点EP 侧之间的命令交换协议由主机侧驱动 ntb_hw_epf.c 与端点侧pci-epf-ntb共同实现。命令定义在两端完全一致#define CMD_CONFIGURE_DOORBELL 1 #define CMD_TEARDOWN_DOORBELL 2 #define CMD_CONFIGURE_MW 3 #define CMD_TEARDOWN_MW 4 #define CMD_LINK_UP 5 #define CMD_LINK_DOWN 6端点侧见 pci-epf-ntb.c#L47-L55主机侧见 ntb_hw_epf.c#L16-L22。命令通过 BAR0 的 Config Region 传递其内存布局由struct epf_ntb_ctrl描述pci-epf-ntb.c#L107-L122command、argument、command_status、link_status、topology、64 位addr、64 位size、num_mws、mw1_offset、spad_offset、spad_count、db_entry_size以及最多 32 组db_data/db_offset。各字段含义COMMAND、ARGUMENT、TOPOLOGY、ADDRESS/SIZE、MW1 OFFSET、SPAD OFFSET/COUNT、DB ENTRY SIZE、DB DATA在 pci-ntb-function.rst 中有完整说明要点是CMD_CONFIGURE_DOORBELL0x1主机在分配并初始化 MSI/MSI-X 后下发ARGUMENT低 16 位是门铃数、BIT16 指示用 MSI 还是 MSI-X。端点收到后配置出站 ATU使写 Doorbell BAR 的事务被路由到主机编程的 MSI/MSI-X 地址。端点侧对应epf_ntb_configure_msi()/epf_ntb_configure_msix()pci-epf-ntb.c#L383-L427并把每个中断的 MSI data 写入对端控制区的db_data供对端主机写 BAR 即响铃。CMD_CONFIGURE_MW0x2主机分配一块可被远端主机访问的缓冲区后下发ADDRESS/SIZE填缓冲区地址与大小ARGUMENT填窗口索引端点随后用pci_epc_map_addr()配置出站 ATU把 MW BAR 上的事务路由到主机提供的地址epf_ntb_configure_mw()pci-epf-ntb.c#L235-L283。这里的size ntb-mws_size[mw]检查正是第 3 节 configfs 中mw1~mw4字段的实际约束点。CMD_LINK_UP0x3主机侧 NTB 应用绑定到 EP 设备后下发当端点从两侧主机都收到该命令时通过epf_ntb_link_up()置位link_status的LINK_STATUS_UP并向两端各发一个中断通知两端的 NTB 客户端可以开始通信。主机侧驱动 ntb_hw_epf.c 还定义了配置区各寄存器的偏移NTB_EPF_COMMAND 0x0、NTB_EPF_ARGUMENT 0x4、NTB_EPF_SPAD_OFFSET 0x28、NTB_EPF_DB_DATA(n) 0x34 n*4等见 ntb_hw_epf.c#L16-L45并约束主机侧门铃槽位布局slot 0 保留给链路事件、DB 编号从 slot 2 起故最少需要 3 个向量NTB_EPF_MIN_DB_COUNT 3最多 31 个NTB_EPF_MAX_DB_COUNT 31ntb_hw_epf.c#L47-L60。这也解释了端点侧MAX_DB_COUNT 32的取值为链路事件与门铃向量预留了完整空间。6. 主机侧验证与后续使用端点侧完成绑定并start后在主机RootComplex 侧执行lspci应看到与 configfs 中写入的 vendorid/deviceid 一致的设备来自 pci-ntb-howto.rst# lspci 0000:00:00.0 PCI bridge: Texas Instruments Device b00d 0000:01:00.0 RAM memory: Texas Instruments Device b00d主机侧软件遵循 Linux 标准 NTB 软件架构可配合ntb_hw_epf主机驱动使用既有 NTB 客户端如 NTB Transport、NTB Ping Pong Test、NTB Tool 等更多 NTB 框架信息见 Non-Transparent Bridge 文档。7. 小结pci-ntb.rst 是pci_epf_ntb设备绑定的字段清单标准 EPF 字段中vendorid0x104c、deviceid0xb00dTI J721E、baseclass_code0x5、subclass_code0x00有硬性要求其余 dont careNTB 专有字段为db_count默认 4、mw1~mw4各窗口大小、num_mws最大 4、spad_count默认 64。这些字段的解析与校验逻辑可在 pci-epf-ntb.c 中逐一对应num_mws超过 4 被拒、mwN要求num_mws N、主机映射请求不得大于mws_size[mw]字段值最终决定 6 个 BAR 的打包分配与出站 ATU 映射行为。完整落地流程为configfsmkdir创建设备 → 写标准字段与 NTB 字段 →ln -s绑定 primary/secondary 两个 EP 控制器 →echo 1 .../start建链 → 主机侧经ntb_hw_epf通过 Config Region 命令CONFIGURE_DOORBELL / CONFIGURE_MW / LINK_UP完成 NTB 链路。相关延伸阅读PCI 端点框架总览、EPF ConfigFS 使用、NTB 功能硬件建模、NTB 用户指南。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

最新新闻

日新闻

周新闻

月新闻