中断控制器

在Linux内核中,各个设备驱动可以简单地调用request_irq()、enable_irq()、disable_irq()、
local_irq_disable()、local_irq_enable()等通用API来完成中断申请、使能、禁止等功能。

local_irq_disable()、local_irq_enable()的实现与具体中断控制器无关,对于ARM v6以上的体系结
构而言,是直接调用CPSID/CPSIE指令进行,而对于ARM v6以前的体系结构,则是通过MRS、MSR指令
来读取和设置ARM的CPSR寄存器。由此可见,local_irq_disable()、local_irq_enable()针对的并不是
外部的中断控制器,而是直接让CPU本身不响应中断请求。相关的实现位于arch/arm/include/asm/irqflags.h

1#if __LINUX_ARM_ARCH__ >= 6
2
3static inline unsigned long arch_local_irq_save(void)
4{
5 unsigned long flags;
6
7 asm volatile(
8 " mrs %0, cpsr @ arch_local_irq_save\n"
9 " cpsid i"
10 : "=r" (flags) : : "memory", "cc");
11 return flags;
12}
13
14static inline void arch_local_irq_enable(void)
15{
16 asm volatile(
17 " cpsie i @ arch_local_irq_enable"
18 :
19 :
20 : "memory", "cc");
21}
22
23static inline void arch_local_irq_disable(void)
24{
25 asm volatile(
26 " cpsid i @ arch_local_irq_disable"
27 :
28 :
29 : "memory", "cc");
30}
31#else
32
33/*
34 * Save the current interrupt enable state & disable IRQs
35 */
36static inline unsigned long arch_local_irq_save(void)
37{
38 unsigned long flags, temp;
39
40 asm volatile(
41 " mrs %0, cpsr @ arch_local_irq_save\n"
42 " orr %1, %0, #128\n"
43 " msr cpsr_c, %1"
44 : "=r" (flags), "=r" (temp)
45 :
46 : "memory", "cc");
47 return flags;
48}
49
50/*
51 * Enable IRQs
52 */
53static inline void arch_local_irq_enable(void)
54{
55 unsigned long temp;
56 asm volatile(
57 " mrs %0, cpsr @ arch_local_irq_enable\n"
58 " bic %0, %0, #128\n"
59 " msr cpsr_c, %0"
60 : "=r" (temp)
61 :
62 : "memory", "cc");
63}
64
65/*
66 * Disable IRQs
67 */
68static inline void arch_local_irq_disable(void)
69{
70 unsigned long temp;
71 asm volatile(
72 " mrs %0, cpsr @ arch_local_irq_disable\n"
73 " orr %0, %0, #128\n"
74 " msr cpsr_c, %0"
75 : "=r" (temp)
76 :
77 : "memory", "cc");
78}
79 #endif

与local_irq_disable()和local_irq_enable()不同,disable_irq()、enable_irq()针对的则是中断
控制器,因此它们适用的对象是某个中断。disable_irq()的字面意思是暂时屏蔽掉某中断(其实在内核
的实现层面上做了延后屏蔽),直到enable_irq()后再执行ISR。实际上,屏蔽中断可以发生在外设、中
断控制器、CPU三个位置,如图1所示。对于外设端,是从源头上就不产生中断信号给中断控制器,由
于它高度依赖于外设于本身,所以Linux不提供标准的API而是由外设的驱动直接读写自身的寄存器。
在这里插入图片描述
在内核中,通过irq_chip结构体来描述中断控制器。该结构体内部封装了中断mask、unmask、ack等成
员函数,其定义于include/linux/irq.h中,如代码清单4所示。

1struct irq_chip {
2 const char *name;
3 unsigned int (*irq_startup)(struct irq_data *data);
4 void (*irq_shutdown)(struct irq_data *data);
5 void (*irq_enable)(struct irq_data *data);
6 void (*irq_disable)(struct irq_data *data);
7
8 void (*irq_ack)(struct irq_data *data);
9 void (*irq_mask)(struct irq_data *data);
10 void (*irq_mask_ack)(struct irq_data *data);
11 void (*irq_unmask)(struct irq_data *data);
12 void (*irq_eoi)(struct irq_data *data);
13
14 int (*irq_set_affinity)(struct irq_data *data, const struct
cpumask *dest, bool force);
15 int (*irq_retrigger)(struct irq_data *data);
16 int (*irq_set_type)(struct irq_data *data, unsigned int
flow_type);
17 int (*irq_set_wake)(struct irq_data *data, unsigned int on);
18};

各个芯片公司会将芯片内部的中断控制器实现为irq_chip驱动的形式。受限于中断控制器硬件的能
力,这些成员函数并不一定需要全部实现,有时候只需要实现其中的部分函数即可。譬如
drivers/pinctrl/sirf/pinctrl-sirf.c驱动中的下面代码部分:

