内核中断系统中的设备树

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

  • 基于设备树的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中断结构体来表示

handle_irq操作

  • 调用irqaction链表中的handler
  • 清中断(芯片相关)irq_data.chip

发生中断时内核的执行过程
cpu跳到<code>vector_irq</code>, 保存现场, 调用C函数<code>handle_arch_irq</code>

handle_arch_irq:

  • a. 读 int controller, 得到hwirq
  • b. 根据hwirq得到virq
  • c. 调用<code> irq_desc[virq].handle_irq</code>

如果该中断没有子中断, irq_desc[virq].handle_irq的操作:

  • a. 取出irq_desc[virq].action链表中的每一个handler, 执行它
  • b. 使用irq_desc[virq].irq_data.chip的函数清中断

对于0 中断,加上一个或控制器,形成一个共享中断,可以控制 卡中断irq_net和摄像头中断irq_camera,
在0 中断上有两个设备,那么就需要有两个irqaction,其中irqaction *next指向下一个irqaction
当irq_net发生中断时,会执行irq_desc.handle_irq会把链表里面所有的handler都取出来执行一遍,在irq_net中要访问 卡来判断下中断是否是 卡产生的,如果不是则返回不做任何处理,如果是则做 络处理

链表支持 共享中断,

如果使用中断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 data-tomark-pass>

我们可以通过硬件中断 ,得到虚拟中断 ,这些虚拟中断 就是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

irq_desc[]下标是中断 virq(对应硬件中断),根据硬件中断确定是那个中断发生
得出公式

virq = hwirq + 1
hwirq = virq – 1

假设增加一个子中断控制器

virq =hwirq’ + 36
hwirq’ = virq – 36

在加一个中断控制器
在这种情况下如何使用中断lt;br data-tomark-pass>
以前,对于每一个硬

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2019年6月4日
下一篇 2019年6月4日

相关推荐