NAPI 技术在 Linux 网络驱动上的应用和完善Word下载.docx
- 文档编号:6376727
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:22
- 大小:93.60KB
NAPI 技术在 Linux 网络驱动上的应用和完善Word下载.docx
《NAPI 技术在 Linux 网络驱动上的应用和完善Word下载.docx》由会员分享,可在线阅读,更多相关《NAPI 技术在 Linux 网络驱动上的应用和完善Word下载.docx(22页珍藏版)》请在冰点文库上搜索。
C.有防止NIC队列中排队的数据包冲突的能力。
当关断发送/接收事件中断的时候,NAPI将在POLL中被调用处理,由于POLL方法的时候,NIC中断差不多不能通知包到达,那么那个时候在假如在完成轮询,同时中断打开以后,会赶忙有一个NIC中断产生,从而触发一次POLL事件,这种在中断关断时刻到达的包我们称为"
rotting"
;
如此就会在POLL机制和NIC中断之间产生一个竞争,解决的方法确实是利用网卡的接收状态位,连续接收环形队列缓冲rx-ring中的数据,直到没有数据接收以后,才使能中断。
锁定和防冲突机制:
-1.SMP的保证机制:
保证同时只有一个处理器调用网络设备的POLL方法,因为我们将在下面看到同时只有一个处理器能够对调用netif_rx_schedule挂在POLL队列中的NIC设备调用POLL方法。
-2.网络核心层〔netcore〕调用设备驱动程序使用循环方式发送数据包,在设备驱动层接收数据包的时候完全无锁的接收,而网络核心层那么同样要保证每次只有一个处理器能够使用软中断处理接收队列。
-3.在多个处理器对NIC的rx-ring访问的时刻只能发生在对循环队列调用关闭〔close〕和挂起〔suspend〕方法的时候〔在那个时刻会试图清除接收循环队列〕
-4.数据同步的问题〔关于接收循环队列来说〕,驱动程序是不需要考虑的网络层上的程序差不多把这些情况做完了。
-5.假如没有把全部的部分交给POLL方法处理,那么NIC中断仍旧需要使能,接收链路状态发生变化和发送完成中断仍旧和往常的处理步骤一样,如此处理的假设是接收中断是设备负载最大的的情形,因此并不能说如此一定正确。
下面的部分将详细介绍在接收事件中调用设备的POLL方法。
NAPI提供的重要函数和数据结构和函数:
核心数据结构:
structsoftnet_data结构内的字段确实是NIC和网络层之间处理队列,那个结构是全局的,它从NIC中断和POLL方法之间传递数据信息。
其中包含的字段有:
structsoftnet_data
{
intthrottle;
/*为1表示当前队列的数据包被禁止*/
intcng_level;
/*表示当前处理器的数据包处理拥塞程度*/
intavg_blog;
/*某个处理器的平均拥塞度*/
structsk_buff_headinput_pkt_queue;
/*接收缓冲区的sk_buff队列*/
structlist_headpoll_list;
/*POLL设备队列头*/
structnet_deviceoutput_queue;
/*网络设备发送队列的队列头*/
structsk_buffcompletion_queue;
/*完成发送的数据包等待开释的队列*/
structnet_devicebacklog_dev;
/*表示当前参与POLL处理的网络设备*/
};
核心API:
1.netif_rx_schedule(dev)
那个函数被中断服务程序调用,将设备的POLL方法添加到网络层次的POLL处理队列中去,排队同时预备接收数据包,在使用之前需要调用netif_rx_reschedule_prep,同时返回的数为1,同时触发一个NET_RX_SOFTIRQ的软中断通知网络层接收数据包。
2.netif_rx_schedule_prep(dev)
确定设备处于运行,而且设备还没有被添加到网络层的POLL处理队列中,在调用netif_rx_schedule之前会调用那个函数。
3.netif_rx_complete(dev)
把当前指定的设备从POLL队列中清除,通常被设备的POLL方法调用,注意假如在POLL队列处于工作状态的时候是不能把指定设备清除的,否那么将会出错。
如何在8139CP使用NAPI:
从POLL方法的本质意义上来说就在于尽量减少中断的数目,专门在于大量的小长度的数据包的时候,减少中断,以达到不要让整个操作系统花费太多的时刻在中断现场的爱护和复原上,以便把赢得的时刻用来在我网络层上的处理数据的传输,例如在下面介绍的8139CP中断的处理过程中,目的就在于尽快把产生中断的设备挂在poll_list,同时关闭接收中断,最后直截了当调用设备的POLL方法来处理数据包的接收,直到收到数据包收无可收,或者是达到一个时刻片内的调度完成。
RTL8139C+的数据接收环形缓冲队列:
RTL8139C+的接收方式是一种全新的缓冲方式,能显著的降低CPU接收数据造成的花费,适合大型的服务器使用,适合IP,TCP,UDP等多种方式的数据下载,以及连接IEEE802.1P,802.1Q,VLAN等网络形式;
在8139CP中分别有64个连续的接收/发送描述符单元,对应三个不同的环形缓冲队列--一个是高优先级传输描述符队列,一个是一般优先级传输符描述队列,一个是接收符描述队列,每个环形缓冲队列右64个4个双字的连续描述符组成,每个描述符有4个连续的双字组成,每个描述符的开始地址在256个字节的位置对齐,接收数据之前,软件需要预先分配一个DMA缓冲区,一样关于传输而言,缓冲区最大为8Kbyte同时把物理地址链接在描述符的DMA地址描述单元,另外还有两个双字的单元表示对应的DMA缓冲区的接收状态。
在/driver/net/8139CP.C中关于环形缓冲队列描述符的数据单元如下表示:
structcp_desc{u32opts1;
/*缓冲区状态操纵符,包含缓冲区大小,缓冲区传输启动位*/u32opts2;
/*专门用于VLAN部分*/u64addr;
/*缓冲区的DMA地址*/};
8139CP的NIC中断:
staticirqreturn_t
cp_interrupt(intirq,void*dev_instance,structpt_regs*regs)
structnet_device*dev=dev_instance;
structcp_private*cp=dev->
priv;
u16status;
/*检查rx-ring中是否有中断到达*/
status=cpr16(IntrStatus);
if(!
status||(status==0xFFFF))
returnIRQ_NONE;
if(netif_msg_intr(cp))
printk(KERN_DEBUG"
%s:
intr,status%04xcmd%02xcpcmd%04x\n"
dev->
name,status,cpr8(Cmd),cpr16(CpCmd));
/*清除NIC中断操纵器的内容*/
cpw16(IntrStatus,status&
~cp_rx_intr_mask);
spin_lock(&
cp->
lock);
/*接收状态寄存器表示有数据包到达*/
if(status&
(RxOK|RxErr|RxEmpty|RxFIFOOvr)){
/*把当前的产生中断的NIC设备挂在softnet_data中的POLL队列上,等待网络上层上的应用程序处理*/
if(netif_rx_schedule_prep(dev)){
/*关闭接收中断使能*/
cpw16_f(IntrMask,cp_norx_intr_mask);
__netif_rx_schedule(dev);
}
/*发送中断的处理过程以及8139C+的专门软中断的处理过程,那个地点我们不关怀*/
(TxOK|TxErr|TxEmpty|SWInt))
cp_tx(cp);
/*假如发生链路变化的情形,需要检查介质无关接口〔MII〕的载波状态同样也发生变化,
否那么就要预备重新启动MII接口*/
LinkChg)
mii_check_media(&
mii_if,netif_msg_link(cp),FALSE);
/*假如PCI总线发生错误,需要对8139C+的设备重新复位*/
PciErr){
u16pci_status;
pci_read_config_word(cp->
pdev,PCI_STATUS,&
pci_status);
pci_write_config_word(cp->
pdev,PCI_STATUS,pci_status);
printk(KERN_ERR"
PCIbuserror,status=%04x,PCIstatus=%04x\n"
name,status,pci_status);
/*TODO:
resethardware*/
spin_unlock(&
returnIRQ_HANDLED;
把NIC挂在POLL队列(poll_list)上
在8139CP的中断程序能够看到__netif_rx_schedule的调用方式,它把NIC设备挂在softnet_data结构中的poll_list队列上,以便及时的返回中断,让专门数据包处理bottom-half部分来进行处理,我们先来看一下__netif_rx_schedule的内部工作流程。
staticinlinevoid__netif_rx_schedule(structnet_device*dev)
unsignedlongflags;
local_irq_save(flags);
dev_hold(dev);
/*把当前NIC设备挂在POLL〔poll_list〕队列中,等待唤醒软中断以后进行轮询*/
list_add_tail(&
dev->
poll_list,&
__get_cpu_var(softnet_data).poll_list);
/*确定当前该设备所要预备接收的包大小*/
if(dev->
quota<
0)
dev->
quota+=dev->
weight;
else
quota=dev->
/*启动软中断,在表示所有中断的状态字irq_cpustat_t中关于软中断字段__softirq_pending中,
把关于网络轮循接收软中断位置1,等待调度时机来临时候运行该中断的句柄net_rx_action。
*/
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
local_irq_restore(flags);
由__netif_rx_schedule启动的软中断的处理过程分析
软中断事件触发前差不多在此设备子系统初始化时刻调用subsys_initcall(net_dev_init)在软中断操纵台上被激活,挂在任务队列tasklet上预备在任务调度schedule的时刻运行它了,那个里面最要紧的部分是调用了8139C+网络设备的POLL方法〔dev->
poll〕,从网络设备的rx-ring队列中获得数据,本来它应当放在网络设备中断服务程序中执行的,按照我们前面说明的那样,POLL方法以空间换取时刻的机制把它放在软中断部分来执行轮循机制〔采纳类似老的Bottom-half机制也能够达到同样成效,而且更加容易明白得一些〕在每次进行进程调度的时候就会执行网络设备软中断,轮询rx-ring对NIC进行数据的接收。
软中断的处理过程:
staticvoidnet_rx_action(structsoftirq_action*h)
structsoftnet_data*queue=&
__get_cpu_var(softnet_data);
unsignedlongstart_time=jiffies;
intbudget=netdev_max_backlog;
/*表示队列的最大长度*/
/*锁定当前线程,多处理器的情形之下不能被其他处理器中断处理*/
preempt_disable();
local_irq_disable();
/*检查POLL队列〔poll_list〕上是否有设备在预备等待轮询取得数据*/
while(!
list_empty(&
queue->
poll_list)){
structnet_device*dev;
/*那个地点保证执行当前的POLL过程的时刻不超过一个时刻片,如此不至于被软中断占用太多的时刻,
如此在一次调度的时刻内执行完毕当前的POLL过程,budget表示一个时刻片内最大数据传输的"
块数"
,
块的意思为每个POLL所完成sk_buff数量,每块中间的sk_buff数量为dev->
quota决定,在8139CP驱动中,
budget为300,而quota为16表示每给时刻片最多能够接收到4.8K的sk_buff数量*/
if(budget<
=0||jiffies-start_time>
1)
gotosoftnet_break;
local_irq_enable();
/*从公共的softnet_data数据结构中的轮循队列上获得等待轮循的设备结构*/
dev=list_entry(queue->
poll_list.next,
structnet_device,poll_list);
/*调用设备的POLL方法从NIC上的RingBuffer中读入数据*/
=0||dev->
poll(dev,&
budget)){
/*完成一次POLL过程的数据的接收,重新定义设备接收数据的"
配额"
〔事实上确实是sk_buff缓冲区的数量,每次调用POLL方法的时候能够创建同时最
多能够向上层提交的sk_buff缓冲区数目,那个参数专门重要在高速处理的时候有需要慎重优化那个数值,
在有大量数据接收的情形下,需要增加该数值〕*/
list_del(&
poll_list);
}else{
/*发生了错误的数据接收状况,或者没有完成"
规定"
配额的数据接收,同时没有新的数据进来,
那个也可能表示差不多完成了传输的过程,调用__netif_rx_complete把网络设备从POLL队列上清除
〔介绍POLL过程的时候详细介绍〕*/
dev_put(dev);
out:
preempt_enable();
return;
softnet_break:
__get_cpu_var(netdev_rx_stat).time_squeeze++;
gotoout;
}
8139CP驱动中的轮询方法
poll方法:
那个方法通常被网络层在向驱动的接收循环队列猎取新的数据包时刻调用,而驱动的接收循环队列中能够向网络层交付的包数量那么在dev->
quota字段中表示,我们来看8139cp中POLL的原型:
staticintcp_rx_poll(structnet_device*dev,int*budget)
参数budget的上层任务所需要底层传递的数据包的数量,那个数值不能超过netdev_max_backlog的值。
总而言之,POLL方法被网络层调用,只负责按照网络层的要求值〔"
预算"
值〕提交对应数量的数据包。
8139CP的POLL方法注册通常在设备驱动程序模块初始化(调用probe)的时候进行,如下:
staticintcp_init_one(structpci_dev*pdev,conststructpci_device_id*ent)
……
poll=cp_rx_poll;
设备的POLL方法正如前所说的是被网络层上的软中断net_rx_action调用,我们现在来看具体的流程:
structcp_private*cp=netdev_priv(dev);
unsignedrx_tail=cp->
rx_tail;
/*设定每次进行调度的时候从设备发送到网络层次最大的数据包的大小*/
unsignedrx_work=dev->
quota;
unsignedrx;
rx_status_loop:
rx=0;
/*重新打开NIC中断,在cp_interrupt中断句柄中中断关闭了,现在POLl差不多开始处理环行缓冲队列中的数据,
因此中断能够打开,预备接收新的数据包*/
cpw16(IntrStatus,cp_rx_intr_mask);
while
(1){/*POLL循环的开始*/
u32status,len;
dma_addr_tmapping;
structsk_buff*skb,*new_skb;
structcp_desc*desc;
uns
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- NAPI 技术在 Linux 网络驱动上的应用和完善 技术 网络 驱动 应用 完善