spurious.c 6.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
/*
 * linux/kernel/irq/spurious.c
 *
 * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
 *
 * This file contains spurious interrupt handling.
 */

9
#include <linux/jiffies.h>
L
Linus Torvalds 已提交
10 11 12 13
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
14
#include <linux/moduleparam.h>
L
Linus Torvalds 已提交
15

16
static int irqfixup __read_mostly;
A
Alan Cox 已提交
17 18 19 20

/*
 * Recovery handler for misrouted interrupts.
 */
21
static int misrouted_irq(int irq)
A
Alan Cox 已提交
22 23 24 25 26
{
	int i;
	int ok = 0;
	int work = 0;	/* Did we do work for a real IRQ */

27 28
	for (i = 1; i < NR_IRQS; i++) {
		struct irq_desc *desc = irq_desc + i;
A
Alan Cox 已提交
29 30 31 32
		struct irqaction *action;

		if (i == irq)	/* Already tried */
			continue;
33

A
Alan Cox 已提交
34 35 36 37 38 39 40
		spin_lock(&desc->lock);
		/* Already running on another processor */
		if (desc->status & IRQ_INPROGRESS) {
			/*
			 * Already running: If it is shared get the other
			 * CPU to go looking for our mystery interrupt too
			 */
41
			if (desc->action && (desc->action->flags & IRQF_SHARED))
A
Alan Cox 已提交
42 43 44 45 46 47
				desc->status |= IRQ_PENDING;
			spin_unlock(&desc->lock);
			continue;
		}
		/* Honour the normal IRQ locking */
		desc->status |= IRQ_INPROGRESS;
48
		action = desc->action;
A
Alan Cox 已提交
49
		spin_unlock(&desc->lock);
50

A
Alan Cox 已提交
51 52
		while (action) {
			/* Only shared IRQ handlers are safe to call */
53
			if (action->flags & IRQF_SHARED) {
54
				if (action->handler(i, action->dev_id) ==
A
Alan Cox 已提交
55 56 57 58 59 60 61 62 63 64 65 66
						IRQ_HANDLED)
					ok = 1;
			}
			action = action->next;
		}
		local_irq_disable();
		/* Now clean up the flags */
		spin_lock(&desc->lock);
		action = desc->action;

		/*
		 * While we were looking for a fixup someone queued a real
67
		 * IRQ clashing with our walk:
A
Alan Cox 已提交
68 69 70 71 72 73 74
		 */
		while ((desc->status & IRQ_PENDING) && action) {
			/*
			 * Perform real IRQ processing for the IRQ we deferred
			 */
			work = 1;
			spin_unlock(&desc->lock);
75
			handle_IRQ_event(i, action);
A
Alan Cox 已提交
76 77 78 79 80 81 82 83
			spin_lock(&desc->lock);
			desc->status &= ~IRQ_PENDING;
		}
		desc->status &= ~IRQ_INPROGRESS;
		/*
		 * If we did actual work for the real IRQ line we must let the
		 * IRQ controller clean up too
		 */
84
		if (work && desc->chip && desc->chip->end)
85
			desc->chip->end(i);
A
Alan Cox 已提交
86 87 88 89 90 91
		spin_unlock(&desc->lock);
	}
	/* So the caller can adjust the irq error counts */
	return ok;
}

L
Linus Torvalds 已提交
92 93 94 95 96 97 98 99 100 101 102 103
/*
 * If 99,900 of the previous 100,000 interrupts have not been handled
 * then assume that the IRQ is stuck in some manner. Drop a diagnostic
 * and try to turn the IRQ off.
 *
 * (The other 100-of-100,000 interrupts may have been a correctly
 *  functioning device sharing an IRQ with the failing one)
 *
 * Called under desc->lock
 */

static void
104 105
__report_bad_irq(unsigned int irq, struct irq_desc *desc,
		 irqreturn_t action_ret)
L
Linus Torvalds 已提交
106 107 108 109 110 111 112
{
	struct irqaction *action;

	if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
		printk(KERN_ERR "irq event %d: bogus return value %x\n",
				irq, action_ret);
	} else {
A
Alan Cox 已提交
113 114
		printk(KERN_ERR "irq %d: nobody cared (try booting with "
				"the \"irqpoll\" option)\n", irq);
L
Linus Torvalds 已提交
115 116 117
	}
	dump_stack();
	printk(KERN_ERR "handlers:\n");
118

L
Linus Torvalds 已提交
119 120 121 122 123 124 125 126 127 128
	action = desc->action;
	while (action) {
		printk(KERN_ERR "[<%p>]", action->handler);
		print_symbol(" (%s)",
			(unsigned long)action->handler);
		printk("\n");
		action = action->next;
	}
}

