解析Linux中断子系统之中断映射

中断是当前计算机系统的基础功能,也是系统响应外设事件的必备桥梁。不同的架构对中断控制器有不同的设计理念,本文针对ARM公司提供的通用中断控制器(GIC,Generic Interrupt Controller)介绍在linux系统中的硬件中断号与软件中断号的映射过程。

首先,我们先来理解一下硬件中断号和软件中断号。

  • 硬件中断号:GIC为每一个硬件中断源都分配了一个唯一编号,称为硬件中断号,用于区分不同的中断源。GIC-v3支持的硬件中断类型和分配的硬件中断号范围如下图所示。

IC 分配的中断号范围

  • 软件中断号:系统在中断注册和中断处理过程中使用到的中断号。有的地方也称为虚拟中断号。

为什么要进行中断映射呢?简单来讲,软件可以不需要关注该中断在硬件上是哪个中断来源。简单的SOC内部对中断的管理也比较简单,通常会有一个全局的中断状态寄存器来记录外设中断,这样直接将硬件中断号线性映射到软件中断号即可。但是随着芯片技术的发展,SOC越来越复杂,通常内部会有多个中断控制器(比如GIC interrupt controller, GPIO interrupt controller), 每一个中断控制器对应多个中断号,而硬件中断号在不同的中断控制器上是会重复编码, 这时仅仅用硬中断号已经不能唯一标识一个外设中断。尤其在多个中断控制器级联的情况下,会变得更加复杂。这样对软件编程来讲极不友好,作为软件工程师,我们更愿意集中精力关注软件层面的内容。接下来,我们看看Linux系统中断映射过程涉及到的数据结构,数据结构详细信息请参看Linux内核源码。

□ struct irq_desc,中断描述符,每个irq都会在系统中分配一个该数据结构,用于描述该irq的相关信息,包含了irqaction 。

□struct irq_domain/struct irq_chip, 是对中断控制器的软件抽象。

irq_domain 侧重于对级联关系的描述,以及该中断控制器对某个中断响应的描述在struct irq_domain_ops中进行组织。irq_domain中的linear_revmap[] 和 revmap_tree 用于该domain中hwirq的map。

irq_chip 侧重对该中断控制器响应中断过程的描述。

□struct irq_data, 是中断映射的关键数据结构,映射过程这要是填充该数据结构中的irq与hwirq。irq 为软件系统分配的虚拟中断号,hwirq为该domain分配的硬件中断号。

Linux系统中断映射过程涉及到的数据结构间的关系如下:

映射过程大致分为如下几个过程:

1. 系统维护全局allocated_irqs

2. 中断控制器的初始化

3. 软件中断号的获取与映射

4. 硬件中断号的获取与映射

一、系统维护全局allocated_irqs

在开了CONFIG_SPARSE_IRQ的系统中,系统中维护的全局allocated_irqs有NR_IRQS + 8196 位,每一位代表一个软件中断号。在virq的申请过程中,既可以单个中断号申请,也可以几个中断号一起申请。在申请过程中,从allocated_irqs的低位到高位查询第一个连续N个空闲的位作为软件中断号。

系统中的allocated_irqs 定义如下:

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

二、中断控制器的初始化

中断控制器通过IRQCHIP_DECLARE 宏注册到__irqchip_of_table,系统开机初始化阶段 start_kernel() => init_IRQ()=> irqchip_init 调度到注册的gic_of_init() 对GIC进行初始化。

Gic_of_init中注册domain相关的处理函数,其中gic_irq_domain_translate()将DTS中解析的中断信息翻译得到HWirq。通过irq_domain_create_tree() 申请一个domain内存,赋值后加入到全局的 irq_domain_list中。同时,设置中断处理入口函数。

三、软件中断号的获取与映射

kernel_init() => kernel_init_freeable() => do_pre_smp_initcalls()=> do_one_initcall() => arm64_device_init() => of_platform_populate()=> of_platform_bus_create() => of_platform_device_create_pdata() =>of_device_alloc()

Of_device_alloc()中,想通过of_irq_count() 从dts node中计算出该node中的irq 数量。然后对应每一个irq 调用of_irq_to_resource() => of_irq_get() 获取软件中断号。of_irq_get() 调用of_irq_parse_one() 从dts中收集该中断的相关信息如触发方式,中断号,中断类型等信息并记录在oirq结构体中。然后调用irq_create_of_mapping()进行中断映射并返回软件中断号。

irq_create_of_mapping() => irq_create_fwspec_mapping()通过irq_domain_translate()调用 gic_of_init()过程中注册的gic_irq_domain_translate() 进行翻译得到hwirq。然后调用irq_find_mapping() 尝试通过domain->revmap_tree 获取irq_data,从而后去irq。如果获取到irq说明该中断已完成映射,无需再进行下去。如果没有获取到irq,说明该中断没有进行过映射,继续往下。irq_create_mapping()中先通过bitmap_find_next_zero_area() 从allocated_irqs中找到第一个空闲位 start作为软件中断号。然后申请一个中断描述符irq_desc,完成相关赋值后,将软件中断号作为键值把irq_desc 加入到irq_desc_tree 基树上。此后,

