c - 关于Linux内核中的NAPI实现

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

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

如果我用外行的术语谈论,只要有网络数据包进入接口,它就会通知CPU并执行适当的以太网驱动程序(中断处理程序)代码。然后,以太网驱动程序代码将数据包从以太网的设备内存复制到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缓冲区并推送到上层一样吗?

如果有人给我清晰的图片,那将是很大的帮助。

最佳答案

现在,对于最初启用NAPI的以太网驱动程序,无论何时有数据包进入接口,它都会通知CPU并执行适当的以太网驱动程序代码(中断处理程序)。在中断处理程序代码中,我们检查是否收到了中断类型的数据包。
禁用更多中断意味着什么?

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

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

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

并保存在设备内存中

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

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

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

同样,这意味着CPU正在池化设备,

想必您实际上是在询问“轮询”吗?
轮询只是意味着程序(即驱动程序)询问(即读取和测试)状态位以了解其正在等待的条件。
如果满足条件,则它将以类似于该事件中断的方式处理该事件。
如果不满足该条件,则它可能会循环(在一般情况下)。但是,当轮询表明没有更多帧到达时,NAPI驱动程序将假定数据包突发或洪灾已经结束,并将恢复中断模式。

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

NAPI驱动程序不会在轮询之前延迟或暂停“几秒钟”。
假设以太网帧可能正在端口中泛滥,因此将在对当前帧的处理完成后立即执行轮询。
NAPI驱动程序中可能存在的错误称为“腐烂数据包”。
当驱动程序从轮询模式转换回中断模式时,在此转换过程中可能会到达一个帧,并且驱动程序无法检测到该帧。
直到另一帧到达(并产生中断),NAPI驱动程序才会“找到”并处理前一帧。
BTW
您一直在写类似于“ CPU确实...”或“通知CPU”的语句或问题。
CPU始终(不在睡眠或关闭电源时)执行机器指令。
您应注意这些指令属于哪个逻辑实体(即哪个程序或源代码模块)。
您在问软件问题,因此中断是导致CPU已知的特定序列的事实,这是必须给出的,无需赘述。
附录

我只是想了解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设备驱动程序使用与硬件数据表完全相同的寄存器名称。
使用以下指令在ISR中使用此寄存器偏移量读取此32位寄存器:
u32 intsts = smsc911x_reg_read(pdata, INT_STS);

因此,将中断状态的32位(在intsts变量中)与中断屏蔽的32位(在inten变量中)进行布尔“与”运算。
这会产生驱动程序真正感兴趣的中断状态位。如果硬件为无论如何未启用的中断条件(在INT_EN寄存器中)设置状态位,这也可能是很好的防御性编程。
然后,该if语句执行另一个布尔与,以提取要检查的一位(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中的分支预测功能。驱动程序的作者正在指导编译器优化代码,以实现封闭逻辑表达式的真实结果(例如,三个整数的与运算,这将表明需要维修的中断条件)。

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

我阅读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(即在“第一”帧上中断)。如果此阈值大于零,则可能会“腐烂数据包”。

关于c - 关于Linux内核中的NAPI实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23574203/

相关文章:

Linux Socket编程 : what happen in server socket when client socket gone off in the middle of communication

c - GCC:在获取地址时取消引用 ‘void *’ 指针

c - 错误: incompatible types when assigning to type ‘struct card’ from type struct card *’

c - Linux 原始套接字

linux - 如何判断两个按键是否同时按下?

linux-kernel - Centos Kernelheaders 包括来自 future 内核的更改

c - 存在状态为 `TIME_WAIT` 的 tcp 连接时无法建立 tcp 连接

c - 错误 : expected ‘)’ before ‘:’ token

编译时间恶意软件可能吗?

c - 一次性执行函数