[linux api] of_irq_init

2024-04-14 11:36
文章标签 linux init api irq

本文主要是介绍[linux api] of_irq_init,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

总结

以如下级联的中断控制器为例:
在这里插入图片描述

of_irq_init会确保先初始化父控制器再初始化子控制器,也即整体按照层序遍历的顺序进行初始化,以上图为例,其初始化顺序为:

  1. intc0
  2. intc1-2
  3. intc3-6

具体实现则分为两个阶段:

第一阶段

遍历所有设备节点,并与参数matches进行匹配,找出所有的中断控制器节点,串到一条名为intc_desc_list的链表上(以下节点在链表中的顺序可能和设备节点在DTS文件中的位置有关,这里仅做示例):

intc_desc_list
intc0
intc1
intc2
intc3
intc4
intc5
intc6

第二阶段

parent(初始值为NULL)作为当前的父控制器,从intc_desc_list中找出以其为父控制器的中断控制器,对其进行初始化后,从intc_desc_list取出,并添加到另一条链表intc_parent_list,然后取出intc_parent_list的首元素,作为新一轮的parent再重复上述步骤。这是典型的基于队列实现层序遍历的做法,不再赘述。

参数

matchesstruct of_device_id类型的数组,该结构定义如下:

struct of_device_id {char	name[32];char	type[32];char	compatible[128];const void *data;
};

其中最重要的是compatible字段,用来匹配中断控制器设备节点的compatible属性。

返回值


源码分析如下:

void __init of_irq_init(const struct of_device_id *matches)
{const struct of_device_id *match;struct device_node *np, *parent = NULL;struct of_intc_desc *desc, *temp_desc;struct list_head intc_desc_list, intc_parent_list;/* 初始化两条链表 *//* intc_desc_list串起所有中断控制器设备节点 *//* intc_parent_list用来实现基于队列的层序遍历 */INIT_LIST_HEAD(&intc_desc_list);INIT_LIST_HEAD(&intc_parent_list);/* 遍历所有设备树中的设备节点 *//* 用每个节点和matches数组的每个成员中的compatible字符串比较 *//* 把匹配中的成员赋值给match */for_each_matching_node_and_match(np, matches, &match) {/* 一般来讲,matches数组就是在中断控制器驱动中用IRQCHIP_DECLARE生成的 */         /* 能匹配上就肯定是中断控制器对应的设备节点 *//* 但是严谨起见,还是检擦interrupt-controller属性 */if (!of_property_read_bool(np, "interrupt-controller") ||/* 确定是中断控制器之后,还要检查status属性 *//* status属性不存在或者status="ok"/"okay"表明设备可用 *//* status="disable"表明设备不可用 *//* 设备不可用就继续遍历下一个 */!of_device_is_available(np))continue;/* 到这里,确定设备节点是中断控制器节点且可用 *//* match->data指向中断控制器的初始化函数 *//* 肯定得有初始化函数,不然折腾半天折腾了个寂寞 */if (WARN(!match->data, "of_irq_init: no init function for %s\n",match->compatible))continue;/* 申请of_intc_desc内存 */desc = kzalloc(sizeof(*desc), GFP_KERNEL);if (!desc) {of_node_put(np);goto err;}/* 记录下中断控制器的初始化函数以及设备节点 */desc->irq_init_cb = match->data;desc->dev = of_node_get(np);/* 查找并记录当前中断控制器的父控制器 */desc->interrupt_parent = of_parse_phandle(np, "interrupts-extended", 0);if (!desc->interrupt_parent)desc->interrupt_parent = of_irq_find_parent(np);if (desc->interrupt_parent == np) {of_node_put(desc->interrupt_parent);desc->interrupt_parent = NULL;}/* 将中断控制器串入intc_desc_list */list_add_tail(&desc->list, &intc_desc_list);}/* 到这里,intc_desc_list里面就串上了所有的中断控制器节点 *//* 接下来就是按照层序遍历所有中断控制器并进行初始化 *//* 第一层是root domain,然后第二场是root domain的子控制器,以此类推 *//* intc_desc_list非空表示还有中断控制器尚未完成初始化 */while (!list_empty(&intc_desc_list)) {/* 处理当前所有以parent为父控制器的中断控制器 *//* parent初始值为NULL,NULL表示没有父控制器 *//* 也即第一轮处理root domain(root domain的parent为空) */list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {int ret;/* 不是我们要找的中断控制器则继续遍历下一个 */if (desc->interrupt_parent != parent)continue;/* 是我们要找的控制器,则将该控制器从链表中摘出来 */list_del(&desc->list);/* 设置OF_POPULATED标志标识设备(中断控制器)已经被创建 */of_node_set_flag(desc->dev, OF_POPULATED);pr_debug("of_irq_init: init %pOF (%p), parent %p\n",desc->dev,desc->dev, desc->interrupt_parent);/* 中断控制器初始化 */ret = desc->irq_init_cb(desc->dev,desc->interrupt_parent);if (ret) {pr_err("%s: Failed to init %pOF (%p), parent %p\n",__func__, desc->dev, desc->dev,desc->interrupt_parent);/* 中断控制器初始化失败则要取消OF_POPULATED标志 */of_node_clear_flag(desc->dev, OF_POPULATED);kfree(desc);continue;}/* 将当前完成初始化的中断控制器推入intc_parent_list链表 *//*   intc_parent_list本质上是一个双向链表实现的队列 *//*   是实现层序遍历的关键 */list_add_tail(&desc->list, &intc_parent_list);}/* 至此,当前parent的所有孩子节点初始化完毕 *//* 获取intc_parent_list队列的队首 */desc = list_first_entry_or_null(&intc_parent_list,typeof(*desc), list);if (!desc) {/* intc_parent_list链表为空 *//* 也就是没有爹了(或者说当前爹是最后一个爹,没有可供匹配的新爹了) *//* 此时intc_desc_list有两种可能: *//*   1. intc_desc_list中的节点一个都没与当前的爹匹配上 *//*      而可供尝试匹配的新爹又没有了 *//*   2. intc_desc_list中的节点都与当前的爹匹配上了 *//*      但都初始化失败了,intc_desc_list此时为空 */pr_err("of_irq_init: children remain, but no parents\n");break;}list_del(&desc->list);/* 取出的队首作为新一轮的parent */parent = desc->dev;kfree(desc);}/* 正常执行到这里 *//* intc_parent_list和intc_desc_list都会是空的 *//* 出现错误时,跳出循环,两条链表非空,要做如下的清理工作: */list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {list_del(&desc->list);kfree(desc);}
err:list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {list_del(&desc->list);of_node_put(desc->dev);kfree(desc);}
}