129
static void
130
report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
L
Linus Torvalds 已提交
131 132 133 134 135 136 137 138 139
{
	static int count = 100;

	if (count > 0) {
		count--;
		__report_bad_irq(irq, desc, action_ret);
	}
}

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
static inline int try_misrouted_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
{
	struct irqaction *action;

	if (!irqfixup)
		return 0;

	/* We didn't actually handle the IRQ - see if it was misrouted? */
	if (action_ret == IRQ_NONE)
		return 1;

	/*
	 * But for 'irqfixup == 2' we also do it for handled interrupts if
	 * they are marked as IRQF_IRQPOLL (or for irq zero, which is the
	 * traditional PC timer interrupt.. Legacy)
	 */
	if (irqfixup < 2)
		return 0;

	if (!irq)
		return 1;

	/*
	 * Since we don't get the descriptor lock, "action" can
	 * change under us.  We don't really care, but we don't
	 * want to follow a NULL pointer. So tell the compiler to
	 * just load it once by using a barrier.
	 */
	action = desc->action;
	barrier();
	return action && (action->flags & IRQF_IRQPOLL);
}

173
void note_interrupt(unsigned int irq, struct irq_desc *desc,
174
		    irqreturn_t action_ret)
L
Linus Torvalds 已提交
175
{
176
	if (unlikely(action_ret != IRQ_HANDLED)) {
177 178 179 180 181 182
		/*
		 * If we are seeing only the odd spurious IRQ caused by
		 * bus asynchronicity then don't eventually trigger an error,
		 * otherwise the couter becomes a doomsday timer for otherwise
		 * working systems
		 */
183
		if (time_after(jiffies, desc->last_unhandled + HZ/10))
184 185 186 187
			desc->irqs_unhandled = 1;
		else
			desc->irqs_unhandled++;
		desc->last_unhandled = jiffies;
188
		if (unlikely(action_ret != IRQ_NONE))
L
Linus Torvalds 已提交
189 190 191
			report_bad_irq(irq, desc, action_ret);
	}

192 193 194 195
	if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
		int ok = misrouted_irq(irq);
		if (action_ret == IRQ_NONE)
			desc->irqs_unhandled -= ok;
A
Alan Cox 已提交
196 197
	}

L
Linus Torvalds 已提交
198
	desc->irq_count++;
199
	if (likely(desc->irq_count < 100000))
L
Linus Torvalds 已提交
200 201 202
		return;

	desc->irq_count = 0;
203
	if (unlikely(desc->irqs_unhandled > 99900)) {
L
Linus Torvalds 已提交
204 205 206 207 208 209 210 211 212
		/*
		 * The interrupt is stuck
		 */
		__report_bad_irq(irq, desc, action_ret);
		/*
		 * Now kill the IRQ
		 */
		printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
		desc->status |= IRQ_DISABLED;
T
Thomas Gleixner 已提交
213
		desc->depth = 1;
214
		desc->chip->disable(irq);
L
Linus Torvalds 已提交
215 216 217 218
	}
	desc->irqs_unhandled = 0;
}

219
int noirqdebug __read_mostly;
L
Linus Torvalds 已提交
220

221
int noirqdebug_setup(char *str)
L
Linus Torvalds 已提交
222 223 224
{
	noirqdebug = 1;
	printk(KERN_INFO "IRQ lockup detection disabled\n");
225

L
Linus Torvalds 已提交
226 227 228 229
	return 1;
}

__setup("noirqdebug", noirqdebug_setup);
230 231
module_param(noirqdebug, bool, 0644);
MODULE_PARM_DESC(noirqdebug, "Disable irq lockup detection when true");
L
Linus Torvalds 已提交
232

A
Alan Cox 已提交
233 234 235 236 237
static int __init irqfixup_setup(char *str)
{
	irqfixup = 1;
	printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
	printk(KERN_WARNING "This may impact system performance.\n");
238

A
Alan Cox 已提交
239 240 241 242
	return 1;
}

__setup("irqfixup", irqfixup_setup);
243 244
module_param(irqfixup, int, 0644);
MODULE_PARM_DESC("irqfixup", "0: No fixup, 1: irqfixup mode 2: irqpoll mode");
A
Alan Cox 已提交
245 246 247 248 249 250 251 252 253 254 255 256

static int __init irqpoll_setup(char *str)
{
	irqfixup = 2;
	printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
				"enabled\n");
	printk(KERN_WARNING "This may significantly impact system "
				"performance\n");
	return 1;
}

__setup("irqpoll", irqpoll_setup);