[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 join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Linux云服务器手动配置DNS的方法步骤

《Linux云服务器手动配置DNS的方法步骤》在Linux云服务器上手动配置DNS(域名系统)是确保服务器能够正常解析域名的重要步骤,以下是详细的配置方法,包括系统文件的修改和常见问题的解决方案,需要... 目录1. 为什么需要手动配置 DNS?2. 手动配置 DNS 的方法方法 1:修改 /etc/res

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

linux系统中java的cacerts的优先级详解

《linux系统中java的cacerts的优先级详解》文章讲解了Java信任库(cacerts)的优先级与管理方式,指出JDK自带的cacerts默认优先级更高,系统级cacerts需手动同步或显式... 目录Java 默认使用哪个?如何检查当前使用的信任库?简要了解Java的信任库总结了解 Java 信

Linux命令rm如何删除名字以“-”开头的文件

《Linux命令rm如何删除名字以“-”开头的文件》Linux中,命令的解析机制非常灵活,它会根据命令的开头字符来判断是否需要执行命令选项,对于文件操作命令(如rm、ls等),系统默认会将命令开头的某... 目录先搞懂:为啥“-”开头的文件删不掉?两种超简单的删除方法(小白也能学会)方法1:用“--”分隔命

Linux五种IO模型的使用解读

《Linux五种IO模型的使用解读》文章系统解析了Linux的五种IO模型(阻塞、非阻塞、IO复用、信号驱动、异步),重点区分同步与异步IO的本质差异,强调同步由用户发起,异步由内核触发,通过对比各模... 目录1.IO模型简介2.五种IO模型2.1 IO模型分析方法2.2 阻塞IO2.3 非阻塞IO2.4