Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Aug 2018 17:47:26 +0000 (10:47 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Aug 2018 17:47:26 +0000 (10:47 -0700)
Pull genirq updates from Thomas Gleixner:
 "The irq departement provides:

   - A synchronization fix for free_irq() to synchronize just the
     removed interrupt thread on shared interrupt lines.

   - Consolidate the multi low level interrupt entry handling and mvoe
     it to the generic code instead of adding yet another copy for
     RISC-V

   - Refactoring of the ARM LPI allocator and LPI exposure to the
     hypervisor

   - Yet another interrupt chip driver for the JZ4725B SoC

   - Speed up for /proc/interrupts as people seem to love reading this
     file with high frequency

   - Miscellaneous fixes and updates"

* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits)
  irqchip/gic-v3-its: Make its_lock a raw_spin_lock_t
  genirq/irqchip: Remove MULTI_IRQ_HANDLER as it's now obselete
  openrisc: Use the new GENERIC_IRQ_MULTI_HANDLER
  arm64: Use the new GENERIC_IRQ_MULTI_HANDLER
  ARM: Convert to GENERIC_IRQ_MULTI_HANDLER
  irqchip: Port the ARM IRQ drivers to GENERIC_IRQ_MULTI_HANDLER
  irqchip/gic-v3-its: Reduce minimum LPI allocation to 1 for PCI devices
  dt-bindings: irqchip: renesas-irqc: Document r8a77980 support
  dt-bindings: irqchip: renesas-irqc: Document r8a77470 support
  irqchip/ingenic: Add support for the JZ4725B SoC
  irqchip/stm32: Add exti0 translation for stm32mp1
  genirq: Remove redundant NULL pointer check in __free_irq()
  irqchip/gic-v3-its: Honor hypervisor enforced LPI range
  irqchip/gic-v3: Expose GICD_TYPER in the rdist structure
  irqchip/gic-v3-its: Drop chunk allocation compatibility
  irqchip/gic-v3-its: Move minimum LPI requirements to individual busses
  irqchip/gic-v3-its: Use full range of LPIs
  irqchip/gic-v3-its: Refactor LPI allocator
  genirq: Synchronize only with single thread on free_irq()
  genirq: Update code comments wrt recycled thread_mask
  ...

1  2 
kernel/irq/manage.c

diff --combined kernel/irq/manage.c
@@@ -790,9 -790,19 +790,19 @@@ static irqreturn_t irq_forced_secondary
  
  static int irq_wait_for_interrupt(struct irqaction *action)
  {
-       set_current_state(TASK_INTERRUPTIBLE);
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
  
-       while (!kthread_should_stop()) {
+               if (kthread_should_stop()) {
+                       /* may need to run one last time */
+                       if (test_and_clear_bit(IRQTF_RUNTHREAD,
+                                              &action->thread_flags)) {
+                               __set_current_state(TASK_RUNNING);
+                               return 0;
+                       }
+                       __set_current_state(TASK_RUNNING);
+                       return -1;
+               }
  
                if (test_and_clear_bit(IRQTF_RUNTHREAD,
                                       &action->thread_flags)) {
                        return 0;
                }
                schedule();
-               set_current_state(TASK_INTERRUPTIBLE);
        }
-       __set_current_state(TASK_RUNNING);
-       return -1;
  }
  
  /*
@@@ -1024,11 -1031,8 +1031,8 @@@ static int irq_thread(void *data
        /*
         * This is the regular exit path. __free_irq() is stopping the
         * thread via kthread_stop() after calling
-        * synchronize_irq(). So neither IRQTF_RUNTHREAD nor the
-        * oneshot mask bit can be set. We cannot verify that as we
-        * cannot touch the oneshot mask at this point anymore as
-        * __setup_irq() might have given out currents thread_mask
-        * again.
+        * synchronize_hardirq(). So neither IRQTF_RUNTHREAD nor the
+        * oneshot mask bit can be set.
         */
        task_work_cancel(current, irq_thread_dtor);
        return 0;
@@@ -1068,13 -1072,6 +1072,13 @@@ static int irq_setup_forced_threading(s
        if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT))
                return 0;
  
 +      /*
 +       * No further action required for interrupts which are requested as
 +       * threaded interrupts already
 +       */
 +      if (new->handler == irq_default_primary_handler)
 +              return 0;
 +
        new->flags |= IRQF_ONESHOT;
  
        /*
         * thread handler. We force thread them as well by creating a
         * secondary action.
         */
 -      if (new->handler != irq_default_primary_handler && new->thread_fn) {
 +      if (new->handler && new->thread_fn) {
                /* Allocate the secondary action */
                new->secondary = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
                if (!new->secondary)
@@@ -1251,8 -1248,10 +1255,10 @@@ __setup_irq(unsigned int irq, struct ir
  
        /*
         * Protects against a concurrent __free_irq() call which might wait
-        * for synchronize_irq() to complete without holding the optional
-        * chip bus lock and desc->lock.
+        * for synchronize_hardirq() to complete without holding the optional
+        * chip bus lock and desc->lock. Also protects against handing out
+        * a recycled oneshot thread_mask bit while it's still in use by
+        * its previous owner.
         */
        mutex_lock(&desc->request_mutex);
  
@@@ -1571,9 -1570,6 +1577,6 @@@ static struct irqaction *__free_irq(str
  
        WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
  
-       if (!desc)
-               return NULL;
        mutex_lock(&desc->request_mutex);
        chip_bus_lock(desc);
        raw_spin_lock_irqsave(&desc->lock, flags);
        /*
         * Drop bus_lock here so the changes which were done in the chip
         * callbacks above are synced out to the irq chips which hang
-        * behind a slow bus (I2C, SPI) before calling synchronize_irq().
+        * behind a slow bus (I2C, SPI) before calling synchronize_hardirq().
         *
         * Aside of that the bus_lock can also be taken from the threaded
         * handler in irq_finalize_oneshot() which results in a deadlock
-        * because synchronize_irq() would wait forever for the thread to
+        * because kthread_stop() would wait forever for the thread to
         * complete, which is blocked on the bus lock.
         *
         * The still held desc->request_mutex() protects against a
        unregister_handler_proc(irq, action);
  
        /* Make sure it's not being used on another CPU: */
-       synchronize_irq(irq);
+       synchronize_hardirq(irq);
  
  #ifdef CONFIG_DEBUG_SHIRQ
        /*
         * is so by doing an extra call to the handler ....
         *
         * ( We do this after actually deregistering it, to make sure that a
-        *   'real' IRQ doesn't run in parallel with our fake. )
+        *   'real' IRQ doesn't run in parallel with our fake. )
         */
        if (action->flags & IRQF_SHARED) {
                local_irq_save(flags);
        }
  #endif
  
+       /*
+        * The action has already been removed above, but the thread writes
+        * its oneshot mask bit when it completes. Though request_mutex is
+        * held across this which prevents __setup_irq() from handing out
+        * the same bit to a newly requested action.
+        */
        if (action->thread) {
                kthread_stop(action->thread);
                put_task_struct(action->thread);