static struct irq_chip sirfsoc_irq_chip = {
.name = "sirf-gpio-irq",
.irq_ack = sirfsoc_gpio_irq_ack,
.irq_mask = sirfsoc_gpio_irq_mask,
.irq_unmask = sirfsoc_gpio_irq_unmask,
.irq_set_type = sirfsoc_gpio_irq_type,
};

我们只实现了其中的ack、mask、unmask和set_type成员函数,ack函数用于清中断,mask、unmask用
于中断屏蔽和取消中断屏蔽、set_type则用于配置中断的触发方式,如高电平、低电平、上升沿、下降沿
等。至于到enable_irq()的时候,虽然没有实现irq_enable()成员函数,但是内核会间接调用
irq_unmask()成员函数,这点从kernel/irq/chip.c中可以看出:

void irq_enable(struct irq_desc *desc)
{
irq_state_clr_disabled(desc);
if (desc->irq_data.chip->irq_enable)
desc->irq_data.chip->irq_enable(&desc->irq_data);
else
desc->irq_data.chip->irq_unmask(&desc->irq_data);
irq_state_clr_masked(desc);
}

在芯片内部,中断控制器可能不止1个,多个中断控制器之间还很可能是级联的。举个例子,假设芯
片内部有一个中断控制器,支持32个中断源,其中有4个来源于GPIO控制器外围的4组GPIO,每组GPIO
上又有32个中断(许多芯片的GPIO控制器也同时是一个中断控制器),其关系如图4所示。

在这里插入图片描述
图4 中断控制器典型分布图
那么,一般来讲,在实际操作中,gpio0_0~gpio0_31这些引脚本身在第1级会使用中断号28,而这些
引脚本身的中断号在实现与GPIO控制器对应的irq_chip驱动时,我们又会把它映射到Linux系统的32~63号
中断。同理,gpio1_0~gpio1_31这些引脚本身在第1级会使用中断号29,而这些引脚本身的中断号在实现
与GPIO控制器对应的irq_chip驱动时,我们又会把它映射到Linux系统的64~95号中断,以此类推。对于中
断号的使用者而言,无须看到这种2级映射关系。如果某设备想申请与gpio1_0这个引脚对应的中断,它只
需要申请64号中断即可。这个关系图看起来如图5所示。
在这里插入图片描述
图5 中断级联与映射

要特别注意的是,上述图4和5中所涉及的中断号的数值,无论是base还是具体某个GPIO对应的
中断号是多少,都不一定是如图20.4和图20.5所描述的简单线性映射。Linux使用IRQ Domain来描述一个
中断控制器所管理的中断源。换句话说,每个中断控制器都有自己的Domain。我们可以将IRQ Domain看
作是IRQ控制器的软件抽象。在添加IRQ Domain的时候,内核中存在的映射方法有:
irq_domain_add_legacy()、irq_domain_add_linear()、irq_domain_add_tree()等。

irq_domain_add_legacy()实际上是一种过时的方法,它一般是由IRQ控制器驱动直接指定中断源硬
件意义上的偏移(一般称为hwirq)和Linux逻辑上的中断号的映射关系。类似图20.5的指定映射可以被这
种方法弄出来。irq_domain_add_linear()则在中断源和irq_desc之间建立线性映射,内核针对这个IRQ
Domain维护了一个hwirq和Linux逻辑IRQ之间关系的一个表,这个时候我们其实也完全不关心逻辑中断号
了;irq_domain_add_tree()则更加灵活,逻辑中断号和hwirq之间的映射关系是用一棵radix树来描述的,
我们需要通过查找的方法来寻找hwirq和Linux逻辑IRQ之间的关系,一般适合某中断控制器支持非常多中
断源的情况。

实际上,在当前的内核中,中断号更多的是一个逻辑概念,具体数值是多少不是很关键。人们更多的
是关心在设备树中设置正确的interrupt_parrent和相对该interrupt_parent的偏移。
以drivers/pinctrl/sirf/pinctrl-sirf.c的irq_chip部分为例,在sirfsoc_gpio_probe()函数中,每组GPIO的中
断都通过gpiochip_set_chained_irqchip()级联到上一级中断控制器的中断。

代码清单5 二级GPIO中断级联到一级中断控制器

1static int sirfsoc_gpio_probe(struct device_node *np)
2{
3...
4for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
5 bank = &sgpio->sgpio_bank[i];
6 spin_lock_init(&bank->lock);
7 bank->parent_irq = platform_get_irq(pdev, i);
8 if (bank->parent_irq < 0) {
9 err = bank->parent_irq;
10 goto out_banks;
11 }
12
13 gpiochip_set_chained_irqchip(&sgpio->chip.gc,
14 &sirfsoc_irq_chip,
15 bank->parent_irq,
16 sirfsoc_gpio_handle_irq);
17}
18
19...
20}

