irq: nobody cared (try booting with the “irqpoll” option)

你好!這裏是風箏的博客,

歡迎和我一起交流。


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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章