就可以通过irq从irq_desc_tree 基树上快速获取对应的irq_desc,从而获取其他相关信息。

四、硬件中断号的获取与映射

irq_create_fwspec_mapping()先调用irq_domain_translate()获取到硬件中断号,由于预留了SGI,PPI的中断号,这里需要加上对应的中断号偏移。然后在irq_domain_associate()中通过给该irq_data->hwirq赋值为获取到的硬件中断号,同时在irq_domain_set_mapping()中进行映射建立起hwirq与irq_data之间的联系。

irq_domain_set_mapping()中的映射包含两个部分,一是在该控制器支持一定的线性映射前提下,当hwirq <domain->revmap_size时进行线性映射。否则以hwirq作为键值将irq_data放入该domain的revmap_tree基树中,搭建起通过hwirq快速查询virq的途径。

五、总结

通过以上操作,可以以virq=>从irq_desc_tree中获取该irq的中断描述符结构体desc=> 再从desc中获取irq_data=> 进而获取hwirq;也可以通过hwirq=>从该domain的revmap_tree中获取对应的irq_data=> 从而获取 data->irq。本文大体讲诉了linux kernel中断映射的解析与映射过程,并没有对具体的代码展开详细的讲解。读者可以根据梳理的框架进行代码详情的研究。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Linux GPIO子系统是一个用于控制嵌入式系统中通用输入/输出(GPIO)的软件子系统。它提供了一种标准的接口,使得应用程序可以通过文件系统接口来访问GPIO。这个子系统可以用于控制各种设备,例如LED、按钮、传感器等等。如果你需要更多的信息,可以查看Linux内核文档。 ### 回答2: Linux GPIO子系统是一种用于管理通用输入输出(GPIO)引脚的软件层。GPIO引脚是一种通用可编程引脚,可以在嵌入式系统中用来通过读取输入或设置输出与外部设备进行通信。 Linux GPIO子系统负责将底层硬件 GPIO 引脚的操作抽象为文件系统的接口,使开发者可以通过读写文件的方式来访问和控制 GPIO 引脚。通过该子系统,可以实现对 GPIO 引脚的配置、读取和写入等操作,以满足不同应用下对 GPIO 的需求。 Linux GPIO子系统的核心是GPIO驱动程序,它与底层硬件层进行交互,完成对GPIO引脚的操作。驱动程序将GPIO引脚映射到内存,通过读写该内存地址即可对引脚进行操作。用户通过访问特定目录下的文件来和引脚进行交互,例如将引脚配置为输入模式、输出模式,以及读取或写入引脚的状态。 通过Linux GPIO子系统,开发者可以方便地进行GPIO引脚的控制。可以根据不同的应用需求,灵活配置引脚的输入输出模式,监听引脚上的状态变化,并根据需要对其他外设进行控制。 总之,Linux GPIO子系统为开发者提供了便捷的接口,使得在嵌入式系统中使用GPIO引脚更加简单和灵活。它允许开发者通过读写文件的方式访问和控制GPIO引脚,满足各种不同嵌入式应用对GPIO的需求。 ### 回答3: Linux的GPIO(General Purpose Input/Output)子系统是通过软件硬件上的通用输入/输出引脚进行控制的一种机制。它使得开发者可以利用这些GPIO引脚实现各种功能,比如控制LED灯、读取外部传感器的数据等。 Linux的GPIO子系统提供了许多功能和接口来管理和操作GPIO。首先,它使用sysfs文件系统来组织GPIO资源的目录树,并通过文件的方式来读取和写入GPIO的状态。在/sys/class/gpio目录下,每个GPIO引脚都会有一个对应的目录,在该目录中的文件可以用于配置GPIO的方向(输入或输出)、读取和写入GPIO的电平状态。开发者可以使用命令行工具或者编程语言(如Python、C等)来操作这些文件,从而控制GPIO引脚的行为。 其次,Linux的GPIO子系统还提供了设备树(Device Tree)来描述硬件平台上的GPIO资源。设备树是一种描述硬件的数据结构,在启动时通过设备树绑定机制将设备树中定义的GPIO资源与内核驱动程序关联起来。这样,开发者就可以通过调用相应的驱动程序来控制GPIO引脚,而不需要手动操作sysfs文件系统。 此外,Linux的GPIO子系统还支持中断机制,可以让GPIO引脚在特定事件发生时触发中断。通过注册中断处理函数,开发者可以实现对GPIO输入信的快速响应,提高系统的实时性。 总之,Linux的GPIO子系统为开发者提供了一种方便且灵活的方式来控制硬件上的GPIO引脚。通过sysfs文件系统或设备树,开发者可以轻松地配置、读取和控制GPIO的状态,从而实现各种功能和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值