你好!這裏是風箏的博客,
歡迎和我一起交流。
irq 286: nobody cared (try booting with the “irqpoll” option)
之前看到這個一個warning,我看網上其他人寫的有點奇怪,手癢特此記錄一下:
通過grep查找代碼,可以發現這行語句在:__report_bad_irq函數:
static inline int bad_action_ret(irqreturn_t action_ret)
{
if (likely(action_ret <= (IRQ_HANDLED | IRQ_WAKE_THREAD)))
return 0;
return 1;
}
static void __report_bad_irq(struct irq_desc *desc, irqreturn_t action_ret)
{
unsigned int irq = irq_desc_get_irq(desc);
struct irqaction *action;
unsigned long flags;
if (bad_action_ret(action_ret)) {
printk(KERN_ERR "irq event %d: bogus return value %x\n",
irq, action_ret);
} else {
printk(KERN_ERR "irq %d: nobody cared (try booting with "
"the \"irqpoll\" option)\n", irq);
}
......
}
當bad_action_ret函數返回0的時候,也就是action_ret <= (IRQ_HANDLED | IRQ_WAKE_THREAD)的時候,就會有這條打印。
那action_ret 參數是哪裏傳進來的呢?繼續往上看:
void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret)
{
unsigned int irq;
if (desc->istate & IRQS_POLL_INPROGRESS ||
irq_settings_is_polled(desc))
return;
if (bad_action_ret(action_ret)) {//一般不會爲1,爲1的話是不會打印nobody cared這個log的
report_bad_irq(desc, action_ret);
return;
}
......
if (unlikely(action_ret == IRQ_NONE)) {
/*
* If we are seeing only the odd spurious IRQ caused by
* bus asynchronicity then don't eventually trigger an error,
* otherwise the counter becomes a doomsday timer for otherwise
* working systems
*/
if (time_after(jiffies, desc->last_unhandled + HZ/10))
desc->irqs_unhandled = 1;
else
desc->irqs_unhandled++;
desc->last_unhandled = jiffies;
}
......
if (unlikely(desc->irqs_unhandled > 99900)) {
/*
* The interrupt is stuck
*/
__report_bad_irq(desc, action_ret);//在這裏調用
/*
* Now kill the IRQ
*/
printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
desc->istate |= IRQS_SPURIOUS_DISABLED;
desc->depth++;
irq_disable(desc);
mod_timer(&poll_spurious_irq_timer,
jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
}
desc->irqs_unhandled = 0;
}
note_interrupt函數省略了一些不重要的代碼。
函數裏面可以看出,當action_ret 參數爲IRQ_NONE時,irqs_unhandled會一直累計計數,irqs_unhandled大於99900時,就會調用__report_bad_irq函數,就有可能會打印log:irq xx: nobody cared (try booting with the “irqpoll” option)
這裏我們還是沒有搞清楚action_ret 從哪裏來,繼續往上看:
有兩個函數可能調用了note_interrupt函數,一個是:handle_nested_irq(desc, action_ret),另一個是:handle_irq_event_percpu(desc, retval)。
仔細看可以發現,不管是哪個函數,都應該可以知道,action_ret就是我們在寫驅動時,註冊中斷的回調函數。
而且IRQ_NONE是<= (IRQ_HANDLED | IRQ_WAKE_THREAD)的,所以必定會顯示出那個log:irq xx: nobody cared (try booting with the “irqpoll” option)
所以我們可以得出結論:驅動代碼裏註冊的中斷回調裏返回了IRQ_NONE,且中斷被觸發了99900次,就會有這條log打印
事實也是如此,根據oops裏面的堆棧信息,找到對應驅動裏的中斷函數,確實發現是因爲返回了IRQ_NONE