Linux Irq domain

article/2025/11/7 7:08:43

本节学习下什么是irq domain, 以及irq domain的作用。可以参考内核文档IRQ-domain.txt

为什么引入IRQ-Domain

当早期的系统只存在一个interrupt-controller的时候,而且中断数目也不多的时候,一个很简单的做法就是一个中断号对应到interrupt-contoller的一个号,可以说是简单的线性映射

而当一个系统中有多个interrupt-controller的时候,而且中断号也逐渐增加。linux内核为了应对此问题,引入了IRQ-domain的概念

 

irq-domain的引入相当于一个中断控制器就是一个irq-domain。就是一个中断区域。这样一来所有的irq-contoller会出现级联的布局。

利用树状的结构可以充分的利用irq数目,而且每一个irq-domain区域可以自己去管理自己interrupt的特性

IRQ-Domain的作用

咋们通过/proc/interrupt的值来看下irq-domain的作用

 从这图上可以看出,这些中断只直接连接到root-interrupt-controller的,也就是直接连接到GICv3的中断控制器上的。而Hwirq-num就是dts中配置的irq号

而第一列就是对应的softirq-num,也就是request_irq时传入的irq

 

中断控制器级联的情况图

 

hwirq到softirq的映射

当开机之后,内核会自动将dts全部解析,然后会进行填充,对于中断使用如下函数进行解析dts,然后map

unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
{struct of_phandle_args oirq;if (of_irq_parse_one(dev, index, &oirq))return 0;return irq_create_of_mapping(&oirq);
}

of_irq_parse_one会将dts中的中断信息进行解析,然后通过irq_create_of_mapping函数进行hwirq到softirq的map

  • 首先dts中配置的中断号都是hwirq
  • 刚开机hwirq没有对应的softirq的,所以第一次开机需要进行hwirq和softirq之间建立map
int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq,int node, const struct cpumask *affinity)
{unsigned int hint;if (virq >= 0) {virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE,affinity);} else {hint = hwirq % nr_irqs;if (hint == 0)hint++;virq = __irq_alloc_descs(-1, hint, cnt, node, THIS_MODULE,affinity);if (virq <= 0 && hint > 1) {virq = __irq_alloc_descs(-1, 1, cnt, node, THIS_MODULE,affinity);}}return virq;
}

通过上述的函数分配virq,也就是softirq
 

static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain,struct irq_data *child)
{struct irq_data *irq_data;irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL,irq_data_get_node(child));if (irq_data) {child->parent_data = irq_data;irq_data->irq = child->irq;irq_data->common = child->common;irq_data->domain = domain;}return irq_data;
}

分配一个Irq_data结构,然后将virq设置到irq_data结构中

static void irq_domain_set_mapping(struct irq_domain *domain,irq_hw_number_t hwirq,struct irq_data *irq_data)
{if (hwirq < domain->revmap_size) {domain->linear_revmap[hwirq] = irq_data->irq;} else {mutex_lock(&domain->revmap_tree_mutex);radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);mutex_unlock(&domain->revmap_tree_mutex);}
}

将hwirq和irq_data→irq建立映射。这里有两种映射方式一种是线性映射,一种是树形映射

 

irq和irq_desc的关系

在分配一个softirq的时候,其实最终也会分配一个irq_desc结构的

这里有两种管理方式,一种是通过线性固定开机固定分配好了的,一种是动态分配的

static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags,const struct cpumask *affinity,struct module *owner)
{struct irq_desc *desc;desc = kzalloc_node(sizeof(*desc), GFP_KERNEL, node);if (!desc)return NULL;/* allocate based on nr_cpu_ids */desc->kstat_irqs = alloc_percpu(unsigned int);if (!desc->kstat_irqs)goto err_desc;if (alloc_masks(desc, node))goto err_kstat;raw_spin_lock_init(&desc->lock);lockdep_set_class(&desc->lock, &irq_desc_lock_class);mutex_init(&desc->request_mutex);init_rcu_head(&desc->rcu);desc_set_defaults(irq, desc, node, affinity, owner);irqd_set(&desc->irq_data, flags);kobject_init(&desc->kobj, &irq_kobj_type);return desc;err_kstat:free_percpu(desc->kstat_irqs);
err_desc:kfree(desc);return NULL;
}

开机已经分配好了的,用于irq比较少

struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {[0 ... NR_IRQS-1] = {.handle_irq = handle_bad_irq,.depth      = 1,.lock       = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),}
};

