一、中断简介

中断是指 CPU 在执行程序的过程中,出现了某些突发事件急待处理,CPU 必须暂停当前程序的执行, 转去处理突发事件,处理完毕后又返回原程序被中断的位置继续执行。由于中断的存在极大的提高了 CPU 的运行效率,但是设备的中断会打断内核进程中的正常调度和运行,系统对更高吞吐率的追求势必要求中断服务程序尽量短小精悍。

二、中断上下文

为保证系统实时性,中断服务程序必须足够简短,但实际应用中某些时候发生中断时必须处理大量的 事物,这时候如果都在中断服务程序中完成,则会严重降低中断的实时性,基于这个原因,linux 系统提出了一个概念:把中断服务程序分为两部分:中断上下文,也叫做顶半部-底半部 。

  • 中断上文(顶半部):完成尽可能少的比较急的功能,它往往只是简单的读取寄存器的中断状态,并清除中断标志后就进行“中断标记”(也就是把底半部处理程序挂到设备的底半部执行队列中)的工作。 顶半部的特点就是响应速度快。
  • 中断下文(底半部):处理中断的剩余大部分任务,可以被新的中断打断。

三、linux开发使用中断的总体思路

linux 中断有专门的中断子系统,其实现原理很复杂,但是驱动开发者不需要知道其实现的具体细节, 只需要知道怎么在设备树中指定中断,如何应用该子系统提供的 API 函数来编写中断相关驱动代码即可。其他的事情,比如设备树中的中断控制器,这些都是由原厂的BSP工程师帮我们写好了,我们不需要来修改他。

四、设备树中配置中断

如果一个设备需要用到中断功能,开发人员就需要在设备树中配置好中断属性信息,因为设备树是用来描述硬件信息的,然后Linux内核通过设备树配置的中断属性来配置中断功能。

参考文档:

内核Documentation\devicetree\bindings\interrupt-controller\interrupts.txt

1、各级中断中断控制器

在硬件上,“中断控制器”只有GIC这一个,但是我们在软件上也可以把上图中的“GPIO”称为“中断控制器”。

GPIO1连接到GIC,GPIO2连接到GIC,所以GPIO1的父亲是GIC,GPIO2的父亲是GIC。

假设GPIO1有32个中断源,但是它把其中的16个汇聚起来向GIC发出一个中断,把另外16个汇聚起来向GIC发出另一个中断。这就意味着GPIO1会用到GIC的两个中断,会涉及GIC里的2个hwirq。

这些层级关系、中断号(hwirq),都会在设备树中有所体现。

2、中断控制器节点的语法

在设备树中,中断控制器节点中必须有的两个属性:

interrupt-controller,表明它是“中断控制器”。

#interrupt-cells,表明引用这个中断控制器的话需要多少个cell。

#interrupt-cells的,别的节点要引用这个中断控制器时,需要用几个cells来描述

3、示例

比如,在imx6u11.dtsi文件,其中的inc节点就是imx6ul1的中断控制器节点,如下图所示:

imx6ul.dtsi - arch/arm/boot/dts/imx6ul.dtsi - Linux source code (v5.16.16) - Bootlin

intc: interrupt-controller@a01000 {compatible = "arm,gic-400", "arm,cortex-a7-gic";interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(1) | IRQ_TYPE_LEVEL_HIGH)>;#interrupt-cells = <3>;interrupt-controller;interrupt-parent = <&intc>;reg = <0x00a01000 0x1000>,<0x00a02000 0x2000>,<0x00a04000 0x2000>,<0x00a06000 0x2000>;
};

compatible 属性值为“arm,cortex-a7-gic”在 Linux 内核源码中搜索“arm,cortex-a7- gic”即可找到 GIC 中断控制器驱动文件。

interrupt-controller 节点为空,表示当前节点是中断控制器。

#interrupt-cells 和#address-cells、#size-cells 一样。指它的子节点是用多少个cells来描述一个中断。的对于 ARM 处理的 GIC 来说,一共有 3 个 cells,这三个 cells 的含义如下:

  1. cells:中断类型,0 表示 SPI 中断,1 表示 PPI 中断。
  2. cells:中断号,对于 SPI 中断来说中断号的范围为 0~987,对于 PPI 中断来说中断号的范围为 0~15。
  3. cells:标志,bit[3:0]表示中断触发类型,为 1 的时候表示上升沿触发,为 2 的时候表示下降沿触发,为 4 的时候表示高电平触发,为 8 的时候表示低电平触发。bit[15:8]为 PPI 中断的 CPU 掩码。

比如,GPI0的节点也可以作为中断控制器,在imx6ul.dtsi文件中GPlO1的节点内容如下图所示:

gpio1: gpio@209c000 {compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";reg = <0x0209c000 0x4000>;interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_GPIO1>;gpio-controller;#gpio-cells = <2>;interrupt-controller;#interrupt-cells = <2>;gpio-ranges = <&iomuxc  0 23 10>, <&iomuxc 10 17 6>,<&iomuxc 16 33 16>;
};

interrupts中就是用三个cells来描述中断的:

interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>
  • GIC_SPI:代表共享中断(GIC_PPI代表私有中断)
  • 66:代表中断号,一组gpio共享一个中断号
  • IRQ_TYPE_LEVEL_HIGH:中断类型
打开可以打开《IMX6ULLRM.pdf》的“Chapter 3 Interrupts and DMA Events”章节,找到表 3-1,
GPIO1 一共用了 2 个中断号,一个是 66,一个是 67。
66 对 应 GPIO1_IO00~GPIO1_IO15 这低 16 个 IO,67 对应 GPIO1_IO16~GPIOI1_IO31 这高16 位 IO。
interrupt-controller 表明了 gpio1 节点也是个中断控制器,用于控制 gpio1 所有 IO 的中断。

上述工作都是由原厂的BSP工程师来帮我们写好的,并不需要我们来写。我们需要关注的点是怎么在设备树里面描述一个外设的中断节点,我们来看一个例子:

在这个例子中,我们先使用pinctrl和gpio子系统把这个引脚设置为了gpio功能,因为我们在使用中断的时候需要把引脚设置成输入。然后使用interrupt-parent和interrupts 属性来描述中断。

我们的引脚使用的是gpiol里面的io18,所以我们使用的是gpio1这个中断控制器

interrupts属性设置的是中断源,为什么里面是俩个cells呢,因为我们在gpio1这个中断控制器里面#interrupt-cells的值为2

五、驱动代码中使用中断

1、获取中断号

当在设备数中使用了interrupt-parent和interrupts 属性来描述中断后,可以通过irq_of_parse_and_map来获取中断号。gpio中断也可以不使用这两个属性,直接通过gpio号来获取中断号。

2、request_irq 函数申请中断

request_irq 函数可能会导致睡眠,因此不能在中断上下文或者其他禁止睡眠的代码段中使用。

request_irq 函数会激活(使能)中断,所以不需要我们手动去使能中断

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
irq:要申请中断的中断号。  
handler:中断处理函数,当中断发生以后就会执行此中断处理函数。
flags:中断标志,可以在文件 include/linux/interrupt.h 里面查看所有的中断标志
name:中断名字,设置以后可以在/proc/interrupts 文件中看到对应的中断名字。
dev:如果将 flags 设置为 IRQF_SHARED 的话,dev 用来区分不同的中断,一般情况下将 dev 设置为 设备结构体,dev 会传递给中断处理函数 irq_handler_t 的第二个参数。
返回值:0 中断申请成功,其他负值 中断申请失败,如果返回-EBUSY 的话表示中断已经被申请了。

3、编写中断处理函数

使用 request_irq 函数申请中断的时候需要设置中断处理函数,中断处理函数格式如下所示:

irqreturn_t (*irq_handler_t) (int, void *)

第一个参数是要中断处理函数要相应的中断号。

第二个参数是一个指向 void 的指针,也就是个通用指针,需要与 request_irq 函数的 dev 参数保持一致。用于区分共享中断的不同设备,dev 也可以指向设备数据结构。

中断处理函数的返回值为 irqreturn_t 类型,定义如下所示:

enum irqreturn {
IRQ_NONE = (0 << 0),  //表示不是本驱动的中断不处理
IRQ_HANDLED = (1 << 0), //表示正常处理,通常是这个
IRQ_WAKE_THREAD = (1 << 1), //表示在中断下文中处理
}typedef enum irqreturn irqreturn_t;
一般中断服务函数返回值使用如下形式: return IRQ_RETVAL(IRQ_HANDLED)

4、释放中断资源

中断使用完成以后就要通过 free_irq 函数释放掉相应的中断。如果中断不是共享的,那么 free_irq 会 删除中断处理函数并且禁止中断。free_irq 函数原型如下所示:

void free_irq(unsigned int irq, void *dev)
irq:要释放的中断。
dev:如果中断设置为共享(IRQF_SHARED)的话,此参数用来区分具体的中断。共享中断
只有在释放最后中断处理函数的时候才会被禁止掉。

5、中断使能和禁止函数

常用的中断使用和禁止函数如下所示:

void enable_irq(unsigned int irq);
void disable_irq(unsigned int irq);
void disable_irq_nosync(unsigned int irq);
  • disable_irq 函数要 等到当前正在执行的中断处理函数执行完才返回,因此使用者需要保证不会产生新的中断,并且确保所有已经开始执行的中断处理程序已经全部退出。
  • disable_irq_nosync 函数调用以后立即返回,不会等待当前中断处理程序执行完毕。

6、其他

local_irq_disable(); //屏蔽中断
local_irq_enable(); //打开中断
local_irq_save(flags); //禁止中断并保存当前 CPU 中断信息
local_irq_restore(flags); //打开中断并回复之前保存的 CPU 中断信息

六、综合示例:

1、设备树

2、驱动代码

3、调试手段

查看中断是否申请注册成功:cat /proc/interrupts命令

其中:48就是中断号

拿到中断号之后,可以看这个中断触发了多少次:

ref:

【原创】Linux中断子系统(三)-softirq和tasklet - LoyenWang - 博客园

韦东山:在Linux设备树(DTS)中指定中断_在代码中获得中断(附.视频) - 知乎

【北京迅为】嵌入式学习之Linux驱动篇_哔哩哔哩_bilibili

https://elixir.bootlin.com/linux/v5.16.16/source/arch/arm/boot/dts/imx6ul.dtsi

linux内核中断(一)相关推荐

  1. Linux内核中断系统处理机制-详细分析

    原文地址::https://blog.csdn.net/weixin_42092278/article/details/81989449 相关文章 1.Linux中断管理 (1)Linux中断管理机制 ...

  2. 《linux内核中断》之 法外狂徒张三删库跑路

    法外狂徒张三删库跑路 真实案例:在今年2月份,国内一个程序员删库的消息传遍it界.他的几行代码,直接让上市公司微盟的市值一天蒸发超10亿,300百万用户直接受到影响.网上是谣言四起,可谓是最牛逼的删库 ...

  3. linux内核看门狗关闭方法,linux内核中断之看门狗

    一:内核中断 linux内核中的看门狗中断跟之前的裸板的中断差不多,在编写驱动之前,需要线把内核自带的watch dog模块裁剪掉,要不然会出现错误:在Device Drivers /Watchdog ...

  4. linux内核中断详解

    linux内核中断详解 1.中断的硬件触发流程 外设:如果外设有操作或者有数据可用,那么就会产生一个电信号,这个电信号发送给中断控制器. 中断控制器:中断控制器接收到外设发来的电信号以后,进行进一步的 ...

  5. Linux 内核中断体系 初探

    还是要先理解整个中断的体系,首先要理解对中断的含义 如果这是涉及到的软件的调试的话,没有接触过硬件的同学会对,gdb的调试中的中断有一定的认知 但是,这两个中断指的意思是不相同的,gdb的调试中的中断 ...

  6. 初步了解Linux内核中断初始化

    在linux内核中,用struct irq_chip结构体描述一个可编程中断控制器,它的整个结构和调度器中的调度类类似,里面定义了中断控制器的一些操作: 在中断处理中所涉及的几个重要的数据结构:中断描 ...

  7. linux 内核中断与时钟的冲突 问题 del_timer,Linux内核开发之中断与时钟(三)

    晚上7点10分.. "小涛哥,这章不是叫Linux设备驱动程序之中断与时钟,前边你讲了中断,还给了我很多模版,我都看懂了,这次是不是要开始讲时钟了.." "真聪明,越来越 ...

  8. Linux 内核中断内幕【转】

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/ 本文对中断系统进行了全面的分析与探讨,主要包括中断控制器.中断分类 ...

  9. [arm驱动]linux内核中断编程

    第一部分获取中断(开启硬件中断) 一.中断的申请注销: 1)中断的申请 1 2 int request_irq(unsigned int irq, irq_handler_t handler,     ...

  10. c6x Linux 内核中断分析

    1. 内核中断介绍 1.1 中断简介 所有支持Linux的平台都采用了中断(interrupt)的概念,以便(因种种原因)引入周期性的中断.需要区分两种类型的中断. 1. 硬件中断(hardware ...

最新文章

  1. winform让子窗体始终居于父窗体的中间
  2. React 开发环境搭建
  3. leetcode算法题--地图中的最高点
  4. fastjson 使用总结
  5. 直播电商加速合规,引爆消费潜力
  6. 经典正则表达式——常用的正则表达式
  7. 牛客多校3 - Operation Love(几何+叉积确定三点顺逆)
  8. 简述python定义中的五个要点_Python基础知识复习
  9. python-工具-pycharm的基本操作
  10. 【Vegas原创】导入结构一致表的SQL语句
  11. 网络的小区号和网络tac_网络问政|城基路老旧小区排污管长期堵塞没人管?
  12. 全志 起家产品 A31S四核:昂达V819mini平板试玩
  13. 图像相似的算法有哪些,图像相似的算法是什么
  14. cold start
  15. 蓝旭暑期培训——DOM事件+正则表达式
  16. 低代码开发专题月 | YonBuilder低代码开发平台,企业数智化转型的新动力
  17. 云顶之奕pbe服务器注册,云顶之弈手游pbe服
  18. KKS1(生产订单计算-计算差异)时 常见差异问题
  19. 雷军VS黄章:现实主义和梦幻主义的商业对决
  20. 耦合性(耦合度) -- Coupling

热门文章

  1. 各种深度学习模型与框架的文件后缀名
  2. github与码云的界面英文介绍
  3. 单片机关键字sfr和sbit的理解
  4. elk + kafka 简单搭建日志分析系统
  5. Facebook推出防止网络欺凌的“检举”功能
  6. 五 跳个舞你就满足了吗?--机器人动力学
  7. gff文件用什么打开_GTF/GFF文件的差异及其相互转换
  8. LDR、STR、MOV、B、BL、BX、BLX 和 BXJ
  9. VUE 在线编辑 EXCEL , SPERADJS的使用
  10. nacos作为配置中心