5.3中断系统中的设备树——中断号的演变与irq_domain
通过上一节我们知道,在内核中有一个irq_desc数组,数组里面的每一项对应一个中断,数组的下标就是对应中断的虚拟中断号(virq)。
假设只有一个中断控制器,有32个中断,那么中断和irq_desc数组可以一一对应,每一个数组项对应一个中断。
因为第0项一般不用,所以是从第1项开始,一一对应。
此时虚拟中断号和硬件中断号的对应关系为:virq = hwirq + 1。
如果再加一个中断控制器sub_intc,它也会发出中断,并且sub_intc发出的中断会触发上一级的中断控制器的n号中断。
也就是说,sub_intc的0,1,2,3号中断,都会触发上一级中断控制器的n号中断。
根据上一节的说明,sub_intc的0,1,2,3号中断,在irq_desc数组中也会有对应的单独项和它们一一对应。
假设irq_desc数组项中的第36,37,38,39项,分别对应sub_intc的0,1,2,3号中断。
sub_intc的硬件中断号称为hwirq',那么就可以得到hwirq'和virq的转换公式。
virq = hwirq' + 36
也就是说,不论是intc还是sub_intc,都可以根据硬件中断号获得对应的虚拟中断号,并且这些中断号对应的数组项,并不重合。
再增加一个外部中断控制器external intc,让系统更复杂一点。
与sub_intc类似,external intc对应intc的m号中断,我们让external intc的0号中断对应数组项的第48项。
那么,也可以得到一个硬件中断号和虚拟中断之间的转换公式:virq = hwirq'' + 48。
以前, 对于每一个硬件中断(hwirq)都预先确定它的中断号(virq),这些中断号一般都写在一个头文件里, 比如:arch\arm\mach-s3c24xx\include\mach\irqs.h。
这里的每一个宏,就是一个虚拟中断号。
使用时:
- 执行 request_irq(virq, my_handler) :内核根据virq可以知道对应的硬件中断号,然后去设置、使能中断等;
- 发生硬件中断时,内核读取硬件信息,确定hwirq,反算出virq,然后调用 irq_desc[virq].handle_irq,最终会用到 my_handler;
问:前面说了三个中断控制器,intc,sub_intc,external intc,在这三个中断控制器中,不同的硬件中断号对应的虚拟中断号是不同。
但是,intc,sub_intc,external intc都有各自的0号,1号中断等,内核怎么根据这些硬件中断号,推算出对应的虚拟中断号?
答:需要引入了一个新的概念——域(irq_domain),intc,sub_intc,external intc分别有自己的域(irq_domain)。
在不同的域(irq_domain)中,相同的硬件中断号(hwirq)对应的虚拟中断号(virq)是不同的。
所以,在描述hwirq时,应该注意“是哪个域的hwirq”。
那么,怎么使用域将硬件中断号,转化为虚拟中断号?稍后再说。
之前,virq和硬件的对应关系是固定的,比如virq 38固定对应串口3的接收中断,virq 56固定对应GPIO外部中断等。
但现在的趋势是,virq跟硬件无关,仅仅是一个标号(中断描述数组的标号)而已。
问:为什么会变成这样呢?
答:如果只有几个中断,那么可以事先确定好中断号,并且只要几个宏就可以让中断和数组项一一对应。
但是如果有成百上千个中断,就需要成百上千个宏,并且这些数组项要各自独立互不影响,工作量就变得多得多。(想想要定义上千个宏,很恐怖的。。。)
为了避免这种复杂的情况,就将硬件中断号和虚拟中断号之间固定的关系取消掉,它们依旧是一一对应,但是对应关系不再固定了。
当需要使用某个硬件中断(hwirq)时,来查找irq_desc数组,在数组中查找到一个空余项,这个空余项的下标就是这个硬件中断号对应的virq。
我们在这个空余项中存放对应的处理函数就可以了。
假设,要使用inc的INT2。
那么,先要在 irq_desc 数组中,找到一个空余项。
问:怎么查找空余项呢?
答:最笨的方法,就是从下标0开始依次查找。这当然也是一种方法,但是效率可能不好,这种方法的时间复杂度应该是O(n)。
内核使用的是另一种方法。在内核中定义了一个位图,用来记录哪些空余项被使用了。
这个位图其实就是一个数组——allocated_irqs。
allocated_irqs的bit0对应下标0,bitn对应下标n。当某一位等于1时,表示这一项被占用了。
那么,比如硬件ID为2,那么就从bit2开始,bit2,bit3依次查找,直到找到空余项。
这样做的效率应该是比从左到右一个一个找要快。
假设,要设置2号中断,并且allocated_irqs的bit2为0,那么它的virq就等于2。
问:以后处理2号中断时,我们可以从中断控制器里面获得hwirq为2,但是怎么知道对应的virq呢?
答:这就需要在设置中断时,将中断的virq保存下来了。
事实上,这个virq保存在对应的irq_domain里面。
@linear_revmap: Linear table of hwirq->virq reverse mappings
struct irq_domain {......unsigned int linear_revmap[];
};
irq_domain里面有一个数组linear_revmap,叫做反向映射数组。
为什么叫反向映射数组呢?
以前,我们使用中断时,是在驱动程序里面执行 request_irq,通过virq找到对应的hwirq。
现在呢,反过来,使用hwirq找到virq。
把hwirq对应的virq,保存在对应的irq_domain的linear_revmap数组中,也就是 linear_revmap[hwirq] = virq。
对于本例,hwirq=2,virq=2,所以就是linear_revmap[2] = 2。
这样,后续发生2号中断时:
- 首先根据中断向量进入到指定地址执行中断处理流程,将会调用到C语言的中断处理函数。
- 然后,在中断处理函数中读取中断控制器,得到硬件中断号。
- 之后,再根据这个中断控制器,得到对应的irq_domain。
- 通过irq_domain的linear_revmap数组以及硬件中断号,就可以得到一个virq。
- 最后,在irq_desc数组中,根据virq,找到对应的那一项,把其中的handle_irq拿出来执行。
假设要使用子中断控制器(subintc)的n号中断, 它发生时会导致父中断控制器(intc)的m号中断:
- 设备树表明要使用<subintc n>,subintc表示要使用<intc m>
- 解析设备树时,会为<subintc n>找到空闲项 irq_desc[virq'],
sub irq_domain.linear_revmap[n] = virq';
会为<intc m> 找到空闲项 irq_desc[virq],
irq_domain.linear_revmap[m] = virq;
并且设置它的handle_irq为某个分析函数demux_func - 设置驱动程序 request_irq(virq', my_handler);
- 发生硬件中断时,内核读取intc硬件信息, 确定hwirq = m, 确定 virq = irq_domain.linear_revmap[m];
然后调用 irq_desc[m].handle_irq, 即demux_func - demux_func:读取sub intc硬件信息, 确定hwirq = n, 确定 virq' = sub irq_domain.linear_revmap[n];
- 然后调用 irq_desc[n].handle_irq, 即my_handler。
在旧的中断配置方法中,irq_domain也有linear_revmap成员,只是它的linear_revmap数组都预先设置好了,只有新的中断配置方法中,linear_revmap才是设置了才不为空(0)。
也就是说,新旧配置方法是兼容的,只是配置方法略有不同。
旧的配置方法是通过宏固定配置,可以直接通过 request_irq 函数配置中断(因为virq是已知的,固定的),而新的配置方法在一开始并不知道virq,需要先在设备树中表明要使用哪个中断(hwirq),然后程序会将这个hwirq和某个virq绑定,确定virq后,才可以调用request_irq函数设置中断。
那么,要怎么在设备树中表明要使用哪个中断?这个下节再说明。
在设备树中表明要使用的中断信息后,会通过xlate函数对设备树进行解析,获得对应的hwirq和irq_type(中断触发方法)。
然后,再把hwirq映射得到virq,之后驱动程序才能来设置和使用中断。
还有一个map函数,用来建立hwirq和virq之间的映射关系的,比如,若配置的是子中断,那么map函数还要去设置父中断。
xlate和map都是irq_domain.ops的成员,他们都是函数指针。
struct irq_domain {......const struct irq_domain_ops *ops;......
};struct irq_domain_ops {int (*match)(struct irq_domain *d, struct device_node *node,enum irq_domain_bus_token bus_token);int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec,enum irq_domain_bus_token bus_token);int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);void (*unmap)(struct irq_domain *d, unsigned int virq);int (*xlate)(struct irq_domain *d, struct device_node *node,const u32 *intspec, unsigned int intsize,unsigned long *out_hwirq, unsigned int *out_type);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY/* extended V2 interfaces to support hierarchy irq_domains */int (*alloc)(struct irq_domain *d, unsigned int virq,unsigned int nr_irqs, void *arg);void (*free)(struct irq_domain *d, unsigned int virq,unsigned int nr_irqs);int (*activate)(struct irq_domain *d, struct irq_data *irqd, bool reserve);void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,unsigned long *out_hwirq, unsigned int *out_type);
#endif
#ifdef CONFIG_GENERIC_IRQ_DEBUGFSvoid (*debug_show)(struct seq_file *m, struct irq_domain *d,struct irq_data *irqd, int ind);
#endif
};
关于 xlate 和 map 的更详细的说明,会在后面的文章中说明。
5.3中断系统中的设备树——中断号的演变与irq_domain相关推荐
- 韦东山 IMX6ULL和正点原子_【预习】韦东山:剥丝抽茧分析Linux中断系统中的重要数据结构...
导语: 众所周知,目前升级版视频正在录中断系统,已经录到[Linux系统对中断处理的演进],配套文档发布后,颇受学员好评,知乎文章: https://zhuanlan.zhihu.com/p/1130 ...
- zynq开发中的设备树
在zynq开发中经常会修改设备树,每次遇到这种情况都有点发愁,今天把设备树相关的知识点总结一下,希望以后遇到设备树时,能够自如应对. 什么是设备树 设备树时描述硬件的数据结构,Linux系统可以通过设 ...
- 07 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(上)
上一节,我用一个 Nginx+PHP 的案例,给你讲了服务器 CPU 使用率高的分析和应对方法.这里你一定要记得,当碰到无法解释的 CPU 使用率问题时,先要检查一下是不是短时应用在捣鬼. 短时应用的 ...
- Linux驱动开发中与设备树相关的6种debug方法
整理出了6种驱动开发时与设备注册.设备树相关的调试方法,彼此间没有优先级之分,每种方法不一定是最优解,但可以作为一种debug查找问题的手段,快速定位问题原因.例如在芯片验证时,不同时钟频率下系统启动 ...
- 08 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(下)
上一节,我给你讲了 Linux 进程状态的含义,以及不可中断进程和僵尸进程产生的原因,我们先来简单复习下. 使用 ps 或者 top 可以查看进程的状态,这些状态包括运行.空闲.不可中断睡眠.可中断睡 ...
- 在Linux系统中存储设备的两种表示方法
作者:北南南北 来自:LinuxSir.Org 摘要: 硬盘和硬盘分区在Linux都表示为设备,按我们通俗的说法来说,就是怎么来表示或描述硬盘和或硬盘分区,但这种描述应该是科学和具体的:比如IDE硬盘 ...
- 在WindowsMobil系统中实现透明树组件
因一个工程中需要使用WM来开发一款IM软件,后期实现界面的时候很费了一翻功夫,主要是在WM系统下TreeView的功能太有限了,不行添加背景,也不能实现行选择,这样效果就很差,单击事件也没有,后来通过 ...
- Mtk android中的设备树,msm8909+android5.1 device tree(dt) 设备树组成和编译
1.Device tree设备树概述 设备树包含DTC(device treecompiler),DTS(device treesource和DTB(device treeblob).其对应关系如图1 ...
- 中断系统详解、外部中断
51单片机各个引脚功能 IO口引脚: 中断系统的主要功能:处理随机突发事件 中断系统结构: 什么是中断系统: 数据的输入/输出传送方式: 中断传送方式特点: 51系统允许的5个中断源: 51单片机中断 ...
最新文章
- 虚拟化--015 配置VMware View Event database失败:
- javascript 与vbscript 互相调用
- 02 | 系统可用性:没有故障,系统就一定是稳定的吗?
- 将字符转换成数字(atoi),将数字转换成字符(itoa)
- json模拟数据怎么用_在使用axios获取自己模拟的json数据是踩到的坑
- 把一个数组的值赋给另一个数组(VB.NET)
- 【js高三】---js模块模式
- 计算机老年学校讲义,天津老年大学计算机类教学大纲
- 微信客服我是这样管理的
- Fiddler对安卓模拟器里的APP抓包(步骤详细,各种抓包工具总结)
- iOS开发之定位神器-超简单方式解决iOS后台定时定位
- 详解 Flutter engine多线程、Dart isolate和异步
- 柔光混合模式android,滤色与柔光两种图层混合模式的理解和应用实例
- 我的世界服务器连接协议,go-mc: Minecraft(我的世界)各种协议的Go实现
- 你看到的都是错的!——虚拟化技术的真相
- thinkphp3.2 微信 Native扫码支付功能
- PS:“内容识别填充”去水印
- Java 基础——HashMap 遍历方式
- 《詹姆斯·高斯林Java白皮书1996自译》00:概览
- Java性能调优杀手锏JMH
热门文章
- Rosalind第五题:计算GC内容
- Python Qt5 入门教程
- R read.table Error:appears to contain embedded nulls
- mysql list dbs 代替_mysql_list_dbs函数的用法实例汇总
- Multiple users(Guest mode) 多用户或访客模式调试
- 如何挑选自己喜欢的colormap样式
- ffmpeg视频剪切与拼接
- 反编译工具ILSpy
- Linux内核中的IPSEC实现(3)
- 【001】光学系统的像质评价方法