首页 > 系统相关 >[IMX6ULL驱动开发]-Linux对中断的处理(二)

[IMX6ULL驱动开发]-Linux对中断的处理(二)

时间:2024-05-28 22:33:03浏览次数:26  
标签:count 中断 irq 处理 半部 Linux 线程 IMX6ULL

上一篇文章中,引入了Linux对于中断的一些简略流程以及中断抽象为具体实际形象。此文章主要是继续加深对Linux对中断的处理流程以及一些相应的数据结构。

目录

Linux对中断的扩展:硬件中断、软件中断

多中断处理

中断上下部处理流程

发生中断A,并被中断A打断

发生中断A,并被中断B打断

下半部处理时间过长

Linux中断系统重要的数据结构

irq_desc

irqaction结构体

irq_data结构体

irq_domain 结构体

irq_chip 结构体


Linux对中断的扩展:硬件中断、软件中断

对于像按键等硬件所产生的中断称之为硬件中断,Linux中每一个硬件中断都有一个对应的中断号以及处理函数。可以这么简单的理解,有一个硬件中断函数数组,数组中第几个数据对应第几个中断号,以及对应的中断处理函数。

相应的,也有软件中断,相比于硬件中断,软件中断多了一个flag标志位,用来表示中断是否发生了 。

对于软件中断,只要flag标志位被置为1,那么就表示发生了该软件中断。同时,相比于硬件中断,软件中断的优先级会更低,优先处理的是硬件中断。如下是软件中断的枚举。

那么如何触发软件中断呢,最核心的函数是raise_softirq,它的形参是软件中断号,当设置后,系统会设置改软件中断为待处理状态,等到硬件中断处理完成后,会处理这个软件中断。

void raise_softirq(unsigned int nr);

那如何注册软件中断的处理函数呢,系统使用open_softirq函数,这个函数可以给对应的软件中断注册处理函数。

void open_softirq(int nr, void (*action) (struct soft_action*));

多中断处理

如果一个中断需要消耗过多的时间来处理,那么我们可以把中断分为中断上部和中断下部,中断上部用来处理紧急的中断,下部用来处理非紧急的中断。当我们在中断上部处理紧急的中断的时候,是关闭中断的,当处理完紧急的中断,来到中断下部,此时重新打开中断,处理比较不紧急的中断。

中断上下部处理流程

发生中断A,并被中断A打断

假如发生中断A,中断上半部优先级高首先执行,count首先++,执行完中断后--,此时count为0,进入中断下半部,此时count++,开启中断,此时再次发生中断A打断中断下半部,继续走到步骤1这里,count++,执行中断,count--,此时count等于1,并不会进入中断下半部,而是直接完成处理,此时恢复现场,到步骤7,执行完中断A的下半部,count--,此时count为0。完成完整的中断流程。可见,不管多少个中断,中断上半部和中断下半部是N对1的关系,也就是中断下半部只会执行一次。

发生中断A,并被中断B打断

假如发生中断A,中断上半部优先级高首先执行,count首先++,执行完中断后--,此时count为0,进入中断下半部,此时count++,开启中断,此时,B中断打断了A中断的中断下半部,回到步骤1,此时执行的是中断B的中断上半部,count++,执行中断B,count--,此时count等于1,并不会进入中断下半部,而是直接完成处理,此时恢复现场,到步骤7,执行完中断A以及中断B的下半部,count--,此时count为0。完成完整的中断流程。可见,中断下半部的处理是多个中断下半部一起进行处理的,而不是单独处理。


下半部处理时间过长

一般来说,中断下半部是用来处理那些比较不重要的软件中断,那么假如中断下半部处理的中断也需要占用非常久的时间怎么办呢。

毕竟还是在中断中,其他进程线程是无法执行的,假如存在GUI的进程,会导致页面卡死。所以,假如中断所需要的时间实在是太耗时了,我们就不使用软件中断来处理,而是使用内核线程来处理,此时中断下半部就是内核线程,和进程一样都有竞争执行的机会。

