interrupt子系统中的数据结构

我们接着上一篇,开始真正的interrupt子系统:

现在有一个共享的中断,网卡跟开关共享同一个gpio中断,然后当触发中断的时候,GIC会发信号给CPU,告诉他已经发生了中断了,然后CPU会去读取GIC里面的寄存器,查看是发生了什么中断,然后发现是GPIO中断后,就会去查看GPIO各个引脚的寄存器,查看是哪个引脚发生了中断,发现是B号中断来着,接着会去调取产生这个引脚中断的各种外设的中断判断函数,看看是哪一个发生了中断,然后去执行他的处理函数

外部设备1、外部设备n共享一个GPIO中断B,多个GPIO中断汇聚到GIC(通用中断控制器)的A号中断,GIC再去中断CPU。那么软件处理时就是反过来,先读取GIC获得中断号A,再细分出GPIO中断B,最后判断是哪一个外部芯片发生了中断。

所以,中断的处理函数来源有三:

① GIC的处理函数:

假设irq_descA.handle_irq是XXX_gpio_irq_handler(XXX指厂家),这个函数需要读取芯片的GPIO控制器,细分发生的是哪一个GPIO中断(假设是B),再去调用irq_descB. handle_irq。

注意:irq_descA.handle_irq细分出中断后B,调用对应的irq_descB.handle_irq。

显然中断A是CPU感受到的顶层的中断,GIC中断CPU时,CPU读取GIC状态得到中断A。

② 模块的中断处理函数:

比如对于GPIO模块向GIC发出的中断B,它的处理函数是irq_descB.handle_irq。

BSP开发人员会设置对应的处理函数,一般是handle_level_irq或handle_edge_irq,从名字上看是用来处理电平触发的中断、边沿触发的中断。

注意:导致GPIO中断B发生的原因很多,可能是外部设备1,可能是外部设备n,可能只是某一个设备,也可能是多个设备。所以irq_descB.handle_irq会调用某个链表里的函数,这些函数由外部设备提供。这些函数自行判断该中断是否自己产生,若是则处理。

③ 外部设备提供的处理函数:

这里说的"外部设备"可能是芯片,也可能总是简单的按键。它们的处理函数由自己驱动程序提供,这是最熟悉这个设备的"人":它知道如何判断设备是否发生了中断,如何处理中断。

对于共享中断,比如GPIO中断B,它的中断来源可能有多个,每个中断源对应一个中断处理函数。所以irq_descB中应该有一个链表,存放着多个中断源的处理函数。

一旦程序确定发生了GPIO中断B,那么就会从链表里把那些函数取出来,一一执行。

这个链表就是action链表。

对于我们举的这个例子来说,irq_desc数组如下:

irqaction 结构体

当调用request_irq、request_threaded_irq注册中断处理函数时,内核就会构造一个irqaction结构体。在里面保存name、dev_id等,最重要的是handler、thread_fn、thread。

handler是中断处理的上半部函数,用来处理紧急的事情。

thread_fn对应一个内核线程thread,当handler执行完毕,Linux内核会唤醒对应的内核线程。在内核线程里,会调用thread_fn函数。

可以提供handler而不提供thread_fn,就退化为一般的request_irq函数。

可以不提供handler只提供thread_fn,完全由内核线程来处理中断。

也可以既提供handler也提供thread_fn,这就是中断上半部、下半部。

里面还有一个名为sedondary的irqaction结构体,它的作用以后再分析。

在reqeust_irq时可以传入dev_id,为何需要dev_id?作用有2:

① 中断处理函数执行时,可以使用dev_id

② 卸载中断时要传入dev_id,这样才能在action链表中根据dev_id找到对应项

所以在共享中断中必须提供dev_id,非共享中断可以不提供。

下面来看看设备树跟这些数据结构的关系:

它就是个中转站,里面有irq_chip指针 irq_domain指针,都是指向别的结构体。

比较有意思的是irq、hwirq,irq是软件中断号,hwirq是硬件中断号。比如上面我们举的例子,在GPIO中断B是软件中断号,可以找到irq_descB这个数组项;GPIO里的第x号中断,这就是hwirq。

谁来建立irq、hwirq之间的联系呢?由irq_domain来建立。irq_domain会把本地的hwirq映射为全局的irq,什么意思?比如GPIO控制器里有第1号中断,UART模块里也有第1号中断,这两个"第1号中断"是不一样的,它们属于不同的"域"──irq_domain。

相关推荐
祖力551 小时前
数据结构的基本概念与单向链表(链表数据类型构造、创建、头插、尾插、头删、尾删)
数据结构·链表
ltl4 小时前
实时 OS 巡礼:VxWorks、QNX、Zephyr 与 PREEMPT_RT
linux
我是谁??4 小时前
Ubuntu22.04更换清华源
linux·运维·服务器
白狐_7984 小时前
408数据结构第8章:排序②——性质对比秒杀、场景选择与外部排序
java·数据结构·算法
zander2584 小时前
LeetCode 84:柱状图中的最大矩形——单调栈如何确定左右边界
java·数据结构·算法
Shell运维手记5 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
船厂电气自动化ai大模型5 小时前
AI大模型与数学 第32课 函数凹凸性与二阶导数:拐点求解、凹凸区间计算(10道二阶导数计算题)
数据结构·人工智能·python·深度学习·算法
旖旎夜光5 小时前
LeetCode 3:无重复字符的最长子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
测试运维日常笔记6 小时前
Linux系统安装配置TigerVNC服务器完整指南
linux·运维·服务器
雾时之林7 小时前
Linux----cron定时服务
linux·运维·服务器