欢迎来到Doc100.Net免费学习资源知识分享平台!
您的位置:首页 > 程序异常 >

linux中止的沿触发和电平触发

更新时间: 2014-05-15 02:01:32 责任编辑: Author_N3

 

Linux中断的沿触发和电平触发

Linux中断的沿触发和电平触发

 

初始化中断向量表时,有一个重要的操作就是set_irq_handler。这个函数参数一般为handle_edge_irq或者handle_level_irq。对于边缘中断,使用handle_edge_irq作参数;对于电平中断,使用handle_level_irq作为中断。那这两个函数有什么区别呢?

1. handle_edge_irq

kernel源代码中的注释为:

c代码

/**
* handle_edge_irq - edge type IRQ handler
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
*
* Interrupt occures on the falling and/or rising edge of a hardware
* signal. The occurence is latched into the irq controller hardware
* and must be acked in order to be reenabled. After the ack another
* interrupt can happen on the same source even before the first one
* is handled by the assosiacted event handler. If this happens it
* might be necessary to disable (mask) the interrupt depending on the
* controller hardware. This requires to reenable the interrupt inside
* of the loop which handles the interrupts which have arrived while
* the handler was running. If all pending interrupts are handled, the
* loop is left.
*/

下面翻译为中文:

中断发生在硬件信号的上升沿/下降沿。中断事件保存在中断控制器中并且必须被立刻响应以重新打开中断。响应之后,即使第一个中断还没有被相关的中断函数处理完,另一个中断也可能在同一个中断源发生。如果这种情况发生的话就有必要关闭中断。这样,在中断处理函数运行时发生的中断就会被标记为阻塞,在中断处理循环处理完这些阻塞的中断之后,就有必要在循环内部重新打开中断。如果全部的阻塞中断处理完毕,就可以离开中断处理循环。

2. handle_level_irq

c代码

/**
* handle_level_irq - Level type irq handler
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
*
* Level type interrupts are active as long as the hardware line has
* the active level. This may require to mask the interrupt and unmask
* it after the associated handler has acknowledged the device, so the
* interrupt line is back to inactive.
*/

一旦硬件线路达到了激活电平,电平类型的中断就会被触发。这可能需要屏蔽中断,并且在相关的中断处理程序响应了设备之后重新打开中断,这样中断线才能恢复反激活状态。

对比上述两个函数可见,对于电平中断,一进入中断处理程序就会立刻屏蔽中断,直到退出中断的时候才会unmask中断;而对于边缘中断,除非在处理当前中断时有一个新的中断被触发否则不会屏蔽中断。这两个处理函数的特点刚好和这两种中断的特点一致:对于电平中断,只要中断脚在激活电平电平,就会不断地触发中断;而边缘中断只在上升沿或者下降沿被触发。

下面是linux 2.6.32版本kernel的代码。

//觉得很奇怪,既然电平中断一开始就mask了中断,
//
退出的时候才unmask,怎么会与同类型的其他中断冲突呢?

c代码


void
handle_level_irq
(unsigned int irq, struct irq_desc *desc)
{
struct irqaction *action;
irqreturn_t action_ret
; 

spin_lock
(&desc->lock);
//一开始以为对于电平中断ack不会被调用,但是发现
//mask_ack_irq会间接调用ack
mask_ack_irq
(desc, irq); 

if (unlikely(desc->status & IRQ_INPROGRESS))
goto out_unlock;
desc
->status &= ~(IRQ_REPLAY | IRQ_WAITING);
kstat_incr_irqs_this_cpu
(irq, desc); 

/*
* If its disabled or no action available
* keep it masked and get out of here
*/

action 
= desc->action;
if (unlikely(!action || (desc->status & IRQ_DISABLED)))
goto out_unlock; 

desc
->status |= IRQ_INPROGRESS;
spin_unlock
(&desc->lock); 

action_ret 
= handle_IRQ_event(irq, action);
if (!noirqdebug)
note_interrupt
(irq, desc, action_ret); 

spin_lock
(&desc->lock);
desc
->status &= ~IRQ_INPROGRESS; 

if (unlikely(desc->status & IRQ_ONESHOT))
desc
->status |= IRQ_MASKED;
else if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
desc
->chip->unmask(irq);
out_unlock
:
spin_unlock
(&desc->lock);
}
EXPORT_SYMBOL_GPL
(handle_level_irq); 

void
handle_edge_irq
(unsigned int irq, struct irq_desc *desc)
{
spin_lock
(&desc->lock); 

desc
->status &= ~(IRQ_REPLAY | IRQ_WAITING); 

/*
* If we're currently running this IRQ, or its disabled,
* we shouldn't process the IRQ. Mark it pending, handle
* the necessary masking and go out
*/

//正如注释中所说,在处理一个中断时下一个同中断源的中断会被标记为阻塞,
//然后屏蔽这个中断源的中断。注意:只有在这个时候才会屏蔽中断,否则
//linux不会做无谓的屏蔽。
if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
!desc->action)) {
desc
->status |= (IRQ_PENDING | IRQ_MASKED);
mask_ack_irq
(desc, irq);
goto out_unlock;
}
kstat_incr_irqs_this_cpu
(irq, desc); 

/* Start handling the irq */
if (desc->chip->ack)
desc
->chip->ack(irq); 

/* Mark the IRQ currently inprogress.*/
desc
->status |= IRQ_INPROGRESS; 

do {
struct irqaction *action = desc->action;
irqreturn_t action_ret
; 

if (unlikely(!action)) {
desc
->chip->mask(irq);
goto out_unlock;
} 

/*
* When another irq arrived while we were handling
* one, we could have masked the irq.
* Renable it, if it was not disabled in meantime.
*/

//因为这时中断处理函数没有运行,所以可以unmask中断
if (unlikely((desc->status &
(IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
(IRQ_PENDING | IRQ_MASKED))) {
desc
->chip->unmask(irq);
desc
->status &= ~IRQ_MASKED;
} 

desc
->status &= ~IRQ_PENDING;
spin_unlock
(&desc->lock);
action_ret 
= handle_IRQ_event(irq, action);
if (!noirqdebug)
note_interrupt
(irq, desc, action_ret);
spin_lock
(&desc->lock); 

} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING); 

desc
->status &= ~IRQ_INPROGRESS;
out_unlock
:
spin_unlock
(&desc->lock);
}

 

上一篇:上一篇
下一篇:下一篇

 

随机推荐程序问答结果

 

 

如对文章有任何疑问请提交到问题反馈,或者您对内容不满意,请您反馈给我们DOC100.NET论坛发贴求解。
DOC100.NET资源网,机器学习分类整理更新日期::2014-05-15 02:01:32
如需转载,请注明文章出处和来源网址:http://www.doc100.net/bugs/t/337791/
本文WWW.DOC100.NET DOC100.NET版权所有。