共享中断

一、问题:

  使用共享中断获取散热风扇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次,系统没有报错,成功解决问题。

 共享中断

 这个问题和共享中断的特性有关,共享中断的相关知识还得深入去研究。

上一篇:MySql的使用


下一篇:中断唤醒系统流程