这篇关于[linux api] of_irq_init的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/902903

相关文章

Linux线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

Linux下进程的CPU配置与线程绑定过程

《Linux下进程的CPU配置与线程绑定过程》本文介绍Linux系统中基于进程和线程的CPU配置方法,通过taskset命令和pthread库调整亲和力,将进程/线程绑定到特定CPU核心以优化资源分配... 目录1 基于进程的CPU配置1.1 对CPU亲和力的配置1.2 绑定进程到指定CPU核上运行2 基于

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

Linux在线解压jar包的实现方式

《Linux在线解压jar包的实现方式》:本文主要介绍Linux在线解压jar包的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux在线解压jar包解压 jar包的步骤总结Linux在线解压jar包在 Centos 中解压 jar 包可以使用 u

linux解压缩 xxx.jar文件进行内部操作过程

《linux解压缩xxx.jar文件进行内部操作过程》:本文主要介绍linux解压缩xxx.jar文件进行内部操作,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、解压文件二、压缩文件总结一、解压文件1、把 xxx.jar 文件放在服务器上,并进入当前目录#

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

在Linux中改变echo输出颜色的实现方法

《在Linux中改变echo输出颜色的实现方法》在Linux系统的命令行环境下,为了使输出信息更加清晰、突出,便于用户快速识别和区分不同类型的信息,常常需要改变echo命令的输出颜色,所以本文给大家介... 目python录在linux中改变echo输出颜色的方法技术背景实现步骤使用ANSI转义码使用tpu

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri

linux hostname设置全过程

《linuxhostname设置全过程》:本文主要介绍linuxhostname设置全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录查询hostname设置步骤其它相关点hostid/etc/hostsEDChina编程A工具license破解注意事项总结以RHE