Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
Linus Torvalds [Fri, 3 Aug 2012 17:56:44 +0000 (10:56 -0700)]
Pull irq fix from Ingo Molnar.

* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  genirq: Allow irq chips to mark themself oneshot safe

1  2 
kernel/irq/manage.c

diff --combined kernel/irq/manage.c
@@@ -781,7 -781,7 +781,7 @@@ static void wake_threads_waitq(struct i
                wake_up(&desc->wait_for_threads);
  }
  
 -static void irq_thread_dtor(struct task_work *unused)
 +static void irq_thread_dtor(struct callback_head *unused)
  {
        struct task_struct *tsk = current;
        struct irq_desc *desc;
   */
  static int irq_thread(void *data)
  {
 -      struct task_work on_exit_work;
 +      struct callback_head on_exit_work;
        static const struct sched_param param = {
                .sched_priority = MAX_USER_RT_PRIO/2,
        };
  
        sched_setscheduler(current, SCHED_FIFO, &param);
  
 -      init_task_work(&on_exit_work, irq_thread_dtor, NULL);
 +      init_task_work(&on_exit_work, irq_thread_dtor);
        task_work_add(current, &on_exit_work, false);
  
        while (!irq_wait_for_interrupt(action)) {
@@@ -893,6 -893,22 +893,6 @@@ __setup_irq(unsigned int irq, struct ir
                return -ENOSYS;
        if (!try_module_get(desc->owner))
                return -ENODEV;
 -      /*
 -       * Some drivers like serial.c use request_irq() heavily,
 -       * so we have to be careful not to interfere with a
 -       * running system.
 -       */
 -      if (new->flags & IRQF_SAMPLE_RANDOM) {
 -              /*
 -               * This function might sleep, we want to call it first,
 -               * outside of the atomic block.
 -               * Yes, this might clear the entropy pool if the wrong
 -               * driver is attempted to be loaded, without actually
 -               * installing a new handler, but is this really a problem,
 -               * only the sysadmin is able to do this.
 -               */
 -              rand_initialize_irq(irq);
 -      }
  
        /*
         * Check whether the interrupt nests into another interrupt
        }
  
        /*
+        * Drivers are often written to work w/o knowledge about the
+        * underlying irq chip implementation, so a request for a
+        * threaded irq without a primary hard irq context handler
+        * requires the ONESHOT flag to be set. Some irq chips like
+        * MSI based interrupts are per se one shot safe. Check the
+        * chip flags, so we can avoid the unmask dance at the end of
+        * the threaded handler for those.
+        */
+       if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
+               new->flags &= ~IRQF_ONESHOT;
+       /*
         * The following block of code has to be executed atomically
         */
        raw_spin_lock_irqsave(&desc->lock, flags);
                 */
                new->thread_mask = 1 << ffz(thread_mask);
  
-       } else if (new->handler == irq_default_primary_handler) {
+       } else if (new->handler == irq_default_primary_handler &&
+                  !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {
                /*
                 * The interrupt was requested with handler = NULL, so
                 * we use the default primary handler for it. But it
@@@ -1338,6 -1367,7 +1351,6 @@@ EXPORT_SYMBOL(free_irq)
   *    Flags:
   *
   *    IRQF_SHARED             Interrupt is shared
 - *    IRQF_SAMPLE_RANDOM      The interrupt can be used for entropy
   *    IRQF_TRIGGER_*          Specify active edge(s) or level
   *
   */