admin管理员组

文章数量:1538723

2024年1月10日发(作者:)

嵌入式loader下PCIe网卡驱动设计与实现

1 么刚1 2 张武2

王劲林2

(中国科学院研究生院 北京100080)2(中国科学院声学研究所 北京 100080)

摘要:某些嵌入式系统需要在Bootloader中驱动网卡完成特定的网络功能。 本文针对嵌入式系统存储容量有限的特点,提出了PCIe类网卡简化驱动模型,并给出一个具体实现。对于嵌入式系统Bootloader下的网卡驱动开发有一定的借鉴作用。

关键词:PCI Express(周边原件高速扩展接口);嵌入式系统;网卡驱动

The Design and Realization of Simplification Model for PCIe NIC

Driver in Embedded Loader

Yao Gang1 2, Zhang Wu2 ,Wang Jinlin2

12(Graduate University of China Academy of Science. Beijing 100080)

(Institute of Acoustics, Chinese Academy of Science. Beijing 100080)

Abstract:Some embedded systems need to drive the NIC to

complete some network functions.

According to the limited storage capacity in embedded systems, this article presents a

simplification model for PCIe NICs, and gives an implementation. This will have some reference

value for NIC driver design in embedded Bootloader.

【Key Words】PCIe;embedded system;NIC driver

基金资助项目名称:家庭网络与IP多媒体子系统网络融合中的关键技术研究。

科学技术部(国家863计划);项目申请人:张武;项目编号:2007AA01Z238。

基金颁发部门:文献标示码:A;中图分类号:Tp336。

一、引言

为了兼容各厂商、型号的网卡,linux内核提出了四层结构的网卡驱动模型。但是有些嵌入系统需要在系统BIOS的引导装载程序(Bootloader)中完成特定的网络功能。嵌入式系统存储容量有限,往往不可能完全移植内核驱动。针对这种情况,结合PCIe类网卡逐渐成为主流网卡类型的趋势,本文提出了一种PCIe网卡驱动的简化模型,并以RealTek8101E网卡为例,给出实现。

二、LINUX内核中的网卡驱动模型

在linux操作系统中已经实现完备的网卡驱动程序,按照体系结构可以将linux网络驱动程序分为4个层次,由下至上依次为:设备媒介层、设备驱动功能层、网络设备接口层和网络协议接口层。其中网络协议接口层是网卡驱动程序和TCP/IP协议栈的接口层。网络设备接口层主要围绕着struct net_device结构展开,为所有的网络设备提供统一的接口,主要包括:设备的初始化、打开、关闭、发送、接收、中断处理、属性设置等等,不同的网卡设备对于网络设备接口层和网络协议接口层是透明的。设备驱动功能层针对不同的网卡进行设计,主要实现网卡数据的收发。设备媒介层是对网卡设备内部的寄存器进行配置。结构图如图1。

出于兼容性的考虑,Linux内核实现的网卡驱动引入了大量复杂的数据结构而且代码量巨大。然而嵌入式系统存储容量有限,需要进行简化处理。

图1、网络设备驱动程序结构图

三、PCIe网卡驱动简化模型的设计与实现

3.1PCIe网卡简化驱动模型的设计

受到嵌入式系统存储容量的限制,我们针对PCIe网卡,对网络设备驱动程序进行简化,该模型针对linux网络驱动的网络设备接口层和设备媒介层进行简化。出于兼容性的考提出了PCIe网卡驱动简化模型。

虑,Linux网卡驱动模型将网络设备接口层作为适配层,为不同厂家不同型号的网络设备提供统一接口。但是对于厂家型号都已经确定的特定的嵌入式系统而言,适配层不是必须的。而linux网卡驱动设备媒介层的主要功能是对网卡的寄存器进行操作,这是通过总线驱动进行管理的。为了方便管理,Linux内核为所有的总线(PCI,USB,I2C等等)提供了统一的接口,这也使linux内核不得不引入大量复杂的数据结构和代码。如果嵌入式系统仅需使用PCIe总线,那么完全可以对设备媒介层进行简化。

PCIe简易网卡驱动模型自上而下分为网络协议接口层、设备驱动层和PCIe配置层。

