1、网卡简介
44b0开发板上用的网络芯片是rtl8019as,但是在移植u-boot到开发板的时候,网络的移植出了一点问题。
所以想看看rtl8019as这个网卡是如何工作的,很不幸的是,正如网络上很多人说的那样,rtl8019的文档及其的烂,真的不是一般的烂。
基本上看过它的文档,跟没看过没什么区别。
还好,参考了一些网络上的文章和自己的bios的网络驱动部分,对于rtl8019的工作方式,工作流程有了一个总体的概念。
主要参考了下面的几篇文章:
http://www.cnitblog.com/buf/archive/2008/11/01/50953.html
http://www.eaw.com.cn/news/techhotdisplay/article/15982
还有一篇很久之前杨屹的一篇关于rtl8019的介绍,这篇介绍非常的好。
rtl8019as网卡的功能:
一句话来说,网卡所完成的功能就是收发数据。
- 接收功能:从网络上接收数据,然后存储于网卡内部的RAM(本网卡为16KB)中,然后触发中断,通知CPU来取走数据。
- 发送功能:CPU发送的数据被复制到网卡内部的RAM中,然后网卡自主的在网络上发送这些数据。
由此可见,对于程序员来说,网卡其实就是一片内存区域。程序员对网卡的操作实际上可以认为是对内存的读写操作。
当网络上有数据传来时,网卡存储这些数据到内存,并通知CPU到内存的相应位置取相应大小的数据。
当CPU想向网络上传输数据时,只需要将数据写入网卡的内存,然后给网卡一个”发送”命令即可。
就是这么简单。
问题是,我们这里说的”数据”到底是什么?
很明显的,网络数据是一个层次性 很强的东西,OSI就规定了网络的7层协议,TCP/IP规定了5层协议,
从数据上来说,tcp帧作为IP帧的数据被打包进IP帧,而IP帧又作为以太网帧的数据被打包进以太网帧。
如上所述,CPU跟网卡的交互就是数据的读和写”数据”,但是,这个数据到底是什么数据呢?
我们该怎么理解从网卡中接收到的二进制数据呢?我应该认为它是一帧IP帧,还是一帧以太网帧呢?
我们写内存来发送数据,那么,我们发送的应该是什么格式的数据呢?我们是打包成IP数据,还是需要打包成以太网数据呢?
参考扬屹的那篇文章,接收和发送的数据的帧格式并不一样,如下图所示:
由上图可见,应用程序只需要将如上图所示的IP帧写入RAM中,其余的就叫给网卡去办就可以了。
而接收的数据,其实是一个修改过了的IP帧,整体还是在IP这个层次上。
由此可见,对于网络数据,应用层程序只需要处理到IP层,将数据打包成变形的IP帧即可。至于将IP帧打包成以太网帧然后在网络上传输,这些功能都是网卡自己完成的。
接收数据也是一样,从网卡的RAM中接收到的数据就是变形的IP帧,至于底层的物理链路数据和以太帧的解析,这些都是网卡完成的。
也就是说,IP层以下的处理,对于程序员来说,是透明的。
今天只是简单说说网卡的概念。
下一篇想分析一下rtl8019as的寄存器。
2、寄存器说明
rtl8019as的寄存器的介绍,可以直接参照它的数据手册。
但是,对于网卡的整个工作机制和工作流程不清楚的话,对某些寄存器的认识就会不得要领。
rtl8019as的工作机制以及原理:
- 接收:
rtl8019as的RAM是一个循环RAM空间,当网卡从网络上接收到数据后,会按照RAM地址从小到大依次存放接收到的数据。
但是RAM的空间只有16K,而且,有一部分还是划为用来做发送缓存,另外的那一部分才是用来做接收缓存的。当网络上的数据超过了缓存的大小怎么办呢?
这里就需要介绍一些,rtl8019as的RAM是一种循环RAM,所谓循环RAM,比如说用来做接收缓存的RAM的页是从50页~80页,接收的数据从第50页开始存放,一直存放到第80页。
当接收的数据过多,超过了上限的第80页时,再接收到的数据就会重新从第50页开始依次从低到高存放!!
这个机制难道没有问题么??难道不会将原先存放在第50页中的数据冲掉么?
如果仅仅是这么简单的一个机制的话,确实会有这样的问题,但是可以考虑到的就是,在网卡接收数据的时候,
CPU也在同时的从RAM中读取走数据,所以只要安排得当,采用循环RAM,还是有可能不会将原先的数据冲掉的。而且RAM的利用率将会得到提高。
那么怎么样才叫安排得当呢?
在实际的机制中,引入了CURR和BNRY这两个”指针”(两个实际的寄存器)。这两个寄存器都是存放的RAM的页地址(rtl8019as也是以页为单位存储的)
CURR表示如果网卡接收到了数据,应该从CURR页开始存放。而且这个CURR寄存器的值是网卡自动为它赋值的,每填满一个页,CURR寄存器的值就增加1,表示下一次有数据来的时候从下一个页开始存放。
BNRY表示,CPU已经从RAM中接收的数据,到BNRY页为止,就是BNRY+1页的数据还没有被CPU取走。CPU下来再来取数据的时候就应该从BNRY+1页来取数据。
那么可以想见,当网卡从网络上接收到数据,已经超过了接收缓冲的上限,重新从下限开始存放的时候,只要我不存放到超过BNRY页,都是不会引起将原来被有被CPU取走的数据覆盖的,不是么?
正是这样。这真是一个很好的方法啊。下图就将这种原理解释的比较的清楚了:

CURR_BURY机制
那如果接收的数据实在是太多,以至于存放的数据直到存放到BNRY页都放还放不下,那怎么办呢?
那没有办法,那就停止接收数据,等待CPU将一些数据从RAM中接收走再从网络上接收数据吧。
那么,当网卡接收到了帧数据,怎么通知CPU来取走数据呢?
有两种方法,当使用中断的时候,网卡收到帧数据后会触发中断,CPU只要查看中断寄存器就能够知道有数据到达,然后取走数据就可。
如果不用中断,采用轮训方式的话,那么只要一直查看BNRY+1是否等于CURR就可以了。如果不等的话,即表明RAM中有数据没有被取走,那么取走即可(原因很明白吧)。
- 发送:
相对于接收,发送功能就要简单一点了。
应用程序只需要将数据写入到RAM中,想网卡发出发送命令即可完成数据向网络的发送了(置RD2,RD1,RD0的值为011即可)
- DMA
rtl8019的文档中提到了DMA,而且有两种DMA,local DMA和remote DMA.
local DMA其实是网卡内部的DMA,负责与网络的数据收发,remote DMA是指CPU和网卡之间的DMA(程序的角度只需要关注这个DMA即可)
查阅网上的资料,大家都说,此处的DMA跟大家映像中的DMA其实不是一回事。收发并不是自动的。
此处的DMA是指这样的一种读取和写RAM的方式:
当网口通知CPU有数据到来,或者CPU检测到RAM中有数据需要读取的时候,设置两个地址值RSAR和RBCR。
RSAR0,1:要读取的数据的起始地址
RBCR0,1:要读取的数据的大小(可以以字节为单位)
然后我们从数据寄存器中读取数据,每读取一次,数据寄存器中所指向的地址就会增加1。。。(这也算是一种DMA吧。。。)
可见,设置好上面的两个寄存器后,我们只要从数据寄存器中读取RNCR0,1次,就能将数据帧读出来了。
发送也是同理。
下面简单的介绍一下rtl8019的工作模式。
rtl8019的内存结构如下所示(本系统中BaseAddress为0×06000300):
- 0×00~0×20:偏移量为这一段的地址是rtl8019as的寄存器的空间。
- 0×4000~0×8000:偏移量为这一段的地址是rtl8019as的RAM空间,CPU接收和发送的数据都在这一段里面。需要注意的是,这里的地址是分页的,每一页的大小为256个字节,可见共有64个页。
rtl8019的寄存器表如下图所示:
由上图可见,在0×00~0×20的空间里面,同时并行存在了Page0,Page1,Page2,Page3这四个页。
也就是说,这四个页共享00~20的空间,大家的地址都是从00~20.
但是每次操作,实际上是针对一个特定的页的,而这个页的选择是通过00的CR来进行的。
CR的位定义如下:

CR
如上图所示,PS1,PS0就是用来选择页的,00表示选择Page0,01表示选择Page1,10表示选择Page2,11表示选择Page3。
所以,通过CR寄存器,就能够使得在4个页之间共享00~20这一段地址空间(这个方法跟CTRL按键的原理类似,多了一个按键,却使可使用的按键范围扩大了一倍。。)
重要寄存器及其作用:
CR:
如上图所示,7,6bit是用来选寄存器的页的,设置完之后,对01~20的寄存器的操作,就都是对选定的页的响应的寄存器的操作了。
设置5-3bit位下列值时有不同的功能:
设置RD2RD1RD0=000->表示启动网卡的remote读功能,此时可以从BNRY开始通过DMA从RAM中读出数据
设置RD2RD1RD0=010->表示启动网卡的remote写功能,此时可以从TPSR开始通过DMA写入数据到RAM中去
设置RD2RD1RD0=100->表示启动网卡的向外传输数据功能,当bit2被置位,则网卡启动传输,开始向网络传输存在于RAM中的数据帧。(是这样理解么)???
1,0bit的组合用来启动和关闭网卡,01的情况下,网卡的传输操作被禁止,只有在10的情况下,才允许进行接收的操作,相当于一个总开关。
CLDA0,1:
current local DMA address,当前local DMA的地址,不知道用来干吗的,感觉没啥用。
PSTART:
PSTOP:
上面的两个寄存器是用来表示接收缓冲在RAM中的起始页和结束页的,注意单位是页!!
BNRY:
这个寄存器的意义想必应该知道了吧。
TPSR:
传输时的DMA的起始页号,注意,单位也是页!!不懂的话参考上面原理部分
TBCR0,1:
传输时的数据大小,单位是字节!!
NCR:
FIFO:
CRDA0,1:
current remote DMA address,不知道有什么用
RSAR0,1:
接收数据时的DMA的起始地址,注意,单位是字节!!
RBCR0,1:
接收数据时需要接收的数据的大小,单位是字节
CNTR0:
CNTR1:
CNTR2:
PAR0-5:
实际地址寄存器,这个寄存器需要好好的设置一下。
CURR:
MAR0-7:
还有三个重要的寄存器下次再说了,很重要的寄存器:
ISR:
ISR是中断状态寄存器,在中断方式下,CPU收到中断时,查询此寄存器的值便可知道是中断的原因是什么,这个寄存器的位定义如下:

ISR
上面的各个位的意义基本上已经和明显了。在中断时,查看PRX即可知道是否有新帧被收到了。
IMR:
中断屏蔽寄存器。这个寄存器也不难理解,跟上面的ISR寄存器对应,当某一位被置位时,相应中断被打开。
TCR: 传输配置寄存器

TCR
OFST的值一般设为0,LB1,LB0正常情况下设为0,0,表示正常模式。
CRC,根据其描述不难知道,正常模式下,接收到的数据会进行CRC的检验,发送的数据会自动的添加CRC尾。
DCR :数据配置寄存器

DCR
这个寄存器主要是用来配置字节序(BOS)和每次DMA传输的大小(8位还是16位)
TSR:传输状态寄存器

TSR
这个寄存器的作用是判断传输的状态?
一直很奇怪,PTX的作用是什么呢?用来判断一帧的传输是否结束??
RSR:接收状态寄存器

RSR
同上面的发送状态寄存器一样,这个寄存器的作用是判断传输时出现的各种状态?
而且根据PRX能否来判断有一帧已经被接收到了么?
RCR:接受配置寄存器

RCR
MON:设置Monitor模式,在此模式下,接收到的数据不被复制到内存
PRO:置位则表示接收所有的以太网帧?清除则表示只接收目标地址为PAR0-5里面设置的地址
AM:设置是否接收多播数据帧
AB:设置是否接收广播数据帧
AR和SEP:如图,很清晰,一般都设为0
3、寄存器结构示意图
稍稍总结一下rtl8019as的寄存器的组织结构,也即将寄存器按照其控制功能的分工稍稍的分一下类。
示意图如下图所示:

原文博客地址:http://my.unix-center.net/~xiaoshe/