中断子系统

在kernel发生中断后,会跳转到汇编代码entry-armv.S中__irq_svc处,进而调用handle_arch_irq,每个中断控制器的drivver会使用如下:
handle_arch_irq = gic_handle_irq
将自己的中断入口处理函数赋值给这个指针,这里是gic的入口函数,从而进入GIC驱动,进行后续的中断处理

http://blog.csdn.net/yimu13/article/details/6803957
http://bbs.chinaunix.net/thread-3566316-1-1.html
http://blog.csdn.net/droidphone/article/details/7467436 Linux中断(interrupt)子系统之二:arch相关的硬件封装层
http://blog.chinaunix.net/uid-23046336-id-3279553.html 解密ARM based Linux内核中断处理框架
http://blog.csdn.net/hanchaoman/article/details/7099142 kernel 中断详解
http://blog.csdn.net/droidphone/article/details/7445825
http://www.bubuko.com/infodetail-1033486.html
http://www.cnblogs.com/pengdonglin137/p/6349209.html#_lab2_3_2
http://www.cnblogs.com/wmx-learn/p/5360269.html 老的do_asm方式的中断,基本流程可以借鉴
http://blog.sina.com.cn/s/blog_95268f5001013ve7.html gpio中断的例子
http://blog.csdn.net/laviolette/article/details/51577604 共享中断

以上图为例:
ARM CPU 对外的连接只有 2 个中断,一个是 IRQ ,一个是 FIQ ,相对应的处理模式分别是一般中断( IRQ )处理模式和快速中断( FIQ )处理模式。所以 GIC 最后要把中断汇集成 2 条线,与 CPU 对接。一个core只能连接一个中断控制器(即一个core只能同时处理一个任务),但是一个中断控制器可以连多个core(即中断控制器可以下发中断任务给多个core)
arm的中断控制器以gic为例,作为 ARM 系统中通用中断控制器的是 GIC(Generic Interrupt Controller) ,目前有四个版本,V1~V4(V2最多支持8个ARM core,V3/V4支持更多的ARM core,主要用于ARM64系统结构)。目前在ARM官方网站只能下载到Version 2的GIC architecture specification。其中GIC-500最多支持128个 cpu core,它要求ARM core必须是ARMV8指令集的(例如Cortex-A57),符合GIC architecture specification version 3。
中断控制器用于收集中断,它可以支持的中断状态寄存器的bit位代表它支持多少位中断输入,我们这里暂且是4个32位的中断中断状态寄存器,即共有4 x 32 = 128个中断输入接口。
每一个中断接口又可以级联更多的中断源,如图中bit 0,即0号硬件中断外边连了128个gpio pin,每个pin都支持中断发生。但是这些pin是共享中断控制器这一层的0号中断接口。当gpio的任何一个pin发生中断时,都会触发中断控制器的状态寄存器的bit0置位,表示发生了gpio中断,然后去通知core去执行中断程序。
那这128个gpio pin共享一个硬件中断是如何区分哪一个pin的中断发生?在gpio这一级又有它自己的中断状态寄存器,128个pin也就有4个状态寄存器,供128个bit,每个bit的置位表示一个gpio中断的发生。
所以一个中断发生时,会先查询中断控制器的状态寄存器,看是哪一个中断源发生了中断,然后在看这个中断源上是否级联了下一级中断源(例如GPIO共享一个硬件中断入口),如果有就继续查询,如果没有,就直接处理当前的中断
当外设发生中断时,首先进入中断控制器,让中断控制器进行裁决,然后在去触发连着的cpu的中断接口。

在linux kernel中,对于每一个外设的IRQ都用struct irq_desc来描述,我们称之中断描述符(struct irq_desc)。linux kernel中会有一个数据结构保存了关于所有IRQ的中断描述符信息,我们称之中断描述符DB(上图中红色框图内)。当发生中断后,首先获取触发中断的HW interupt ID,然后通过irq domain翻译成IRQ nuber,然后通过IRQ number就可以获取对应的中断描述符。调用中断描述符中的highlevel irq-events handler来进行中断处理就OK了

在软件的角度:
中断系统分为2个层面:

1,core
2,core外部的中断控制器

       local_irq_disable()、local_irq_enable()    -------------->对应的是core内部的中断,就是core接不接受你这个中断进来,或者要不要响应
disable_irq()、enable_irq()---------------------------->对应的是连接core的外部中断控制器的中断

在内核中,透过irq_chip 结构体来描述中断控制器。该结构体内部封装了中断mask、unmask、ack 等成员函数
local_irq_disable()、local_irq_enable() 常用来做数据的保护和互斥
gic是arm core常用的中断控制器:
只要有这几个中断类型
SGI(Software-generated interrupt),PPI(Private peripheral interrupt )、SPI(Shared peripheral interrupt)
顾名思义SGI为软件可以触发的中断,经常用于各个core之间的通信,PPI为每个core的私有外设中断,SPI为各个core公用的中断
SGI:0~15
PPI:16-31
SPI:32~1019

对于root GIC
hwirq_base = 16;
gic_irqs = 系统支持的所有的中断数目-16。之所以减去16主要是因为root GIC的0~15号HW interrupt 是for IPI的,因此要去掉。也正因为如此hwirq_base从16开始

一般前32(0-31)个我们不去使用,我们从32开始映射我们的中断状态寄存器,加入我们有32*4个寄存器,那么我们就会抽象出(32~(32+32*4))的中断号,用于软件上使用。
中断的核心过程,首先是我们提前按照这个中断号去注册我们的中断执行函数;
然后当硬件中断发生后,软件层面去获取这个发生的硬件中断号(是否有映射),然后和注册的中断号去匹配,匹配成功后然后去执行该中断号绑定的中断函数。

中断控制器的描述:struct irq_chip
中断号的描述:struct irq_desc

关于HW interrupt ID映射到IRQ number上 这事,在过去系统只有一个interrupt controller的时候还是很简单的,中断控制器上实际的HW interrupt line的编号可以直接变成IRQ number。例如我们大家都熟悉的SOC内嵌的interrupt controller,这种controller多半有中断状态寄存器,这个寄存器可能有64个bit(也可能更多),每个bit就是一个IRQ number,可以直接进行映射。这时候,GPIO的中断在中断控制器的状态寄存器中只有一个bit,因此所有的GPIO中断只有一个IRQ number,在该通用GPIO中断的irq handler中进行deduplex,将各个具体的GPIO中断映射到其相应的IRQ number上
问题1:我们如何知道这个硬件中断的系统中断号是多少?是线性排列的还是动态获取的?
2:为什么root gic在映射系统中断号的时候要从16开始而不是32开始

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章