第三十四期-ARM Linux内核的中断(4)
作者:罗宇哲,中国科学院软件研究所智能软件研究中心
上一期中我们介绍了ARM Linux内核中外设中断处理的部分流程,这一期我们将继续介绍ARM Linux内核的外设中断处理流程中与中断描述符相关的部分。
一、ARM Linux内核的中断描述符
上一期我们提到ARM Linux内核处理外设中断时会通过调用Linux中断号对应的中断描述符里的handle_irq()函数来处理相关中断。中断描述符在ARM Linux中由结构体irq_desc来表示,其代码在openEuler源码仓库的/openeuler/kernel/blob/kernel-4.19/include/linux/irqdesc.h文件中可以找到:
struct irq_desc {……irq_flow_handler_t handle_irq;……struct irqaction *action; /* IRQ action list */……} ____cacheline_internodealigned_in_smp;
该结构体中定义了两层中断处理函数[1]:
- 第一层中断处理函数是handle_irq,irq_flow_handler_t是一个函数指针;
- 第二层中断处理函数保存在结构体irqaction组成的链表里,每一个链表元素都保存了一个设备驱动注册的中断处理函数。因为多个硬件设备可能共享同一个硬件中断号,所以irqaction组成的链表里可能有多个元素。
irq_flow_handler_t的定义代码可以在openEuler源码仓库的/openeuler/kernel/blob/kernel-4.19/include/linux/irqhandler.h文件中可以找到:
该函数指针指向的函数输入为指向结构体irq_desc的指针类型,输出为void类型。我们在openEuler源码仓库的/openeuler/kernel/blob/kernel-4.19/include/linux/irq.h文件中可以找到多个符合irq_flow_handler_t类型的替换函数:
当硬件中断号小于16时中断为软件产生的中断(SGI),中断处理程序调用handle_IPI()函数处理;当硬件中断号大于或等于16而小于32时中断为私有外设中断(PPI),handle_irq()函数被设置为handle_percpu_devid_irq();当硬件中断号大于等于32但小于gic_data.irq_nr(该值在irq-gic-v3.c文件中的gic_init_bases()函数中初始化,其最大值为1020,表示GICv3最多支持1020个中断源(SGI+PPI+SPI))时中断为共享外设中断,handle_irq()被设置为handle_fasteoi_irq();当硬件中断号大于等于8192但小于GIC_ID_NR时中断为局部特定外设中断(LPI),handle_irq()被设置为handle_fasteoi_irq()。有关中断类型的知识可以在第二十八期找到。设置handle_irq()的代码可以在openEuler源码仓库的/openeuler/kernel/blob/kernel-4.19/drivers/irqchip/irq-gic-v3.c文件中可以找到:
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,irq_hw_number_t hw){struct irq_chip *chip = &gic_chip;if (static_branch_likely(&supports_deactivate_key))chip = &gic_eoimode1_chip;/* SGIs are private to the core kernel */if (hw < 16)return -EPERM;/* Nothing here */if (hw >= gic_data.irq_nr && hw < 8192)return -EPERM;/* Off limits */if (hw >= GIC_ID_NR)return -EPERM;/* PPIs */if (hw < 32) {irq_set_percpu_devid(irq);irq_domain_set_info(d, irq, hw, chip, d->host_data,handle_percpu_devid_irq, NULL, NULL);irq_set_status_flags(irq, IRQ_NOAUTOEN);}/* SPIs */if (hw >= 32 && hw < gic_data.irq_nr) {irq_domain_set_info(d, irq, hw, chip, d->host_data,handle_fasteoi_irq, NULL, NULL);irq_set_probe(irq);irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));}/* LPIs */if (hw >= 8192 && hw < GIC_ID_NR) {if (!gic_dist_supports_lpis())return -EPERM;irq_domain_set_info(d, irq, hw, chip, d->host_data,handle_fasteoi_irq, NULL, NULL);}return 0;}
handle_percpu_devid_irq()和handle_fasteoi_irq()两个函数最终都会调用中断描述符中irqaction结构体里面的handler()函数(action->handler())从而调用中断处理函数。其中handle_fasteoi_irq()->handle_irq_event()->__handle_irq_event_percpu()还会遍历中断处理描述符action的链表,调用所有中断处理描述符里的中断处理函数handler(),__handle_irq_event_percpu()的代码可以在openEuler源码仓库的/openeuler/kernel/blob/kernel-4.19/kernel/irq/handle.c文件中可以找到:
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags){……struct irqaction *action;……for_each_action_of_desc(desc, action) {……res = action->handler(irq, action->dev_id);……}return retval;}
irqaction结构体的代码在openEuler源码仓库的/openeuler/kernel/blob/kernel-4.19/include/linux/interrupt.h文件中可以找到:
/*** struct irqaction - per interrupt action descriptor* @handler: interrupt handler function* @name: name of the device* @dev_id: cookie to identify the device* @percpu_dev_id: cookie to identify the device* @next: pointer to the next irqaction for shared interrupts* @irq: interrupt number* @flags: flags (see IRQF_* above)* @thread_fn: interrupt handler function for threaded interrupts* @thread: thread pointer for threaded interrupts* @secondary: pointer to secondary irqaction (force threading)* @thread_flags: flags related to @thread* @thread_mask: bitmask for keeping track of @thread activity* @dir: pointer to the proc/irq/NN/name entry*/struct irqaction {irq_handler_t handler;void *dev_id;void __percpu *percpu_dev_id;struct irqaction *next;irq_handler_t thread_fn;struct task_struct *thread;struct irqaction *secondary;unsigned int irq;unsigned int flags;unsigned long thread_flags;unsigned long thread_mask;const char *name;struct proc_dir_entry *dir;} ____cacheline_internodealigned_in_smp;
该结构体通过next指针构成了链表,从而可以保存多个设备驱动注册的处理函数并使多个设备共享同一个硬件中断号。中断中驱动有关的知识我们将在设备驱动一章详细介绍。
二、结语
本期我们介绍了中断描述符及与其相关的重要函数,下一期我们将介绍软件产生的中断(SGI)的处理流程。
参考文献
[1] 《Linux内核深度解析》,余华兵著,2019
第三十四期-ARM Linux内核的中断(4)相关推荐
- 第四十一期-ARM Linux内核的系统调用(1)
作者:罗宇哲,中国科学院软件研究所智能软件研究中心 上一期中我们介绍了工作队列相关的关键函数,这一期我们将介绍ARM Linux内核中的系统调用. 一.ARM Linux内核中的系统调用 在ARM L ...
- 微软安全新闻聚焦-双周刊第三十四期
Biweekly Spotlights ==== 2013. 6. 5– 2013. 6. 20 第 34 期 ==== 微软发布 EMET 4.0 2013年6月17日 Enhanced Miti ...
- 第一百三十四期:MySQL分页查询方法及优化
在MySQL中,分页查询一般都是使用limit子句实现,limit子句声明如下:LIMIT子句可以被用于指定 SELECT 语句返回的记录数. 作者:青芽草 分页查询方法: 在MySQL中,分页查询 ...
- 第三十四期:花了一个星期,我终于把RPC框架整明白了!
RPC(Remote Procedure Call):远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想. 作者:李金葵 RPC(Remote Procedure ...
- Android Studio第三十四期 - git企业级应用命令
1.git status 2.git add -A 3.git commit -m "merger" 4.git pull 5.git push origin master 6.g ...
- Android第三十四期 - 极光推送
代码已经整理好,参照官网的文档很快你会可以配置出来,如下效果:
- 第三十四期:一次非常有意思的sql优化经历
风过无痕的博客 6月24日 场景 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表: create table Course(c_id int PRIMARY KEY,name varch ...
- Rigetti完成英国量子计算机的搭建;拓扑量子计算遭遇严重的挫折 | 全球量子科技与工业快讯第三十九期
Rigetti完成英国量子计算机的搭建 Rigetti及其合作伙伴已经在英国完成了首个量子计算系统的建设,并计划在2022年初通过Rigetti量子云服务提供该系统.这台商用量子计算机是英国的第一台, ...
- 第四十二期-ARM Linux内核的系统调用(2)
作者:罗宇哲,中国科学院软件研究所智能软件研究中心 上一期中我们介绍了ARM Linux内核中的系统调用和定义系统调用的流程,这一期我们将介绍系统调用的执行过程. 一.ARM Linux内核中系统调用 ...
最新文章
- jsp页面展示更加商品的分类,控制商品的显示
- 三维的对象表示---OpenGL二次曲面和三次曲面函数
- 华为主题锁屏壁纸换不掉_快来看看华为与荣耀手机的这16款主题!别一直用系统默认主题啦!...
- IBM AIX 5.3 系统管理 -- 系统启动过程详解
- 多所高校通知,新学期延期开学!做好线上教学准备
- poj 2226 Muddy Fields(合理建图+二分匹配)
- java bean 工厂模式_通过annotation(注解)实现BeanFactory工厂模式(三)
- sql无法写入mysql_windows7 sqlserver2012 无法写入受保护的内存 解决办法
- 今日恐慌与贪婪指数为72 贪婪程度有所缓解
- xp计算机重启记录,XP电脑关机后自动重启的解决方法
- 【渝粤教育】电大中专Office办公软件 (5)作业 题库
- [CTSC2018]假面(概率DP)
- HTML中怎么适应所有浏览器,css如何自适应浏览器高度?
- linux格式化磁盘fdisk,linux下使用fdisk工具为磁盘分区格式化
- 植物大战僵尸修改器 - 简易版
- Heat Map在生物信息学中的应用
- 微信小程序豆瓣电影学习知识总结
- 揭秘!腾讯程序员告诉你当今最热门的5门编程语言
- prototype鼠标指针_html5鼠标点击页面光标圆点动画特效
- Sqlite3 学习记录