linux驱动 中断?linux中断处理机制

其实linux驱动 中断的问题并不复杂,但是又很多的朋友都不太了解linux中断处理机制,因此呢,今天小编就来为大家分享linux驱动 中断的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!

Linux内核中断上半部处理程序

硬件中断--异步中断中断本质上是一种电信号,由硬件设备发出,用于通知处理器特定事件。不同设备对应不同中断,每个中断通过唯一的数字标识,称为中断请求(IRQ)线。处理器内部对其编号,也称为中断号。

异常--同步中断异常不同于中断,产生时必须考虑与处理器时钟同步。异常常称为同步中断,是处理器执行时由于编程失误而导致的错误指令(如除0),或者执行期间出现特殊情况(如缺页),必须靠内核来处理时,处理器就会产生一个异常。我们通常所说的是中断,是指由硬件产生的异步中断。

软中断工作方式类似于异步中断,区别是它是通过软件引起的中断,异步中断是由硬件引起的。

中断处理程序中断处理程序(interrupt handler)或中断服务例程(interrupt service routine,ISR)响应一个特定中断时执行的函数。设备产生的每个中断,都有一个中断处理程序关联。一个设备可能产生多种不同的中断,那么该设备就可以对应多个中断处理程序。相应地,设备驱动程序就需要准备多个这样的函数。

Linux中断处理程序特点 Linux中,中断处理程序看起来像普通C函数,按特定类型声明,以便内核能以标准的方式传递处理程序的信息。中断处理程序与其他内核函数的区别:中断处理程序是被内核调用来响应中断的,而它们运行于被称为中断上下文的特殊上下文中。由于中断随时可能产生,因此中断处理程序必须随时、尽快执行,这样才能尽快响应中断,同时恢复中断代码的执行。

上下半部的对比一般把中断处理切分为2个部分或两半:1)上半部(top half)中断处理程序是上半部,接收到一个中断,就立即开始执行,但只做严格时限的工作。如对接收中断进行应答或复位硬件,这些工作都是在所有中断被禁止的情况下完成的。2)下半部(bottom half)中断处理程序中,能被允许稍后完成的工作会推迟到下半部。Linux提供下半部的各种机制。

编写中断处理程序一个典型的中断处理程序声明:其签名必须与request_irq()中参数handler所要求函数类型一致。参数说明:返回值:返回值是一个特殊类型:irqerturn_t。实际是int类型,为了与早期内核兼容,因为2.6以前实际是void类型。可能返回2个特殊值:IRQ_NONE和IRQ_HANDLED。当中断处理程序检测到一个中断,但该中断并非注册处理函数时指定的产生源时,返回IRQ_NONE;当中断处理程序被正确调用,而且确实是它所对应的设备产生的中断时,返回IRQ_HANDLED。返回值也可以用宏IRQ_RETVAL(x):x为非0,宏返回IRQ_HANDLED;x为0,返回IRQ_NONE。定义说明:中断处理程序通常标记为static,因为从来不会在其他文件被直接调用。可重入性 Linux中中断处理程序无需重入。当一个给定的中断处理程序正在执行时,相应的中断线在所有处理器上都会被屏蔽,以防在同一个中断线上接收另一个新的中断。也就是说,同一个中断线,同一个中断处理程序,在执行完毕之前不可能同时在2个处理器上执行,加上中断处理程序不能休眠,因此无需考虑可重入性。

中断控制 Linux内核提供一组接口用于操作机器上的中断状态:能用于禁止当前处理器的中断系统,屏蔽整个机器的一条中断线。例程与体系结构相关,位于。

禁止内核抢占:preempt_disable、preempt_enable等;禁止和激活中断用于禁止当前处理器上的本地中断,随后由激活:。由于flags包含具体体系结构的数据,即中断系统的状态,因此,flags不能传递给另一个函数,必须驻留在同一栈帧中。基于此,local_irq_save和restore的调用必须在同一个函数中。

