e1000e网卡驱动分析笔记

news/2025/3/4 8:20:46/

驱动中有e1000的e1000e两个版本, 差别不大, e1000e使用了msix, 更先进一点点.  比较难懂的都是一些基础系的东西, 如下

1) PCIE的配置空间初始化

2) msix机制及初始化

3) napi机制

4) dma机制

下面一个个回答这些问题,  因为内容实在太多, 没法每个问题将的很清楚, 而且我们这个帖子主要是分析e1000e, 只能每个初步说下机理, 如果需要补充这方面的知识, 自行找其他帖子了解

1) PCIE的配置空间初始化: PCIE卡都遵循一个标准,  x86通过往2个内存地址读写就可以控制IO桥访问一个内部寄存器+一个地址偏移, 就可以读写PCI的配置空间, 操作系统实际上就是用这个机制, 判断卡位是否插上了卡, 卡是否合法, 以及写对应的配置区域(相当于初始化).

    这个内部寄存器, 是每个PCIE卡独有的, 通过跟PCI兴趣小组申请, 并通过物理接线的方式接上的, 所以可以唯一的确定一个卡.

2) msix机制及初始化

OS在初始化配置区的时候, 会根据卡将pci卡的msix起始地址写到pci配置的扩展能力区域,  驱动只需要去读取对应的区域, 像os申请msix向量, 即可使用

msix中断是一种特殊的中断, 不需要中断线, 但需要PCIE具备msix能力, 主机也必须支持apic才可.  当系统初始化时, 同时初始化主机上2个特殊硬件, IOAPIC和LocalAPIC,  在内存虚拟地址中开辟一段内存,  给每个cpu分配中断向量. 后面只要往这个内存上写触发设备信息, 那么就会被内存控制器劫持,  内存控制立即明白这是有外设触发了中断, 通知ioapic发送广播,  当对应的cpu判断对应的向量, 知道这个是要被自己处理, 就会处理这个中断.

3) napi机制

napi也是网络设备的一个机制,  把设备的napi的list挂到系统上, 随即发送一个软中断,  调用一个回调函数

4) dma机制

e1000采用的是自动收发, 就是说数据包从网卡的fifo到skb里面,  或者从skb到网卡的fifo是由dma自动完成的,  在完成后会触发msix中断 

   机制的问题讲完了, 这些是比较难懂的(有些我也是一知半解, 比如msix),  系统都有专门的api可以调用. 但是不理解, 会给你阅读代码造成困难.

 

正式进入代码阅读(按照代码阅读顺序): 

netdev.c

1) e1000_init_module() 只干了一个事情, 注册了一个pci驱动结构体到pci驱动链表, 当pci注册后, 根据pci驱动框架, 匹配成功后自然会执行probe函数

 

2) e1000_probe

   <1> pci_set_dma_mask/pci_set_consistent_dma_mask  协调bus总线宽度

   <2> pci_request_selected_regions_exclusive 霸占虚拟地址映地址

            pci_set_master 设置主,  前两部都是常规操作

           alloc_etherdev 分配并初始化网络设备struct net_device及struct e1000_adapter, 其中net_device主要描述设备驱动相关信息,  struct e1000_adapter,主要描述硬件, 及设备内存, 控制调度等信息

         这2个结构随即被初始化, 初始化的内容非常多, 网卡的收发队列net_queue, 网卡的mac地址链表, name space挂载到内核链表, 报文最大长度, napi, 设备名称,  硬件frame长度, 映射bar0,  分配中断信息, 分配adapter的ring结构, 读取eeprom的信息, 等等...

       这个阶段有几个部分需要注意:

       1)  网络设备基础信息被分配, 但是真正数据传输相关结构和内存没有分配, 中断线没有分配,  也就是说, 这个过程仅仅实例化了一个网卡设备的空壳, 并没有占用实际的硬件资源.

      2) struct net_device的操作函数被初始化, 也就是说, 后面后面网卡执行up和down的时候, 就可直接调用网卡的ops方法 . 这种设计是非常好的, 用的时候分配, 不用的时候不占用资源.

 

3) e1000_open:   当网卡执行up的时候, e1000_open被调用. 

      1> e1000e_setup_tx_resources/e1000e_setup_rx_resources:  分配adapter的buffer_info结构, 共256个,  分配adapter->tx_ring的desc一致性内存, 共256个desc, 并初始化tx_ring.  

         其中desc是真正要送给dma控制器的, 而buffer_info只是一个描述结构体

    2> e1000_configure:

          e1000_set_rx_mode, e1000_restore_vlan, e1000_init_manageability 设置收包模式, 设置管理信息等, 略过.   

         e1000_configure_tx: 重要函数,  设置dma控制的传输地址

         e1000_configure_rx: 重要函数, 设置收包函数内存分配回调函数, 和清理回调函数. 及设置dma控制的传输地址

         adapter->clean_rx = e1000_clean_rx_irq;  收包函数 (umap已收取的报文skb, 并申请新的skb, 做dma map到desc上, 并把报文传递给e1000_receive_skb(内核中上层报文处理函数)
         adapter->alloc_rx_buf = e1000_alloc_rx_buffers;  skb分配和映射函数, 被e1000_clean_rx_irq以及网卡初始化过程调用

         e1000_configure同时调用e1000_alloc_rx_buffers, 分配收函数的skb缓冲区, 直接就分配256个, 同时将skb的物理地址传给dma控制器, 并提示dma可以0处开始收包, 可以一直收256个

     

4) e1000_request_irq : 申请msix中断和常规中断

   看网卡支持那种类型的中断, 我们这里支持最优先的msix中断(在param.c里面配置).    根据adapter->msix_entries的个数, 逐个申请msix中断, 并注册中断向量.

  分别注册了3个中断函数: e1000_intr_msix_rx,    e1000_intr_msix_tx  , e1000_msix_other

   e1000_intr_msix_rx: 调用系统收包函数. 通过调用发送软中断, 通知内核调度网卡napi的poll函数. 调用e1000_clean, 这个函数清理收队列skb的映射信息. 申请同等数量的skb, 同时根据流量, 设置是否卡其常规中断

   e1000_intr_msix_tx: 清理中间信息. 调用e1000_clean_tx_irq释放已经发送完成的skb内存, 解除skb的dma映射

   e1000_configure_msix: 重要函数, 设置dma发送中断的频率以及内容

   常规中断回调函数: e1000_intr, 作用和e1000_intr_msix_rx差不多, 也是唤醒内核收包

 

