linux irq 接口,LINUX 中断子系统专栏之一 子系统架构简述

之前在做spi、iic等虚拟设备驱动时,就在思考如何开发虚拟的irq controller驱动,因为完成虚拟irqcontroller驱动后,进行虚拟外设驱动开发时,就可以使用irq。因此这周就简要介绍irq子系统框架,然后再开发一个虚拟的irq controller driver 。

针对irq 子系统专栏,主要包括如下两部分内容:

一、IRQ子系统框架简述

二、虚拟IRQ CONTROLLER DRIVER实例

本篇主要是IRQ子系统框架简述,本篇文章主要分为如下几个小章节:

一、IRQ相关概念说明

二、IRQ子系统相关数据结构及其关联说明

三、IRQ子系统提供的相关接口

对于irq子系统,我也就是对IRQ子系统的实现有所了解,并基于对mips框架的的中断处理有一点了解,对于arm架构的GIC则不熟悉。本专栏的内容也可能存在大量的漏洞,还请大家斧正。

一、IRQ相关概念说明

针对cpu而言,其提供硬件中断,而外设则可以通过硬件中断线来中断系统。和clk、regulator子系统类似,在soc中也可以级联多个irq controller,实现irq 的扩展。

54d3c42adb85c3e1ad46e68fca60c67f.png

上图就是soc中存在3种irq controller的级联,而内核IRQ子系统则通过抽象对应的数据结构,实现在一片soc中支持多个irq controller。

针对每一个irq controller而言,其本身的中断号基本上也是从0开始,因此针对一个系统中存在多个irq controller而言,需要识别不同控制器的相同中断号信息。

二、IRQ子系统相关数据结构及其关联说明

下面我们通过IRQ子系统提供的数据结构,说明IRQ子系统的框架。以便我们能够快速理解IRQ子系统的实现,并理解如何实现irq controller driver。针对一个irq controller而言,一个irq controller可以包含多个hw irq line,而一个hw irq line上可以由多个外设共用(共享中断),因此针对一个hw irq line,需支持提供多个action,实现针对不同外设的中断响应。

另外针对每一个irq controller而言,其本身的中断号基本上也是从0开始,因此针对一个系统中存在多个irq controller而言,需要识别不同控制器的相同中断号信息,而在LINUX子系统中针对系统中所有存在的hw irq line,均为其分配logic irq index,且logic irq index是系统唯一的,因此需要提供一种map机制,实现logic irq index与hw irq line的映射。另外针对一个irq controller的所有hw irq line而言,针对该hw irq line的enable、disable。

基于此,针对IRQ子系统的数据结构大致可分为如下三类:

一、 struct irq_domain,用于描述irq域,该数据结构主要用于存储hw irq line与logic irq index的映射关系,并提供irq domain ops,实现该irq域下hw irq line的top handler的设置等操作;

二、hw irq line的抽象,主要是struct irq desc,包括该hw irq line中断触发时,值行的对应操作,包括top handler(该hw irq line的顶层处理接口),以及使用该irq的外设注册的操作接口(当一个hw irq line是共享中断时,可注册多个操作接口)等等信息;

三、irq controller的操作接口,主要是数据结构struct irq_chip,提供中断的使能与否接口等。

基本上就是这三类。其中:

struct irq_chip用于操作irq controller,实现hw irq line的使能、去使能、中断触发类型等操作;

struct irq_desc,主要用于hw irq line触发后的处理操作接口的注册等,而且该struct irq_desc是IRQ子系统的最主要数据结构,其连接了irq_chip、irq_domain数据结构;

而struct irq_domain主要用于实现logic irq index与hw irq index的映射关系,以便根据logic irq index,即可找到该irq_domain下对应的hw irq index。struct irq_domain相关定义说明

如下即是struct irq_domain的定义,系统中所有的struct irq_domain均加入到链表irq_domain_list中。

struct irq_domain主要实现如下几个功能:

存储该irq controller的所有hw irq line与对应的logic irq inex的映射关系,而这种映射关系主要包括如下三种类型:

若irq controller支持修改hw irq line的index,则无需存储hw irq line与对应的logic irq inex的映射关系,只需设置hw irq line与对应的logic irq index相同即可;

若该irq controller支持的irq个数较小,则直接实现linear map,即使用数组存储hw irq line与logic irq index;

