[翻译] Section 5.4. Interaction Between Devices and Kernel 设备与内核的交互

几乎所有的设备(包括NICs)都有两种方式与内核交互:

polling轮询方式

内核方发起。内核定期检查设备状态,看看它有什么想说的

interrupt中断方式

设备方发起。当需要内核处理时,设备发送IRQ信号给内核

在第九章,有NIC驱动程序设计方案以及软中断的详细讨论,并且还有Linux如何使用轮询和中断的组合提高效率。在本章中只基于中断进行讨论。

本书不会详细介绍硬件如何引起中断,interrupt和exception的区别,还有总线内核如何设计等问题。本书只简要描述中断,以帮助来理解设备驱动程序如何初始化和注册,尤其是网络设备方面

硬中断

本章不会介绍硬件中断的底层细节实现。但是,一些细节值得探究。从而更加容易理解NIC驱动是如何编写的,并且了解如何与上层网络交互。

所有的中断在运行时都会跑在中断处理函数中,中断处理函数应该由驱动进行定制化设计。通常当驱动注册NIC时,会请求并分配一个IRQ。注册和卸载IRQ是两个架构相关的函数,它们在kernel/irq/management定义,在arch/XXX/kernel/irq.c中重载(XXX是特定体系结构的目录):

int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs*), unsigned long irqflags, const char * devname, void *dev_id)

第一个参数是有效地irq号,要保证这个irq在其他driver中没有使用,要不就是共享IRQ

void free_irq(unsigned_int irq, void *dev_id)

将指定dev_id的IRQ禁用。注意:为了识别中断处理程序,irq和设备标识符一样重要

扫描二维码关注公众号,回复: 3166608 查看本文章

当内核收到IRQ之后,会根据中断处理向量表(公共位置)去查找对应的中断处理程序,然后去执行对应的中断处理程序。这种关联可以是一对一的,也可以是一对多的。即一个中断IRQ对应多个中断处理程序,这一特性会在后面的共享IRQ中介绍。

中断类型

NIC通过中断可以与驱动交互几种不同的事件,包括:

1、frame 接收

这是最经典最常见的情况

2、传输失败

这个只会发生在碰撞阶段,只是发生在设备和NIC的硬件层。需要注意的是,这个错误不会向网络层传递。

3、DMA传输完成

给定一帧数据去传输,当该帧上传至NIC缓存区,驱动程序就会释放保护,使数据可以在介质上传输。在同步传输(即没有DMA的情况)时,驱动程序可以立即知道何时NIC有数据需要传输。但是在异步传输(有DMA)的时候,就需要中断去通知NIC去处理数据。

4、设备有足够的空间处理新的连接

对于NIC驱动程序,当没有足够的空间去处理最大帧(比如Ethernet 是1536字节)时,会停止传输队列禁止传输,然后内存可以用时,再重启队列。后面讲详细讲这一点

在前面的列表中的最后一点,介绍了一种复杂的降低传输速率的方法,如果可以运用得到,可以有效地提高效率。在该系统中,设备驱动程序由于队列空间不足而使得传输队列被禁,当可用内存大于给定值时(通常是设备最大传输单元或者MTU)时,请求NIC发送中断,在中断处理程序中重启传输

设备驱动程序也可以在传输前将出口队列禁用,为了防止内核在这时生成另个传输请求。然后驱动再检测设备内存是否足够,如果足够,就允许内核再次发出传输请求,否则,就需要等待有足够空间的中断时,再打开传输队列

共享IRQ

IRQ线是有限资源。增加系统的可容纳设备数量常用的方法是允许多个设备共享一条IRQ线。一般都是每一个驱动程序将自己的中断程序注册到内核中。但内核所做的并不是接收中断、找对对应的设备、执行对应的中断服务程序。而是通过共享IRQ的驱动共同注册相同的中断服务程序,在中断服务程序中,去判断执行哪个设备的部分(例如通过读取设备中的注册表)。

对于一组共享IRQ的设备,这些设备都必须具有可以共享IRQ的设备驱动程序。换句话说,每当设备注册IRQ时,它必需明确地表示它是否支持IRQ共享。如果另一个设备在注册IRQ时,如果该IRQ之前被分配的驱动程序不支持共享IRQ,那么该设备注册会注册失败

IRQ到中断处理程序的映射

IRQ的处理程序映射在中断向量表中

猜你喜欢

转载自blog.csdn.net/qq_28351465/article/details/81974960