中断控制器及域

一、中断控制器

       外围设备不是把中断请求 直接发给处理器,而是发给中断控制器,由中断控制器转发给处理器。ARM公司提供一种标准的中断控制器,称为通用中断控制器,如GIC v2。GIC架构规范有四个版本:V1-V4。GIC v2最多支持8个处理器,GIC v3最多支持128个处理器,GIC v3和GIC v4只支持ARM处理器。

        厂商研发自己的ARM处理器,向ARM公司购买GIC的控制权,ARM公司提供的GIC型号有:GIC-400,GIC-500,GIC-600。其中GIC-400遵循GIC v2规范,GIC-500和GIC-600遵循GIC v3规范。厂商直接向ARM公司购买处理器的授权,这些处理器包含了GIC。

        从软件角度看,GIC v2控制器有两个主要的功能:分发器(Distributor)和处理器接口(CPU Interface)。分发器:系统中所有的中断源连接分发器,分发器的寄存器用来控制单个中断的属性:优先级、状态、安全、转发信息(可以被发送到哪些处理器)和使能状态。分发器决定哪个中断应该通过处理器接口转发到哪个处理器;处理器接口:处理器通过处理器接口接收中断。处理器接口提供的寄存器用来屏蔽和识别中断,控制中断的状态。每个处理器有一个单独的处理器接口。

        回顾中断3种类型:软件生成中断、私有外设中断、共享外设中断。软件生成中断(SGI,Software Generated Interrupt),通常用来实现处理器中断 IPI(Inter-Processor Interrupt),中断号 0-15。这种中断是由软件写分配器的软件生成中断寄存器(GICD_SGIR)生成的。私有外设中断(PPI,Private Peripheral Interrupt),中断号 16-31。处理器私有的中断源,不同处理器的相同中断源没有关系,比如每个处理器的定时器。共享外设中断(SPI,Shared Peripheral Interrupt),中断号 32-1019。这种中断可以被中断控制器转发到多个处理器。

        中断可以是边沿触发,也可以是电平触发。边沿触发是在电压变化的一瞬间触发,电压由高到低变化处罚的中断称为下降沿触发,电压由低到高变化触发的中断称为上升沿触发。

在ARM架构中,中断管理通过**通用中断控制器(GIC)**实现,其核心作用是为外设中断提供集中管理和分发。以下是对GIC v2及其相关概念的详细解析:


1. 中断控制器的作用

外设不直接将中断发送给处理器,而是通过**中断控制器(GIC)**中转,主要原因包括:

  • 集中管理:统一处理多外设的中断请求,避免处理器直接面对大量中断源。

  • 优先级控制:对中断进行优先级排序,确保高优先级事件优先处理。

  • 多核调度:在SMP系统中,动态分配中断到不同处理器核心,实现负载均衡。


2. GIC v2的核心模块

GIC v2从软件视角分为两个关键模块:

(1) 分发器(Distributor)
  • 功能

    • 中断收集:接收所有外设的中断请求(包括SPI、PPI、SGI)。

    • 优先级排序:根据配置的优先级对中断进行排序。

    • 路由决策:决定将中断发送到哪个处理器(针对共享中断)。

    • 中断使能/屏蔽:全局控制中断的使能与禁用。

    • 触发类型配置:设置中断为电平触发或边沿触发。

  • 配置对象:作用于所有处理器,属于全局资源。

(2) 处理器接口(CPU Interface)
  • 功能

    • 中断传递:将分发器分配的中断传递给特定处理器核心。

    • 中断确认(ACK):处理器读取中断ID后,通知GIC已接收中断。

    • 中断结束(EOI):处理器处理完成后,通知GIC可释放中断。

    • 优先级屏蔽:动态调整处理器可接受的中断优先级阈值。

  • 配置对象:每个处理器核心有独立的接口,属于核心本地资源。


3. 中断的三种类型

在GIC v2中,中断分为以下三类(用户提到的第四种可能是描述误差或特定扩展):

(1) 软件生成中断(SGI, Software Generated Interrupt)
  • ID范围:0-15。

  • 触发方式:由软件写入GIC寄存器触发(如核间通信)。

  • 特点:用于多核间同步,例如核心A通过SGI唤醒核心B。

(2) 私有外设中断(PPI, Private Peripheral Interrupt)
  • ID范围:16-31。

  • 触发源:每个处理器独有的外设(如本地定时器、性能监控单元)。

  • 特点:仅对所属处理器有效,不可共享。

