关于Linux内核中的NAPI实现

时间:2014-05-09 21:23:05

标签: linux-kernel network-programming linux-device-driver

我正在尝试了解启用NAPI的网络驱动程序,并对此有一些疑问。

如果我在接口处有网络数据包的时候谈论外行人的术语,就会通知CPU并执行相应的以太网驱动程序(中断处理程序)代码。以太网驱动程序代码然后从以太网复制数据包&# 39; s设备内存到DMA缓冲区,最后数据包被推送到上层。

NAPI禁用的以太网驱动程序是否真的如此?

现在,对于NAPI启用的以太网驱动程序,无论何时数据包到达接口,都会通知CPU并执行相应的以太网驱动程序代码(中断处理程序)。在中断处理程序代码中,我们检查是否接收到中断类型。

 if(statusword & SNULL_RX_INTER)
   snull_rx_ints(dev,0);//Disbale further interrupts
   netif_rx_schedule(dev);

禁用进一步中断是什么意思?

是不是意味着数据包仍然被设备捕获并保存在设备内存中,但没有通知CPU有关这些数据包的可用性?

另外,CPU的意思是汇集设备,就像CPU每隔几秒就会运行snull_poll()方法并将设备内存中的任意数量的数据包复制到DMA缓冲区并推送到上层?

如果有人为我提供了清晰的图片,那将会很有帮助。

1 个答案:

答案 0 :(得分:6)

  

现在,对于NAPI启用的以太网驱动程序,无论何时数据包到达接口,都会通知CPU并执行相应的以太网驱动程序代码(中断处理程序)。在中断处理程序代码中,我们检查是否接收到中断类型。

     

禁用进一步中断是什么意思?

通常情况下,驱动程序会清除导致中断的条件。但是,NAPI驱动程序也可能在ISR完成时禁用接收中断 假设一个以太网帧的到达可能是帧的突发或泛滥的开始。因此,为什么不测试(即轮询)是否已经到达更多帧,而不是退出中断模式并且可能立即重新进入中断模式?

  

是否意味着数据包仍被设备捕获

是。
每个到达的帧由以太网控制器存储在帧缓冲区中。

  

并保存在设备内存中

它通常不是"设备内存" 它通常是在分配给以太网控制器的主存储器中分配的一组缓冲器(例如环形缓冲器)。

  

但没有通知CPU有关这些数据包的可用性?

由于已禁用接收中断,因此不会通知NAPI驱动程序此事件 但由于驱动程序正忙于处理前一帧,因此无论如何都无法立即处理中断请求。

  

此外,CPU的意思是汇集设备,

据推测,你实际上是在询问"民意调查"? 轮询只是意味着程序(即驱动程序)询问(即读取和测试)状态位以查找它正在等待的条件。
如果满足条件,则它将以类似于该事件的中断的方式处理事件 如果不满足条件,那么它可以循环(在通用情况下)。但是,当轮询表明没有更多帧到达时,NAPI驱动程序将假设数据包突发或泛洪已经结束,并将恢复中断模式。

  

就像CPU每隔几秒就会运行snull_poll()方法并将设备内存中的任意数量的数据包复制到DMA缓冲区并推送到上层?

NAPI驱动程序 假设以太网帧可能会泛滥端口,因此只要对当前帧的处理完成就会执行轮询。

NAPI驱动程序中可能存在的错误称为" rotting packet" 当驾驶员从轮询模式转换回中断模式时,在此过渡期间帧可能会到达,并且驾驶员无法检测到。
直到另一帧到达(并产生中断),前一帧才会被发现"并由NAPI驱动程序处理。

<强>顺便说一句
你总是写一些类似于&#34; CPU的声明或问题...... &#34;或&#34; 通知CPU &#34;。
CPU始终(未休眠或未关闭时)执行机器指令 您应该关注这些指令属于哪个逻辑实体(即哪个程序或源代码模块) 您正在询问软件问题,因此中断导致CPU发出已知的特定序列的事实是给定的,无需提及。

ADDENDUM

  

我只是想了解Linux源代码中的drivers / net / ethernet / smsc / smsc911x.c。

SMSC LAN911x以太网芯片比我过去以及之前描述的更为复杂。除了MAC之外,这些芯片还具有集成的PHY,并且具有TX和RX FIFO,而不是在主存储器中使用缓冲环或列表。

  

根据您的建议,我已经开始阅读SMSCLan9118数据表并尝试使用 smsc911x_irqhandler 功能映射它,其中中断状态( INT_STS )和中断启用( INT_EN )寄存器已被阅读,但不知道如何         if (likely(intsts & inten & INT_STS_RSFL_))
  条件在1627行检查。

INT_STS在头文件中定义为

#define INT_STS                         0x58

和数据表中第5.3节“系统控制和状态寄存器”中的表列出了(相对)地址0x58处的寄存器

58h INT_STS Interrupt Status 

因此smsc911x设备驱动程序使用与HW数据表完全相同的寄存器名称 使用以下命令在ISR中使用该寄存器偏移读取该32位寄存器:

u32 intsts = smsc911x_reg_read(pdata, INT_STS);

因此中断状态的32位(在变量 intsts 中)与中断屏蔽的32位进行布尔运算(在变量中)。
这会产生驱动程序实际感兴趣的中断状态位。如果硬件为未启用的中断条件设置状态位(在INT_EN寄存器中),这也可能是良好的防御性编程。
然后 if 语句执行另一个布尔AND以提取正在检查的一位( INT_STS_RSFL _ )。

5.3.3 INT_STS—Interrupt Status Register

RX Status FIFO Level Interrupt (RSFL).
Generated when the RX Status FIFO reaches the programmed level

likely()运算符用于编译器优化,以利用CPU中的分支预测功能。驱动程序的作者指示编译器优化代码以获得所附逻辑表达式的真实结果(例如,三个整数的AND运算,这将指示需要服务的中断条件)。

  

同样在收到接口上的数据包时,哪个位设置在哪个寄存器上。

我对阅读LAN9118数据表的看法是,确实没有专门用于接收帧的中断。
相反,当RX FIFO超过阈值时,可以通知主机。

5.3.6 FIFO_INT—FIFO Level Interrupts

RX Status Level.
The value in this field sets the level, in number of DWORDs, at which the RX Status FIFO Level interrupt (RSFL) will be generated. 
When the RX Status FIFO used space is greater than this value an RX Status FIFO Level interrupt (RSFL) will be generated. 

smsc911x驱动程序显然使用此阈值的默认值为零 RX状态FIFO中的每个条目都占用一个DWORD。此阈值的默认值为0x00(即中断&#34;第一个&#34;帧)。如果此阈值大于零,则有可能“丢弃数据包”#34;。