中断系统的状态如何了解中断系统的状态,如中断当前是禁止的还是激活的?或者当前是否正处于中断上下文的执行状态中?本小节提供这方面回答。中 irqs_disable()如果本地处理器上的中断系统被禁止,则返回非0;否则,返回0。中 in_interrupt()如果内核处于中断上下文,则返回非0;如果在进程上下文,返回0。in_irq()如果当前正在执行中断处理程序,则返回非0;否则,返回0.

中断处理机制的实现中断处理系统的实现依赖于体系结构。中断的入口点是:硬件产生了中断,处理器开始跳转到对应的一个唯一位置,在栈中保存这个号,并存放当前寄存器的值(被中断任务),开始处理中断。中断产生到内核处理中断的步骤:1)硬件产生中断。2)处理器跳转到中断向量表对应的中断处理程序,栈中保存中断号及打断任务保存线程。3)内核调用do_IRQ()。之后,大多数中断处理代码用C编写。do_IRQ()提取中断号,对应x86代码:计算出中断号后,do_IRQ()对所接收的中断进行应答,禁止这条线上的中断传递。这些操作通过调用mask_and_ack_8259A()来完成。4)处理中断如果中断线上已安装中断处理程序,就调用handle_IRQ_event()处理;如果没有,就直接调用ret_from_intr(),返回内核运行中断的代码。x86上,handle_IRQ_event():5)调用ret_from_intr()类似于初始入口代码,用汇编编写。用于检查重新调度释放正在挂起(意味着设置了need_resched)。如果重新调度正在挂起,并且内核正在返回用户空间(i.e.中断了用户进程),那么schedule()被调用。如果内核正在返回内核空间(i.e.中断了内核本身),只有preempt_count(抢占计数器)为0时,schedule()才会被调用(否则,抢占内核便是不安全的)。schedule()返回后,或者如果没有挂起的工作,那么原来的寄存器被恢复,内核恢复到曾经中断的点。

/proc/interrupts查看中断统计信息 procfs是一个虚拟文件系统,只存在于内核内存,一般安装于/proc目录下。在procfs中读写文件都要调用内核函数,这些函数模拟从真实文件中读或写。/proc/interrupts文件存放系统中与中断相关的统计信息。

中断处理程序实例一个来自RTC驱动程序的中断处理程序,可在drivers/char/rtc.c中找到。RTC用于设置系统时钟,提供alarm或周期性定时器。

Linux几种中断信号的区别:HUP,INT,KILL,TERM,TSTP

Linux的HUP,INT,KILL,TERM,TSTP中断信号区别为:键入不同、对应操作不同、启用不同。

一、键入不同

1、HUP中断信号:HUP中断信号是当用户键入<Ctrl+X>时由终端驱动程序发送的信号。

2、INT中断信号:INT中断信号是当用户键入<Ctrl+I>时由终端驱动程序发送的信号。

3、KILL中断信号:KILL中断信号是当用户键入<Ctrl+Z>时由终端驱动程序发送的信号。

4、TERM中断信号:TERM中断信号是当用户键入<Ctrl+\>时由终端驱动程序发送的信号。

5、TSTP中断信号:TSTP中断信号是当用户键入<Ctrl+T>时由终端驱动程序发送的信号。二、对应操作不同

1、HUP中断信号:HUP中断信号的对应操作为让进程挂起,睡眠。

2、INT中断信号:INT中断信号的对应操作为正常关闭所有进程。

3、KILL中断信号:KILL中断信号的对应操作为强制关闭所有进程。

4、TERM中断信号:TERM中断信号的对应操作为正常的退出进程。

5、TSTP中断信号:TSTP中断信号的对应操作为暂时停用进程。

三、启用不同

1、HUP中断信号:HUP中断信号发送后,可以重新被用户再次输入恢复启用进程。