其中网络协议接口层是网卡驱动程序和TCP/IP协议栈的接口层。设备驱动层实现了linux内核中设备驱动功能层和网络设备接口层的主要功能,主要给出了net_device结构中的3个核心方法:设备初始化,数据接收和数据发送。实现PCIe配置层是为了可以方便的对网卡内部寄存器进行操作,是对设备媒介层的简化。

下面以RTL8101E网卡为例,说明网卡驱动简易模型的实现。

3.2PCIe网卡简化驱动模型的实现

PCIe网卡简化驱动流程如图2所示。网络接口层位于设备驱动层和协议栈之间,负责网络报文的拆分和组装。设备驱动层主要是通过主设备内存、网卡寄存器的操作完成设备初始化、数据发送、数据接收的功能。PCIe配置层隐藏在设备驱动层之下,负责实现对网卡寄存器的操作。

图2:PCIe网卡驱动简化模型流程图

3.2.1PCIe配置层的实现

PCIe配置层是对linux内核设备媒介层的简化。为方便对总线的管理,Linux内核使用了大量复杂的数据结构,实现对总线和挂载在总线上的设备的管理。然而嵌入式系统的BootLoader功能相对单一,不需要对总线和设备进行复杂的管理。因此,在PCIe配置层中,绕过了内核中复杂的数据结构,直接按照PCIe协议规范,实现对网卡寄存器的管理。

PCIe有3种地址空间:PCIe I/O空间,PCIe内存空间和PCIe配置空间。驱动程序将通过PCIe配置空间设置PCIe设备属性,将设备寄存器映射到PCIe I/O空间或内存空间,进而实现对设备内部寄存器的读写操作。为了完成映射,需要设置配置空间的Command和Base

Address。由Command指定映射方式(I/O映射或内存映射),由Base Address指定映射的起始地址。

映射完成后,驱动程序需要使用PCIe总线专用的地址寄存器和数据寄存器来实现对网卡内部寄存器的访问。访问PCIe设备的内部寄存器时,首先向地址寄存器中写入目标地址,然后在通过数据寄存器进行读写。这里写入地址寄存器的目标地址是一个包括了总线号、设备号、功能号以及配置寄存器地址的32bit综合地址。设置好地址寄存器后,对数据寄存器的读写操作即可映射到对应的内部寄存器上。

3.2.2网络协议接口层的实现

网络协议接口层是驱动程序和TCP/IP协议栈的接口,负责向协议栈屏蔽网卡数据收发

的细节。之所以要实现接口层,是与网卡对存储空间的组织形式有关,一般地,网卡存储空间组织结构如图3所示。描述头数组和数据存储区都位于主设备存储空间中,描述头数组是一块连续的储存空间,描述头数组的首地址由网卡寄存器指定,实际数据空间由描述头指定,可以是不连续的。描述头用于描述数据的属性,数据空间用于存放实际的网络数据。一般网卡至少有两组这样的两级结构,一组用于数据接收,一组用于数据发送。由于网卡的DataBuffer有大小的限制,一个大的网络数据包可能要拆分成几块分别存储在几DataBuffer中。网络协议接口层的主要功能就是对这些大的网络数据包进行拆分和组装。

图3、 网卡存储空间组织结构

接收描述头和发送描述头的结构略有不同,但都包含有OWN、EOR、FS、LS和Frame_Length等几个重要字段。OWN表示描述头对应的数据区中是否包含有效数据;EOR表示这个描述头位于描述头数组的末尾;FS置1表示所对应的数据是一个完整网络包的第一个分段;LS置1表示所对应的数据是一个完整网络包的最后一个分段;Frame_Length表示分段中有效数据长度。

当协议栈有数据需要发送时,接口层首先检查数据包大小,如果没有超出DataBuffer的大小,在发送描述头数组中选择一个空闲的描述头项,同时设置OWN、FS和LS位,表示这是一个完整的网络数据包;如果超出了DataBuffer的大小,则计算所需DataBuffer的个数,选择所需的空闲描述头项,并设置对应字段。将数据拷贝至DataBuffer之后,接口层通知驱动层的数据发送模块,数据区中有数据需要发送。

