aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2016-06-17 18:00:20 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-06-18 04:00:55 -0400
commitedd14cfebc4404698544d407ecf8eda6e19aa19e (patch)
treec8e821937f59152ba61129fdcfda0d52416302f8
parent21c57fd135894f69ba2b8acc715ca81e90eeba15 (diff)
genirq: Add untracked irq handler
This adds a software irq handler for controllers that multiplex interrupts from multiple devices, but don't know which device generated the interrupt. For these devices, the irq handler that demuxes must check every action for every software irq using the same h/w irq in order to find out which device generated the interrupt. This will inevitably trigger spurious interrupt detection if we are noting the irq. The new irq handler does not track the handling for spurious interrupt detection. An irq that uses this also won't get stats tracked since it didn't generate the interrupt, nor added to randomness since they are not random. Signed-off-by: Keith Busch <keith.busch@intel.com> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: linux-pci@vger.kernel.org Cc: Jon Derrick <jonathan.derrick@intel.com> Link: http://lkml.kernel.org/r/1466200821-29159-1-git-send-email-keith.busch@intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/irq.h1
-rw-r--r--kernel/irq/chip.c43
-rw-r--r--kernel/irq/handle.c18
-rw-r--r--kernel/irq/internals.h1
4 files changed, 59 insertions, 4 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 6c92a847394d..562cef010aa8 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -484,6 +484,7 @@ extern void handle_fasteoi_irq(struct irq_desc *desc);
484extern void handle_edge_irq(struct irq_desc *desc); 484extern void handle_edge_irq(struct irq_desc *desc);
485extern void handle_edge_eoi_irq(struct irq_desc *desc); 485extern void handle_edge_eoi_irq(struct irq_desc *desc);
486extern void handle_simple_irq(struct irq_desc *desc); 486extern void handle_simple_irq(struct irq_desc *desc);
487extern void handle_untracked_irq(struct irq_desc *desc);
487extern void handle_percpu_irq(struct irq_desc *desc); 488extern void handle_percpu_irq(struct irq_desc *desc);
488extern void handle_percpu_devid_irq(struct irq_desc *desc); 489extern void handle_percpu_devid_irq(struct irq_desc *desc);
489extern void handle_bad_irq(struct irq_desc *desc); 490extern void handle_bad_irq(struct irq_desc *desc);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index ad8131473774..b4c1bc7c9ca2 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -426,6 +426,49 @@ out_unlock:
426} 426}
427EXPORT_SYMBOL_GPL(handle_simple_irq); 427EXPORT_SYMBOL_GPL(handle_simple_irq);
428 428
429/**
430 * handle_untracked_irq - Simple and software-decoded IRQs.
431 * @desc: the interrupt description structure for this irq
432 *
433 * Untracked interrupts are sent from a demultiplexing interrupt
434 * handler when the demultiplexer does not know which device it its
435 * multiplexed irq domain generated the interrupt. IRQ's handled
436 * through here are not subjected to stats tracking, randomness, or
437 * spurious interrupt detection.
438 *
439 * Note: Like handle_simple_irq, the caller is expected to handle
440 * the ack, clear, mask and unmask issues if necessary.
441 */
442void handle_untracked_irq(struct irq_desc *desc)
443{
444 unsigned int flags = 0;
445
446 raw_spin_lock(&desc->lock);
447
448 if (!irq_may_run(desc))
449 goto out_unlock;
450
451 desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
452
453 if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
454 desc->istate |= IRQS_PENDING;
455 goto out_unlock;
456 }
457
458 desc->istate &= ~IRQS_PENDING;
459 irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
460 raw_spin_unlock(&desc->lock);
461
462 __handle_irq_event_percpu(desc, &flags);
463
464 raw_spin_lock(&desc->lock);
465 irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
466
467out_unlock:
468 raw_spin_unlock(&desc->lock);
469}
470EXPORT_SYMBOL_GPL(handle_untracked_irq);
471
429/* 472/*
430 * Called unconditionally from handle_level_irq() and only for oneshot 473 * Called unconditionally from handle_level_irq() and only for oneshot
431 * interrupts from handle_fasteoi_irq() 474 * interrupts from handle_fasteoi_irq()
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index a15b5485b446..d3f24905852c 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -132,10 +132,10 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
132 wake_up_process(action->thread); 132 wake_up_process(action->thread);
133} 133}
134 134
135irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) 135irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
136{ 136{
137 irqreturn_t retval = IRQ_NONE; 137 irqreturn_t retval = IRQ_NONE;
138 unsigned int flags = 0, irq = desc->irq_data.irq; 138 unsigned int irq = desc->irq_data.irq;
139 struct irqaction *action; 139 struct irqaction *action;
140 140
141 for_each_action_of_desc(desc, action) { 141 for_each_action_of_desc(desc, action) {
@@ -164,7 +164,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
164 164
165 /* Fall through to add to randomness */ 165 /* Fall through to add to randomness */
166 case IRQ_HANDLED: 166 case IRQ_HANDLED:
167 flags |= action->flags; 167 *flags |= action->flags;
168 break; 168 break;
169 169
170 default: 170 default:
@@ -174,7 +174,17 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
174 retval |= res; 174 retval |= res;
175 } 175 }
176 176
177 add_interrupt_randomness(irq, flags); 177 return retval;
178}
179
180irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
181{
182 irqreturn_t retval;
183 unsigned int flags = 0;
184
185 retval = __handle_irq_event_percpu(desc, &flags);
186
187 add_interrupt_randomness(desc->irq_data.irq, flags);
178 188
179 if (!noirqdebug) 189 if (!noirqdebug)
180 note_interrupt(desc, retval); 190 note_interrupt(desc, retval);
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index d5edcdc9382a..0c6f35ba9cc0 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -84,6 +84,7 @@ extern void irq_mark_irq(unsigned int irq);
84 84
85extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); 85extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
86 86
87irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags);
87irqreturn_t handle_irq_event_percpu(struct irq_desc *desc); 88irqreturn_t handle_irq_event_percpu(struct irq_desc *desc);
88irqreturn_t handle_irq_event(struct irq_desc *desc); 89irqreturn_t handle_irq_event(struct irq_desc *desc);
89 90