第五课. 内核中断系统中的设备树

这节课讲解如何在中断系统中使用设备树,也就是用设备树如何描述中断。
中断体系在4.x内核中变化很大,中断体系又跟pinctrl系统密切相关,pinctrl中又涉及GPIO子系统,这样讲下去的话,设备树课程就变成驱动专题了,所以我打算只讲中断体系统,对于pinctrl、gpio等系统留待以后在驱动课程中扩展。<br>
这一课的参考资料链接如下:

  • 基于设备树的TQ2440的中断(1)
  • 基于设备树的TQ2440的中断(2)
  • 基於tiny4412的Linux內核移植 — 实例学习中断背后的知识(1)
  • Linux kernel的中断子系统之(一):综述
  • Linux kernel的中断子系统之(二):IRQ Domain介绍
  • linux kernel的中断子系统之(三):IRQ number和中断描述符
  • linux kernel的中断子系统之(四):High level irq event handler
  • Linux kernel中断子系统之(五):驱动申请中断API
  • Linux kernel的中断子系统之(六):ARM中断处理过程
  • linux kernel的中断子系统之(七):GIC代码分析

本课视频预计分为五节。
其中第01节描述中断概念的引入与处理流程,这节视频来自”韦东山第1期裸板视频加强版”, 如果已经理解了中断的概念, 请忽略该节。

第01节_中断概念的引入与处理流程

  • 点击下面链接跳转到相应文章页面
    [[第014课_异常与中断 | 第01节_中断概念的引入与处理流程文章地址 ]]

    第02节_Linux对中断处理的框架及代码流程简述

当CPU发生中断时,CPU会跳到一个固定的地址去执行中断,对于中断来说,
中断地址是在24的地方,

.globl _start
0—> _start: b reset
4—> ldr pc, _undefined_instruction
8—> ldr pc, _software_interrupt
c—> ldr pc, _prefetch_abort
16–> ldr pc, _data_abort
20–> ldr pc, _not_used
24–> ldr pc, _irq //发生中断时,CPU跳到这个地址执行该指令
ldr pc, _fiq

这些地址就是vector,可以放在0地址,也可以放在0xffff0000(对于这个地址是启动mmu之后才存在的)
对于其它芯片,向量所在地址可能不同,但都是用来处理异常
打开内核源码
a. 异常向量入口: <code>archarmkernelentry-armv.S</code>

使用宏vector_stub表示这个vector_irq
b. 中断向量: vector_irq

<code>archarmkernelentry-armv.S</code>

处理完成后返回到被中断的现场

c.<code> __irq_usr/__irq_svc</code>

这2个函数的处理过程类似:
保存现场
调用 irq_handler
恢复现场

d. 核心是irq_handler: 将会调用C函数 handle_arch_irq

linux-4.19-rc3kernelirqhandle.c

e. handle_arch_irq的处理过程: 请看视频和图片

  • 读取寄存器获得中断信息: hwirq
  • 把hwirq转换为virq
  • 调用 irq_desc[virq].handle_irq

对于S3C2440,通过set_handle_irq函数设置 s3c24xx_handle_irq 是用于处理中断的C语言入口函数
中断处理流程:
假设中断结构如下:

sub int controller —> int controller —> cpu

中断控制中有32位,每一位代表一种中断,也就是控制器可以向CPU发出32种中断,每一种中断的处理方式不同,如何管理这些中断呢br>最简单方法是创建指针数组,每一项对应一个中断,在这个中断里存放处理函数,这个数组用irq_desc中断结构体来表示

第五课. 内核中断系统中的设备树

如果使用中断4_7则一旦产生中断,那么都会向cpu发出4号中断,也可以通过irqdesc.irq_action构造4个irqaction结构体,
将四个中断链接到一起,当发生中断时,这四个函数都会被调用一次,这种方式可以用,但是并不好用
对于sub interrupt controller(子中断控制器)对于可以读取SUBSRCPND寄存器用来确定是哪一个产生了更加细致的中断
那么我们就可以让 irq_desc.handle_irq指向s3c_irq_demux(中断分发函数)

  • hwirq(表示硬件中断号)
  • (virq(表示虚拟中断号)

s3c_irq_demux做了以下几件事
如果该中断是由子中断产生, irq_desc[virq].handle_irq的操作:

  • a. 读 sub int controller, 得到hwirq’
  • b. 根据hwirq’得到virq
  • c. 调用 irq_desc[virq].handle_irq

硬件中断号和虚拟中断号<br>

我们可以通过硬件中断号,得到虚拟中断号,这些虚拟中断号就是irq_desc[]数组项的下标
可以定义这么一个公式

我们假设中断5接有一个按键irq_key,我们注册这个中断时会注册对应的中断号(这里是37),这时irq_desc会创建一个irqaction这个handle就等于irq_key,当我们按下时,这个子中断控制器会向上一级中断控制器发出信号,上一级中断控制器就会向cpu发出信号,cpu读取控制器时会找到对应的virq通过irq_desc找到这一项对应的handle_irq,让后去读寄存器进一步来分辨是发生了哪一个子中断,得到虚拟中断号,进入irq_desc链表得到irqaction取出handler来执行irq_key

第03节_中断号的演变与irq_domain

第五课. 内核中断系统中的设备树

假设使用 int2
如何查找空闲项/strong>
从中断号开始依次查找,直到找到最后空闲项,
如果bit=0则虚拟中断号就是2

虚拟中断号保存在irq_domain结构体中

irq_domain
    linear_revmap[hwirq] = virq

把hwirq对应的virq保存在irq_domain的linear_revmap
假如使用子EINT4中断

使用子中断EINT4的过程
1.使用父中断(intc,4)设置irq_desc:
    a.找空闲项,virq=4,保存起来:intc’s irq_domain.linear_revmap[4] = 4
    b.设置irq_desc[4].handle_irq = s3c_irq_demux

2.为子中断eint4(subintc,4)设置irq_desc:
    a.找空闲项,virq=5,保存起来:subintc’s irq_domain.linear_revmap[4] = 5

3.驱动程序request_irq(5.my_handler),
    会把my_handler保存在irq_desc[5].action链表中

4.发生了中断,内核读取intc,得到hwirq=4,virq = intc’s irq_domain.liner_revmap[4] = 4调用irq_desc[4].handle_irq,即s3c_irq_demux

5.s3c_irq_demux:
    读取subintc,得到<code>hwirq=4,virq = subintc’s </code> <code>irq_domain.liner_remap[4] = 5</code>,调用irq_desc[5].handle_irq,它会调用action链表中保存的my_handler
每一个中断控制器都有一个<code>irq_domain.linera_revmap</code>得到虚拟中断号,
调用irq_desc.handle_irq;这个分发函数会读取下级中断控制器,得到子中断控制器的4号中断,
再次读取子中断控制器对应的irq_domain.liner_revmap[4] = 5对应的虚拟中断号是5,那么就会调用第五个irq_desc,执行handle_irq

在<code>irq_domain.linear_revmap[]</code>大部分数组项都是空闲的<br>

怎么兼容老的固定中断号/strong>

也要保存的硬件中断号和虚拟中断号之间的对应关系,在irq_domain也有liner_revmap[]对每一个[hwirq] = 预先设置号的virq
我们写驱动程序直接 request_irq(virq,….),中断号是通过宏方式进行定义的,所以直接使用中断号进行注册<br>

如何使用新型中断号,注册irq
先在

来源:weixin_34407348

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2018年11月3日
下一篇 2018年11月3日

相关推荐