如下为一些系统的内核线程

kworker线程是内核线程的一种,它要去工作队列(work queue)上取出一个个工作(work)来执行,那么我们该怎么把一个个work放在work queue上面呢。

、创建work,先写一个处理函数,在调用函数把这个处理函数填充进work结构体中。

、结构体创建完成了,我们需要把该结构体提交给work queue,一般在中断上半部,调用schedule_work 函数把work交给work queue

、放进后,只需要等线程抢占运行即可,这样中断下半部就可以和其他进程抢占CPU执行,这样就不存在因为中断时间过久导致其他进程过久无法相应

总的来说,对于那些很耗时的中断,我们可以交给内核线程来进行处理,内核线程我们可以看成线程,不当成中断来看待,那对应可以抢占运行,也会休眠。


Linux中断系统重要的数据结构

irq_desc

irq_desc结构体的主要内容如下:

每一个 irq_desc 数组项中都有一个函数:handle_irq,还有一个 action 链表。handle_irq为中断处理函数,action链表主要存放各个中断控制器上下级中断的中断处理函数。

外部中断1、中断n共享了B号中断,多个GPIO控制器的中断汇集到GIC的A号中断。当发生了中断,是从左到右依次中断,最后中断掉CPU。

CPU处理的时候,则是从右到左依次进行处理,CPU会首先读取GIC,获取中断号A,调用中断A的handle_irq(irq_desc[A].handle_irq 中断处理函数,BSP工程师提供),获取到发生中断的中断号B,此时调用irq_desc[B]. handle_irq,中断B为共享中断,irq_desc[B]存在一个action链表,里面记录了各个共享中断的外部设备中断函数,一旦确定了中断来自中断B,此时会一一执行中断B中(irq_desc[B])的action链表,把各个B号中断下的外接设备的中断函数一一执行,以此确定到底是哪个外部设备发生了中断。

irqaction结构体

irqaction 结构体存在于irq_desc结构体下,主要的内容如下:

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

handler 是中断处理的上半部函数,用来处理紧急的事情。 thread_fn 对应一个内核线程 thread,当 handler 执行完毕,Linux内核会唤醒对应的内核线程。在内核线程里,会调用 thread_fn 函数。

irq_data结构体

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

还有两个成员: irq、hwirq,irq 是软件中断号,hwirq 是硬件中断号。 比如上面我们举的例子,在 GPIO 中断 B 是软件中断号,可以找到 irq_desc[B] 这个数组项;GPIO 里的第 x 号中断,这就是 hwirq。比如说GPIO3的5号引脚中断和GPIO4的5号引脚中断,两个的软件中断号是不同的。

irq_domain结构体中的函数会把hwirq映射为软件中断号irq。

irq_domain 结构体

interrupt-parent = <&gpio1>;

interrupts = <5 IRO_TYPE_EDGE_RISING>;

如上表示 GPIO1的5号引脚,通过上升沿触发中断。此时,hwirq就是5,但是它属于的domain属于GPIO1。

irq_domain 结构体中的如下两个函数用来解析设备树中得到的中断数据:

 xlate :用来解析设备树的中断属性,提取出 hwirq、type 等信息。比如上面举例的,hwirq就是5,type 就是IRO_TYPE_EDGE_RISING

 map :把 hwirq 转换为 irq。

irq_chip 结构体

irq_chip 结构体的主要成员如下:

在 request_irq 创建中断后,并不需要手工去使能中断,原因就是系统调用对 应的 irq_chip 里的函数帮我们使能了中断。

我们提供的中断处理函数中,也不需要执行主芯片相关的清中断操作,也是 系统帮我们调用 irq_chip 中的相关函数。 但是对于外部设备相关的清中断操作,还是需要我们自己做的。

标签:count,中断,irq,处理,半部,Linux,线程,IMX6ULL
From: https://blog.csdn.net/m0_72372635/article/details/139247723

