网络设备驱动(3)

1.从应用层send()到发送到网线上的过程

send之后触发系统调用陷入内核态,调用copy_from_user()的位置:

简述应用层到网线上发送数据的过程:

(1)应用层调用send,系统调用陷入内核态,通过copy_from_user()将原始skb拷贝至内核空间;

(2)抵达网络协议栈,经过TCP和IP分别为skb添加帧头,添加MAC帧头(即以太网帧头)。到此skb准备好了,接下来调用网卡驱动中的ndo_start_xmit();

(3)抵达网卡驱动,进入ndo_start_xmit(),将skb中的数据的虚拟地址转换为DMA地址(即对skb->data调用dma_map_single(),获得物理地址dma_addr),接着将转换好的dma_addr和数据长度写入在ndo_open中准备好的TX Descriptor,并通知网卡数据准备好;

(4)网卡把 TX Descriptor 从 DDR 读取到网卡内部的描述符暂存器中,解析出数据物理地址后网卡的DMA控制器再次发起请求,把 DDR 中的真实数据包搬运到网卡内部的 TX FIFO 缓冲区。

------------------------------至此和CPU已经没有关系了,数据已经发出了---------------------------------------

(5)数据进入 TX FIFO 后,网卡 MAC 芯片实时补充前导码(Preamble)和 CRC 校验码(FCS),最后交给 PHY 芯片转换成电脉冲发往网线。

问题1:TX Descriptor的创建与流转,以及dma_map_single()与dma_alloc_coherent()

在网卡启动时,如ip link set dev eth0 up,调用ndo_open,驱动调用dma_alloc_coherent()在DDR中开辟一段Ring Buffer,作为TX Descriptor槽位,等待后续内容填入。

当数据到达ndo_start_xmit()时,即网络协议栈提交skb后,驱动通过dma_map_single()或dma_alloc_coherent()将skb->data映射为物理地址dma_addr,并dma_addr和数据长度放入上述开辟好的槽位。

最后Doorbell后,网卡将TX Descriptor拉入网卡暂存器。

DMA 映射方式 API 适用场景与工作原理 性能与拷贝特征
单区映射(Single Mapping) dma_map_single() 映射 skb->data 对应的线性连续内存块。产生单个 DMA 物理地址。 依赖 CPU 内存分配,适合小包或普通数据包。
页级分散映射(Page Mapping) dma_map_page() 针对零散物理页。支持 Scatter-Gather DMA,一个逻辑包占用多个相邻 TX Descriptor。
一致性 DMA 分配(Coherent DMA) dma_alloc_coherent() 直接分配一块 CPU 与网卡共享的、关闭 Cache 或保持强缓存一致性的物理连续内存区。 专门用于创建 TX/RX Ring Buffer 描述符本身,不用于发送具体的 Payload。
跨设备缓冲区共享(dma-buf) dma_buf_attach() 允许网卡直接从 GPU 显存或 V4L2 采集卡内存中 DMA 拉取数据并发送。 跨硬件零拷贝:数据无需经过 CPU 内存中转,适合 AI 训练与视频实时传输。

网卡驱动中用到的是前三种,dma_buf_attach() 较为特殊,dma_buf_attach() 函数用于将一个访问方硬件设备(Importer)绑定到指定的 DMA 缓冲区(Exporter)上。其传入的参数是:通过 dma_buf_get(fd)(根据用户态文件描述符获取)或由 Exporter 驱动导出的 struct dma_buf 指针。

问题2:为什么TX Descriptor被设计出Ring Buffer?

  • 提高并行效率:CPU可以和DMA并行,CPU 填后面的 TX Descriptor,DMA 同时发送前面的包,形成流水线。
  • 减少申请释放开销:Descriptor 在 open() 时一次性申请,之后循环复用,不需要每发一个包都重新申请。
  • 方便队列管理:通过 tx_head,tx_tail 管理待发送和已完成的 Descriptor,容易判断 Ring 是否为空或已满。
相关推荐
H.莓飛2 分钟前
【数据结构】队列_OJ题
linux·数据结构·centos
H.莓飛18 分钟前
【数据结构】栈_OJ题
linux·数据结构·算法·centos
Ruiery24 分钟前
Linux 6.6内核 CPU 深度解析(一):BSP 拉起 — 从实模式到 kernel_init 的完整旅程
linux·运维·服务器
通信瓦工26 分钟前
利用浊度和电导率测量确定乙二醇基流体的质量
网络·数据库·ai
赵民勇29 分钟前
dconf命令详解
linux·运维
阿钱真强道35 分钟前
33 嵌入式操作系统 | 模块七验收:端到端一键验收 + 项目答辩
网络·网络协议·粘包·回归测试·uloop
代码方舟35 分钟前
零信任架构实战:基于天远学历信息高级版构建自动化智库入驻审查网关
运维·人工智能·架构·自动化
ggaofeng36 分钟前
Ctrl+C结束进程是如何实现的
服务器·c语言·网络
xingzhemengyou142 分钟前
STM32F427将函数设定在固定位置
stm32·单片机·嵌入式硬件
和裕1 小时前
年度框架直供 vs 零散按需采购:定制纸箱采购成本、交付与服务核心区别全对比
大数据·运维·网络·人工智能·算法