Linux NTB 学习笔记:ntb_transport 的 MW 和 Queue Pair 模型 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() 是 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。
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 是 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。
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() 里完成。
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。