若该irq controller支持的irq个数较多,则使用基数树存储hw irq line与logic irq index的映射。Irq domain也定义了操作接口,其中xlate则主要是获取hw irq line与对应的logic irq index,而map接口则主要用于设置irq desc与irq_chip的关联,同时完成irq desc与top handler的关联。

467d21ee9fb52612b34b4ec8a6c94e75.png

struct irq desc与struct irq_chip相关关联说明

如下所示,struct irq_desc与struct irq_chip、struct irq_data、struct irqaction。其中struct irq_chip主要定义了一个irq controller的操作接口,包含enable、disable、unmask、mask等接口等。而struct irq_data则主要用于存储struct irq_desc的数据信息,包含该irq所属的irq controller的操作接口、所属的irq domain、hw irq line与logic irq index等,而这些关联一般通过调用irq_domain->map接口实现设置(包括irq_desc与irq_chip关联、该irq_desc的Interrupt flow handler的设置)。

26e80076af46fffd91138f60960711bf.png

irq_desc的存储方式

以上就是IRQ子系统相关的数据结构间的定义及关联。而针对irq_desc的存储,存在两种不同的存储方式,若系统不支持通过基数树存储系统中存在的irq_desc,则主要使用数组存储,如下图所示:

0dddc460aba8d53c46af3d43faead3be.png

显然使用数组存储的话,不管系统中是否真正使用了所有的中断,均需要为其定义内存空间,因此也就提供了基于基数树的存储方式,基于该存储方式,仅在创建一个irq_desc时方才为其申请内存空间,并存储至基数树中,其关联如下图所示

e721ea6a7712ccd7e22ee4329640f048.png

中断处理流程

而下图即是硬件中断触发后,中断处理函数执行的流程。主要包含如下几个方面:

各架构的芯片接收到硬件中断后,最终均会调用do_IRQ接口,进行硬件中断的处理操作;

do_IRQ接口则调用generic_handle_irq接口进行处理;

而在generic_handle_irq接口中,则通过irq获取该irq对应的irq_desc,获取该irq的Interrupt flow handler(如针对电平触发的中断一般注册为handle_level_irq,而针对边缘触发的中断,则注册为handle_edge_irq等);

而在irq的Interrupt flow handler接口中,则执行所有注册到irq_desc上的handler接口(即通过request_irq等接口注册的中断处理函数)

b6021745ec9d45bdd08fcf7774b58dc4.png

三、IRQ子系统提供的相关接口

irq子系统提供的接口主要包括两部分:

一、用于irq controller dirver使用的接口 irq_alloc_descs(申请irq desc的接口)

通过调用irq_alloc_descs申请一个irq对应的struct irq_desc(若是使用数组存储struct irq_desc,则该接口直接返回对该irq_desc在数组中地址即可;若使用基数树存储,则需要为该irq_desc申请内存,并加入到基数树中);

Irq domain创建的接口

主要有irq_domain_add_legacy、irq_domain_add_simple、irq_domain_add_linear、irq_domain_add_tree、irq_domain_add_nomap,其中irq_domain_add_legacy、irq_domain_add_simple主要是选择linear存储irq domain中hw irq line与logic irq index的映射关系。

Irq_desc与irq_chip的绑定接口

主要是接口irq_set_chip_and_handler_name、irq_set_handler、irq_set_chip接口。

二、用于外设申请irq的接口

主要是request_irq、request_threaded_irq接口等,而对于大多数驱动工程师而言,基本上只需要使用该接口即可完成中断处理函数的注册。

以上就是IRQ子系统的简述内容,其实对于大多数驱动工程师而言,只需要会使用中断处理函数的注册即可,无须太关注IRQ controller driver的实现。但我们了解一些irq controller driver的开发流程,对于我们以后开发驱动也是有所帮助的。比如我们需要实现一个gpio controller driver驱动,而该gpio controller支持gpio中断,硬件上是将该gpio的中断输出脚连接到一个系统中断上,那么我们就可以为该gpio注册一个irq domain,并为该gpio controller的各引脚注册对应的irq desc,同时还需要定义irq_chip实现中断使能相关的操作接口等。因此知道IRQ子系统实现以及irq controller driver的实现也有助于我们开发这一类的驱动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值