5.3中断系统中的设备树——中断号的演变与irq_domain

news2024/12/24 18:47:34

通过上一节我们知道,在内核中有一个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。

这里的每一个宏,就是一个虚拟中断号。

使用时:

  1. 执行 request_irq(virq, my_handler) :内核根据virq可以知道对应的硬件中断号,然后去设置、使能中断等;
  2. 发生硬件中断时,内核读取硬件信息,确定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_domainlinear_revmap数组中,也就是 linear_revmap[hwirq] = virq

对于本例,hwirq=2,virq=2,所以就是linear_revmap[2] = 2。

这样,后续发生2号中断时:

  1. 首先根据中断向量进入到指定地址执行中断处理流程,将会调用到C语言的中断处理函数
  2. 然后,在中断处理函数中读取中断控制器,得到硬件中断号
  3. 之后,再根据这个中断控制器,得到对应的irq_domain
  4. 通过irq_domain的linear_revmap数组以及硬件中断号,就可以得到一个virq
  5. 最后,在irq_desc数组中,根据virq,找到对应的那一项,把其中的handle_irq拿出来执行。

假设要使用子中断控制器(subintc)的n号中断, 它发生时会导致父中断控制器(intc)的m号中断:

  1. 设备树表明要使用<subintc n>,subintc表示要使用<intc m>
  2. 解析设备树时,会为<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
  3. 设置驱动程序 request_irq(virq', my_handler);
  4. 发生硬件中断时,内核读取intc硬件信息, 确定hwirq = m, 确定 virq =  irq_domain.linear_revmap[m];
    然后调用 irq_desc[m].handle_irq, 即demux_func
  5. demux_func:读取sub intc硬件信息, 确定hwirq = n, 确定 virq' =  sub irq_domain.linear_revmap[n];
  6. 然后调用 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函数对设备树进行解析,获得对应的hwirqirq_type中断触发方法)。

然后,再把hwirq映射得到virq,之后驱动程序才能来设置和使用中断。

还有一个map函数,用来建立hwirq和virq之间的映射关系的,比如,若配置的是子中断,那么map函数还要去设置父中断。

xlatemap都是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_DEBUGFS
	void (*debug_show)(struct seq_file *m, struct irq_domain *d,
			   struct irq_data *irqd, int ind);
#endif
};

关于 xlate map 的更详细的说明,会在后面的文章中说明。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/392891.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

654. 最大二叉树

题目 leetcode题目地址 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返…

项目黑马面面-学科列表-增删改查

查 1.布局2.定义api3.导入api4.进入页面就调用api5.获取数据6.存储并渲染7.与分页建立关联a.请求参数值要与分页组件绑定b.total值存储并绑定到分页组件c.页码改变与页容量改变都要请求api1.布局 <template><div><el-card><el-form :inline"true&q…

C语言例程:猜数字游戏

猜数字游戏 实现一个简单的猜数字游戏&#xff0c;学习 while 循环语句的用法。 实例解析 while 循环语句 while 语句的一般形式为&#xff1a; while(表达式)语句; 其中表达式是循环条件&#xff0c;语句为循环体。 while 语句的语义是&#xff1a;计算表达式的值&#xf…

Vue使用ElemenUI对table的指定列进行合算

前言 最近有一个想法&#xff0c;就是记录自己花销的时候&#xff0c;table中有一项内容是花销的金额。然后想在table的底部有一项内容是该金额的总计。 然后我就顺着elemetui的table组件寻找相关的demo&#xff0c;还真发现了一个这样的demo。 对于这个demo&#xff0c;官方…

嵌入式 Linux进程之间的通信

目录 1、Linux进程间的通信继承 2、Linux进程之间的通信种类 3、管道 3.1 管道概述 3.2 管道文件 3.3 管道特点 3.4 通信框架 3.5 对管道文件进行操作 4、标准流管道 5、无名管道 PIPE 5.1 无名管道特点 5.2 创建管道函数 6、有名管道&#xff08;FIFO&#x…

FPGA lattice 深力科LCMXO3LF-2100C-5BG324I拥有很强的灵活性和适应性可编程内核的FPGA 值得期待

FPGA lattice 深力科LCMXO3LF-2100C-5BG324I MachXO3系列 拥有很强的灵活性和适应性可编程内核的FPGA 值得期待 &#xff0c;FPGA 现场可编程逻辑器件,小尺寸&#xff0c;高性能&#xff01;在工业领域&#xff0c;它可以用于网络控制器&#xff0c;PLC,网络边缘计算&#xff0…

kubernetes--分析容器系统调用:Sysdig

目录 Sysdig介绍&#xff1a; sysdig工作流程 安装Sysdig sysdig常用参数&#xff1a; sysdig过滤&#xff1a; sysdig之Chisels&#xff08;工具箱&#xff09;&#xff1a; 其他常用命令 Sysdig介绍&#xff1a; Sysdig是一个非常强大的系统监控分析和故障排查工具。汇…

MOEA/D: A Multiobjective Evolutionary Algorithm Based on Decomposition

