一、问题:
使用共享中断获取散热风扇FG脚的脉冲信号的频率,在进中断第100000次时,出现中断异常,系统diable掉IRQ,error信息如下:
irq 71: nobody cared (try booting with the "irqpoll" option)
[] (dump_stack+0x0/0x14) from [] (__report_bad_irq+0x7c/0xac)
[] (__report_bad_irq+0x0/0xac) from [] (note_interrupt+0x244/0x28c)
r4:00000000
[] (note_interrupt+0x0/0x28c) from [] (handle_level_irq+0xf0/0x110)
[] (handle_level_irq+0x0/0x110) from [] (asm_do_IRQ+0x48/0x60)
r5:c0316b50 r4:c02e9880
[] (asm_do_IRQ+0x0/0x60) from [] (__irq_svc+0x24/0x80)
Exception stack(0xc45dfd18 to 0xc45dfd60)
fd00: 0000001d c45de000
fd20: c45de000 00000000 00000022 c0316b50 00000000 40000013 0000000a c4425000
fd40: c030b360 c45dfd84 c45dfd88 c45dfd60 c003d3a0 c003d130 20000113 ffffffff
r6:20000000 r5:fe170000 r4:ffffffff
[] (__do_softirq+0x0/0xd0) from [] (irq_exit+0x44/0x4c)
[] (irq_exit+0x0/0x4c) from [] (asm_do_IRQ+0x4c/0x60)
[] (asm_do_IRQ+0x0/0x60) from [] (__irq_svc+0x24/0x80)
Exception stack(0xc45dfdb8 to 0xc45dfe00)
fda0: 00000000 c02e4960
fdc0: 20000000 00000000 c45c3620 c02e9880 0000001d 40000013 00000000 c4425000
fde0: c4425000 c45dfe20 c45dfddc c45dfe00 c005e3c0 c005d7ec a0000013 ffffffff
r6:20000000 r5:fe170000 r4:ffffffff
[] (setup_irq+0x0/0x1c8) from [] (request_irq+0x9c/0xcc)
r8:00000080 r7:c015bf6c r6:00000000 r5:0000001d r4:c45c3620
[] (request_irq+0x0/0xcc) from [] (e1000_open+0xa4/0x198)
[] (e1000_open+0x0/0x198) from [] (dev_open+0xc8/0xd4)
r5:00000000 r4:c4425000
[] (dev_open+0x0/0xd4) from [] (dev_change_flags+0x98/0x1a4)
r5:00001043 r4:c4425000
[] (dev_change_flags+0x0/0x1a4) from [] (devinet_ioctl+0x63c/0x738)
r7:c458b4e0 r6:c45de000 r5:beb05d8c r4:00000000
[] (devinet_ioctl+0x0/0x738) from [] (inet_ioctl+0x1b8/0x1e0)
[] (inet_ioctl+0x0/0x1e0) from [] (sock_ioctl+0x190/0x284)
[] (sock_ioctl+0x0/0x284) from [] (do_ioctl+0x70/0x8c)
r8:c0021fc4 r7:00000036 r6:ffffffe7 r5:beb05d8c r4:00008914
[] (do_ioctl+0x0/0x8c) from [] (vfs_ioctl+0x94/0x2b0)
r6:00000000 r5:beb05d8c r4:c45910e0
[] (vfs_ioctl+0x0/0x2b0) from [] (sys_ioctl+0x40/0x64)
r6:00008914 r5:fffffff7 r4:c45910e0
[] (sys_ioctl+0x0/0x64) from [] (ret_fast_syscall+0x0/0x2c)
r6:beb05e74 r5:000dcf10 r4:beb05d8c
handlers:
[] (e1000_intr+0x0/0x164)
Disabling IRQ #71
二、问题分析
由打印信息得知,系统出现异常后,自动Disableing IRQ。
(1)出现这个问题后,执行cat /proc/interrupts查看中断号为71的中断线中断累计次数为99999次。
由打印信息 ”Disabling IRQ #71“搜索相关处理过程:
//Linux-4.14.25/kernel/irq/spurious.c
irq = irq_desc_get_irq(desc);
if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
int ok = misrouted_irq(irq);
if (action_ret == IRQ_NONE)
desc->irqs_unhandled -= ok;
}
desc->irq_count++;
if (likely(desc->irq_count < 100000))
return;
desc->irq_count = 0;
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;
}
由上述处理过程得知中断累计次数小于100000次,返回继续处理,超过100000继续进行未处理中断次数的判断,未处理中断大于99900次,报告bad irq,并进行diable irq.
这里 我就有些疑惑,明明中断服务程序执行了,说明进中断处理了,怎么会未处理呢?
然后就想到了,在中断服务程序中先disable_irq,在执行中断函数,然后再enable_irq来进行中断的复位。但是实验结果显示中断累计次数并不会复位,问题还是没有得到解决。
于是在网上找到这么一段话:
当一个中断号上有多个中断共享的时候,该中断来的时候,内核会依次调用共享该中断号的各个中断处理函数,如果中断处理函数检测到该中断不是自己的中断时就会返回IRQ_NONE,这时内核就会调用下一个中断处理函数,而这些中断处理函数中必须至少有一个返回IRQ_HANDLED告知内核该中断是自己的中断,已经正常处理,若内核依次调用完所有该中断号的中断处理函数仍未得到IRQ_HANDLED的返回值,内核就会报告上述错误,并在该中断出现一定次数后关闭该中断。即只有中断处理函数返回 IRQ_HANDLED ,这个中断才是被正确完成的。
于是查看自己的中断服务程序,果然返回值为IRQ_NONE,返回值不对,虽然中断服务程序执行了,但是系统是通过返回值来判断中断是否被处理,返回值不对,则未处理次数会被累加。达到一定次数就会disable.
返回值修改为IRQ_HANDLED后,查看IRQ 71的相关信息,
进中断总数1680次,未处理数为0,说明所有中断被处理了。等待进中断超过100000次,查看中断信息,中断次数已超过100000次,系统没有报错,成功解决问题。
这个问题和共享中断的特性有关,共享中断的相关知识还得深入去研究。