相关文章

  • openssh9.7p1(OpenSSL 1.1.1w)适用于各Linux系统的rpm包
    本人近几日编译的openssh9.7p1包,用于解决漏洞扫描器提示openssh相关漏洞的问题处理。包含多个Linux发行版本(包含el6\el7\el8\openeuler2110\openeuler2203\BCLinux\eulerOS2.10对应版本等)。一、适用openeuler2203和openeuler2203sp*系列(含BClinux对应系列):openssh9.7P1forop......
  • 0Linux GDB学习笔记
    LinuxGDB使用目录文章目录LinuxGDB使用先编译文件1.检查安装1.1安装GDB2.启动GDB3.退出GDB4.设置断点4.1在指定行号处设置断点4.2在指定函数名处设置断点4.3在指定源文件和行号处设置断点4.4查看断点信息4.5删除断点5.运行5.1<fontcolor=#ff0000>逐过程:遇到......
  • 外部中断配置步骤
    (1)禁止CPU中断,初始化PIE中断控制寄存器和PIE中断向量表IER=0x0000;IFR=0x0000;InitPieCtrl();InitPieVectTable();(2)使能IO口时钟,配置IO口为输入(3)设置IO口与中断线的映射关系GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL=12;  //XINT1是GPIO12(4)指定中断向量表中断服......
  • 原子上下文、中断上下文
    原子上下文内核的一个基本原则就是:在中断或者说原子上下文中,内核不能访问用户空间,而且内核是不能睡眠的。也就是说在这种情况下,内核是不能调用有可能引起睡眠的任何函数。一般来讲原子上下文指的是在中断或软中断中,以及在持有自旋锁的时候。内核提供了四个宏来判断是否处于这几......
  • 在 windows 通过 vscode 查看 linux 上的代码
    原理使用vscode的 Remote-SSH插件,通过SSH连接linux,直接查看linux上的代码,免手动同步vscodessh配置文件Config 私钥IdentityFile默认是~/.ssh/id_rsa,所以可省略登录界面打开linux文件夹 ......
  • linux恢复数据
    linux恢复数据在Linux系统中恢复数据,可以采取多种方法,具体取决于数据丢失的原因和文件系统的类型。以下是一些常见的数据恢复方法:使用Undelete工具:首先,你需要使用如yum或apt-get等命令安装Undelete工具。查找被删除的文件。例如,在CentOS系统中,你可以使用sudoundelete/......
  • 在Linux中,如何进行用户行为监控?
    在Linux中,进行用户行为监控可以通过多种工具和命令来实现。以下是详细的方法,结合了参考文章中的信息:1.使用命令行工具a.w命令功能:显示当前登录的所有用户的列表,以及他们的登录时间、当前进程和系统负载。示例:在终端中输入w命令,将显示当前登录到系统的用户列表、登录时间......
  • 在Linux中,如何进行系统安全加固?
    在Linux系统中,进行系统安全加固是一个多层面、多策略的过程,涉及到从物理环境到应用层的多个方面。以下将详细阐述在Linux系统中进行系统安全加固的几个主要方面及具体操作步骤:一、系统防火墙的配置使用iptables(CentOS6):iptables是Linux系统中的一个灵活的工具,可以用来管理IP信......
  • 在Linux中,如何进行数据恢复?
    在Linux中进行数据恢复是一个相对复杂的过程,它涉及到多个方面和不同的恢复方法。以下是详细的数据恢复步骤和注意事项:1.评估数据丢失情况确定数据丢失原因:硬件故障、软件问题、误删除等。检查文件系统状态:使用如fsck命令检查文件系统的完整性。确定要恢复的数据:明确需要恢复......
  • 在Linux中,如何进行网络资源的优化?
    在Linux中进行网络资源优化,主要目标是提高网络吞吐量、降低延迟、确保稳定性和安全性。以下是一些常见的优化措施:1.调整网络参数修改TCP缓冲区大小:通过调整/proc/sys/net/core/wmem_max和rmem_max来增大发送和接收缓冲区的大小,可以提高大文件传输或高带宽链接的性能。使用sys......