5) 后面就是一些网卡使能工作, 通知系统开始收包, 可以working了

最后要说明一下的是发包函数, 系统发包调用底层的的e1000_xmit_frame,  这个函数重要的功能就是把要发送的报文地址映射到dma发射区. 通知dma发送

 

收包的大致流程:

1) 申请skb, 把skb映射到dma, 开启dma收包,

2) dma收包后发起中断, 调用, 清理dma映射区, 申请同等数量的skb, 把这些skb重新映射到dma, 相当于把空闲的dma补上

3) 把收到的报文, 丢给系统内核协议栈解析

4) 并根据流量大小,  看是否开启传统中断(传统中断的处理上面有描述)

5) 循环

e1000_intr_msix_rx ->   e1000_clean ->    e1000_clean_rx_irq -> e1000_receive_skb

 

发包的大致流程:

1) send发送到skb

2) 调用底层驱动e1000_xmit_frame发送skb

3) 申请dma映射到dma发送队列, 准备发送

4) 发送完成,发送中断, 调用e1000_intr_msix_tx, 解除skb的dma映射

5) 循环

e1000_xmit_frame-> e1000_tx_map -> e1000_tx_queue ->    e1000_intr_msix_tx -> e1000_clean_tx_irq -> (skb_dma_unmap, dev_kfree_skb_any)

相关数据结构:

 

 

 

 

 

 

 

 

 


http://www.ppmy.cn/news/585099.html

相关文章

e100网卡收包流程分析

四、网卡的数据接收内核如何从网卡接受数据&#xff0c;传统的经典过程&#xff1a; 1、数据到达网卡&#xff1b; 2、网卡产生一个中断给内核&#xff1b; 3、内核使用I/O指令&#xff0c;从网卡I/O区域中去读取数据&#xff1b; 我们在许多网卡驱动中&#xff0c;都可以在网卡…

E100.C简析(~/drivers/net/ethernet/intel/e100.c)

2019独角兽企业重金招聘Python工程师标准>>> 支持网络协议栈的底层网卡驱动是一个怎么也绕不过去的话题&#xff0c;以Intel PRO/100网卡驱动为例&#xff0c;分析一下Linux下网卡驱动的实现。同时也兼谈一些pci总线的问题。PCI总线的框架系统只提供对PCI总线系统的…

Intel E100 网卡驱动实例分析

本来是做zero-copy的&#xff0c;顺便把分析记录写下来&#xff0c;供大家参考&#xff0c;如果有错误清大家多包涵。只挑重要的来说&#xff0c;一些细节的地方我也不大懂&#xff0c;要看芯片手册才行&#xff0c;我们作软件的就别看那么细了&#xff0c;最重要是把主要流程弄…

Java获取文件的hash值(SHA256)

目录 简介 获取网络文件的sha256值&#xff08;方式一&#xff09; 获取本地文件的sha256值&#xff08;方式二&#xff09; 简介 在工作开发当中需求要通过文件的hash值比对文件是否被篡改过&#xff0c;于是通过使用了&#xff08;sha256&#xff09;hash值进行比对&#x…

【STL】容器适配器

放在专栏【C知识总结】&#xff0c;会持续更新&#xff0c;期待支持 1、什么是适配器&#xff1f; 我们生活中就存在大量的适配器&#xff0c;最常见的莫过于我们常见的电源适配器&#xff0c;它的作用就是将交流电源转化为直流电源进行输出&#xff0c;可以说电源适配器在电流…

[算法前沿]--022-Pytorch从0编写Transformer算法

文章目录 预备工作背景模型架构Encoder部分和Decoder部分EncoderDecoderAttention模型中Attention的应用基于位置的前馈网络Embeddings and Softmax位置编码完整模型训练批处理和掩码Training Loop训练数据和批处理硬件和训练时间Optimizer正则化标签平滑实例<

Ansys Zemax | 内窥镜物镜系统初始结构的优化提升(下)

系统性能提升 根据上篇的内窥镜系统分析&#xff0c;我们可以从四个方面对内窥镜物镜系统进行优化&#xff1a;元件间距、圆锥系数、MTF 值以及畸变值。点击优化-评价函数编辑器以设置具体的评价函数。&#xff08;联系我们获取文章附件&#xff09; 首先&#xff0c;用三个 CO…

4K、2K、1080p、720p、480p、240p常见视频清晰度

记录自用 一、清晰度对应的格式 标号视频类型格式尺寸类型比例14K4096*21604K16:922K2560*14402K16:93全高清1920*10801080p16:94高清1280*720720p16:95标清720*480480p3:26标清640*480480p4:37流畅320*240240p​4:3 注&#xff1a; 字母P意为逐行扫描 多数情况下4k特指4096…