通过irq_to_desc函数来获取desc通过irq的值,两种方式

struct irq_desc *irq_to_desc(unsigned int irq)
{return radix_tree_lookup(&irq_desc_tree, irq);
}struct irq_desc *irq_to_desc(unsigned int irq)
{return (irq < NR_IRQS) ? irq_desc + irq : NULL;
}

申请中断

通过request_irq函数来设置中断的回调函数,最终会设置到Irqaction中去

int request_threaded_irq(unsigned int irq, irq_handler_t handler,irq_handler_t thread_fn, unsigned long irqflags,const char *devname, void *dev_id)
{struct irqaction *action;struct irq_desc *desc;action->handler = handler;                   //设置中断回调函数action->thread_fn = thread_fn;               //如果中断是线程化,则需要设置此回调action->flags = irqflags;action->name = devname;action->dev_id = dev_id; }

 

处理中断

irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{irqreturn_t retval = IRQ_NONE;unsigned int irq = desc->irq_data.irq;struct irqaction *action;record_irq_time(desc);for_each_action_of_desc(desc, action) {irqreturn_t res;trace_irq_handler_entry(irq, action);res = action->handler(irq, action->dev_id);           //处理中断trace_irq_handler_exit(irq, action, res);if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n",irq, action->handler))local_irq_disable();switch (res) {case IRQ_WAKE_THREAD:/** Catch drivers which return WAKE_THREAD but* did not set up a thread function*/if (unlikely(!action->thread_fn)) {warn_no_thread(irq, action);break;}__irq_wake_thread(desc, action);/* Fall through to add to randomness */case IRQ_HANDLED:*flags |= action->flags;break;default:break;}retval |= res;}return retval;
}
  • 处理中断,action->handler(irq, action->dev_id);
  • 如果是中断线程的话,唤醒线程 __irq_wake_thread(desc, action);


http://chatgpt.dhexx.cn/article/rVkOlgGt.shtml

相关文章

linux IRQ Management(四)- IRQ Domain

了解IRQ Domain(中断控制器) 1.如何理解中断号&#xff1f; 每个IRQ同时有"irq"和"hwirq"两个编号。 "hwirq"是硬件中断号&#xff08;物理中断号&#xff09;&#xff0c;即芯片手册上写的号码&#xff0c;Interrupt controller用hwirq来标识…

linux设备驱动:中断处理中的hardirq与softirq详细流程

中断处理的整体框架&#xff1a; 内核用于标识中断上下文(in_interrupt())的变量preempt_count的布局&#xff1a; 按照x86处理器在外部中断发生时的硬件逻辑&#xff0c;在do_IRQ被调用时&#xff0c;处理器已经屏蔽了对外部中断的响应。在图中我们看 到中断的处理大体上被…

Java 字段封装快捷键

快捷键:shift alt s 选择&#xff1a;

Java封装阿里云对象存储OSS

Java封装阿里云对象存储OSS 阿里云对象存储OSS官网 本篇博客简单封装了阿里云的OSS存储中的建立连接&#xff1b;本地文件&#xff0c;输入流和URL三种方式上传文件&#xff0c;获取文件的输入流&#xff0c;删除文件&#xff0c;获取所有文件列表等功能。 OSS官方Api OSSp…

java 枚举 封装操作方法

前言&#xff1a; 由于刚转java项目&#xff0c;所以对于java语言比较陌生&#xff0c;尤其是lambda和一些诸如&#xff08;一个java文件只能有一个public class&#xff09;等等的零散知识点之类。。。 使我觉得就语言的层级来说。.net真的超越java不是一星半点。奈何.net跨…

Java封装和封装的案例

Java封装和封装的案例 目录 一、Java封装知识点简介 二、Java程序中的包 三、static关键字、代码块 四、封装的综合应用案例&#xff1a; 一、Java封装知识点简介 1、面向对象三大特性之封装的概念&#xff1a; 隐藏类的某些内部细节&#xff0c;不允许外部程序直接访问…

Java的封装方法

在面向对象程式设计方法中&#xff0c;封装&#xff08;英文名称&#xff1a;Encapsulation&#xff09;是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。封装可以被认为是一个保护屏障&#xff0c;防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的…

Java封装如何封装 封装的好处是什么?

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、封装的作用是什么&#xff1f;二、封装的好处三、封装的步骤 1.引入库2.private的应用总结 前言 我要看电视&#xff0c;只需要按一下开关和换台就可以了。…

15、JAVA入门——封装

目录 一、封装 1、封装概述 2、封装的步骤 二、Java里的包 1、包的概述 2、包的定义 3、包的使用 4、注意事项 三、Java访问修饰符 1、类和类成员的访问控制 2、类的访问修饰符 3、类成员的访问修饰符 四、static关键字 1、static特点 2、static修饰属性 3、static修饰方法 4、…

初学java封装

封装 初识java封装 封装的用处&#xff1a; 1.提高程序的安全性&#xff0c;保护数据 2.隐藏代码的实现细节 3.统一接口 4.增加系统可维护性 这里创建一个类 public class Package {//属性私有private String name;//名字private int age; //年龄private int sex;//性别//1.…

java如何实现封装_java如何实现封装

Java中类的封装是如何实现的封装是将对象的信息隐藏在对象内部,禁止外部程序直接访问对象内部的属性和方法。 java封装类通过三个步骤实现: (1)修改属性的可见性,限制访问。 (2)设置属性的读取方法。 (3)在读取属性的方法中,添加对属性读取的限制。 Java中什么叫封装呢? 继…

java封装dll文件_java类封装成dll

1&#xff0c;建立测试类&#xff0c;注意英文注释部分&#xff0c;用汉语直接编译会乱码 public classHello {//native method is used for call other language procedure//if use chinese here then Compile would be gibberish public native voidprintHello();static{ Sys…

java之封装

1.封装 1. 封装 1.1 private关键字 private是一个修饰符&#xff0c;可以用来修饰成员&#xff08;成员变量&#xff0c;成员方法&#xff09; 被private修饰的成员&#xff0c;只能在本类进行访问&#xff0c;针对private修饰的成员变量&#xff0c;如果需要被其他类使用&…

【JavaScript】js中非常常见的面试题

文章目录 1、手动实现防抖和节流2、let、const、var 的区别3、箭头函数与普通函数区别4、Promise5、数据类型6、检测数据类型的常用方法1 .typeof2 . instanceof3 .constructor4 . 使用 Object.prototype.toString.call()检测对象类型⭐5 . 自己封装函数6、isArray 7、数组的常…

JS的100道经典面试题(一)只看这四篇就够了,收藏起来以后偷偷看

年轻人你不讲武德&#xff0c;耗子尾汁~~~ 总结就是为了形成自己的js知识网&#xff0c;提升自己&#xff0c;加油&#xff01; 开始干 1、介绍js的基本数据类型   答&#xff1a; Undefined、Null、Boolean、Number、String 2、js有哪些内置对象&#xff1f;  答&…

大前端JS部分基础面试题(含答案)

1.几种基本数据类型?复杂数据类型?值类型和引用数据类型?堆栈数据结构? 基本数据类型&#xff1a;Undefined、Null、Boolean、Number、String 值类型&#xff1a;数值、布尔值、null、undefined。 引用类型&#xff1a;对象、数组、函数。 堆栈数据结构&#xff1a;是一种支…

Js面试题__附答案

1、什么是JavaScript&#xff1f;&#xff08;这是基本题&#xff0c;对很多程序员来说也是送分题&#xff01;&#xff09; JavaScript是客户端和服务器端脚本语言&#xff0c;可以插入到HTML页面中&#xff0c;并且是目前较热门的Web开发语言。同时&#xff0c;JavaScript也…

js 变量及作用域经典面试题

function Foo() {getName function () { alert (1); };return this; } Foo.getName function () { alert (2);}; Foo.prototype.getName function () { alert (3);}; var getName function () { alert (4);}; function getName() { alert (5);}//请写出以下输出结果&#x…

前端面试题集锦——JavaScript

JavaScript 栈和队列的区别? 栈的插入和删除操作都是在一端进行的&#xff0c;而队列的操作却是在两端进行的。 队列先进先出&#xff0c;栈先进后出。 栈只允许在表尾一端进行插入和删除&#xff0c;而队列只允许在表尾一端进行插入&#xff0c;在表头一端进行删除 栈和…

收集的面试题 js面试题

题库推荐网址&#xff1a;https://github.com/FEGuideTeam/FEGuide/tree/master/javascript%E9%97%AE%E9%A2%98 第1题: ## JavaScript 由以下三部分组成&#xff1a;1. ECMAScript&#xff08;核心&#xff09;&#xff1a;JavaScript 语言基础2. DOM&#xff08;文档对象模…