下面用一个实例来呈现这个过程,假设GPIO0_0~31对应上级中断号28,而外设A使用了GPIO0_5(即
第0组GPIO的第5个),并假定外设A的中断号为37,即32+5,中断服务程序为deva_isr()。那么,当
GPIO0_5中断发生的时候,内核的调用顺序是:sirfsoc_gpio_handle_irq()->generic_handle_irq()-

deva_isr()。如果硬件的中断系统有更深的层次,这种软件上的中断服务程序级联实际上可以有更深的
级别。

在上述实例中,GPIO0_0~31的interrupt_parrent实际是上级中断控制器,而外设A的interrupt_parrent就
是GPIO0,这些都会在设备树中进行呈现。

特别值得一提的是,目前多数主流ARM芯片内部的一级中断控制器都使用了ARM公司的GIC,我们
几乎不需要实现任何代码,只需要在设备树中添加相关的节点。

如在arch/arm/boot/dts/exynos5250.dtsi中即含有:

gic:interrupt-controller@10481000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x10481000 0x1000>, <0x10482000 0x2000>;
};

打开drivers/irqchip/irq-gic.c,发现GIC驱动的入口声明如下:

IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);

这说明drivers/irqchip/irq-gic.c这个驱动可以兼容arm,gic-400、arm,cortex-a15-gic、arm,cortex-a7-gic
等,但是初始化函数都是统一的gic_of_init。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/1150.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32----MPU6050

前言&#xff1a;最近几个月没有写文章了&#xff0c;因为这学期的事情真的有点多&#xff0c;但是想了想&#xff0c;文章还是要更新&#xff0c;总结自己学习的知识&#xff0c;真的很重要&#xff01;&#xff01;&#xff01; 废话不多说&#xff0c;正文开始&#xff1a;…

【vue.js】在网页中实现一个金属抛光质感的按钮

文章目录前言效果电脑效果手机效果说明完整代码index.html前言 诶&#xff1f;这有一个按钮(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e;&#xff0c;这是一个在html中实现的具有金属质感并且能镜面反射的按钮~ 效果 电脑效果 手机效果 说明 主要思路是使用 navig…

【算法基础】二分图(染色法 匈牙利算法)

一、二分图 1. 染色法 一个图是二分图,当且仅当,图中不含奇数环。在判别一个图是否为二分图⑩,其实相当于染色问题,每条边的两个点必须是不同的颜色,一共有两种颜色,如果染色过程中出现矛盾,则说明不是二分图。 for i = 1 to n:if i 未染色DFS(i, 1); //将i号点染色未…

Leetcode138. 复制带随机指针的链表

复制带随机指针的链表 第一步 拷贝节点链接在原节点的后面 第二步拷贝原节点的random &#xff0c; 拷贝节点的 random 在原节点 random 的 next 第三步 将拷贝的节点尾插到一个新链表 ,并且将原链表恢复 从前往后遍历链表 ,将原链表的每个节点进行复制&#xff0c;并l链接到原…

【STL二】STL序列式容器(array、vector、deque、list、forward_list)

【STL二】STL序列式容器&#xff08;array、vector、deque、list、forward_list&#xff09;1.array<T,N>&#xff08;数组容器&#xff09;2.vector<T>&#xff08;向量容器&#xff09;3.deque<T>&#xff08;双端队列容器&#xff09;&#xff1a;4.list&…

第一个 Qt 程序

第一个 Qt 程序 “hello world ”的起源要追溯到 1972 年&#xff0c;贝尔实验室著名研究员 Brian Kernighan 在撰写 “B 语言教程与指导(Tutorial Introduction to the Language B)”时初次使用&#xff08;程序&#xff09;&#xff0c;这是目前已 知最早的在计算机著作中将…

用sql计算两个经纬度坐标距离(米数互转)

目录 一、sql示例&#xff08;由近到远&#xff09; 二 、参数讲解 三、查询效果 - 距离&#xff08;公里 / 千米&#xff09; 四、查询效果 - 距离&#xff08;米&#xff09; 五、距离四舍五入保留后2位小数&#xff08;java&#xff09; 一、sql示例&#xff08;由近到远…

2023年最新最全 VSCode 插件推荐

Visual Studio Code 是由微软开发的一款免费的、针对于编写现代Web和云应用的跨平台源代码编辑器。它包含了一个丰富的插件市场&#xff0c;提供了很多实用的插件。下面就来分享 2023 年前端必备的 VS Code 插件&#xff01; 前端框架 ES7 React/Redux/React-Native snippets …