(3) 共享外设中断(SPI, Shared Peripheral Interrupt)
  • ID范围:32-1019。

  • 触发源:全局外设(如GPU、网卡、USB控制器)。

  • 特点:可路由到任意处理器,由分发器动态分配。


4. 中断处理流程示例

  1. 外触发中断:网卡(SPI)发送中断请求至GIC分发器。

  2. 分发器处理:检查中断使能状态、优先级,并决定路由到CPU0。

  3. 处理器接口响应:CPU0的接口接收中断,置位中断请求信号。

  4. 处理器处理:CPU0跳转到中断处理程序,读取中断ID并处理。

  5. 中断结束:处理完成后,CPU0向GIC发送EOI,GIC清除中断状态。

        中断的状态分为以下四种,Inactive:中断源没有发送中断;Pending:中断源已经发送中断,等待处理器处理;Active:处理器已经确认中断,正在处理;Active and Pending:处理器正在处理中断,相同的中断源又发送了一个中断。

        中断状态转换过程:Inactive-->Pending:外围设备发送了中断;Pending-->Active:处理器确认了中断;Active-->Inactive:处理器处理完中断。

GIC v2控制器的描述符:

该结构体用于描述中断控制器(如GIC, Generic Interrupt Controller)的操作接口,是Linux内核中管理中断的核心数据结构之一。每个这样的结构体实例代表一个具体的中断控制器驱动,通过函数指针定义了控制器与内核中断子系统交互的底层操作。


关键字段解析

  1. .inq_mask
    函数指针,指向屏蔽特定中断的硬件操作。例如,当需要暂时禁用某个外设的中断时,内核会调用此函数对中断控制器编程,使其不再响应该中断。

  2. .inq_unmask
    函数指针,指向取消中断屏蔽的操作。当中断处理完成后,内核通过此函数重新启用中断,允许后续中断触发。

  3. .inq_eoi
    函数指针,指向“中断结束”(End Of Interrupt)操作。内核在处理完中断后调用此函数,通知中断控制器当前中断已处理完毕,控制器可以准备接收新的中断。

  4. .inq_set_type
    函数指针,用于配置中断的触发类型(如边沿触发或电平触发)。例如,按键中断通常需要配置为边沿触发,而某些硬件错误中断可能需要电平触发。

  5. .inq_retrigger
    函数指针,用于重新触发中断。此函数通常用于调试或强制重新处理某个中断。


具体案例:处理一个GPIO按键中断

假设系统中有一个GPIO按键连接到GIC控制器,其工作流程如下:

  1. 中断触发
    用户按下按键,GPIO硬件检测到电平变化,向GIC发送中断信号。

  2. 中断屏蔽
    GIC通知CPU有中断发生,内核首先调用.inq_mask函数屏蔽该中断线,防止按键抖动导致多次触发。

  3. 中断处理
    CPU执行按键对应的中断处理程序(如记录按键事件)。

  4. 中断结束
    处理完成后,内核调用.inq_eoi通知GIC中断已处理完毕。此时GIC可以重新响应此中断。

  5. 取消屏蔽
    内核调用.inq_unmask重新启用该中断线,允许下次按键再次触发中断。

        

二、中断域

        在复杂系统中,可能存在多个级联的中断控制器(如GIC作为根控制器,其他控制器如GPIO或PCIe控制器级联到GIC)。每个中断控制器有自己本地的硬件中断号(如GPIO控制器的0~31号中断),但这些本地中断号在全局范围内可能冲突。
irq_domain是Linux内核为统一管理中断号映射而设计的机制,其核心作用是将本地硬件(当前中断控制器)中断号(HW IRQ)转换为全局唯一的Linux虚拟中断号(Virq)。每个中断控制器对应一个irq_domain,负责其所属中断号的映射和管理。

irq_domain结构体关键字段解析

字段作用
ops指向irq_domain_ops结构体的指针,定义中断号映射的核心操作(如xlatemap)。这是最关键的字段
host_data指向中断控制器私有数据的指针(如寄存器基地址、设备树节点信息等),在映射过程中供ops函数使用。
fwnode关联设备树(Device Tree)或ACPI的固件节点,用于描述中断控制器的硬件拓扑关系。
name中断域的名称(如"gic400"或"gpio-controller"),用于调试和日志。

 创建中断域:中断控制器的驱动程序使用分配函数irq_domain_add_*()创建和注册中断域。每种映射方法提供不同的分配函数,调用者必须给分配函数提供irq_domain_ops结构体,分配函数在执行成功的时候返回irq_domain的指针。

        创建映射:内核提供函数irq_create_mapping()

        查找映射:内核提供函数irq_find_mapping()

 中断域支持的映射方法

