]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - kernel/irq/chip.c
Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / kernel / irq / chip.c
index e28169dd1c36a51f92523208984ec4c7a4b5b251..15206453b12aab09cf96dd09cc3fa2da92fd9c14 100644 (file)
 
 #include "internals.h"
 
+static irqreturn_t bad_chained_irq(int irq, void *dev_id)
+{
+       WARN_ONCE(1, "Chained irq %d should not call an action\n", irq);
+       return IRQ_NONE;
+}
+
+/*
+ * Chained handlers should never call action on their IRQ. This default
+ * action will emit warning if such thing happens.
+ */
+struct irqaction chained_action = {
+       .handler = bad_chained_irq,
+};
+
 /**
  *     irq_set_chip - set the irq chip for an irq
  *     @irq:   irq number
@@ -227,6 +241,13 @@ void irq_enable(struct irq_desc *desc)
  * disabled. If an interrupt happens, then the interrupt flow
  * handler masks the line at the hardware level and marks it
  * pending.
+ *
+ * If the interrupt chip does not implement the irq_disable callback,
+ * a driver can disable the lazy approach for a particular irq line by
+ * calling 'irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY)'. This can
+ * be used for devices which cannot disable the interrupt at the
+ * device level under certain circumstances and have to use
+ * disable_irq[_nosync] instead.
  */
 void irq_disable(struct irq_desc *desc)
 {
@@ -234,6 +255,8 @@ void irq_disable(struct irq_desc *desc)
        if (desc->irq_data.chip->irq_disable) {
                desc->irq_data.chip->irq_disable(&desc->irq_data);
                irq_state_set_masked(desc);
+       } else if (irq_settings_disable_unlazy(desc)) {
+               mask_irq(desc);
        }
 }
 
@@ -669,7 +692,7 @@ void handle_percpu_irq(struct irq_desc *desc)
        if (chip->irq_ack)
                chip->irq_ack(&desc->irq_data);
 
-       handle_irq_event_percpu(desc, desc->action);
+       handle_irq_event_percpu(desc);
 
        if (chip->irq_eoi)
                chip->irq_eoi(&desc->irq_data);
@@ -746,6 +769,8 @@ __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
                if (desc->irq_data.chip != &no_irq_chip)
                        mask_ack_irq(desc);
                irq_state_set_disabled(desc);
+               if (is_chained)
+                       desc->action = NULL;
                desc->depth = 1;
        }
        desc->handle_irq = handle;
@@ -755,6 +780,7 @@ __irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle,
                irq_settings_set_noprobe(desc);
                irq_settings_set_norequest(desc);
                irq_settings_set_nothread(desc);
+               desc->action = &chained_action;
                irq_startup(desc, true);
        }
 }