aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/irq/spurious.c46
1 files changed, 37 insertions, 9 deletions
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index b0d81aae472f..bd9e272d55e9 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -135,6 +135,39 @@ report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
135 } 135 }
136} 136}
137 137
138static inline int try_misrouted_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
139{
140 struct irqaction *action;
141
142 if (!irqfixup)
143 return 0;
144
145 /* We didn't actually handle the IRQ - see if it was misrouted? */
146 if (action_ret == IRQ_NONE)
147 return 1;
148
149 /*
150 * But for 'irqfixup == 2' we also do it for handled interrupts if
151 * they are marked as IRQF_IRQPOLL (or for irq zero, which is the
152 * traditional PC timer interrupt.. Legacy)
153 */
154 if (irqfixup < 2)
155 return 0;
156
157 if (!irq)
158 return 1;
159
160 /*
161 * Since we don't get the descriptor lock, "action" can
162 * change under us. We don't really care, but we don't
163 * want to follow a NULL pointer. So tell the compiler to
164 * just load it once by using a barrier.
165 */
166 action = desc->action;
167 barrier();
168 return action && (action->flags & IRQF_IRQPOLL);
169}
170
138void note_interrupt(unsigned int irq, struct irq_desc *desc, 171void note_interrupt(unsigned int irq, struct irq_desc *desc,
139 irqreturn_t action_ret) 172 irqreturn_t action_ret)
140{ 173{
@@ -144,15 +177,10 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
144 report_bad_irq(irq, desc, action_ret); 177 report_bad_irq(irq, desc, action_ret);
145 } 178 }
146 179
147 if (unlikely(irqfixup)) { 180 if (unlikely(try_misrouted_irq(irq, desc, action_ret))) {
148 /* Don't punish working computers */ 181 int ok = misrouted_irq(irq);
149 if ((irqfixup == 2 && ((irq == 0) || 182 if (action_ret == IRQ_NONE)
150 (desc->action->flags & IRQF_IRQPOLL))) || 183 desc->irqs_unhandled -= ok;
151 action_ret == IRQ_NONE) {
152 int ok = misrouted_irq(irq);
153 if (action_ret == IRQ_NONE)
154 desc->irqs_unhandled -= ok;
155 }
156 } 184 }
157 185
158 desc->irq_count++; 186 desc->irq_count++;