在代码里想写一个这样的中断
static irqreturn_t xxx_interrupt(int irq, void *arg)
{
disable_irq(irq);
xxxxx
enable_irq(irq);
}
使用的时候,发现系统会卡死在中断处理函数中.
追踪代码发现和使用disable_irq导致(linux3.2)
void disable_irq(unsigned int irq)
{
if (!__disable_irq_nosync(irq))
synchronize_irq(irq);
}
static int __disable_irq_nosync(unsigned int irq)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
if (!desc)
return -EINVAL;
__disable_irq(desc, irq, false);
irq_put_desc_busunlock(desc, flags);
return 0;
}
从disable_irq的源码中我们可以看出
__disable_irq_nosync
-> __disable_irq(desc, irq, false);
这里已经关闭了中断,而后面继续执行synchronize_irq函数
void synchronize_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
bool inprogress;
if (!desc)
return;
do {
unsigned long flags;
/*
* Wait until we're out of the critical section. This might
* give the wrong answer due to the lack of memory barriers.
*/
/* 根据 IRQD_IRQ_INPROGRESS 标志位判断当前中断是不是还在处理
* 如果还在处理,则等待处理结束
*/
while (irqd_irq_inprogress(&desc->irq_data))
cpu_relax();
/* Ok, that indicated we're done: double-check carefully. */
raw_spin_lock_irqsave(&desc->lock, flags);
inprogress = irqd_irq_inprogress(&desc->irq_data);
raw_spin_unlock_irqrestore(&desc->lock, flags);
/* Oops, that failed? */
} while (inprogress);
/*
* We made sure that no hardirq handler is running. Now verify
* that no threaded handlers are active.
*/
wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active));
}
static inline bool irqd_irq_inprogress(struct irq_data *d)
{
return d->state_use_accessors & IRQD_IRQ_INPROGRESS;
}
也就是说disable_irq
一方面关闭中断 ( __disable_irq_nosync )
另一方面等待当前的中断结束( synchronize_irq )
这是好事,很严禁,但是放在中断函数中就不好了,代码会卡死在
while (irqd_irq_inprogress(&desc->irq_data))
卡死的原因说起来还是和中断的执行流程有关系,摘取部分中断执行流程如下:
handle_irq_event
-> irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
-> handle_irq_event_percpu
-> xxx_interrupt
-> irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
...
这样一贴流程很明显就看到原因了 IRQD_IRQ_INPROGRESS标志位的清除是在退出中断函数进行的,
而代码一直在中断函数中等待IRQD_IRQ_INPROGRESS标志位清空,不卡死才怪.
到了这里,问题原因就找到了!
那么,如果中断函数里关中断用什么api?
__disable_irq_nosync就可以,但是这个函数前面有下划线,看起来不是个api,查找一下调用
void disable_irq_nosync(unsigned int irq)
{
__disable_irq_nosync(irq);
}
ok,以后就用disable_irq_nosync了.
static irqreturn_t xxx_interrupt(int irq, void *arg)
{
disable_irq_nosync(irq);
xxxxx
enable_irq(irq);
}