linux 下ARC的中断机制

linux 下ARC的中断机制

一、Idu 中断控制器初始化

Idu 是arc 处理器内部中断控制模块, 类似于arm 内部的gic 中断控制模块

首先,Idu中断控制器在初始化时, 会解析DTS信息中定义了几个idu控制器,每个Idu控制器注册一个struct irq_domain数据结构。

DTS(arch/arc/boot/dts)和中断相关的信息如下:
在这里插入图片描述

struct irq_domain用于描述一个中断控制器, 这个结构体很重要, dts 的信息会保存在这里面, 另外这里面还会保存hwirq和virq 的对应关系。
在这里插入图片描述

初始化的流程如下:
linux 正常流程会先进入Start_kernel 函数,分别会做如下几件事:
1、进入 setup_arch函数, 然后调用 unflatten_and_copy_device_tree 函数,把device tree 信息保存在of_root 的device_node 节点中
在这里插入图片描述
2、进入Init_IRQ进行初始化,后面会进入Irqchip_init函数,

在这里插入图片描述

__irqchip_of_table 就是内核irq chip table的首地址,这个table也就保存了kernel支持的所有的中断控制器的ID信息

(用于和device node的匹配), 这些信息保存在.init.ramfs section 中, of_irq_init 函数实际上就是根据DTS 的内容

(已经保存在of_root 的device_node中) 去进行搜索匹配,一旦匹配到,就调用该interrupt controller 的初始化函数,

并把该中断控制器的device node以及parent中断控制器的device node作为参数传递给irq chip driver。

在这里插入图片描述

__irqchip_of_table 的内容是通过IRQCHIP_DECLARE的宏来实现的,如下图所示,这个宏其实就是初始化了一个struct of_device_id的静态

常量,并放置在__irqchip_of_table_end中。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在 .map 文件中可以看到 irqchip_of_table 是 irq chip table的首地址, 后面通过 IRQCHIP_DECLEAR 宏定义的具体内容
在这里插入图片描述

在这里插入图片描述


idu_of_init 函数的功能如下:

(a). 读取IDU的最大支持的中断数目

(b). 分配一个 irq_domain 的结构,一个 irq_domain 代表了一个 IDU控制器

©. 在irq_default_domain中,将hwirq和virq进行映射,irq_create_mapping

中domain 参数是NULL, 所以使用default domain, 所以,virq 是等于 hwirq

的,不做转换。然后设置中断响应函数入口为:idu_cascade_isr
在这里插入图片描述

在这里插入图片描述

二、中断处理流程

处理器正常中断处理程序(handler)一般包含4个步骤:

(1) 保存现场,保存各个寄存器的值

(2) 运行处理中断的需要的命令

(3) 恢复现场,恢复各个寄存器的值

(4) 返回到进行中断处理前的地方继续运行
在这里插入图片描述


以 arc 处理器为例, 外部产生中断信号后的流程如下:

首先, 进入异常向量表(vectors), 跳转到相应的异常中断(arch/arc/kernel/entry-arcv2.S),正常会跳转到handle_interrupt

函数, 该函数会进行 保存现场,处理中断和恢复现场 的工作,具体如下:

在这里插入图片描述

在arc中 vector table, 如下图所示,前面16个是异常向量表, 后面开始是中断向量表, 都会跳转到handle_interrupt 函数
在这里插入图片描述

主要工作分为三个部分:

1、保护现场

将arc 的寄存器进行压栈处理,需要注意的是,arc 处理器会对大部分寄存器进行自动压栈,但是,仍然有少部分寄存器需要我们

手动压栈(r12, r25, r30, sp, fp, gp,ACCL pair)

2、中断处理

保存完现场后,就会执行中断跳转函数 arch_do_IRQ

b.d arch_do_IRQ

arch_do_IRQ 函数会把硬件中断号传递给handle_domain_irq 函数, handle_domain_irq 函数内部调用__handle_domain_irq函数

在这里插入图片描述

__handle_domain_irq 函数是中断处理的核心函数, 内部需要关注的函数有四个, 分别如下:
在这里插入图片描述

其中,由于触发中断后,不知道domain信息,所以 irq_find_mapping中domain 的参数为NULL,默认在irq_default_domain中根据hwirq找到

virq (Linux的irq), generic_handle_irq参数是irq号,这个是linux 中断号,irq_to_desc()根据irq号找到对应的struct irq_desc。

然后调用irq_desc->handle_irq处理对应的中断, 会先调用idu_cascade_isr的中断处理函数(一级中断函数),这是一个idu提供的标准中断,

后面再调用具体中断函数。

在这里插入图片描述

generic_handle_irq 函数中获取到逻辑 irq 之后,通过 irq_to_desc 函数获取对应的 irq desc,irq desc 中包含了该中断相关的信息,包括对应的中断执行函数以及参数,执行 irq_desc 中的 high level 回调函数.

需要注意的是,irq desc 并不属于 domain 单独维护,而是全局的.

因此irq domain 目前只负责 hwirq-逻辑irq 之间的映射,irq desc 的保存是全局的,这样处理起来会更简单,和逻辑 irq 的映射类型,irq desc 与逻辑 irq 的映射也存在静态数组和 radix tree 两种方式.
在这里插入图片描述
注意:由于irq desc 和 irq的映射关系是全局维护的,不属于某一个domain, 因此irq应该是唯一的 和irq_desc 一一对应。
如下图所示 irq 以及 irq desc 的映射基于线性映射,当然也可以基于 radix 的映射方式,这里就都做介绍了。
在这里插入图片描述
下图中,idu_domain 的父级是cpu_domain, domain 内部将hwirq 映射为linux irq (映射出来的irq是唯一的), irq会和irq desc 进行映射,
然后跳转到handle_irq 函数。
在这里插入图片描述

三、初始化&处理具体中断

这里简单举一下pcie中断的例子:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/shenjin_s/article/details/128785027