Pull irq fix from Thomas Gleixner: "A fix for the threaded interrupt core. A quick sequence of request/free_irq() can result in a hang because the interrupt thread did not reach the thread function and got stopped in the kthread core already. That leaves a state active counter arround which makes a invocation of synchronized_irq() on that interrupt hang forever. Ensure that the thread reached the thread function in request_irq() to prevent that" * tag 'irq-urgent-2022-05-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: genirq: Synchronize interrupt thread startup
Showing the changes to kernel (3 of 3 files). Show all
Unified · Split
| @@ -29,12 +29,14 @@ extern struct irqaction chained_action; · 28 unmodified lines | ||
| 29 | 29 | * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed |
| 30 | 30 | * IRQTF_AFFINITY - irq thread is requested to adjust affinity |
| 31 | 31 | * IRQTF_FORCED_THREAD - irq action is force threaded |
| 32 | + * IRQTF_READY - signals that irq thread is ready | |
| 32 | 33 | */ |
| 33 | 34 | enum { |
| 34 | 35 | IRQTF_RUNTHREAD, |
| 35 | 36 | IRQTF_WARNED, |
| 36 | 37 | IRQTF_AFFINITY, |
| 37 | 38 | IRQTF_FORCED_THREAD, |
| 39 | + IRQTF_READY, | |
| 38 | 40 | }; |
| 39 | 41 | |
| 40 | 42 | /* |
| @@ -407,6 +407,7 @@ static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags, · 406 unmodified lines | ||
| 407 | 407 | lockdep_set_class(&desc->lock, &irq_desc_lock_class); |
| 408 | 408 | mutex_init(&desc->request_mutex); |
| 409 | 409 | init_rcu_head(&desc->rcu); |
| 410 | + init_waitqueue_head(&desc->wait_for_threads); | |
| 410 | 411 | |
| 411 | 412 | desc_set_defaults(irq, desc, node, affinity, owner); |
| 412 | 413 | irqd_set(&desc->irq_data, flags); |
| @@ -575,6 +576,7 @@ int __init early_irq_init(void) · 162 unmodified lines | ||
| 575 | 576 | raw_spin_lock_init(&desc[i].lock); |
| 576 | 577 | lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); |
| 577 | 578 | mutex_init(&desc[i].request_mutex); |
| 579 | + init_waitqueue_head(&desc[i].wait_for_threads); | |
| 578 | 580 | desc_set_defaults(i, &desc[i], node, NULL, NULL); |
| 579 | 581 | } |
| 580 | 582 | return arch_early_irq_init(); |
| @@ -1248,6 +1248,31 @@ static void irq_wake_secondary(struct irq_desc *desc, struct irqaction *action) · 1247 unmodified lines | ||
| 1248 | 1248 | raw_spin_unlock_irq(&desc->lock); |
| 1249 | 1249 | } |
| 1250 | 1250 | |
| 1251 | +/* | |
| 1252 | + * Internal function to notify that a interrupt thread is ready. | |
| 1253 | + */ | |
| 1254 | +static void irq_thread_set_ready(struct irq_desc *desc, | |
| 1255 | + struct irqaction *action) | |
| 1256 | +{ | |
| 1257 | + set_bit(IRQTF_READY, &action->thread_flags); | |
| 1258 | + wake_up(&desc->wait_for_threads); | |
| 1259 | +} | |
| 1260 | + | |
| 1261 | +/* | |
| 1262 | + * Internal function to wake up a interrupt thread and wait until it is | |
| 1263 | + * ready. | |
| 1264 | + */ | |
| 1265 | +static void wake_up_and_wait_for_irq_thread_ready(struct irq_desc *desc, | |
| 1266 | + struct irqaction *action) | |
| 1267 | +{ | |
| 1268 | + if (!action || !action->thread) | |
| 1269 | + return; | |
| 1270 | + | |
| 1271 | + wake_up_process(action->thread); | |
| 1272 | + wait_event(desc->wait_for_threads, | |
| 1273 | + test_bit(IRQTF_READY, &action->thread_flags)); | |
| 1274 | +} | |
| 1275 | + | |
| 1251 | 1276 | /* |
| 1252 | 1277 | * Interrupt handler thread |
| 1253 | 1278 | */ |
| @@ -1259,6 +1284,8 @@ static int irq_thread(void *data) · 5 unmodified lines | ||
| 1259 | 1284 | irqreturn_t (*handler_fn)(struct irq_desc *desc, |
| 1260 | 1285 | struct irqaction *action); |
| 1261 | 1286 | |
| 1287 | + irq_thread_set_ready(desc, action); | |
| 1288 | + | |
| 1262 | 1289 | sched_set_fifo(current); |
| 1263 | 1290 | |
| 1264 | 1291 | if (force_irqthreads() && test_bit(IRQTF_FORCED_THREAD, |
| @@ -1683,8 +1710,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) · 418 unmodified lines | ||
| 1683 | 1710 | } |
| 1684 | 1711 | |
| 1685 | 1712 | if (!shared) { |
| 1686 | − init_waitqueue_head(&desc->wait_for_threads); | |
| 1687 | − | |
| 1688 | 1713 | /* Setup the type (level, edge polarity) if configured: */ |
| 1689 | 1714 | if (new->flags & IRQF_TRIGGER_MASK) { |
| 1690 | 1715 | ret = __irq_set_trigger(desc, |
| @@ -1780,14 +1805,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) · 89 unmodified lines | ||
| 1780 | 1805 | |
| 1781 | 1806 | irq_setup_timings(desc, new); |
| 1782 | 1807 | |
| 1783 | − /* | |
| 1784 | − * Strictly no need to wake it up, but hung_task complains | |
| 1785 | − * when no hard interrupt wakes the thread up. | |
| 1786 | − */ | |
| 1787 | − if (new->thread) | |
| 1788 | − wake_up_process(new->thread); | |
| 1789 | − if (new->secondary) | |
| 1790 | − wake_up_process(new->secondary->thread); | |
| 1808 | + wake_up_and_wait_for_irq_thread_ready(desc, new); | |
| 1809 | + wake_up_and_wait_for_irq_thread_ready(desc, new->secondary); | |
| 1791 | 1810 | |
| 1792 | 1811 | register_irq_proc(irq, desc); |
| 1793 | 1812 | new->dir = NULL; |