1. 线性映射(Linear Map)

核心思想
使用固定大小的数组(表)存储硬件中断号(HW IRQ)到Linux虚拟中断号(Virq)的映射关系。数组的索引直接对应硬件中断号。

适用场景

  • 硬件中断号范围固定且较小(如0~255)。

  • 例如:GPIO控制器(通常支持32~256个中断)、简单的I2C/SPI控制器。

函数与参数

struct irq_domain *irq_domain_add_linear(
    struct device_node *of_node,  // 设备树节点(关联中断控制器)
    unsigned int size,            // 支持的最大硬件中断号数量
    const struct irq_domain_ops *ops, // 操作函数集合(xlate、map等)
    void *host_data               // 控制器私有数据(如寄存器地址)
);

示例:GPIO控制器
假设GPIO控制器支持32个中断(HW IRQ 0~31),使用线性映射:

// 从设备树获取GPIO节点
struct device_node *gpio_node = of_find_node_by_name(NULL, "gpio_controller");

// 创建线性映射的irq_domain
struct irq_domain *gpio_domain = irq_domain_add_linear(
    gpio_node,
    32,                          // 最大硬件中断号+1(0~31共32个)
    &gpio_domain_ops,            // 自定义的xlate和map函数
    gpio_priv_data               // GPIO控制器的寄存器地址
);

映射过程

  • 硬件中断号 5 映射到Virq gpio_domain->linear_revmap[5](例如Virq 105)。

  • 直接通过数组索引实现快速查找。


2. 树映射(Tree Map)

核心思想
使用基数树(Radix Tree)动态管理硬件中断号到Virq的映射,适用于中断号范围大且稀疏的场景。

适用场景

  • 硬件中断号范围大(如0~65535)。

  • 例如:PCIe控制器(支持大量设备中断)、复杂SoC中的多功能中断控制器。

函数与参数

struct irq_domain *irq_domain_add_tree(
    struct device_node *of_node,  // 设备树节点
    const struct irq_domain_ops *ops, 
    void *host_data
);

示例:PCIe控制器
假设PCIe控制器支持1024个中断(HW IRQ 0~1023),使用树映射:

// 创建树映射的irq_domain
struct irq_domain *pcie_domain = irq_domain_add_tree(
    pcie_node,                   // PCIe控制器的设备树节点
    &pcie_domain_ops,            // 自定义的xlate和map函数
    pcie_priv_data               // PCIe控制器的私有数据
);

映射过程

  • 硬件中断号 128 动态插入基数树,映射到Virq 512

  • 树结构节省内存,避免预先分配大数组。


3. 不映射(No Map)

核心思想
硬件中断号(HW IRQ)直接作为Linux虚拟中断号(Virq)使用,无需转换。

适用场景

  • 中断控制器本身支持灵活的中断号配置,且硬件中断号与Virq一一对应。

  • 例如:PowerPC的MPIC(Multi-Processor Interrupt Controller)。

函数与参数

struct irq_domain *irq_domain_add_nomap(
    struct device_node *of_node, 
    unsigned int max_irq,        // 最大硬件中断号
    const struct irq_domain_ops *ops,
    void *host_data
);

示例:PowerPC MPIC

// 创建不映射的irq_domain
struct irq_domain *mpic_domain = irq_domain_add_nomap(
    mpic_node,                   // MPIC的设备树节点
    1024,                        // 最大硬件中断号
    &mpic_domain_ops,            // 空操作或简单配置
    mpic_priv_data
);

映射过程

  • 硬件中断号 200 直接作为Virq 200 使用。

  • 内核直接操作硬件中断号,无需额外映射表。


映射方法对比

特性线性映射树映射不映射
数据结构固定大小数组基数树
内存占用与最大中断号成正比动态分配,节省内存无额外内存
适用场景中断号范围小且密集中断号范围大或稀疏硬件中断号与Virq直接对应
查找速度O(1)(数组索引)O(log n)(树查找)O(1)
典型应用GPIO、I2C控制器PCIe、复杂SoC中断控制器PowerPC MPIC

https://github.com/0voice 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值