linux irq 自动探测
前言
编写驱动的时候,经常会用到中断,这时候我们在驱动初始化时就得申请中断,那么问题来了,中断号是多少呢?以前的中断号在板级相关的头文件里面已经静态定义好了,bsp的代码在内核启动过程也会根据那个帮我们建立好hw irq到irq的映射,我们直接用它静态定义的irq就可以了。但是在硬件越来越复杂的今天,经常会碰到一个系统里同时有几个中断控制器同时存在的情况(级联),内核因此实现了另一套处理机制(irq domain),这个时候,我们通过翻看datasheet,也仅仅能知道hw irq,最终具体映射到哪个irq上了呢,还真不是那么容易知道的,运气好的呢,在sdk开发文档里面已经标明清楚了,否则我们就只能read the fucking source code了。当然,我们还有另一种尝试方法,就是内核提供的irq探测机制。
irq探测机制使用
以下是LDD3中的并口示例代码:
int count = 0;
do
{
unsigned long mask;
mask = probe_irq_on();
outb_p(0x10,short_base+2); /* enable reporting */
outb_p(0x00,short_base); /* clear the bit */
outb_p(0xFF,short_base); /* set the bit: interrupt! */
outb_p(0x00,short_base+2); /* disable reporting */
udelay(5); /* give it some time */
short_irq = probe_irq_off(mask);
if (short_irq == 0) { /* none of them? */
printk(KERN_INFO "short: no irq reported by probe\n");
short_irq = -1;
}
} while (short_irq < 0 && count++ < 5);
if (short_irq < 0)
printk("short: probe failed %i times, giving up\n", count);
调用probe_irq_on函数之后,驱动程序要安排设备产生至少一次中断,上面的例子就是通过控制寄存器来使设备触发一次中断,在设备产生中断之后,驱动程序要调用probe_irq_off,并将前面probe_irq_on返回的位掩码作为参数传递给它(其实该掩码暂时无意义,后面分析内部实现的时候会发现这点)。probe_irq_off返回probe_irq_on之后发生的中断编号。如果没有中断发生,就返回0。如果产生了多次中断,出现了二义性,就返回负数(该负数是最小中断号的负数)。
使用内核提供的接口探测中断号时,需要注意在调用probe_irq_on之后启用设备中断,在调用probe_irq_off之前禁用中断。另外,在probe_irq_off之后,需要处理设备上待处理的中断,同时,irq探测机制是不适合中断共享方式的。
irq 探测原理
需要注意的是,只有在配置了CONFIG_GENERIC_IRQ_PROBE的时候,irq探测机制才会生效。下面看probe_irq_on内部实现:
/*
* Autodetection depends on the fact that any interrupt that
* comes in on to an unassigned handler will get stuck with
* "IRQS_WAITING" cleared and the interrupt disabled.
*/
unsigned long probe_irq_on(void)
{
struct irq_desc *desc;
unsigned long mask = 0;
int i;
/*
* quiesce the kernel, or at least the asynchronous portion
*/
async_synchronize_full();
mutex_lock(&probing_active);
/*
* something may have generated an irq long ago and we want to
* flush such a longstanding irq before considering it as spurious.
*/
for_each_irq_desc_reverse(i, desc) {
raw_spin_lock_irq(&desc->lock);
if (!desc->action && irq_settings_can_probe(desc)) {
/*
* Some chips need to know about probing in
* progress:
*/
if (desc->irq_data.chip->irq_set_type)
desc->irq_data.chip->irq_set_type(&desc->irq_data,
IRQ_TYPE_PROBE);
irq_startup(desc, false);
}
raw_spin_unlock_irq(&desc->lock);
}
/* Wait for longstanding interrupts to trigger. */
msleep(20);
/*
* enable any unassigned irqs
* (we must startup again here because if a longstanding irq
* happened in the previous stage, it may have masked itself)
*/
for_each_irq_desc_reverse(i, desc) {
raw_spin_lock_irq(&desc->lock);
if (!desc->action && irq_settings_can_probe(desc)) {
desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;
if (irq_startup(desc, false))
desc->istate |= IRQS_PENDING;
}
raw_spin_unlock_irq(&desc->lock);
}
/*
* Wait for spurious interrupts to trigger
*/
msleep(100);
/*
* Now filter out any obviously spurious interrupts
*/
for_each_irq_desc(i, desc) {
raw_spin_lock_irq(&desc->lock);
if (desc->istate & IRQS_AUTODETECT) {
/* It triggered already - consider it spurious. */
if (!(desc->istate & IRQS_WAITING)) {
desc->istate &= ~IRQS_AUTODETECT;
irq_shutdown(desc);
} else
if (i < 32)
mask |= 1 << i;
}
raw_spin_unlock_irq(&desc->lock);
}
return mask;
}
三次循环遍历irq_desc,第一次反向遍历,如果对应的irq还没有注册,即desc->action为NULL,且该irq允许探测irq_settings_can_probe(desc),那么使能该中断;第二次还是反向遍历,如果对应的irq还没有注册且允许探测,那么就在该irq对应的desc上的istate里添加IRQS_AUTODETECT | IRQS_WAITING标志;第三次,正向遍历,如果发现irq对应的desc上的istate的IRQS_AUTODETECT存在,但是它的IRQS_WAITING被清除了,那么说明运行到这里,发生了莫名其妙的中断,这个中断当然不是我们将要探测的中断,毕竟我们都还没触发它产生中断,于是就清除掉IRQS_AUTODETECT并禁用它的中断。从上面的分析可以看出,probe_irq_on就是在适合的中断上添加了IRQS_AUTODETECT | IRQS_WAITING标志,并暂时开启了它们的中断能力。
分析完probe_irq_on,现在继续分析probe_irq_off:
int probe_irq_off(unsigned long val)
{
int i, irq_found = 0, nr_of_irqs = 0;
struct irq_desc *desc;
for_each_irq_desc(i, desc) {
raw_spin_lock_irq(&desc->lock);
if (desc->istate & IRQS_AUTODETECT) {
if (!(desc->istate & IRQS_WAITING)) {
if (!nr_of_irqs)
irq_found = i;
nr_of_irqs++;
}
desc->istate &= ~IRQS_AUTODETECT;
irq_shutdown(desc);
}
raw_spin_unlock_irq(&desc->lock);
}
mutex_unlock(&probing_active);
if (nr_of_irqs > 1)
irq_found = -irq_found;
return irq_found;
}
注意,在probe_irq_off前,需要我们自己触发中断,这个请参考前面的例子。probe_irq_off里面就是一次遍历,寻找有设置IRQS_AUTODETECT,但是无IRQS_WAITING的,这种情况,意味着该irq号对应的设备有中断产生(后面我会分析具体清除IRQS_WAITING的地方)。另外,我们也会发现,probe_irq_off只会记录第一个发现的中断,并且在发现有多个中断产生时,会将第一个发现的中断号取反并返回。
下面分析下具体清除IRQS_WAITING的地方,以以前的中断处理为例,毕竟现在的中断控制器都会定义自己控制器的中断处理,各式各样,这里面的思想是一样的。当一个中断产生时,调用的逻辑如下:
irq_handler-->arch_irq_handler_default-->asm_do_IRQ-->handle_IRQ-->generic_handle_irq-->generic_handle_irq_desc-->desc->handle_irq-->handle_level_irq|handle_edge_irq
在handle_level_irq中:
void
handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
...
...
...
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
...
...
...
}
这说明,只要某个irq有中断产生,它对应的desc里面的IRQS_WAITING就会被清除。
总结
本文讨论的中断探测机制在我们不知道中断号的情况时,也不失为一种获取中断号的方法,对吧!
完!
2013年7月
linux irq 自动探测的更多相关文章
- Linux轻量级自动运维工具-Ansible浅析【转】
转自 Linux轻量级自动运维工具-Ansible浅析 - ~微风~ - 51CTO技术博客http://weiweidefeng.blog.51cto.com/1957995/1895261 Ans ...
- Linux轻量级自动运维工具-Ansible浅析 转
转自 Linux轻量级自动运维工具-Ansible浅析 - ~微风~ - 51CTO技术博客http://weiweidefeng.blog.51cto.com/1957995/1895261 Ans ...
- Linux 每天自动备份mysql数据库的方法
Linux 每天自动备份mysql数据库的方法 作者: 字体:[增加 减小] 类型:转载 linux下为了安全有时候需要自动备份mysql数据库,下面是具体的实现步骤. /usr/bin为my ...
- linux - 怎么自动填写有交互的shell脚本 - SegmentFault
linux - 怎么自动填写有交互的shell脚本 - SegmentFault TCL/Expect交互式自动化测试概要 - - ITeye技术网站 expect是一种基于TCL,能与交互式程序进行 ...
- Linux Makefile自动生成--config.h
Linux Makefile自动生成--config.h http://blog.csdn.net/spch2008/article/details/12510805
- 在 Linux 中自动生成 Cordova/Phonegap for Android 的 APK 安装程序
在 Linux 中自动生成 Cordova/Phonegap for Android 的 APK 安装程序 本贴首发于: http://xuekaiyuan.com/forum.php?mod=vie ...
- Linux项目自动部署
场景:linux中自动部署项目在工作中经常遇到,快速高效的部署项目能够大幅提高工作效率.现在将项目部署的过程记录下来,以供参考,其中用到的知识点现在还有很多不很清楚,后面要好好琢磨琢磨! 1 项目部署 ...
- Linux下自动备份MySQL数据库并上传到远程FTP服务器
Linux下自动备份MySQL数据库并上传到远程FTP服务器且删除指定日期前的备份Shell脚本 说明: 1.备份MySQL数据库存放目录/var/lib/mysql下面的xshelldata数据库 ...
- 在 Linux 中自动配置 IPv6 地址
在 Linux 中自动配置 IPv6 地址 在本文中,我们将学习如何为 ULA 自动配置 IP 地址. 何时使用唯一本地地址 唯一本地地址unique local addresses(ULA)使用 f ...
随机推荐
- 【bzoj4300】绝世好题 dp
题目描述 给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len). 输入 输入文件共2行. 第一行包括一个整数n. 第二行包括n个 ...
- P3808 【模板】AC自动机(简单版)
题目背景 这是一道简单的AC自动机模板题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 管理员提示:本题数据内有重复的单词,且重复单词应该计算多次, ...
- ictclas4j 分词工具包 安装流程
首先把 ictclasj解压缩,然后 1.把 Data文件夹整个拷贝到 Eclipse项目的文件夹下, 2.而 bin目录下的 org文件夹整个拷贝到你 Eclipse项目的 bin目录下,(将cla ...
- [牛客练习赛29D]禁止动规
description newcoder 你在一个无限长的数轴上,一开始你在原点 本来你只有两种操作:向左dp,以及向右dp 然而由于禁止dp 于是你只能另寻出路 万幸的是,dp之神随机给了你n个变量 ...
- BZOJ3926:[ZJOI2015]诸神眷顾的幻想乡——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3926 https://www.luogu.org/problemnew/show/P3346 幽香 ...
- BZOJ1047:[HAOI2007]理想的正方形——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=1047 https://www.luogu.org/problemnew/show/P2216#sub ...
- BZOJ3329:Xorequ——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=3329 原式化为x^2x=3x,而且实际上异或就是不进位的加法. 那么我们又有x+2x=3x,所以在做 ...
- BZOJ2659 [Beijing wc2012]算不出的算式 【数形结合】
题目链接 BZOJ2659 题解 真没想到,, 观察式子 \[\sum\limits_{k = 1}^{\frac{p - 1}{2}} \lfloor \frac{kq}{p} \rfloor\] ...
- HDOJ(HDU).2159 FATE (DP 带个数限制的完全背包)
HDOJ(HDU).2159 FATE (DP 带个数限制的完全背包) 题意分析 与普通的完全背包大同小异,区别就在于多了一个个数限制,那么在普通的完全背包的基础上,增加一维,表示个数.同时for循环 ...
- Spring多个数据源问题:DataSourceAutoConfiguration required a single bean, but * were found
原因: @EnableAutoConfiguration 这个注解会把配置文件号中的数据源全部都自动注入,不会默认注入一个,当使用其他数据源时再调用另外的数据源. 解决方法: 1.注释掉这个注解 2. ...