台湾realtek 8139 在全球欠发达国家PC系统里充当网络适配器相当的普遍,但是在芯片制造中的简陋也足以让人惊讶,就算是8169在GMII的网络通信中也非常勉强,凭借极小的8kB发送缓冲,和48kB的接受Buffer,流量一大些,便足以让cpu忙得焦头烂额的,细心的网络工程师不难发现8kB发送缓冲几个uS发送完毕,以及从DMA中,多少PCI时钟足以填满发送Buffer,招致CPU极度频繁的中断,这是realtek 8169在作为服务器端拖死有限CPU资源的首要原因。下面的资料看得出BroadCOM NC7782(96KB receive buffer;16KB sent),NC7784(64KBx2;收发均64KB),这样的适配器才象有点人样。现在才知道BroadCOM NC77系列网络芯片会在很多中低端服务领域大量普及的原因。遗憾的是,通常的台式电脑,尚且停留在realtek 8139 这种10块钱一个的居于贫民级别的应用。
TYPE | 调制/速率 | 发送缓冲 | 接受缓冲 |
RealTEK 8139 | 4b/5b:100Mbits/S | 2KB | 2KB |
RealTEK 8169 | 4b/5b:100Mbits/S 8b/10b:GM/GMII | 8kB | 48kB |
NC7782 | 4b/5b:100Mbits/S 8b/10b:GM/GMII | 16kB | 96kB |
NC7784 | 4b/5b:100Mbits/S 8b/10b:GM/GMII | 64kB | 64kB |
看得出,BroadCOM5702用在低端交换机是非常好的,接受缓冲特别大,而NC5704则侧向于发送缓冲,以大幅度减少CPU的开销。
但是目前的任务,是针对螃蟹8139而来,至于其他高性能芯片讨论太多并无意义。
RTL8139驱动程序Rtl8139End.c是完全按照END格式编写的代码,提供了所有MUX层规定的接口函数,只要写好RTL8139 PCI配制空间寄存器,在sysRtl8139End.c中传入PCI空间首地址、中断向量号和中断优先级参数,按照END格式驱动装载程序,装载成功后RTL8139就能顺利运行。
Internet上经常有突发的数据包,而RTL8139的接收FIFO和发送FIFO都只有2Kb,加之RTL8139对收发数据包采取完全拷贝方式,在数据包突发期间,CPU占用率过高,来不及处理过多的数据包,从而造成丢包。在Rtl8139End.c中,驱动的数据包缓冲和协议栈的内存池是完全分开的,数据包接收和发送都有1次拷贝过程,而高性能以太网控制器一般只在发送时需要拷贝1次,这样每收发一个包,CPU需要多拷贝1次,这是导致RTL8139性能不高的重要原因,但这种包处理方式是由硬件决定的,驱动程序不能改变。事实上,在突发包很多的情况下,以太网控制器丢包是允许的,但突发时间过后,应恢复正常的收发包流程。
RTL8139有4个发送描述符,有各自的发送状态寄存器TSD0~TSD3和发送起始地址寄存器TSAD0~TSAD3,每个发送描述符可发送1个数据包。在函数Rtl8139Send()中申请1个发送数据包缓冲区,将协议栈传下来的数据包拷贝进该缓冲区,然后将该缓冲区的首地址写入发送起始地址寄存器,最后填写发送状态寄存器,并将其OWN位置0,表示将该缓冲区交给RTL8139的发送DMA管理,启动发送操作。发送完成后RTL8139产生中断,进人中断服务程序Rtl8139Int(),调用Rtl8139HandleSendInt(),在该函数中读取发送状态寄存器。如果OWN位为1,则表示发送DMA操作完成,释放相应的发送缓冲;否则表示发送DMA操作未完成,该发送缓冲仍由RTL8139硬件所有,下次进入发送中断再重新查看OWN位。如此循环往复,直到OWN位变为1,才能释放相应的发送缓冲,其占用的发送描述符变为可用。
希望文章能起到抛砖引玉的作用,大陆Linux高手完全可以自己编写优秀的RTL8139驱动,或者直接接管TCP/IP协议栈、居于IP-SAN的SCSI块映射、甚至包括到CPU定时访问发送缓冲的寄存器,或者直接合并前端INETD响应和PF,(相当于Windows 2000的TCPIP.SYS和居于IP筛选的安全策略等)尽量减少通过中断对CPU有限运算资源的消耗。