diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2017-06-29 17:33:38 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2017-07-04 06:46:16 -0400 |
commit | 46e48e257360f0845fe17089713cbad4db611e70 (patch) | |
tree | bd2a904fb949d135cf8bd09964fe734a1d9138e1 /kernel/irq/manage.c | |
parent | 9114014cf4e6df0b22d764380ae1fc54f1a7a8b2 (diff) |
genirq: Move irq resource handling out of spinlocked region
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
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r-- | kernel/irq/manage.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0139908b8d53..3e693430bfe1 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -1168,6 +1168,14 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
1168 | new->flags &= ~IRQF_ONESHOT; | 1168 | new->flags &= ~IRQF_ONESHOT; |
1169 | 1169 | ||
1170 | mutex_lock(&desc->request_mutex); | 1170 | mutex_lock(&desc->request_mutex); |
1171 | if (!desc->action) { | ||
1172 | ret = irq_request_resources(desc); | ||
1173 | if (ret) { | ||
1174 | pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n", | ||
1175 | new->name, irq, desc->irq_data.chip->name); | ||
1176 | goto out_mutex; | ||
1177 | } | ||
1178 | } | ||
1171 | 1179 | ||
1172 | chip_bus_lock(desc); | 1180 | chip_bus_lock(desc); |
1173 | 1181 | ||
@@ -1271,13 +1279,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
1271 | } | 1279 | } |
1272 | 1280 | ||
1273 | if (!shared) { | 1281 | if (!shared) { |
1274 | ret = irq_request_resources(desc); | ||
1275 | if (ret) { | ||
1276 | pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n", | ||
1277 | new->name, irq, desc->irq_data.chip->name); | ||
1278 | goto out_unlock; | ||
1279 | } | ||
1280 | |||
1281 | init_waitqueue_head(&desc->wait_for_threads); | 1282 | init_waitqueue_head(&desc->wait_for_threads); |
1282 | 1283 | ||
1283 | /* Setup the type (level, edge polarity) if configured: */ | 1284 | /* Setup the type (level, edge polarity) if configured: */ |
@@ -1386,6 +1387,10 @@ out_unlock: | |||
1386 | 1387 | ||
1387 | chip_bus_sync_unlock(desc); | 1388 | chip_bus_sync_unlock(desc); |
1388 | 1389 | ||
1390 | if (!desc->action) | ||
1391 | irq_release_resources(desc); | ||
1392 | |||
1393 | out_mutex: | ||
1389 | mutex_unlock(&desc->request_mutex); | 1394 | mutex_unlock(&desc->request_mutex); |
1390 | 1395 | ||
1391 | out_thread: | 1396 | out_thread: |
@@ -1484,7 +1489,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
1484 | if (!desc->action) { | 1489 | if (!desc->action) { |
1485 | irq_settings_clr_disable_unlazy(desc); | 1490 | irq_settings_clr_disable_unlazy(desc); |
1486 | irq_shutdown(desc); | 1491 | irq_shutdown(desc); |
1487 | irq_release_resources(desc); | ||
1488 | irq_remove_timings(desc); | 1492 | irq_remove_timings(desc); |
1489 | } | 1493 | } |
1490 | 1494 | ||
@@ -1527,6 +1531,9 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
1527 | } | 1531 | } |
1528 | } | 1532 | } |
1529 | 1533 | ||
1534 | if (!desc->action) | ||
1535 | irq_release_resources(desc); | ||
1536 | |||
1530 | mutex_unlock(&desc->request_mutex); | 1537 | mutex_unlock(&desc->request_mutex); |
1531 | 1538 | ||
1532 | irq_chip_pm_put(&desc->irq_data); | 1539 | irq_chip_pm_put(&desc->irq_data); |