当前位置:首页>Linux>从 PCIe P2P 到 Linux NTB:高速互联驱动学习笔记 五

从 PCIe P2P 到 Linux NTB:高速互联驱动学习笔记 五

  • 2026-10-10 12:24:05
从 PCIe P2P 到 Linux NTB:高速互联驱动学习笔记 五
           Linux NTB 学习笔记:ntb_transport 的 MW 和 Queue Pair 模型        
           一、transport 解决什么问题        

ntb_pingpong 只验证控制面,而 ntb_transport 开始真正使用 Memory Window。它在 MW 和 doorbell 之上封装软件 queue pair,让上层 client 不必自己处理每个包的 offset、header、doorbell bit。

ntb_netdev 就是 ntb_transport 的用户。它通过 transport queue 收发 skb,最终呈现成一个 Linux 虚拟网卡。

           二、ntb_transport_probe        

ntb_transport_probe() 是 transport 接管 ntb_dev 的入口。它会检查硬件是否支持 transport 需要的 MW API,分配 ntb_transport_ctx,映射 peer MW aperture,根据 doorbell 和 MW 数量计算 QP 数量,然后初始化每个 QP。

ntb_transport 从 probe 到 link work probe 阶段主要准备软件结构。它会把本端可写的 peer MW aperture 映射出来,这个 aperture 从本端视角看就是 TX 区域:本端写这里,数据会被 NTB 转到对端。

最后它调用 ntb_set_ctx() 注册 link/db 回调,ntb_link_enable() 打开 link,并主动触发一次 link_event。

           三、为什么 init_queue 只切 TX        

ntb_transport_init_queue() 会从 MW 中切出当前 QP 的 TX 区域。这里切的是本端 outbound MW aperture,也就是本端用来访问 peer 的窗口。

RX 区域不是在 init_queue 里建立的,而是在 link up 后由 ntb_transport_link_work() 分配本端 DMA buffer,再通过 ntb_mw_set_trans() 暴露给 peer。之后 ntb_transport_setup_qp_mw() 才会把本端 RX buffer 按 QP 切分。

所以从本端视角看,probe 阶段只能先准备 TX,RX 要等 link 协商和 inbound MW translation 配好。

           四 、QP 是什么        

QP 是 Queue Pair,是 transport 基于 MW、doorbell 和软件链表实现的一条逻辑通道。每个 QP 有自己的 TX 状态、RX 状态、doorbell bit、link_work、tasklet 和上层回调。

QP 不是硬件 PCIe queue,而是 transport 软件抽象。上层 client 调 ntb_transport_create_queue() 领取一个 QP,再通过 ntb_transport_tx_enqueue() 和 ntb_transport_rx_enqueue() 收发数据。

           五 、ntb_transport_link_work        

link_event 到来后,transport 不在回调里直接做重活,而是调度 ntb_transport_link_work()。

link_work 会把本端版本、QP 数、MW 数、MW 大小写到 peer scratchpad,再读取本地 scratchpad 中 peer 写来的信息。

双方信息匹配后,它调用 ntb_set_mw() 分配本端接收 buffer,并调用 ntb_mw_set_trans() 把这块 buffer 暴露给 peer。

随后它为每个 QP 调 ntb_transport_setup_qp_mw(),切出本端 RX buffer。

如果上层 client 已经 ready,就继续调度 QP 级别 link_work,让 QP 进入 link up。

           六 、doorbell callback        

peer 写完数据后会敲 doorbell。本端硬件驱动调用 ntb_db_event(),transport 收到后进入 ntb_transport_doorbell_callback()。

这个函数根据 doorbell vector 找到对应 QP bit,只处理已经被分配且 active 的 QP,然后调度 rxc_db tasklet。真正读取 RX entry、调用上层 rx_handler、清 doorbell 的逻辑在 ntb_transport_rxc_db() 里完成。

           七 、transport 的边界        

ntb_transport 是通用传输层,适合把 NTB 做成 queue pair,再给 ntb_netdev 或类似 client 使用。它默认模型是 peer host memory 的 MW buffer,不一定适合所有特殊数据路径。

如果项目需要把 MW target 指向特殊地址,例如某个 peer BAR 或自定义窗口,通常更适合写一个专用 client,直接使用 ntb_mw_set_trans、ntb_peer_mw_set_trans、doorbell/message 等基础 API。

写至此处,也该画上句号了。常言道,程序员的世界由0和1构成,但我逐渐意识到——更多的时候,我们面对的是“咦?这怎么又出错了?”

感谢您的阅读,希望我的些许探索,能够助您避开一些陷阱,更接近事实的真相。

敬请关注「码上求真」,期待下次与您相逢。

Ps:准备了一些电子书,菜单中获取哦

最新文章

随机文章