A. 请教linux irq 中断能使用mutex互斥锁吗
从Backtrace来看,应该是i2c_transfer中调用mutex_lock导致schele调用而产生进程调度,导致死机.而在中断上下文,这种情况是绝对不允许发生的.换句话说是不允许
睡眠的,不允许进程调度.
你可以把mutex_lock注释掉再试试.
B. 请教linux irq 中断能使用mutex互斥锁吗
多线程的效果就是同一时间各个线程都在执行。 加锁不是给线程上锁。 pthread_mutex_lock(&qlock);表示尝试去把qlock上锁,它会先判断qlock是否已经上锁,如果已经上锁这个线程就会停在这一步直到其他线程把锁解开。它才继续运行。 所以代码中要...
C. linux驱动中断,程序运行几个小时后系统崩溃
中断与定时器:
中断的概念:指CPU在执行过程中,出现某些突发事件急待处理,CPU暂停执行当前程序,转去处理突发事件
,处理完后CPU又返回原程序被中断的位置继续执行
中断的分类:内部中断和外部中断
内部中断:中断源来自CPU内部(软件中断指令、溢出、触发错误等)
外部中断:中断源来自CPU外部,由外设提出请求
屏蔽中断和不可屏蔽中断:
可屏蔽中断:可以通过屏蔽字被屏蔽,屏蔽后,该中断不再得到响应
不可平布中断:不能被屏蔽
向量中断和非向量中断:
向量中断:CPU通常为不同的中断分配不同的中断号,当检测到某中断号的中断到来后,就自动跳转到与该中断号对应的地址执行
非向量中断:多个中断共享一个入口地址。进入该入口地址后再通过软件判断中断标志来识别具体哪个是中断
也就是说向量中断由软件提供中断服务程序入口地址,非向量中断由软件提供中断入口地址
/*典型的非向量中断首先会判断中断源,然后调用不同中断源的中断处理程序*/
irq_handler()
{
...
int int_src = read_int_status();/*读硬件的中断相关寄存器*/
switch(int_src){//判断中断标志
case DEV_A:
dev_a_handler();
break;
case DEV_B:
dev_b_handler();
break;
...
default:
break;
}
...
}
定时器中断原理:
定时器在硬件上也以来中断,PIT(可编程间隔定时器)接收一个时钟输入,
当时钟脉冲到来时,将目前计数值增1并与已经设置的计数值比较,若相等,证明计数周期满,产生定时器中断,并
复位计数值。
如下图所示:
Linux中断处理程序架构:
Linux将中断分为:顶半部(top half)和底半部(bottom half)
顶板部:完成尽可能少的比较紧急的功能,它往往只是简单的读取寄存器中的中断状态并清除中断标志后就进行
“登记中断”(也就是将底半部处理程序挂在到设备的底半部执行队列中)的工作
特点:响应速度快
底半部:中断处理的大部分工作都在底半部,它几乎做了中断处理程序的所有事情。
特点:处理相对来说不是非常紧急的事件
小知识:Linux中查看/proc/interrupts文件可以获得系统中断的统计信息。
如下图所示:
第一列是中断号 第二列是向CPU产生该中断的次数
介绍完相关基础概念后,让我们一起来探讨一下Linux中断编程
Linux中断编程:
1.申请和释放中断
申请中断:
int request_irq(unsigned int irq,irq_handler_t handler,
unsigned long irqflags,const char *devname,void *dev_id)
参数介绍:irq是要申请的硬件中断号
handler是向系统登记的中断处理程序(顶半部),是一个回调函数,中断发生时,系统调用它,将
dev_id参数传递给它
irqflags:是中断处理的属性,可以指定中断的触发方式和处理方式:
触发方式:IRQF_TRIGGER_RISING、IRQF_TRIGGER_FALLING、IRQF_TRIGGER_HIGH、IRQF_TRIGGER_LOW
处理方式:IRQF_DISABLE表明中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断
IRQF_SHARED表示多个设备共享中断,dev_id在中断共享时会用到,一般设置为NULL
返回值:为0表示成功,返回-EINVAL表示中断号无效,返回-EBUSY表示中断已经被占用,且不能共享
顶半部的handler的类型irq_handler_t定义为
typedef irqreturn_t (*irq_handler_t)(int,void*);
typedef int irqreturn_t;
2.释放IRQ
有请求当然就有释放了
void free_irq(unsigned int irq,void *dev_id);
参数定义与request_irq类似
3.使能和屏蔽中断
void disable_irq(int irq);//等待目前中断处理完成(最好别在顶板部使用,你懂得)
void disable_irq_nosync(int irq);//立即返回
void enable_irq(int irq);//
4.屏蔽本CPU内所有中断:
#define local_irq_save(flags)...//禁止中断并保存状态
void local_irq_disable(void);//禁止中断,不保存状态
下面来分别介绍一下顶半部和底半部的实现机制
底半部机制:
简介:底半部机制主要有tasklet、工作队列和软中断
1.底半部是想方法之一tasklet
(1)我们需要定义tasklet机器处理器并将两者关联
例如:
void my_tasklet_func(unsigned long);/*定义一个处理函数*/
DECLARE_TASKLET(my_tasklet,my_tasklet_func,data);
/*上述代码定义了名为my_tasklet的tasklet并将其余
my_tasklet_func()函数绑定,传入的参数为data*/
(2)调度
tasklet_schele(&my_tasklet);
//使用此函数就能在是当的时候进行调度运行
tasklet使用模板:
/*定义tasklet和底半部函数并关联*/
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet,xxx_do_tasklet,0);
/*中断处理底半部*/
void xxx_do_tasklet(unsigned long)
{
...
}
/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq,void *dev_id)
{
...
tasklet_schele(&xxx_tasklet);//调度地板部
...
}
/*设备驱动模块加载函数*/
int __init xxx_init(void)
{
...
/*申请中断*/
result = request_irq(xxx_irq,xxx_interrupt,
IRQF_DISABLED,"xxx",NULL);
...
return IRQ_HANDLED;
}
/*设备驱动模块卸载函数*/
void __exit xxx_exit(void)
{
...
/*释放中断*/
free_irq(xxx_irq,xxx_interrupt);
...
}
2.底半部实现方法之二---工作队列
使用方法和tasklet类似
相关操作:
struct work_struct my_wq;/*定义一个工作队列*/
void my_wq_func(unsigned long);/*定义一个处理函数*/
通过INIT_WORK()可以初始化这个工作队列并将工作队列与处理函数绑定
INIT_WORK(&my_wq,(void (*)(void *))my_wq_func,NULL);
/*初始化工作队列并将其与处理函数绑定*/
schele_work(&my_wq);/*调度工作队列执行*/
/*工作队列使用模板*/
/*定义工作队列和关联函数*/
struct work_struct(unsigned long);
void xxx_do_work(unsigned long);
/*中断处理底半部*/
void xxx_do_work(unsigned long)
{
...
}
/*中断处理顶半部*/
/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq,void *dev_id)
{
...
schele_work(&my_wq);//调度底半部
...
return IRQ_HANDLED;
}
/*设备驱动模块加载函数*/
int xxx_init(void)
{
...
/*申请中断*/
result = request_irq(xxx_irq,xxx_interrupt,
IRQF_DISABLED,"xxx",NULL);
...
/*初始化工作队列*/
INIT_WORK(&my_wq,(void (*)(void *))xxx_do_work,NULL);
}
/*设备驱动模块卸载函数*/
void xxx_exit(void)
{
...
/*释放中断*/
free_irq(xxx_irq,xxx_interrupt);
...
}
D. linux系统中的中断指令是什么
什么是中断
Linux 内核需要对连接到计算机上的所有硬件设备进行管理,毫无疑问这是它的份内事。如果要管理这些设备,首先得和它们互相通信才行,一般有两种方案可实现这种功能:
轮询(polling) 让内核定期对设备的状态进行查询,然后做出相应的处理;中断(interrupt) 让硬件在需要的时候向内核发出信号(变内核主动为硬件主动)。
第一种方案会让内核做不少的无用功,因为轮询总会周期性的重复执行,大量地耗用 CPU 时间,因此效率及其低下,所以一般都是采用第二种方案 。
对于中断的理解我们先看一个生活中常见的例子:QQ。第一种情况:你正在工作,然后你的好友突然给你发送了一个窗口抖动,打断你正在进行的工作。第
二种情况:当然你有时候也会每隔 5 分钟就去检查一下 QQ
看有没有好友找你,虽然这很浪费你的时间。在这里,一次窗口抖动就可以被相当于硬件的中断,而你就相当于 CPU,你的工作就是 CPU
这在执行的进程。而定时查询就被相当于 CPU 的轮询。在这里可以看到:同样作为 CPU 和硬件沟通的方式,中断是硬件主动的方式,较轮询(CPU
主动)更有效些,因为我们都不可能一直无聊到每隔几分钟就去查一遍好友列表。
CPU
有大量的工作需要处理,更不会做这些大量无用功。当然这只是一般情况下。好了,这里又有了一个问题,每个硬件设备都中断,那么如何区分不同硬件呢?不同设
备同时中断如何知道哪个中断是来自硬盘、哪个来自网卡呢?这个很容易,不是每个 QQ 号码都不相同吗?同样的,系统上的每个硬件设备都会被分配一个
IRQ 号,通过这个唯一的 IRQ 号就能区别张三和李四了。
从物理学的角度看,中断是一种电信号,由硬件设备产生,并直接送入中断控制器(如
8259A)的输入引脚上,然后再由中断控制器向处理器发送相应的信号。处理器一经检测到该信号,便中断自己当前正在处理的工作,转而去处理中断。此后,
处理器会通知 OS 已经产生中断。这样,OS
就可以对这个中断进行适当的处理。不同的设备对应的中断不同,而每个中断都通过一个唯一的数字标识,这些值通常被称为中断请求线。
E. 请教linux irq 中断能使用mutex互斥锁吗
从Backtrace来看,应该是i2c_transfer中调用mutex_lock导致schele调用
而产生进程调度,导致死机.而在中断上下文,这种情况是绝对不允许发生的.换句话说是不允许
睡眠的,不允许进程调度.
你可以把mutex_lock注释掉再试试.
F. 初学linux触摸屏驱动,请求IRQ_ADC和IRQ_TC中断总是返回EBUSY,请问怎么解决啊
是该中断线被占用了,可能是其他设备占用的,把那个地方找到,把中断线释放掉就行了
G. Linux下通过哪个命令怎么查看中断
与Linux设备驱动中中断处理相关的首先是申请与释放IRQ的API request_irq()和free_irq()。
C++是一种面向对象的计算机程序设计语言,由美国AT&T贝尔实验室的本贾尼·斯特劳斯特卢普博士在20世纪80年代初期发明并实现,最初它被称作“C with Classes”(包含类的C语言)。
它是一种静态数据类型检查的、支持多重编程范式的通用程序设计语言,支持过程化程序设计、数据抽象、面向对象程序设计、泛型程序设计等多种程序设计风格。
在C基础上,一九八三年又由贝尔实验室的Bjarne Strou-strup推出了C++,C++进一步扩充和完善了C语言,成为一种面向 对象的程序设计语言。
C++目前流行的编译器最新版本是Borland C++ 4.5,Symantec C++ 6.1,和Microsoft Visual C++ 2012。
H. linux禁用、打开中断
local_irq_save是内核中用的函数吧,不能用到应用层。
对 local_irq_save的调用将把当前中断状态保存到flags中,然后禁用当前处理器上的中断发送。
unsigned long flags;
local_irq_save(flags); //禁止
local_irq_restore(flags); // 激活
I. Linux 系统中的中断是不是没有中断优先级
关于中断嵌套:在linux内核里,如果驱动在申请注册中断的时候没有特别的指定,do_irq在做中断响应的时候,是开启中断的,如果在驱动的中断处理函数正在执行的过程中,出现同一设备的中断或者不同设备的中断,这时候新的中断会被立即处理,还是被pending,等当前中断处理完成后,再做处理。在2.4和2.6内核里,关于这一块是否有什么不同。 一般申请中断的时候都允许开中断,即不使用SA_INTERRUPT标志。如果允许共享则加上 SA_SHIRQ,如果可以为内核熵池提供熵值(譬如你写的驱动是ide之类的驱动),则再加上 SA_SAMPLE_RANDOM标志。这是普通的中断请求过程。对于这种一般情况,只要发生中断,就可以抢占内核,即使内核正在执行其他中断函数。这里有两点说明:一是因为linux不支持 中断优先级,因此任何中断都可以抢占其他中断,但是同种类型的中断(即定义使用同一个 中断线的中断)不会发生抢占,他们会在执行本类型中断的时候依次被调用执行。二是所谓 只要发生中断,就可以抢占内核这句是有一定限制的,因为当中断发生的时候系统由中断门 进入时自动关中断(对于x86平台就是将eflags寄存器的if位置为0),只有当中断函数被执行 (handle_IRQ_event)的过程中开中断之后才能有抢占。 对于同种类型的中断,由于其使用同样的idt表项,通过其状态标志(IRQ_PENDING和 IRQ_INPROGRESS)可以防止同种类型的中断函数执行(注意:是防止handle_IRQ_event被重入, 而不是防止do_IRQ函数被重入),对于不同的中断,则可以自由的嵌套。因此,所谓中断嵌套, 对于不同的中断是可以自由嵌套的,而对于同种类型的中断,是不可以嵌套执行的。以下简单解释一下如何利用状态标志来防止同种类型中断的重入:当某种类型的中断第一次发生时,首先其idt表项的状态位上被赋予IRQ_PENDING标志,表示有待处理。 然后将中断处理函数action置为null,然后由于其状态没有IRQ_INPROGRESS标志(第一次),故将其状态置上IRQ_INPROGRESS并去处IRQ_PENDING标志,同时将action赋予相应的中断处理函数指针(这里是一个重点,linux很巧妙的用法,随后说明)。这样,后面就可以顺利执行handle_IRQ_event进行中断处理,当在handle_IRQ_event中开中断后,如果有同种类型的中断发生,则再次进入do_IRQ函数,然后其状态位上加上IRQ_PENDING标志,但是由于前一次中断处理中加上的IRQ_INPROGRESS没有被清除,因此这里无法清除IRQ_PENDING标志,因此action还是为null,这样就无法再次执行handle_IRQ_event函数。从而退出本次中断处理,返回上一次的中断处理函数中,即继续执行handle_IRQ_event函数。当handle_IRQ_event返回时检查IRQ_PENDING标志,发现存在这个标志,说明handle_IRQ_event执行过程中被中断过,存在未处理的同类中断,因此再次循环执行handle_IRQ_event函数。直到不存在IRQ_PENDING标志为止。2.4和2.6的差别,就我来看,主要是在2.6中一进入do_IRQ,多了一个关闭内核抢占的动作,同时在处理中多了一种对IRQ_PER_CPU类型的中断的处理,其他没有什么太大的改变。这类IRQ_PER_CPU的中断主要用在smp环境下将中断绑定在某一个指定的cpu上。例如arch/ppc/syslib/open_pic.c中的openpic_init中初始化ipi中断的时候。 其实简单的说,中断可以嵌套,但是同种类型的中断是不可以嵌套的,因为在IRQ上发生中断,在中断响应的过程中,这个IRQ是屏蔽的,也就是这个IRQ的中断是不能被发现的。 同时在内核的临界区内,中断是被禁止的 关于do_IRQ可能会丢失中断请求:do_IRQ函数是通过在执行完handle_IRQ_event函数之后判断status是否被设置了IRQ_PENDING标志来判断是否还有没有被处理的同一通道的中断请求。 但是这种方法只能判断是否有,而不能知道有多少个未处理的统一通道中断请求。也就是说,假如在第一个中断请求执行handle_IRQ_event函数的过程中来了同一通道的两个或更多中断请求,而这些中断不会再来,那么仅仅通过判断status是否设置了IRQ_PENDING标志不知道到底有多少个未处理的中断,handle_IRQ_event只会被再执行一次。这算不算是个bug呢? 不算,只要知道有中断没有处理就OK了,知道1个和知道N个,本质上都是一样的。作为外设,应当能够处理自己中断未被处理的情况。不可能丢失的,在每一个中断描述符的结构体内,都有一个链表,链表中存放着服务例程序关于中断中使用的几个重要概念和关系: 一、基本概念 1. 产生的位置 发生的时刻 时序 中断 CPU外部 随机 异步 异常 CPU正在执行的程序 一条指令终止执行后 同步 2.由中断或异常执行的代码不是一个进程,而是一个内核控制路径,代表中断发生时正在运行的进程的执行 中断处理程序与正在运行的程序无关 引起异常处理程序的进程正是异常处理程序运行时的当前进程 二、特点 (2)能以嵌套的方式执行,但是同种类型的中断不可以嵌套 (3)尽可能地限制临界区,因为在临界区中,中断被禁止 2.大部分异常发生在用户态,缺页异常是唯一发生于内核态能触发的异常 缺页异常意味着进程切换,因此中断处理程序从不执行可以导致缺页的操作 3.中断处理程序运行于内核态 中断发生于用户态时,要把进程的用户空间堆栈切换到进程的系统空间堆栈,刚切换时,内核堆栈是空的 中断发生于内核态时, 不需要堆栈空间的切换 三、分类 1.中断的分类:可屏蔽中断、不可屏蔽中断 2.异常的分类: 分类 解决异常的方法 举例 故障 那条指令会被重新执行 缺页异常处理程序 陷阱 会从下一条指令开始执行 调试程序
J. Linux如何及时响应外部中断
FPGA每隔100us给运行linux的ARM一个中断,要求在20us内响应中断,并读走2000*16bit的数据。
目前主要的问题是,当系统同时发生多个中断时,会严重影响linux对FPGA中断的响应时间。如何解决?
1、首先想到了ARM的FIQ,它可以打断IRQ中断服务程序,保证对外部FIQ的及时响应。但是发现linux只实现了IRQ,没有显示FIQ。
linux是从devicetree读取中断号,加入中断向量表的。
interrupts = <0x0 0x32 0x0>;中的第一个字段0表示非共享中断,非零表示共享中断,SDK产生的dts统一为0,此时第二字段的值比XPS中的小32;如果第一字段非零,则第二字段比XPS小16.
最后字段表示中断的触发方式。
IRQ_TYPE_EDGE_RISING =0x00000001,
IRQ_TYPE_EDGE_FALLING =0x00000002,
IRQ_TYPE_LEVEL_HIGH =0x00000004,
IRQ_TYPE_LEVEL_LOW =0x00000008,
很明显,devicetree根本没有提供通知linux有FIQ的渠道。
2、再来看linux的IRQ
linux的中断分为上半部和下半部,上半部运行在IRQ模式,会屏蔽所有中断,下半部运行在SVC模式,会重新打开中断。
也就是说,当一个中断的上半部正在运行时(不能再次响应中断),FPGA的中断是不能被linux响应的;
反过来,当FPGA中断的上半部正在运行时(不能再次响应中断),其他的中断也不能被linux响应;
unsigned long flags;
...
local_irq_save(flags);
....
local_irq_restore(flags);
3.
ARM有七种模式,我们这里只讨论SVC、IRQ和FIQ模式。
我们可以假设ARM核心有两根中断引脚(实际上是看不见的),一根叫 irq pin, 一根叫fiq pin.
在ARM的cpsr中,有一个I位和一个F位,分别用来禁止IRQ和FIQ的。
先不说中断控制器,只说ARM核心。正常情况下,ARM核都只是机械地随着pc的指示去做事情,当CPSR中的I和F位为1的时候,IRQ和FIQ全部处于禁止状态。无论你在irq
pin和fiq pin上面发什么样的中断信号,ARM是不会理你的,你根本不能打断他,因为他耳聋了,眼也瞎了。
在I位和F位为0的时候,当irq
pin上有中断信号过来的时候,就会打断arm的当前工作,并且切换到IRQ模式下,并且跳到相应的异常向量表(vector)位置去执行代码。这个过程是自动的,但是返回到被中断打断的地方就得您亲自动手了。当你跳到异常向量表,处于IRQ的模式的时候,这个时候如果irq
pin上面又来中断信号了,这个时候ARM不会理你的,irq
pin就跟秘书一样,ARM核心就像老板,老板本来在做事,结果来了一个客户,秘书打断它,让客户进去了。而这个时候再来一个客户,要么秘书不断去敲门问,要么客户走人。老板第一个客户没有会见完,是不会理你的。
但是有一种情况例外,当ARM处在IRQ模式,这个时候fiq pin来了一个中断信号,fiq
pin是什么?是快速中断呀,比如是公安局的来查刑事案件,那才不管你老板是不是在会见客户,直接打断,进入到fiq模式下,并且跳到相应的fiq的异常向量表处去执行代码。那如果当ARM处理FIQ模式,fiq
pin又来中断信号,又就是又一批公安来了,那没戏,都是执法人员,你打不断我。那如果这个时候irq
pin来了呢?来了也不理呀,正在办案,还敢来妨碍公务。
所以得出一个结论: IRQ模式只能被FIQ模式打断,FIQ模式下谁也打不断。
在打不断的情况下,irq pin 或 fiq pin随便你怎么发中断信号,都是白发。
所以除了fiq能打断irq以外,根本没有所谓中断嵌套的情况。
Linux不用FIQ,只用到了IRQ。但是我们有时候一个中断需要处理很长时间,那我们就需要占用IRQ模式那么长的时间吗?没有,linux在IRQ模式下只是简单的记录是什么中断,马上就切换回了SVC模式,换句话说,Linux的中断处理都是在SVC模式下处理的。
只不过SVC模式下的ISR上半部关闭了当前中断线,下半部才重新打开