本节学习下什么是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);

Linux Irq domain相关推荐

  1. Linux kernel的中断子系统之(二):IRQ Domain介绍

    一.概述 在linux kernel中,我们使用下面两个ID来标识一个来自外设的中断: 1.IRQ number.CPU需要为每一个外设中断编号,我们称之IRQ Number.这个IRQ number ...

  2. linux IRQ Management(四)- IRQ Domain

    了解IRQ Domain(中断控制器) 1.如何理解中断号?   每个IRQ同时有"irq"和"hwirq"两个编号. "hwirq"是硬件 ...

  3. irq domain介绍和代码导读

    补充IRQ Domain介绍 在linux kernel中,我们使用下面两个ID来标识一个来自外设的中断: 1.IRQ number.CPU需要为每一个外设中断编号,我们称之IRQ Number.这个 ...

  4. linux IRQ Management(五)- irq_desc

    了解中断描述符struct irq_desc 参考韦东山百问网 1.通用中断代码处理   通用中断处理示意图:   对于每一个外设的IRQ 都用struct irq_desc来描述,称之为中断描述符. ...

  5. linux IRQ Management(三)- IRQ Framework

    了解irq management framework 1.Introduction   Linux is a system on which devices notify the kernel abo ...

  6. linux IRQ Management(六)- DTS及调试

    了解DTS Interrupt 设置方式. 1.DTS 中 interrupt 描述 interrupt-controller - 一个空的属性定义, 该节点作为一个接收中断信号的设备. #inter ...

  7. 从一个NPU失效问题看Linux PM Domain Framework的实现逻辑

    用最新SDK测试NPU AI Demo用例的时候,发现对NPU的寄存器操作直接导致内核show callstack,打印堆栈显示在调用NPU的初始化CMD (CMD号:KERNEL_CMD_INIT) ...

  8. irq domain 分析 GICV3

    文章目录 GICV3 irq-domain irq domain 的左膀与右臂是怎么创建的 irq_domain_ops 创建时机 irq_domain_ops 的实现 irq_chip 的 绑定时机 ...

  9. linux irq 接口,中断机制 – Linux内核API irq_set_chip_data

    irq_set_chip_data函数功能描述:此函数是为irq_desc(结构体变量irq_desc的定义参见文件linux-3.19.3/include/linux/irqdesc.h)数组中对应 ...

  10. 设备树学习(十五、番外篇-中断子系统之IRQ Domain介绍)

    之前的文章分析过没使用设备树时,中断是如何初始化的 https://blog.csdn.net/qq_16777851/article/details/82556519 用一句话总结就是,启动过程,通 ...

最新文章

  1. python商业爬虫_商业爬虫学习笔记day1
  2. 图论 ---- 图论构造成二分图去判断 F. Figure Fixing
  3. 斯坦福大学马超:探寻「隐式偏差」的完整理论框架
  4. 传承or创新 ?解密分布式数据库自研修炼之路
  5. mod php是什么意思,mod函数是什么意思
  6. python处理信号机制_Python的Flask框架中的signals信号机制
  7. Kotlin Native新增Objective-C互操作能力以及对WebAssembly的支持
  8. 连接硬盘计算机没显示,新买的移动硬盘在我的电脑中无法显示,但是右下角图标显示已经连接,? 爱问知识人...
  9. New to My Oracle Support?
  10. 蓝桥2021模拟真题 (跳跃 )DFS
  11. HCIE-RS面试--P/A协商(超详细!)
  12. arcsde 10.2 for oracle 安装,ArcSDE 10.2 for Oracle 12C安装注意事项
  13. python安装包的时候报错 ERROR: Exception: Traceback (most recent call last): File “C:\Users\
  14. Excel函数之~计算日期、天数、星期
  15. 广州欧米区块链科技×浙江墨客奇迹区块链科技丨达成战略合作共识
  16. Mesh networking----Mesh 网络管理(Mesh network management)
  17. oracle查看dblink信息,找出调用DBLINK的SESSION信息
  18. Arcgis影像合并
  19. 夺宝网站服务器配置,3月27日服务器公告:夺宝小分队
  20. 我读 《国富论》 - 亚当 · 斯密 / 分工

热门文章

  1. BZOJ 1935: [Shoi2007]Tree 园丁的烦恼
  2. 在Linux环境下安装MYSQL
  3. java猫和猫的名字
  4. Linux下的帮助命令
  5. 今天8月5号 2011-08-05
  6. win32 api 显示一张位图的简单代码,释疑用的。
  7. 当前网络存在的安全问题
  8. python绘制3d动态模型_给大家介绍一个python三维动画制作库,数学作图,数据可视化建模...
  9. 三年JAVA开发经验如何做到年薪35万
  10. 13.4 Shelve模块