Merge branch 'for-3.18-consistent-ops' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / kernel / irq / chip.c
index cca7292fc61ec9f8a90831332896ee2a36fce68b..e5202f00cabcdb892b3f4ad39c53f7fe943a0751 100644 (file)
@@ -342,6 +342,31 @@ static bool irq_check_poll(struct irq_desc *desc)
        return irq_wait_for_poll(desc);
 }
 
+static bool irq_may_run(struct irq_desc *desc)
+{
+       unsigned int mask = IRQD_IRQ_INPROGRESS | IRQD_WAKEUP_ARMED;
+
+       /*
+        * If the interrupt is not in progress and is not an armed
+        * wakeup interrupt, proceed.
+        */
+       if (!irqd_has_set(&desc->irq_data, mask))
+               return true;
+
+       /*
+        * If the interrupt is an armed wakeup source, mark it pending
+        * and suspended, disable it and notify the pm core about the
+        * event.
+        */
+       if (irq_pm_check_wakeup(desc))
+               return false;
+
+       /*
+        * Handle a potential concurrent poll on a different core.
+        */
+       return irq_check_poll(desc);
+}
+
 /**
  *     handle_simple_irq - Simple and software-decoded IRQs.
  *     @irq:   the interrupt number
@@ -359,9 +384,8 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc)
 {
        raw_spin_lock(&desc->lock);
 
-       if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
-               if (!irq_check_poll(desc))
-                       goto out_unlock;
+       if (!irq_may_run(desc))
+               goto out_unlock;
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
        kstat_incr_irqs_this_cpu(irq, desc);
@@ -412,9 +436,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
        raw_spin_lock(&desc->lock);
        mask_ack_irq(desc);
 
-       if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
-               if (!irq_check_poll(desc))
-                       goto out_unlock;
+       if (!irq_may_run(desc))
+               goto out_unlock;
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
        kstat_incr_irqs_this_cpu(irq, desc);
@@ -485,9 +508,8 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
 
        raw_spin_lock(&desc->lock);
 
-       if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
-               if (!irq_check_poll(desc))
-                       goto out;
+       if (!irq_may_run(desc))
+               goto out;
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
        kstat_incr_irqs_this_cpu(irq, desc);
@@ -517,6 +539,7 @@ out:
                chip->irq_eoi(&desc->irq_data);
        raw_spin_unlock(&desc->lock);
 }
+EXPORT_SYMBOL_GPL(handle_fasteoi_irq);
 
 /**
  *     handle_edge_irq - edge type IRQ handler
@@ -540,19 +563,23 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
        raw_spin_lock(&desc->lock);
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
+
+       if (!irq_may_run(desc)) {
+               desc->istate |= IRQS_PENDING;
+               mask_ack_irq(desc);
+               goto out_unlock;
+       }
+
        /*
-        * If we're currently running this IRQ, or its disabled,
-        * we shouldn't process the IRQ. Mark it pending, handle
-        * the necessary masking and go out
+        * If its disabled or no action available then mask it and get
+        * out of here.
         */
-       if (unlikely(irqd_irq_disabled(&desc->irq_data) ||
-                    irqd_irq_inprogress(&desc->irq_data) || !desc->action)) {
-               if (!irq_check_poll(desc)) {
-                       desc->istate |= IRQS_PENDING;
-                       mask_ack_irq(desc);
-                       goto out_unlock;
-               }
+       if (irqd_irq_disabled(&desc->irq_data) || !desc->action) {
+               desc->istate |= IRQS_PENDING;
+               mask_ack_irq(desc);
+               goto out_unlock;
        }
+
        kstat_incr_irqs_this_cpu(irq, desc);
 
        /* Start handling the irq */
@@ -601,18 +628,21 @@ void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc)
        raw_spin_lock(&desc->lock);
 
        desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
+
+       if (!irq_may_run(desc)) {
+               desc->istate |= IRQS_PENDING;
+               goto out_eoi;
+       }
+
        /*
-        * If we're currently running this IRQ, or its disabled,
-        * we shouldn't process the IRQ. Mark it pending, handle
-        * the necessary masking and go out
+        * If its disabled or no action available then mask it and get
+        * out of here.
         */
-       if (unlikely(irqd_irq_disabled(&desc->irq_data) ||
-                    irqd_irq_inprogress(&desc->irq_data) || !desc->action)) {
-               if (!irq_check_poll(desc)) {
-                       desc->istate |= IRQS_PENDING;
-                       goto out_eoi;
-               }
+       if (irqd_irq_disabled(&desc->irq_data) || !desc->action) {
+               desc->istate |= IRQS_PENDING;
+               goto out_eoi;
        }
+
        kstat_incr_irqs_this_cpu(irq, desc);
 
        do {