数据接收是数据发送的逆过程,不同的是接收描述头项中的OWN、FS、LS和Frame_Length等字段是由网卡按照数据接收的情况自动设置的。接口层在接到驱动层数据接收模块的通知后,检查接收描述头数组OWN、FS、LS位,并结合描述头项中数据包的源/目的地址、类型、CRC等信息,将数据分段进行分类,传递给协议栈。将分段传送给协议栈之后,接口层还负责将接收描述头设为空闲态。

3.2.3设备驱动层的实现

网卡驱动简易模型的设备驱动层实现了linux内核网卡驱动设备驱动功能层的主要功能,并根据嵌入式系统中设备型号固定,功能简单的特点,去掉了作为适配层的网络设备接口层,直接针对特定网卡的寄存器进行操作,完成网卡初始化,数据接收和数据发送的功能。

网卡的初始化

网卡在上电时会按照默认配置设置网卡的寄存器,如网卡厂商ID、设备ID和MAC地址等。但是为了使网卡可以正常工作,仍然需要对网卡寄存器进行初始化操作。初始化操作因网卡的厂商型号略有不同,但是在初始化时必须完成的操作有:重启芯片,并等待Reset位自动复位,即重启完成;为数据发送和数据接收申请存储空间,并用申请得到空间的首地址设置网卡内部的地址寄存器。设置网卡数据接收和数据发送的行为属性,如可接收数据包的

类型,数据接收区的大小等;设置中断屏蔽位,一般必须打开的中断屏蔽位有:TxOK,TxErr,RxOK,RxErr。

数据发送与数据接收

设备驱动层的数据发送和接收模块通过检测和维护网卡寄存器以及数据描述头的状态

数据发送模块在收到接口层的数据发送通知后,设置网卡的命令寄存器,启动网卡的,完成实际网络数据分段的发送和接收的功能。

DMA,将数据由主设备存储器经DMA传输到网卡内存,并发送到网络中。设置完成后,采取轮询方式检测中断状态位。如果检测到TxOK置位后,说明发送成功,把对应的描述头设置为空闲态,准备下一次数据发送;如果检测到TxErr置位,说明发送失败,重新发送。

数据接收模块负责用轮询方式测试中断寄存器中RxOK是否置位,如果RxOK位置位,说明有数据到达网卡,并且已经通过DMA将数据传输到主设备的存储器中。这时数据接收模块将通知网络协议接口层有数据达到,由接口层负责数据分段的拼接和接收描述头的状态复位。

四、结论

通过对linux内核中网卡驱动模型的简化,本文提出一种适用于嵌入式系统BootLoader下的PCIe网卡驱动模型,并以RTL8101E为例,给出了一个具体实现。按照这种方法驱动网卡,可以在嵌入式系统的BootLoader下完成在线升级等特定的网络功能。

本文作者创新点:在充分研究了linux内核网卡驱动模型的基础上,针对嵌入式终端存储容量有限的特点,提出了一种适用于嵌入式终端Bootloader下的PCIe网卡驱动简化模型,并给出一个实现。

参考文献

[1] RTL8101E_Registers_DataSheet_1.0(official)[R]

[2] 8101 Programming Guide[R]

[3] 裴喜龙, 童莉. 基于PCI总线的高速数据采集卡系统设计与实现[J].微计算机信息.2006-07s:129~131

[4] 刘峥嵘. 嵌入式Linux应用开发详解[M]. 机械工业出版社 2005.6:360~392

[5] 倪继利. Linux内核分析及编程[M]. 电子工业出版社 2006.1:374~394

作者简介:

么刚(1981-),男,河北秦皇岛人,中国科学院声学研究所在读博士生,研究方向:宽带通信/嵌入式系统研究

Biography: Yao Gang(1981-), Male, Born in Qinhuangdao, Hebei. Doctoral student in Acoustic

Institute of the Chinese Academy of Sciences. Research direction: Broadband communications/

Embedded Systems Research

王劲林(1964-),研究员,主任研究员。中国科学院声学研究所网络与数字信号处理技术研究中心主任;中国科学院网络新媒体技术工程研究中心主任;

张武,博士,助理研究员。

联系方式:北京北四环西路21号,中科院声学研究所DSP中心。邮编:100080。

本文标签: 网卡数据驱动设备接口