Merge tag 'qcom-soc-for-3.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / kernel / irq / manage.c
index d3bf660..d34131c 100644 (file)
@@ -32,24 +32,10 @@ static int __init setup_forced_irqthreads(char *arg)
 early_param("threadirqs", setup_forced_irqthreads);
 #endif
 
-/**
- *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
- *     @irq: interrupt number to wait for
- *
- *     This function waits for any pending IRQ handlers for this interrupt
- *     to complete before returning. If you use this function while
- *     holding a resource the IRQ handler may need you will deadlock.
- *
- *     This function may be called - with care - from IRQ context.
- */
-void synchronize_irq(unsigned int irq)
+static void __synchronize_hardirq(struct irq_desc *desc)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
        bool inprogress;
 
-       if (!desc)
-               return;
-
        do {
                unsigned long flags;
 
@@ -67,12 +53,56 @@ void synchronize_irq(unsigned int irq)
 
                /* Oops, that failed? */
        } while (inprogress);
+}
 
-       /*
-        * We made sure that no hardirq handler is running. Now verify
-        * that no threaded handlers are active.
-        */
-       wait_event(desc->wait_for_threads, !atomic_read(&desc->threads_active));
+/**
+ *     synchronize_hardirq - wait for pending hard IRQ handlers (on other CPUs)
+ *     @irq: interrupt number to wait for
+ *
+ *     This function waits for any pending hard IRQ handlers for this
+ *     interrupt to complete before returning. If you use this
+ *     function while holding a resource the IRQ handler may need you
+ *     will deadlock. It does not take associated threaded handlers
+ *     into account.
+ *
+ *     Do not use this for shutdown scenarios where you must be sure
+ *     that all parts (hardirq and threaded handler) have completed.
+ *
+ *     This function may be called - with care - from IRQ context.
+ */
+void synchronize_hardirq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       if (desc)
+               __synchronize_hardirq(desc);
+}
+EXPORT_SYMBOL(synchronize_hardirq);
+
+/**
+ *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
+ *     @irq: interrupt number to wait for
+ *
+ *     This function waits for any pending IRQ handlers for this interrupt
+ *     to complete before returning. If you use this function while
+ *     holding a resource the IRQ handler may need you will deadlock.
+ *
+ *     This function may be called - with care - from IRQ context.
+ */
+void synchronize_irq(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       if (desc) {
+               __synchronize_hardirq(desc);
+               /*
+                * We made sure that no hardirq handler is
+                * running. Now verify that no threaded handlers are
+                * active.
+                */
+               wait_event(desc->wait_for_threads,
+                          !atomic_read(&desc->threads_active));
+       }
 }
 EXPORT_SYMBOL(synchronize_irq);
 
@@ -150,7 +180,7 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
        struct irq_chip *chip = irq_data_get_irq_chip(data);
        int ret;
 
-       ret = chip->irq_set_affinity(data, mask, false);
+       ret = chip->irq_set_affinity(data, mask, force);
        switch (ret) {
        case IRQ_SET_MASK_OK:
                cpumask_copy(data->affinity, mask);
@@ -162,7 +192,8 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
        return ret;
 }
 
-int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask)
+int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
+                           bool force)
 {
        struct irq_chip *chip = irq_data_get_irq_chip(data);
        struct irq_desc *desc = irq_data_to_desc(data);
@@ -172,7 +203,7 @@ int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask)
                return -EINVAL;
 
        if (irq_can_move_pcntxt(data)) {
-               ret = irq_do_set_affinity(data, mask, false);
+               ret = irq_do_set_affinity(data, mask, force);
        } else {
                irqd_set_move_pending(data);
                irq_copy_pending(desc, mask);
@@ -187,13 +218,7 @@ int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask)
        return ret;
 }
 
-/**
- *     irq_set_affinity - Set the irq affinity of a given irq
- *     @irq:           Interrupt to set affinity
- *     @mask:          cpumask
- *
- */
-int irq_set_affinity(unsigned int irq, const struct cpumask *mask)
+int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
@@ -203,7 +228,7 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *mask)
                return -EINVAL;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       ret =  __irq_set_affinity_locked(irq_desc_get_irq_data(desc), mask);
+       ret = irq_set_affinity_locked(irq_desc_get_irq_data(desc), mask, force);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
        return ret;
 }
@@ -718,7 +743,7 @@ again:
 
        if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
            irqd_irq_masked(&desc->irq_data))
-               unmask_irq(desc);
+               unmask_threaded_irq(desc);
 
 out_unlock:
        raw_spin_unlock_irq(&desc->lock);
@@ -727,7 +752,7 @@ out_unlock:
 
 #ifdef CONFIG_SMP
 /*
- * Check whether we need to chasnge the affinity of the interrupt thread.
+ * Check whether we need to change the affinity of the interrupt thread.
  */
 static void
 irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
@@ -880,6 +905,33 @@ static int irq_thread(void *data)
        return 0;
 }
 
+/**
+ *     irq_wake_thread - wake the irq thread for the action identified by dev_id
+ *     @irq:           Interrupt line
+ *     @dev_id:        Device identity for which the thread should be woken
+ *
+ */
+void irq_wake_thread(unsigned int irq, void *dev_id)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       struct irqaction *action;
+       unsigned long flags;
+
+       if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc)))
+               return;
+
+       raw_spin_lock_irqsave(&desc->lock, flags);
+       for (action = desc->action; action; action = action->next) {
+               if (action->dev_id == dev_id) {
+                       if (action->thread)
+                               __irq_wake_thread(desc, action);
+                       break;
+               }
+       }
+       raw_spin_unlock_irqrestore(&desc->lock, flags);
+}
+EXPORT_SYMBOL_GPL(irq_wake_thread);
+
 static void irq_setup_forced_threading(struct irqaction *new)
 {
        if (!force_irqthreads)
@@ -896,6 +948,23 @@ static void irq_setup_forced_threading(struct irqaction *new)
        }
 }
 
+static int irq_request_resources(struct irq_desc *desc)
+{
+       struct irq_data *d = &desc->irq_data;
+       struct irq_chip *c = d->chip;
+
+       return c->irq_request_resources ? c->irq_request_resources(d) : 0;
+}
+
+static void irq_release_resources(struct irq_desc *desc)
+{
+       struct irq_data *d = &desc->irq_data;
+       struct irq_chip *c = d->chip;
+
+       if (c->irq_release_resources)
+               c->irq_release_resources(d);
+}
+
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
@@ -1091,6 +1160,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        }
 
        if (!shared) {
+               ret = irq_request_resources(desc);
+               if (ret) {
+                       pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n",
+                              new->name, irq, desc->irq_data.chip->name);
+                       goto out_mask;
+               }
+
                init_waitqueue_head(&desc->wait_for_threads);
 
                /* Setup the type (level, edge polarity) if configured: */
@@ -1261,8 +1337,10 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
        *action_ptr = action->next;
 
        /* If this was the last handler, shut down the IRQ line: */
-       if (!desc->action)
+       if (!desc->action) {
                irq_shutdown(desc);
+               irq_release_resources(desc);
+       }
 
 #ifdef CONFIG_SMP
        /* make sure affinity_hint is cleaned up */