本文基于 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、查看中断
注册中断最常用的函数是request_irq
第 1个参数 irq 为中断号
第 2 个参数 handler 为要中断服务函数
第 3 个参数 flags为中断标志位包含触发方式,是否共享,是否支持嵌套等
第 4 个参数 name,通常是 设备驱动程序的名称。该值用在 /proc/interrupt 系统文件上
第 5 个参数 dev 中断名称 可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址。建议将 设备结构指针作为 dev参数
flags参数定义
注册中断的另一个函数是request_threaded_irq
request_threaded_irq是将中断处理函数线程化执行的接口,其实request_irq也是直接调用的request_threaded_irq,只不过线程化回调thread_fn设置为NULL,不进行中断处理程序线程化处理。
和request_irq的参数有少许差异
handler:表示中断服务例程,指向primary handler 和request_irq的中断处理函数handler类似。中断发生时优先执行primary handler;
如果primary handler 为NULL,且thread_fn不为NULL,那么执行默认primary handler = irq_default_primary_handler。
thread_fn:中断线程化,NULL表示没有中断线程化。thread_fn如果该参数不为NULL,内核会为该irq创建一个内核线程,
当中断发生时,如果handler回调返回值是IRQ_WAKE_THREAD,内核将会激活中断线程,
在中断线程中,该回调函数将被调用,所以,该回调函数运行在进程上下文中,允许进行阻塞 *** 作。
其中
其中
FPGA每隔100us给运行linux的ARM一个中断,要求在20us内响应中断,并读走2000*16bit的数据。目前主要的问题是,当系统同时发生多个中断时,会严重影响linux对FPGA中断的响应时间。如何解决?
1、首先想到了ARM的FIQ,它可以打断IRQ中断服务程序,保证对外部FIQ的及时响应。但是发现linux只实现了IRQ,没有显示FIQ。
linux是从devicetree读取中断号,加入中断向量表的。
interrupts = <0x0 0x32 0x0>中的第一个字段0表示非共享中断,非零表示共享中断,SDK产生的dts统一为0,此时第二字段的值比XPS中的小32;如果第一字段非零,则第二字段比XPS小16.
最后字段表示中断的触发方式。
IRQ_TYPE_EDGE_RISING=0x00000001,
IRQ_TYPE_EDGE_FALLING=0x00000002,
IRQ_TYPE_LEVEL_HIGH=0x00000004,
IRQ_TYPE_LEVEL_LOW=0x00000008,
很明显,devicetree根本没有提供通知linux有FIQ的渠道。
2、再来看linux的IRQ
linux的中断分为上半部和下半部,上半部运行在IRQ模式,会屏蔽所有中断,下半部运行在SVC模式,会重新打开中断。
也就是说,当一个中断的上半部正在运行时(不能再次响应中断),FPGA的中断是不能被linux响应的;
反过来,当FPGA中断的上半部正在运行时(不能再次响应中断),其他的中断也不能被linux响应;
unsigned long flags
...
local_irq_save(flags)
....
local_irq_restore(flags)
3.
ARM有七种模式,我们这里只讨论SVC、IRQ和FIQ模式。
我们可以假设ARM核心有两根中断引脚(实际上是看不见的),一根叫 irq pin, 一根叫fiq pin.
在ARM的cpsr中,有一个I位和一个F位,分别用来禁止IRQ和FIQ的。
先不说中断控制器,只说ARM核心。正常情况下,ARM核都只是机械地随着pc的指示去做事情,当CPSR中的I和F位为1的时候,IRQ和FIQ全部处于禁止状态。无论你在irq
pin和fiq pin上面发什么样的中断信号,ARM是不会理你的,你根本不能打断他,因为他耳聋了,眼也瞎了。
在I位和F位为0的时候,当irq
pin上有中断信号过来的时候,就会打断arm的当前工作,并且切换到IRQ模式下,并且跳到相应的异常向量表(vector)位置去执行代码。这个过程是自动的,但是返回到被中断打断的地方就得您亲自动手了。当你跳到异常向量表,处于IRQ的模式的时候,这个时候如果irq
pin上面又来中断信号了,这个时候ARM不会理你的,irq
pin就跟秘书一样,ARM核心就像老板,老板本来在做事,结果来了一个客户,秘书打断它,让客户进去了。而这个时候再来一个客户,要么秘书不断去敲门问,要么客户走人。老板第一个客户没有会见完,是不会理你的。
但是有一种情况例外,当ARM处在IRQ模式,这个时候fiq pin来了一个中断信号,fiq
pin是什么?是快速中断呀,比如是公安局的来查刑事案件,那才不管你老板是不是在会见客户,直接打断,进入到fiq模式下,并且跳到相应的fiq的异常向量表处去执行代码。那如果当ARM处理FIQ模式,fiq
pin又来中断信号,又就是又一批公安来了,那没戏,都是执法人员,你打不断我。那如果这个时候irq
pin来了呢?来了也不理呀,正在办案,还敢来妨碍公务。
所以得出一个结论: IRQ模式只能被FIQ模式打断,FIQ模式下谁也打不断。
在打不断的情况下,irq pin 或 fiq pin随便你怎么发中断信号,都是白发。
所以除了fiq能打断irq以外,根本没有所谓中断嵌套的情况。
Linux不用FIQ,只用到了IRQ。但是我们有时候一个中断需要处理很长时间,那我们就需要占用IRQ模式那么长的时间吗?没有,linux在IRQ模式下只是简单的记录是什么中断,马上就切换回了SVC模式,换句话说,Linux的中断处理都是在SVC模式下处理的。
只不过SVC模式下的ISR上半部关闭了当前中断线,下半部才重新打开
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)