xref: /openbmc/linux/kernel/irq/spurious.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1 /*
2  * linux/kernel/irq/spurious.c
3  *
4  * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
5  *
6  * This file contains spurious interrupt handling.
7  */
8 
9 #include <linux/irq.h>
10 #include <linux/module.h>
11 #include <linux/kallsyms.h>
12 #include <linux/interrupt.h>
13 
14 /*
15  * If 99,900 of the previous 100,000 interrupts have not been handled
16  * then assume that the IRQ is stuck in some manner. Drop a diagnostic
17  * and try to turn the IRQ off.
18  *
19  * (The other 100-of-100,000 interrupts may have been a correctly
20  *  functioning device sharing an IRQ with the failing one)
21  *
22  * Called under desc->lock
23  */
24 
25 static void
26 __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
27 {
28 	struct irqaction *action;
29 
30 	if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
31 		printk(KERN_ERR "irq event %d: bogus return value %x\n",
32 				irq, action_ret);
33 	} else {
34 		printk(KERN_ERR "irq %d: nobody cared!\n", irq);
35 	}
36 	dump_stack();
37 	printk(KERN_ERR "handlers:\n");
38 	action = desc->action;
39 	while (action) {
40 		printk(KERN_ERR "[<%p>]", action->handler);
41 		print_symbol(" (%s)",
42 			(unsigned long)action->handler);
43 		printk("\n");
44 		action = action->next;
45 	}
46 }
47 
48 void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
49 {
50 	static int count = 100;
51 
52 	if (count > 0) {
53 		count--;
54 		__report_bad_irq(irq, desc, action_ret);
55 	}
56 }
57 
58 void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
59 {
60 	if (action_ret != IRQ_HANDLED) {
61 		desc->irqs_unhandled++;
62 		if (action_ret != IRQ_NONE)
63 			report_bad_irq(irq, desc, action_ret);
64 	}
65 
66 	desc->irq_count++;
67 	if (desc->irq_count < 100000)
68 		return;
69 
70 	desc->irq_count = 0;
71 	if (desc->irqs_unhandled > 99900) {
72 		/*
73 		 * The interrupt is stuck
74 		 */
75 		__report_bad_irq(irq, desc, action_ret);
76 		/*
77 		 * Now kill the IRQ
78 		 */
79 		printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
80 		desc->status |= IRQ_DISABLED;
81 		desc->handler->disable(irq);
82 	}
83 	desc->irqs_unhandled = 0;
84 }
85 
86 int noirqdebug;
87 
88 int __init noirqdebug_setup(char *str)
89 {
90 	noirqdebug = 1;
91 	printk(KERN_INFO "IRQ lockup detection disabled\n");
92 	return 1;
93 }
94 
95 __setup("noirqdebug", noirqdebug_setup);
96 
97