【OpenCV】车牌自动识别算法的设计与实现

写目录一. &#x1f981; 设计任务说明1.1 主要设计内容1.1.1 设计并实现车牌自动识别算法&#xff0c;基本功能要求1.1.2 参考资料1.1.3 参考界面布局1.2 开发该系统软件环境及使用的技术说明1.3 开发计划二. &#x1f981; 系统设计2.1 功能分析2.1.1 车辆图像获取2.1.2 车牌…

渗透测试靶机vulnhub——DC3实战笔记

vm在导入虚拟机的时候把IDE里面的改成IDE 0:0信息收集fscan扫描存活主机目标机器是192.168.1.106nmap扫描端口nmap -A 192.168.1.106 -p- …

Linux中sudo,su与su -命令的区别

前言 su命令就是切换用户的工具&#xff0c;怎么理解呢&#xff1f;比如我们以普通用户tom登录的&#xff0c;但要添加用户任务&#xff0c;执行useradd &#xff0c;tom用户没有这个权限&#xff0c;而这个权限恰恰由root所拥有。解决办法无法有两个&#xff0c;一是退出tom用…

【AI 工具】文心一言内测记录

文章目录一、申请内测二、收到内测邀请三、激活内测四、开始使用1、普通对话2、生成图片3、生成代码4、写剧本5、生成小说五、问题反馈一、申请内测 到 https://yiyan.baidu.com/welcome 页面 , 点击 " 开始体验 " 按钮 , 申请试用 ; 申请时 , 需要填写相关信息 ; 主…

关于.Net和Java的看法——我见过最牛的一个小实习生经历

1、背景 笔者&#xff08;小方同学在学习&#xff09;是一个专科院校的一名普通学生&#xff0c;目前就职于某三线城市的WEB方面.Net开发实习生&#xff0c;在找实习期间和就业期间的一些看法&#xff0c;发表此文&#xff0c;纯个人想法&#xff0c;欢迎讨论&#xff0c;指正…

JavaWeb《一》概念、服务器部署及servlet

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; 本文是javaweb的第一篇&#xff0c;首先介绍了javaweb&#xff0c;然后进行了一个简单的web服务器部署&#xff0c;把我的一个网页发布到了云端&#xff0c;且叫他小Sa&#xff0c;目前啥也没有&#xff0c;之后会使…

【数据结构】万字深入浅出讲解单链表(附原码 | 超详解)

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;C语言实现数据结构 &#x1f4ac;总结&#xff1a;希望你看完…

进程和线程的区别和联系

进程和线程的区别和联系1. 认识线程2. 进程和线程的关系3. 进程和线程的区别4. 线程共享了进程哪些资源1. 上下文切换2. 线程共享了进程哪些资源1.代码区2. 数据区3. 堆区1. 认识线程 线程是进程的一个实体,它被包含在进程中,一个进程至少包含一个线程,一个进程也可以包含多个…

Python数据分析案例22——财经新闻可信度分析(线性回归,主成分回归,随机森林回归)

本次案例还是适合人文社科领域&#xff0c;金融或者新闻专业。本科生做线性回归和主成分回归就够了&#xff0c;研究生还可以加随机森林回归&#xff0c;其方法足够人文社科领域的硕士毕业论文了。 案例背景 有八个自变量&#xff0c;[微博平台可信度,专业性,可信赖性,转发量,…

什么是栈,如何实现?

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; “但有一枝堪比玉&#xff0c;何须九畹始征兰?” 前言&#xff1a; 栈是一种特殊的线性表&#xff0c;就像开盖的桶一样&#xff0c;从底部开始放数据&#xff0c;从顶部开始取数据&#xff0c;那么栈具体是…

最适合游戏开发的语言是什么?

建议初学者学习主流的开发技术 主流开发技术有大量成熟的教程、很多可以交流的学习者、及时的学习反馈等&#xff1b;技术的内里基本都是相同的&#xff0c;学习主流技术的经验、知识可以更好更快地疏通学习新知识和技术。 因此&#xff0c;对C#或者C二选一进行学习较好。 Un…

Linux: 以太网 PHY 驱动简析

文章目录1. 前言2. 背景3. 硬件拓扑4. 以太网卡 PHY 驱动实现4.1 MDIO 总线对象的创建和注册4.2 MDIO 总线从设的 创建注册 和 驱动注册的加载4.2.1 以太网的 PHY 设备创建和注册4.2.2 以太网的 PHY 设备驱动注册和加载4.3 绑定以太网卡的 MAC 和 PHY4.4 以太网卡 PHY 和 MAC 的…