嵌入式系统的以太网接口设计及linux内核网络设备驱动.docx
- 文档编号:5248470
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:15
- 大小:175.52KB
嵌入式系统的以太网接口设计及linux内核网络设备驱动.docx
《嵌入式系统的以太网接口设计及linux内核网络设备驱动.docx》由会员分享,可在线阅读,更多相关《嵌入式系统的以太网接口设计及linux内核网络设备驱动.docx(15页珍藏版)》请在冰豆网上搜索。
嵌入式系统的以太网接口设计及linux内核网络设备驱动
嵌入式系统的以太网接口设计及linux驱动
1以太网概述
以太网(Ethernet)是当今局域网采用的最通用的通信协议标准。
在以太网中,所有计算机被连接在一条电缆上,采用带冲突检测的载波侦听多路访问(CSMA/CD)方法,采用竞争机制和总线拓扑结构。
基本上,以太网由共享传输媒体,如双绞线电缆或同轴电缆、多端口集线器、网桥或交换机构成。
按照OSI(OpenSystemInterconnectionReferenceModel,开放式系统互联参考模型)7层参考模型,以太网定义的是物理层(PHY)和数据链路层(对应以太网的MAC层)的标准。
2嵌入式处理器上扩展以太网接口
以太网接口控制器主要包括MAC乘PHY两部分,如图1所示为嵌入式处理器集成MAC层控制器。
MAC层控制器和PHY的连接是通过MII、RMII等接口实现的。
在IEEE802的标准系列中,数据链路层包括LLC和MAC两个子层。
其中MAC负责完成数据帧的封装、解封、发送和接受功能。
PHY层的结构随着传输速率的不同而有一定的差异。
对于1OBaseT等网络,从以太网PHY芯片输出的就是传输所需的差分信号。
但是还需要一个网络隔离变压器组成图2的结构。
网络隔离变压器可起到抑制共模干扰、隔离线路以及阻抗匹配等作用。
本文介绍一种新款网络接口芯片DM9000A,它可以很方便的实现与嵌入式CPU的接口,实现扩展以太网口的功能。
DM9000A是中国台湾DAVICOM公司推出的一款高速以太网接口芯片,其基本特征是:
集成10/100M物理层接口;内部带有16K字节SRAM用作接收发送的FIFO缓存;支持8/16bit两种主机工作模式:
通过HP认证的AUTO-Mdix(支持直接互连自动翻转)功能;支持TCP/IP加速,减轻CPU负担,提高整机效能;10nsI/O读写时间。
DM9000A以太网控制器遵循IEEE颁布的802.3以太网传输协议。
该电路还集成了EEPROM接口,自举时通过EEPROM接口输入到芯片中,从而实现自动初始化。
芯片和处理器的连接原理图就不列图表示了,处理器这里选择AT91RM9200,DM9000A与处理器连接时要注意:
◆总线宽度读/写等待周期、时序匹配问题
◆CS8900A芯片复位后,在总线上的默认地址如何配置与保存
◆默认的中断号及中断触发模式问题(上升沿,还是下降沿;低电平,还是高电平触发)
系统上电时,AT91RM9200通过总线配置DM9000A内部网络控制寄存器(NCR)、中断寄存器(ISR)等,完成DM9000A的初始化。
随后,DM9000A进入数据收发等待状态。
当AT91RM9200向以太网发送数据时,先将数据打包成UDP或IP数据包,并通过16bit总线发送到DM9000A的数据发送缓存中,然后将数据长度等信息填充到DM9000A的相应寄存器内,使能发送。
当DM9000A接收到外部网络送来的以太网数据时,首先检测数据帧的合法性,如果帧头标志有误或存在CRC校验错误,则将该帧数据丢弃。
否则将数据帧缓存到内部RAM,并通过中断标志位通知AT91RM9200,由AT91RM9200对DM9000A接收到的数据进行处理。
3linux网络驱动程序
3.1Linux网络驱动程序体系结构
Linux的网络系统主要是基于BSDUNIX的套接字(socket)机制。
在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据传输。
系统支持对发送数据缓存,提供流量控制机制,提供对多协议的支持。
Linux网络驱动程序的体系结构可划分为图2所示的4个层次.Linux内核中提供了网络设备接口及以上层次的代码,所以移植(或编写)特定网络硬件的驱动程序最主要的工作就是完成设备驱动功能层,主要是包括数据的接收,发送等控制。
Linux中所有的网络设备都抽象为一个接口,有结构体structnet_device来表示网络设备在内核中的运行情况,即网络设备接口,此结构体位于网络驱动层的核心地位。
net_device中有很多供系访问和协议层调用的设备方法。
网络驱动就是要实现这些具体的设备方法。
3.2网络设备的初始化
由结构体net_device中的init函数指针所指向的初始化函数来完成。
网络的初始化是设备工作的第一步。
当系统加载网络驱动模块的时候,就会调用初始化过程。
首先利用函数:
request_mem_region映射DM9000A的数据、地址端口,通过dmfe_probe函数检测网络物理设备是否存在,检测DM9000A内部串行NIC的值是否正确,然后再对设备进行资源配置,构造设备的net_device数据结构。
包括一些低层硬件信息:
base_addr(网络接口的I/O基地址),irq(安排的中断号)等。
3.3 打开设备和关闭设备
open方法在网络设备被激活的时被调用,具体DM9000A的硬件初始化工作放到这里来做。
对于DMOOOOA需要完成的初始化包括:
对DM9000A内部上电,软件复位,通过NCR寄存器设置网络工作模式,可以选择设置内部或者外部PHY、全双工或者半双工模式、使能唤醒事件等网络操作,对RX/TX中断使能,使能数据接收功能。
调用request_jrq()申请中断号登记中断处理函数,调用netif_carrier_on侦测连接状态。
启动定时器,调用netif_start_queue激活设备发送队列。
这里对DM9000A的中断设计做了一个特殊处理:
通常AT91RM9200提供最多32个中断源,默认提供7个外部中断源,但对于较复杂的嵌入式系统,可能会面临中断源不够用的情况。
由于AT9lRM9200的PIO可以实现功能复用,因此可以把多余的IO引脚配置为可用的中断源。
故本系统中,设计DM9000A中断源与AT91RM9200外部I/O口PD8引脚相连。
一个PIO端口的32个引脚共享一个中断ID,只需要在中断状态寄存器中区分具体哪个引脚引起中断,然后转向特定的中断处理函数执行操作,就可以实现中断处理。
close所做的工作和open相反,主要释放open获得的资源,以减少系统负担。
3.4 数据包发送
数据包的发送和接收是实现Linux网络驱动程序中两个最关键的过程,对这两个过程处理的好坏将直接影响到驱动程序的整体运行质量。
数据传输通过hard_start_xmit函数实现,首先把存放在套接字缓冲区中的数据发送到网络芯片DM9000A内部的TX FIFO SRAM中,该缓冲区是由数据结构sk buff表示,把要传送的数据长度写入DM9000A中的传输包长度寄存器TXPLL和TXPLH中。
然后使能传输。
如果数据发送成功,则会触发一次中断。
实际中会出现多个数据帧传输,需要考虑做并发处理。
在发送时检测传输队例暂时满载时就要通过netif_stop_queue来暂停,当发送完成触发中断处理时,调用netif_wake_queue函数来重新启动传输队例。
网络传输由于系统忙或硬件的问题发生延迟,则会调用传送超时处理函数tx_timeout,对硬件复位操作。
3.5 数据包接收
数据包的接收是通过中断处理,当有数据到达时,就产生中断信号,网络设备驱动功能层就调用数据包接收程序来处理数据包的接收,然后网络协议接口层调用netif_rx函数把接收到的数据包传输到网络协议的上层进行处理。
DM9000A接收缓存区中的每帧数据由4字节长的首部、有效数据和CRC校验序列构成。
首部4字节依次是01H、以太网帧状态、以太网帧长度低字节和长度高字节,数据包接收程序首先检测如果第一个字节是01H,则说明有数据;如果是00H,则说明无数据,需要进行复位。
然后调用函数dev_alloc_skb申请一块sK_buff结构缓冲区,从DM9000A读出数据放置到缓冲区里,根据获取的长度信息,判断是否读完一帧。
如果读完,接着读下一帧,直到遇到首字节是00H的帧,说明接收数据已读完。
接下来填充sK_buff中的一些信息,使之成为规范的sk_buff结构,最后调用netif_rx()函数将接收到的数据传输到网络协议的上层。
最后,可通过两种方法加载网络设备驱动程序:
系统内核加载和模块加载。
4 网络的应用及测试
通过读取/proc/net中的信息得到当前系统中的网络设备,通过它来测试:
#cat/proc/net/dev
Linux网络配置可在应用程序中通过ifconfig和router两个命令实现,它们都可以在busybox软件包中找到。
可用以下命令来配置ip、网关、子网掩码和域名解析服务器:
# ifconfig eth0 192.168.0.11O
# route add -net default gw 192.168.0.254 netmask 255.255.255.0
# nameserver 202.106.196.115
最后,通过Ping命令,来测试一下和主机的通信是否联通。
在本系统中通过。
在嵌入式应用程序开发及调试中,NFS起着非常重要的应用。
不但可以通过NFS文件系统共享远程硬盘的文件,我们还可以mount远程文件系统直接作为嵌入式的根文件系统。
5 结论
本文完成了Linux下扩展以太网接口及测试网络接口的研究,采用了以太网芯片DM9000,围绕太分析了嵌入式Linux 网络的基本原理。
最后我的嵌入式设备顺利连上网络。
同时本文为移植2.6内核的网络部分提供了移植方法。
浅谈Linux内核开发之网络设备驱动
赵昊翔,软件工程师,CiscoSystems
简介:
本文介绍了网络设备的基本概念,并从Linux内核的角度出发,介绍了网络设备驱动的开发方法和开发中的注意事项。
网络设备介绍
网络设备是计算机体系结构中必不可少的一部分,处理器如果想与外界通信,通常都会选择网络设备作为通信接口。
众所周知,在OSI(OpenSystemsInterconnection,开放网际互连)中,网络被划分为七个层次,从下到上分别是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
我们所讲的网络设备也包括两个层次,一层叫做MAC(MediaAccessControl)层,对应于OSI的数据链路层;另一层叫做PHY(PhysicalLayer)层,对应于物理层。
常用的网络设备有很多,比如PPC85XX的TSEC、AMCC440GX的EMAC、INTEL的82559等,它们的工作原理基本相同。
DMA介绍
网络设备的核心处理模块是一个被称作DMA(DirectMemoryAccess)的控制器,DMA模块能够协助处理器处理数据收发。
对于数据发送来说,它能够将组织好的数据自动发出,无需处理器干预;对于数据接收来说,它能够将收到的数据以一定的格式组织起来,通知处理器,并等待处理器来取。
DMA模块收发数据的单元被称为BD(BufferDescription,缓存描述符),每个包都会被分成若干个帧,而每个帧则被保存在一个BD中。
BD结构通常包含有以下字段:
typedefstruct{
void*bufptr;/*保存当前BD对应缓存的起始地址*/
intlength;/*保存缓存中存储的数据包长度*/
intsc;/*保存当前BD的状态信息*/
}BD_STRUCT;
所有的BD就组成了一张BD表,如图1所示,一般来说发送方向和接收方向的BD表是各自独立的。
图1.BD表结构
数据发送流程
网络设备通过DMA进行数据发送的流程如 图2所示。
图2.数据发送流程
图中各步骤的具体含义描述如下:
(1)协议层通知处理器开始发送数据;
(2)处理器从BD表中取出一个BD,将需要发送的数据拷贝至当前BD对应的缓存内,并设置好BD的状态;
(3)处理器通知网络设备开始发送数据;
(4)MAC模块通知DMA单元开始发送数据;
(5)DMA模块操作BD表,取出当前有效BD;
(6)DMA模块将当前BD对应缓存内的数据发送至MAC模块;
(7)MAC模块将这些数据发送到网络中;
(8)网络设备通知处理器数据发送完毕;
(9)处理器通知协议层发送下面一帧数据。
其中步骤(4)~(8)是硬件自动完成的,不需要软件的干预,如此可以节省处理器的工作量。
数据接收流程
网络设备通过DMA进行数据接收的流程如图3所示。
图3.数据接收流程
图中各步骤的具体含义描述如下:
(1)处理器初始化BD表;
(2)处理器初始化网络设备;
(3)MAC模块从网络中接收数据;
(4)MAC模块通知DMA模块来取数据;
(5)DMA模块从BD表中取出合适的BD;
(6)MAC模块将数据发送至当前BD对应的缓存内;
(7)网络设备通知处理器开始接收数据(以中断方式或轮询方式);
(8)协议层从当前的BD缓存内取走数据。
其中步骤(3)~(6)是硬件自动完成的,不需要软件的干预,如此可以节省处理器的工作量。
回页首
Linux网络设备驱动模型
数据结构
数据结构
Linux内核中对网络设备进行描述的核心结构类型叫做net_device,net_device结构定义在include/linux/netdevice.h文件中。
该结构的字段可以分为以下几类。
全局信息
该类中包含了设备名(name字段)、设备状态(state字段)、设备初始化函数(init字段)等。
硬件信息
该类中包含了设备内存使用情况(mem_end和mem_start字段)、中断号(irq字段)、IO基地址(base_addr字段)等。
接口信息
该类中包含了MAC地址(dev_addr字段)、设备属性(flag字段)、最大传输单元(mtu字段)等。
设备接口函数
该类中包含了当前设备所提供的所有接口函数,比如设备打开函数(open字段),该函数负责打开设备接口,当用户使用ifconfig命令配置网络时,该函数默认被调用;设备停止函数(stop字段),该函数负责关闭设备接口;数据发送函数(hard_start_xmit字段),当用户调用socket开始写数据时,该函数被调用,并负责往网络设备中发送数据。
函数接口
设备初始化函数
网络设备驱动在Linux内核中是以内核模块的形式存在的,对应于模块的初始化,需要提供一个初始化函数来初始化网络设备的硬件寄存器、配置DMA以及初始化相关内核变量等。
设备初始化函数在内核模块被加载时调用,它的函数形式如下:
staticint__initxx_init(void){
……
}
module_init(xx_init);//这句话表明模块加载时自动调用xx_init函数
设备初始化函数主要完成以下功能:
1.硬件初始化
因为网络设备主要分为PHY、MAC和DMA三个硬件模块,开发者需要分别对这三个模块进行初始化。
1.初始化PHY模块,包括设置双工/半双工运行模式、设备运行速率和自协商模式等。
2.初始化MAC模块,包括设置设备接口模式等。
3.初始化DMA模块,包括建立BD表、设置BD属性以及给BD分配缓存等。
2.内核变量初始化
初始化并注册内核设备。
内核设备是属性为net_device的一个变量,开发者需要申请该变量对应的空间(通过alloc_netdev函数)、设置变量参数、挂接接口函数以及注册设备(通过register_netdev函数)。
常用的挂接接口函数如下:
net_device*dev_p;
dev_p->open=xx_open;//设备打开函数
dev_p->stop=xx_stop;//设备停止函数
dev_p->hard_start_xmit=xx_tx;//数据发送函数
dev_p->do_ioctl=xx_ioctl;//其它的控制函数
……
数据收发函数
数据的接收和发送是网络设备驱动最重要的部分,对于用户来说,他们无需了解当前系统使用了什么网络设备、网络设备收发如何进行等,所有的这些细节对于用户都是屏蔽的。
Linux使用socket做为连接用户和网络设备的一个桥梁。
用户可以通过read/write等函数操作socket,然后通过socket与具体的网络设备进行交互,从而进行实际的数据收发工作。
Linux提供了一个被称为sk_buff的数据接口类型,用户传给socket的数据首先会保存在sk_buff对应的缓冲区中,sk_buff的结构定义在include/linux/skbuff.h文件中。
它保存数据包的结构示意图如下所示。
图4.sk_buff数据结构图
1.数据发送流程
当用户调用socket开始发送数据时,数据被储存到了sk_buff类型的缓存中,网络设备的发送函数(设备初始化函数中注册的hard_start_xmit)也随之被调用,流程图如下所示。
图5.数据发送流程图
a.用户首先创建一个socket,然后调用write之类的写函数通过socket访问网络设备,同时将数据保存在sk_buff类型的缓冲区中。
b.socket接口调用网络设备发送函数(hard_start_xmit),hard_start_xmit已经在初始化过程中被挂接成类似于xx_tx的具体的发送函数,xx_tx主要实现如下步骤。
1.从发送BD表中取出一个空闲的BD。
2.根据sk_buff中保存的数据修改BD的属性,一个是数据长度,另一个是数据包缓存指针。
值得注意的是,数据包缓存指针对应的必须是物理地址,这是因为DMA在获取BD中对应的数据时只能识别储存该数据缓存的物理地址。
bd_p->length=skb_p->len;
bd_p->bufptr=virt_to_phys(skb_p->data);
3.修改该BD的状态为就绪态,DMA模块将自动发送处于就绪态BD中所对应的数据。
4.移动发送BD表的指针指向下一个BD。
c.DMA模块开始将处于就绪态BD缓存内的数据发送至网络中,当发送完成后自动恢复该BD为空闲态。
2.数据接收流程
当网络设备接收到数据时,DMA模块会自动将数据保存起来并通知处理器来取,处理器通过中断或者轮询方式发现有数据接收进来后,再将数据保存到sk_buff缓冲区中,并通过socket接口读出来。
流程图如下所示。
图6.数据接收流程图
a.网络设备接收到数据后,DMA模块搜索接收BD表,取出空闲的BD,并将数据自动保存到该BD的缓存中,修改BD为就绪态,并同时触发中断(该步骤可选)。
b.处理器可以通过中断或者轮询的方式检查接收BD表的状态,无论采用哪种方式,它们都需要实现以下步骤。
1.从接收BD表中取出一个空闲的BD。
2.如果当前BD为就绪态,检查当前BD的数据状态,更新数据接收统计。
3.从BD中取出数据保存在sk_buff的缓冲区中。
4.更新BD的状态为空闲态。
5.移动接收BD表的指针指向下一个BD。
c.用户调用read之类的读函数,从sk_buff缓冲区中读出数据,同时释放该缓冲区。
中断和轮询
Linux内核在接收数据时有两种方式可供选择,一种是中断方式,另外一种是轮询方式。
中断方式
如果选择中断方式,首先在使用该驱动之前,需要将该中断对应的中断类型号和中断处理程序注册进去。
网络设备驱动在初始化时会将具体的xx_open函数挂接在驱动的open接口上,xx_open函数挂接中断的步骤如下。
request_irq(rx_irq,xx_isr_rx,……);
request_irq(tx_irq,xx_isr_tx,……);
网络设备的中断一般会分为两种,一种是发送中断,另一种是接收中断。
内核需要分别对这两种中断类型号进行注册。
1.发送中断处理程序(xx_isr_tx)的工作主要是监控数据发送状态、更新数据发送统计等。
2.接收中断处理程序(xx_isr_rx)的工作主要是接收数据并传递给协议层、监控数据接收状态、更新数据接收统计等。
对于中断方式来说,由于每收到一个包都会产生一个中断,而处理器会迅速跳到中断服务程序中去处理收包,因此中断接收方式的实时性高,但如果遇到数据包流量很大的情况时,过多的中断会增加系统的负荷。
轮询方式
如果采用轮询方式,就不需要使能网络设备的中断状态,也不需要注册中断处理程序。
操作系统会专门开启一个任务去定时检查BD表,如果发现当前指针指向的BD非空闲,则将该BD对应的数据取出来,并恢复BD的空闲状态。
由于是采用任务定时检查的原理,从而轮询接收方式的实时性较差,但它没有中断那种系统上下文切换的开销,因此轮询方式在处理大流量数据包时会显得更加高效。
回页首
Linux网络设备驱动优化
随着科技的不断发展,网络设备所能承载的速率在不断提升,当前流行的网络设备普遍都能支持10Mbps/100Mbps/1Gbps这三种速率。
虽然网络设备的硬件性能在不断的提升,但是实际在Linux系统中其运行性能(收发包速率)真能达到多达1Gbps的水平吗?
这和处理器的性能有关,一般来说我们运行的系统中报文的收发速率是达不到1Gbps的(因为我们不可能将所有处理器的资源都贡献给报文的收发),但是我们可以在有限的条件下尽可能的采取一些优化手段提高网络设备的运行性能。
Cache的应用
Cache位于存储系统金字塔的顶层(下面一层是内存),Cache的容量不大(一级Cache一般是几十KB,二级Cache一般是几MB),但是它的访问速率却是内存的几十倍。
因此如果处理器通过Cache来访问内存,将会极大的提高访问速率。
在网络设备的数据收发中,恰当的应用Cache可以优化驱动的性能。
下面列举几点Cache的优化措施。
合理设置内存属性
内存的页表有多种属性,其中有一项就是是否通过Cache访问。
在给BD表配置内存时,这些被分配的内存属性需要支持Cache访问。
Cache的访问还有两种方式:
一种是写回操作(WriteBack),处理器更新内存数据时,该数据首先保存在Cache中,Cache并不及时将数据更新进内存,而是等到Cache需要再次更新时才会将数据写回到内存中。
另一种是写穿操作(WriteThrough),处理器更新内存数据时,该数据首先保存在Cache中,Cache随即将数据立刻更新进内存。
显而易见,写回操作的性能比写穿操作更高,通常我们设置内存页表属性为写回方式。
数据收发时的Cache操作
在内存支持Cache且采用写回方式的情况下,当发送数据时,处理器
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式 系统 以太网 接口 设计 linux 内核 网络设备 驱动
![提示](https://static.bdocx.com/images/bang_tan.gif)