Linux中断补充

Linux中断补充,第1张

在系统结构中,CPU工作的模式有两种,一种是中断,由各种设备发起;一种是轮询,由CPU主动发起。

中断IRQ:

中断允许让设备(如键盘,串口卡,并口等设备)表明它们需要CPU。一旦CPU接收了中断请求,CPU就会暂时停止执行正在运行的程序,并且调用一个称为中断处理器或中断服务程序(interrupt service routine)的特定程序。CPU处理完中断后,就会恢复执行之前被中断的程序。

中断分类:

硬中断+软中断

硬中断:

①非屏蔽中断:不能被屏蔽,硬件发生的错误:内存错误,风扇故障,温度传感器故障等。

②可屏蔽中断:可被CPU忽略或延迟处理。当缓存控制器的外部针脚被触发的时候就会产生这种类型的中断,而中断屏蔽寄存器就会将这样的中断屏蔽掉。我们可以将一个比特位设置为0,来禁用在此针脚触发的中断。

软中断:

是软件实现的中断,也就是程序运行时其他程序对它的中断而硬中断是硬件实现的中断,是程序运行时设备对它的中断。

CPU之间的中断处理(IPI)

处理器间中断允许一个CPU向系统其他的CPU发送中断信号,处理器间中断(IPI)不是通过IRQ线传输的,而是作为信号直接放在连接所有CPU本地APIC的总线上。

CALL_FUNCTION_VECTOR (向量0xfb)

发往所有的CPU,但不包括发送者,强制这些CPU运行发送者传递过来的函数,相应的中断处理程序叫做call_function_interrupt(),例如,地址存放在群居变量call_data中来传递的函数,可能强制其他所有的CPU都停止,也可能强制它们设置内存类型范围寄存器的内容。通常,这种中断发往所有的CPU,但通过smp_call_function()执行调用函数的CPU除外。

RESCHEDULE_VECTOR (向量0xfc)

当一个CPU接收这种类型的中断时,相应的处理程序限定自己来应答中断,当从中断返回时,所有的重新调度都自动运行。

INVALIDATE_TLB_VECTOR (向量0xfd)

发往所有的CPU,但不包括发送者,强制它们的转换后援缓冲器TLB变为无效。相应的处理程序刷新处理器的某些TLB表项。

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

让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的特点和注意事项:

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

本文基于 RockPI 4A 单板Linux4.4内核介绍中断申请的常用接口函数。

1、文件

2、定义

说明:

1)、 irq :要申请的中断号,可通过 platform_get_irq() 获取,见“Linux内核中断之获取中断号”。

2)、 handler :中断处理函数,发生中断时,先处理中断处理函数,然后返回 IRQ_WAKE_THREAD 唤醒中断处理线程。中断处理函数尽可能简单。

中断处理函数定义: typedef irqreturn_t (*irq_handler_t)(int, void *)

中断返回值如下:

3)、 thread_fn :中断处理线程,该参数可为NULL。类似于中断处理函数的下半部分。

4)、 irqflags :中断类型标志。

定义文件: include/linux/interrupt.h ,内容如下:

5)、 devname :中断名称,可使用 cat /proc/interrupts 命令查看。

6)、 dev_id :设备ID,该值唯一。

在使用共享中断时(即设置 IRQF_SHARED ),必须传入 dev_id ,在中断处理和释放函数中都会使用该参数。

注:

1、 request_threaded_irq() 函数可替代 request_irq 加 tasklet 或 workqueue 的方式。

2、对应的中断释放函数为: void free_irq(unsigned int, void *) ,需要和中断申请函数成对出现。

1、文件

2、定义

说明:

1)、 __must_check :指调用函数一定要处理函数的返回值,否则编译器会给出警告。

2)、 request_irq() 函数本质上是中断处理线程 thread_fn 为空的 request_threaded_irq() 函数。

对应的中断释放函数为: void free_irq(unsigned int, void *) ,需要和中断申请函数成对出现。

1、文件

2、定义

说明

devm_request_threaded_irq() 本质上还是使用 request_threaded_irq() 函数实现中断申请。

两者区别:

1)多了一个 dev 参数;

2)在设备驱动卸载时,中断会自动释放;

3)如果想单独释放中断,可使用 void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) 函数。

1、文件

2、定义

devm_request_irq() 函数本质上是中断处理线程 thread_fn 为空的 devm_request_threaded_irq() 函数。

1、获取中断号

2、申请中断

3、中断处理函数

4、中断处理线程

5、查看中断


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7542320.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-06
下一篇 2023-04-06

发表评论

登录后才能评论

评论列表(0条)

保存