genirq: Add untracked irq handler
authorKeith Busch <keith.busch@intel.com>
Fri, 17 Jun 2016 22:00:20 +0000 (16:00 -0600)
committerThomas Gleixner <tglx@linutronix.de>
Sat, 18 Jun 2016 08:00:55 +0000 (10:00 +0200)
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>
include/linux/irq.h
kernel/irq/chip.c
kernel/irq/handle.c
kernel/irq/internals.h

index 6c92a847394dfb5b40ed13105c4a88a60931cecc..562cef010aa8031dee3430efb942e50051155e50 100644 (file)
@@ -484,6 +484,7 @@ extern void handle_fasteoi_irq(struct irq_desc *desc);
 extern void handle_edge_irq(struct irq_desc *desc);
 extern void handle_edge_eoi_irq(struct irq_desc *desc);
 extern void handle_simple_irq(struct irq_desc *desc);
+extern void handle_untracked_irq(struct irq_desc *desc);
 extern void handle_percpu_irq(struct irq_desc *desc);
 extern void handle_percpu_devid_irq(struct irq_desc *desc);
 extern void handle_bad_irq(struct irq_desc *desc);
index ad813147377463f86646497a8311bff51b89f6bd..b4c1bc7c9ca204440c7c51e7df7a49b0c2ae511f 100644 (file)
@@ -426,6 +426,49 @@ out_unlock:
 }
 EXPORT_SYMBOL_GPL(handle_simple_irq);
 
+/**
+ *     handle_untracked_irq - Simple and software-decoded IRQs.
+ *     @desc:  the interrupt description structure for this irq
+ *
+ *     Untracked interrupts are sent from a demultiplexing interrupt
+ *     handler when the demultiplexer does not know which device it its
+ *     multiplexed irq domain generated the interrupt. IRQ's handled
+ *     through here are not subjected to stats tracking, randomness, or
+ *     spurious interrupt detection.
+ *
+ *     Note: Like handle_simple_irq, the caller is expected to handle
+ *     the ack, clear, mask and unmask issues if necessary.
+ */
+void handle_untracked_irq(struct irq_desc *desc)
+{
+       unsigned int flags = 0;
+
+       raw_spin_lock(&desc->lock);
+
+       if (!irq_may_run(desc))
+               goto out_unlock;
+
+       desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
+
+       if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
+               desc->istate |= IRQS_PENDING;
+               goto out_unlock;
+       }
+
+       desc->istate &= ~IRQS_PENDING;
+       irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
+       raw_spin_unlock(&desc->lock);
+
+       __handle_irq_event_percpu(desc, &flags);
+
+       raw_spin_lock(&desc->lock);
+       irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
+
+out_unlock:
+       raw_spin_unlock(&desc->lock);
+}
+EXPORT_SYMBOL_GPL(handle_untracked_irq);
+
 /*
  * Called unconditionally from handle_level_irq() and only for oneshot
  * interrupts from handle_fasteoi_irq()
index a15b5485b446e8ff5575ba87e9a4cabb80aa7286..d3f24905852c9e5068e53760034decefde63bd14 100644 (file)
@@ -132,10 +132,10 @@ void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
        wake_up_process(action->thread);
 }
 
-irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
+irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
 {
        irqreturn_t retval = IRQ_NONE;
-       unsigned int flags = 0, irq = desc->irq_data.irq;
+       unsigned int irq = desc->irq_data.irq;
        struct irqaction *action;
 
        for_each_action_of_desc(desc, action) {
@@ -164,7 +164,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
 
                        /* Fall through to add to randomness */
                case IRQ_HANDLED:
-                       flags |= action->flags;
+                       *flags |= action->flags;
                        break;
 
                default:
@@ -174,7 +174,17 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
                retval |= res;
        }
 
-       add_interrupt_randomness(irq, flags);
+       return retval;
+}
+
+irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
+{
+       irqreturn_t retval;
+       unsigned int flags = 0;
+
+       retval = __handle_irq_event_percpu(desc, &flags);
+
+       add_interrupt_randomness(desc->irq_data.irq, flags);
 
        if (!noirqdebug)
                note_interrupt(desc, retval);
index d5edcdc9382ad9e640e42214895df9f5f351895c..0c6f35ba9cc0811af15ea404371edfe098ee0d11 100644 (file)
@@ -84,6 +84,7 @@ extern void irq_mark_irq(unsigned int irq);
 
 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
 
+irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags);
 irqreturn_t handle_irq_event_percpu(struct irq_desc *desc);
 irqreturn_t handle_irq_event(struct irq_desc *desc);