随着电子信息技术的发展,嵌入式系统应用到了社会生活的各个角落。后PC时代是嵌入式和网络化的时代,将分散在各处的嵌入式设备连接到网络成为近年来以及未来的发展趋势,随时随地都能通过网络去控制这些智能设备,在多种嵌入式设备之间进行数据通信,例如信息终端、信息家电等。用户可以通过信息终端从网络服务商提供的服务中搜索并浏览有用的信息,实现全面交流和互动,实现新型的信息金融终端的概念,同时,用户也可享受到网上金融信息、网上购物、视频会议等其他服务。
本文提出了一种基于Linux 2.4操作系统平台和Intel PXA255处理器的网络设备驱动设计方案,分析了其软硬件实现以及Linux下网络设备驱动的特性。
1 网卡设备
本方案使用的CS8900A是一款低功耗的网络控制器,包含一块片上 RAM、10BASE-T接收和发送滤波器、ISA总线接口,提供了多种性能和配置选项,它独立的包页(packet page)体系结构能自适应改变网络通信模式和可用的系统资源,提高了系统效率。该控制器支持IEEE 802.3的10 Mbit/s模式,全双工单片以太网解决方案。主要模块有:一个直接ISA总线接口;一个802.3 MAC引擎,处理以太网帧发送和接收的各个方面;集成4 kB的页可缓冲存储器,将发送和接收的帧完全缓冲在网卡中;一个串口EEPROM接口;完全模拟前端10BASE-T(10 Mbit/s)和AUI(粗缆网卡接口)。
2 Linux驱动
Linux驱动分为字符设备、块设备和网络设备驱动。字符设备是能够像字节流一样被访问的设备,大多数字符设备只能被顺序访问。块设备驱动程序提供面向块的设备的访问,这种设备以随机访问的方式传输数据,并且数据总是具有固定大小的块,这些块中包含了2的几次幂字节的数据,硬盘就是典型的块设备。
在Linux中,字符设备和块设备都是通过文件系统节点被访问,块驱动程序除了向内核提供与字符驱动程序相同的接口外,还提供了专门面向块驱动设备的接口。
网络接口在系统中的角色与一个已挂装的块设备非常相似。块设备将自己注册到blk_dev数组以及其他内核结构中,然后通过自己的request函数在发生请求时“发送”和“接收”数据块。同样,网络接口也必须在特定的数据结构中注册自己,以便在与外界交换数据包时被调用。但是,块设备接口与网络数据包发送接口之间存在不同。普通的文件操作对网络接口来说没有任何意义,因此,Unix的“所有东西都是文件”这一思想无法应用于网络接口。这样,网络接口存在于它们自己的名字空间中,同时导出一组不同的操作。同一网络接口可以由几百个套接字同时复用。块没备驱动只对来自内核的请求做出响应,而网络驱动程序却异步地接收来自外界的数据包。
网络驱动程序同时必须支持大量的管理任务,例如设置地址、修改传输参数以及维护流量和错误统计等。网络驱动程序的API反映了这种需求。此外,网络驱动程序与内核其余部分之间每次交互处理的是一个网络数据包,因此,驱动程序无需关心协议问题。
3 实现方案
3.1 硬件连接
硬件平台使用Intel PXA255处理器作为主机,工作频率400 MHz,网卡的品振为20 MHz,网卡的数据线和地址线通过缓冲后与CPU直接相连,硬件电路如图1所示。
网卡的读写使能引脚IOR/IOW信号主要由CPU采用Flash存储器的方式给出,与PWE和MOE两个引脚分别连接,其有效时间由CPU内部的寄存器配置而得。
网卡内部寄存器使能引脚AEN由CPU片选脚E_CS组合得出,而网卡复位引脚则通过CPU的一个GPIO口给出。
从电路中可以看出只使用了4根地址线,因此,对网卡中的寄存器的访问采用packet page寄存器间接寻址,即通过地址线先对packet page访问,将欲访问的寄存器R的偏移地址送到packet page寄存器中,然后通过数据线去读或者写此寄存器。
3.2 软件实现
网卡驱动可看做是连接网络层与实际网络设备的一个软件层。在网卡设备驱动中,通过维护一个名为net_device结构的dev指针来实现上层对驱动程序的访问。这个结构包括了对管理网络设备所必须完成的操作,包括设备的打开、关闭、发送数据、接收数据、获得状态、设置网卡地址、处理超时等。
以下主要介绍这些操作的实现,包括设备的初始化和注销、对中断事件的处理。
3.2.1 设备初始化
由于需要通过Memory模式访问网卡设备,因此需要配置存储器控制寄存器VLIO(Variable Latency)模式。关联设备的初始化探测函数cirrus_probe,在cirrus_probe函数中主要是填充该设备的Dev结构。网络接口探测方式不同,所以不能在编泽阶段进行Dev结构的设置。这样从Dev→init返回时,Dev结构中就应该填充正确的值。Dev结构中包含相关的网卡操作函数的指针,为上层调用网卡驱动提供方法。内核提供了ethr_setup函数,可处理以太网的某些缺省设置。在探测函数中还要分配net_device的priv字段,该字段所指向的数据项通常包含接口上的统计信息。用户可以在任何时刻通过调用ifconfig获得统计数据,向内核注册网络设备驱动程序。
这里简要介绍网络设备驱动中两个重要的结构体:Linux内核提供的统一网络设备结构net_device,定义了系统统一的访问接口,此结构体位于网络驱动层的核心地位;net_device_stats结构体用来记录网络驱动发送和接收数据量的统计信息,例如发送包的数目以及丢失包的数目。当应用程序需要获得接口的统计信息时,将调用该方法。
3.2.2 设备的注销
设备的注销过程与设备初始化的过程相反,释放网卡的地址空间及网卡驱动使用的其他相关资源,注销网络设备的Dev结构。
3.2.3 中断处理
网卡工作有轮循和中断两种模式。轮循模式会大量占用CPU资源,影响嵌入式系统性能,因此这里选择中断模式。有5种情况会触发中断,每种情况对应不同的中断寄存器,中断发生会将某一模式寄存器的相应位置位,并且把这种模式寄存器中的内容映射到中断状态寄存器。当有中断事件发生后,进入中断例程,如图2所示,首先读取中断状态寄存器的内容,然后根据其中的信息判断是哪种情况触发的中断,最后进入相应的分支进行处理。
3.2.4 对5种中断状态的处理
1) 接收帧
如图3所示,当网卡接收到数据就会触发一次中断,在中断例程中调用接收包的函数cirrus_receive。首先读取接收的状态和长度,使用dev_alloc_skb分配一段足够大小的缓冲区,得到该包的网络协议ID号,在一个申请好的sK_buff的缓冲区中保留一块空间,这个空间一般是用做下一层协议的头空间;接着将网卡接收缓冲区中的数据读到skb缓冲区中,再使用netif_rx通知上层协定有新的封包传人。当一个封包传送完成后,必须将缓冲区释放。
2) 发送帧
当主机要发送数据时调用hard_start_xmit方法将数据放人外发队列,而此方法关联的函数就是cirrus_send_start。内核处理后的每个数据包位于一个套接字缓冲区(struct sK_buff)结构,核心处理的每个包包含在一个套接字缓冲区结构,输入输出缓冲区都是sk_buff结构的链表,传递给hard_start_xmit的套接字缓冲区含有物理包,它具有传输层的包头。接口不需要修改被发送的数据。实际的硬件接口是异步传输数据包的,硬件中有缓冲区以保存要外发的数据包,但是此缓冲空间非常有限。如图4所示,在此函数中首先通知上层表明硬件缓冲区已经用完不要再送封包下来,然后向网卡发命令表示要开始发送数据并且指明发送数据的长度,接着读BusST寄存器判断当前网卡状态,如果主机中的发送缓冲区可用,则将SKB中数据发到网卡的缓冲区中,最后释放SKB。如果网卡将数据发送成功,则会触发一次中断,在中断处理例程中将net_device_stats结构体中的tx_packets(表示发送的包的个数)元素递增并通知上层可继续送包下来。
3) BufEvent
Buffer事件当RxMiss置位表示由于数据从缓冲区中搬移到主机速度较慢而丢失了一些接收的帧,读寄存器获取丢失的包的数目。当TxUnderrun置位表示在帧结束前网卡运行已过时。改变网络状态结构体中对应元素的值,接着通知上层可往下发送包数据。
4) TxCOL
当传输出现冲突错误时,通过读寄存器值得到当前冲突的个数,加到统计结构体中的对应元素值上。
5) RxMISS
读寄存器获取丢失帧的个数。
3.2.5 传输超时的处理
驱动程序要处理硬件不能正确响应的情况,比如中断丢失或者接口工作异常等。网络系统使用大量定时器控制的多个状态机之间流转来检测传输超时,因此本驱动程序中无需自己检测超时间题而只是通过net_device结构的watchdog_timeo字段设置超时剧期为10 ms,对于一般的传输超时,此值能满足要求。当检测到系统时间超过设备传输开始的时间至少1个超时周期,网络层将调用cirrus_transmit_timeout方法,解决超时所要做的工作,主要是在统计信息中标记该错误,同时调用netif_wake_queue重新启动传输队列。
3.2.6 测试结果
网络设备驱动测试主要从底层硬件测试和上层网络测试两个方面进行。底层硬件测试使用如下方法:在内存中开辟两块区域M1、M2,并按照网络包的格式设置初始值,将M1中的数据通过网卡发送出去,但是以回环方式,最终还是由主机端接收到,存放到M2中,再将M2中的数据通过网卡发送出去,并接收回来。经过多次循环,比较最终的数据包和先前设置的数据包是否一致,经过此项测试表明在最底层数据发送和接收无误。上层网络测试使用如下方法:目标机和PC端通过网线相连,目标机端丌启pure-ftp服务,主机端使用FlashFXP软件,从主机分别传送不同大小(从0 MB到20 MB)文件到目标机,再从目标机传送到主机,执行多次比较传送文件是否有误,并计算网络传送速度。测试结果表明网卡驱动能较好地实现网络应用的功能,速度达到2 Mbit/s~5 Mbit/s。
4 结束语
本文提出了一种基于嵌入式Linux的网卡驱动实现方案,并介绍了Linux下网络设备驱动的一些特性。此方案已应用到基于Intel PXA255处理器的金融信息终端研发中,使用和测试表明此方案稳定可靠,也可为其他嵌人式系统的网络设备开发提供一定的参考。