Skip to content

Commit

Permalink
genirq: Move irq resource handling out of spinlocked region
Browse files Browse the repository at this point in the history
Aside of being conceptually wrong, there is also an actual (hard to
trigger and mostly theoretical) problem.

CPU0				CPU1
free_irq(X)			interrupt X
				spin_lock(desc->lock)
				wake irq thread()
				spin_unlock(desc->lock)
spin_lock(desc->lock)
remove action()
shutdown_irq()			
release_resources()		thread_handler()
spin_unlock(desc->lock)		  access released resources.

synchronize_irq()

Move the release resources invocation after synchronize_irq() so it's
guaranteed that the threaded handler has finished.

Move the resource request call out of the desc->lock held region as well,
so the invocation context is the same for both request and release.

This solves the problems with those functions on RT as well.
 
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Cc: Heiko Stuebner <heiko@sntech.de>
Cc: Julia Cartwright <julia@ni.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Brian Norris <briannorris@chromium.org>
Cc: Doug Anderson <dianders@chromium.org>
Cc: linux-rockchip@lists.infradead.org
Cc: John Keeping <john@metanate.com>
Cc: linux-gpio@vger.kernel.org
Link: http://lkml.kernel.org/r/20170629214344.117028181@linutronix.de
  • Loading branch information
Thomas Gleixner committed Jul 4, 2017
1 parent 9114014 commit 46e48e2
Showing 1 changed file with 15 additions and 8 deletions.
23 changes: 15 additions & 8 deletions kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,14 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
new->flags &= ~IRQF_ONESHOT;

mutex_lock(&desc->request_mutex);
if (!desc->action) {
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_mutex;
}
}

chip_bus_lock(desc);

Expand Down Expand Up @@ -1271,13 +1279,6 @@ __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_unlock;
}

init_waitqueue_head(&desc->wait_for_threads);

/* Setup the type (level, edge polarity) if configured: */
Expand Down Expand Up @@ -1386,6 +1387,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)

chip_bus_sync_unlock(desc);

if (!desc->action)
irq_release_resources(desc);

out_mutex:
mutex_unlock(&desc->request_mutex);

out_thread:
Expand Down Expand Up @@ -1484,7 +1489,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
if (!desc->action) {
irq_settings_clr_disable_unlazy(desc);
irq_shutdown(desc);
irq_release_resources(desc);
irq_remove_timings(desc);
}

Expand Down Expand Up @@ -1527,6 +1531,9 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
}
}

if (!desc->action)
irq_release_resources(desc);

mutex_unlock(&desc->request_mutex);

irq_chip_pm_put(&desc->irq_data);
Expand Down

0 comments on commit 46e48e2

Please sign in to comment.