2、INT中断信号:INT中断信号发送后,不可以重新被用户再次输入恢复启用进程。

3、KILL中断信号:KILL中断信号发送后,不可以重新被用户再次输入恢复启用进程。

4、TERM中断信号:TERM中断信号发送后,可以重新被用户再次输入启用进程。

5、TSTP中断信号:TSTP中断信号发送后,可以重新被用户再次输入继续使用进程。

《Linux设备驱动程序》(十六)-中断处理

设备与处理器之间的工作通常来说是异步,设备数据要传递给处理器通常来说有以下几种方法:轮询、等待和中断。

让CPU进行轮询等待总是不能让人满意,所以通常都采用中断的形式,让设备来通知CPU读取数据。

2.6内核的函数参数与现在的参数有所区别,这里都主要介绍概念,具体实现方法需要结合具体的内核版本。

request_irq函数申请中断,返回0表示申请成功,其他返回值表示申请失败,其具体参数解释如下:

flags掩码可以使用以下几个:

快速和慢速处理例程:现代内核中基本没有这两个概念了,使用SA_INTERRUPT位后,当中断被执行时,当前处理器的其他中断都将被禁止。通常不要使用SA_INTERRUPT标志位,除非自己明确知道会发生什么。

共享中断:使用共享中断时,一方面要使用SA_SHIRQ位,另一个是request_irq中的dev_id必须是唯一的,不能为NULL。这个限制的原因是:内核为每个中断维护了一个共享处理例程的列表,例程中的dev_id各不相同,就像设备签名。如果dev_id相同,在卸载的时候引起混淆(卸载了另一个中断),当中断到达时会产生内核OOP消息。

共享中断需要满足以下一个条件才能申请成功:

当不需要使用该中断时,需要使用free_irq释放中断。

通常我们会在模块加载的时候申请安装中断处理例程,但书中建议:在设备第一次打开的时候安装,在设备最后一次关闭的时候卸载。

如果要查看中断触发的次数,可以查看/proc/interrupts和/proc/stat。

书中讲述了如何自动检测中断号,在嵌入式开发中通常都是查看原理图和datasheet来直接确定。

自动检测的原理如下:驱动程序通知设备产生中断,然后查看哪些中断信号线被触发了。Linux提供了以下方法来进行探测:

探测工作耗时较长,建议在模块加载的时候做。

中断处理函数和普通函数其实差不多,唯一的区别是其运行的中断上下文中,在这个上下文中有以下注意事项:

中断处理函数典型用法如下:

中断处理函数的参数和返回值含义如下:

返回值主要有两个:IRQ_NONE和IRQ_HANDLED。

对于中断我们是可以进行开启和关闭的,Linux中提供了以下函数操作单个中断的开关:

该方法可以在所有处理器上禁止或启用中断。

需要注意的是:

如果要关闭当前处理器上所有的中断,则可以调用以下方法:

local_irq_save会将中断状态保持到flags中,然后禁用处理器上的中断;如果明确知道中断没有在其他地方被禁用,则可以使用local_irq_disable,否则请使用local_irq_save。

locat_irq_restore会根据上面获取到flags来恢复中断;local_irq_enable会无条件打开所有中断。

在中断中需要做一些工作,如果工作内容太多,必然导致中断处理所需的时间过长;而中断处理又要求能够尽快完成,这样才不会影响正常的系统调度,这两个之间就产生了矛盾。

现在很多操作系统将中断分为两个部分来处理上面的矛盾:顶半部和底半部。

顶半部就是我们用request_irq来注册的中断处理函数,这个函数要求能够尽快结束,同时在其中调度底半部,让底半部在之后来进行后续的耗时工作。

顶半部就不再说明了,就是上面的中断处理函数,只是要求能够尽快处理完成并返回,不要处理耗时工作。

底半部通常使用tasklet或者工作队列来实现。

tasklet的特点和注意事项:

工作队列的特点和注意事项:

阅读剩余
THE END