目录1 问题定义2 算法步骤3 代码4 效果1 问题定义 本博客以最小化问题为例 f1x2f2(x−2)2min⁡f(f1(x),f2(x))\begin{aligned} f_1 & x ^2 \\ f_2 & (x - 2) ^2 \\ \min f & (f_1(x), f_2(x)) \end{aligned} f1​f2​minf​x2(x−2)2(f1​(x),f2​(x))​ 代码…

二十、常用调优工具概述与Jprofiler演示

常用调优工具 1.JDK命令行 2.Eclipse:Memory Analyzer Tool 3.Jconsole 4.VisualVM 5.Jprofiler 6.Java Flight Recorder 7.GCViewer 8.GC Easy jprofiler 简介&#xff1a; 他把CPU、执行引擎和内存的剖析组合在一个强大的应用中。JProfiler可提供许多IDE整合和应用服务器整合…

集成学习boosting、bagging、stacking

目录 一、介绍 二、三种架构学习 &#xff08;1&#xff09;boosting &#xff08;2&#xff09;bagging &#xff08;3&#xff09;stacking 一、介绍&#xff1a; 对于单个模型来说很难拟合复杂的数&#xff0c;模型的抗干扰能力较低&#xff0c;所以我们希望可以集成多…

ElasticSearch 8 学习笔记总结(五)

文章目录一、ElasticSearch 8 版本二、ES8 集群 环境安装1. 生成安全证书2. 生成http证书3. 配置第一个节点4. 配置其他节点三、ES集群 关联问题解决四、 Kibana 安装和使用五、kibana 基础操作1. 索引操作2. 文档操作3. 文档搜索4. 索引模板六、分词器七、文档评分机制1. 什么…

上拉电阻与下拉电阻总结

文章目录相关概念介绍IO引脚的三态输出之高阻态---将逻辑门与系统其他部分隔离&#xff0c;电平外部控制IO引脚输出模型 推挽电路 与 开漏电路---单独开漏无高电平驱动能力原理介绍什么是上下拉电阻&#xff1f;---把IO口用电阻拉到正压VCC&#xff08;上拉&#xff09; 或 接地…

如何使用Docker容器部署O2OA(翱途)开发平台与OnlyOffice的集成版本?

O2OA(翱途)开发平台[下称O2OA平台或者O2OA]默认可以和OnlyOffice进行集成来实现在线文档编辑以及流程集成。开发者可以直接安装O2OA官网的OnlyOfficeO2Server的Docker版本用于体验。本文将详细介绍如何安装O2OA OnlyOffice的Docker版本。OnlyOffice Docs Sever可以单独安装,O2…

aws apigateway 使用httpapi私有集成ecs服务

参考资料 https://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/http-api-private-integration.htmlhttps://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/http-api-develop-integrations-private.html 在《aws apigateway 基础概念和入门示…

Vue2.0开发之——购物车案例-Goods组件封装-把购买数量传给counter组件(52)

一 概述 Goods组件中导入Counter组件设置Counter组件的数量 二 Goods组件中导入Counter组件 2.1 Goods组件中导入Counter组件 import Counter from "/components/Counter/Counter.vue";2.2 Goods组件中注册Counter组件 components:{Counter }2.3 Goods组件中使用…

GDKOI2023游记+一周模拟赛题解

温馨提示&#xff1a; 1)有些链接需要在本校OJ上的博客里才能打开。2)没更新完。 Day -6&#xff08;3.4&#xff09; 晚上打了场AtCoder&#xff0c;rank1515rank 1515rank1515&#xff0c;切了5题&#xff0c;信心。 zswangziye的atcoder账号 打T5的时候心态不稳&#xff…

2022年MathorCup数学建模A题大规模指纹图像检索的模型与实现解题全过程文档加程序

2022年第十二届MathorCup高校数学建模 A题 大规模指纹图像检索的模型与实现 原题再现 在生物特征识别领域&#xff0c;指纹作为最具独特性与持久性的生物特征之一&#xff0c;被广泛应用于身份识别。   指纹识别过程分为特征提取和比对两个环节。其中特征提取环节会提取用于…

matplotlib: 绘制柱状图

通过matplotlib绘制柱形图 第一个例子 from matplotlib import pyplot as plty [10, 11, 12, 11, 9, 8, 13, 10] # 创建y轴坐标 x list(range(1,9)) # 创建x轴坐标# 创建x轴显示的参数&#xff08;此功能在与在图像中x轴仅显示能被10整除的刻度&#xff0c;避免刻度过多分…

比亚迪:全球最大电动汽车制造商的坎坷成长之路

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 特斯拉&#xff08;TSLA&#xff09;首席执行官埃隆马斯克表示&#xff0c;特斯拉最接近的竞争对手可能是一家中国电动汽车公司。猛兽财经认为&#xff0c;沃伦•巴菲特支持的比亚迪&#xff08;0211&#xff09;可能是马斯…

在ubuntu上部署与使用docker(python)

1.安装Docker首先&#xff0c;更新现有的包列表sudo apt update接下来安装一些允许童HTTPS才能使用的软件包&#xff1a;sudo apt install apt-transport-https ca-certificates curl software-properties-common然后将官方Docker存储库的GPG秘钥添加到您的系统curl -fsSL http…