Commit 9692df05 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'irq-urgent-2022-05-08' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

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
parents ede4c6d7 8707898e
...@@ -29,12 +29,14 @@ extern struct irqaction chained_action; ...@@ -29,12 +29,14 @@ extern struct irqaction chained_action;
* IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed
* IRQTF_AFFINITY - irq thread is requested to adjust affinity * IRQTF_AFFINITY - irq thread is requested to adjust affinity
* IRQTF_FORCED_THREAD - irq action is force threaded * IRQTF_FORCED_THREAD - irq action is force threaded
* IRQTF_READY - signals that irq thread is ready
*/ */
enum { enum {
IRQTF_RUNTHREAD, IRQTF_RUNTHREAD,
IRQTF_WARNED, IRQTF_WARNED,
IRQTF_AFFINITY, IRQTF_AFFINITY,
IRQTF_FORCED_THREAD, IRQTF_FORCED_THREAD,
IRQTF_READY,
}; };
/* /*
......
...@@ -407,6 +407,7 @@ static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags, ...@@ -407,6 +407,7 @@ static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags,
lockdep_set_class(&desc->lock, &irq_desc_lock_class); lockdep_set_class(&desc->lock, &irq_desc_lock_class);
mutex_init(&desc->request_mutex); mutex_init(&desc->request_mutex);
init_rcu_head(&desc->rcu); init_rcu_head(&desc->rcu);
init_waitqueue_head(&desc->wait_for_threads);
desc_set_defaults(irq, desc, node, affinity, owner); desc_set_defaults(irq, desc, node, affinity, owner);
irqd_set(&desc->irq_data, flags); irqd_set(&desc->irq_data, flags);
...@@ -575,6 +576,7 @@ int __init early_irq_init(void) ...@@ -575,6 +576,7 @@ int __init early_irq_init(void)
raw_spin_lock_init(&desc[i].lock); raw_spin_lock_init(&desc[i].lock);
lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
mutex_init(&desc[i].request_mutex); mutex_init(&desc[i].request_mutex);
init_waitqueue_head(&desc[i].wait_for_threads);
desc_set_defaults(i, &desc[i], node, NULL, NULL); desc_set_defaults(i, &desc[i], node, NULL, NULL);
} }
return arch_early_irq_init(); return arch_early_irq_init();
......
...@@ -1248,6 +1248,31 @@ static void irq_wake_secondary(struct irq_desc *desc, struct irqaction *action) ...@@ -1248,6 +1248,31 @@ static void irq_wake_secondary(struct irq_desc *desc, struct irqaction *action)
raw_spin_unlock_irq(&desc->lock); raw_spin_unlock_irq(&desc->lock);
} }
/*
* Internal function to notify that a interrupt thread is ready.
*/
static void irq_thread_set_ready(struct irq_desc *desc,
struct irqaction *action)
{
set_bit(IRQTF_READY, &action->thread_flags);
wake_up(&desc->wait_for_threads);
}
/*
* Internal function to wake up a interrupt thread and wait until it is
* ready.
*/
static void wake_up_and_wait_for_irq_thread_ready(struct irq_desc *desc,
struct irqaction *action)
{
if (!action || !action->thread)
return;
wake_up_process(action->thread);
wait_event(desc->wait_for_threads,
test_bit(IRQTF_READY, &action->thread_flags));
}
/* /*
* Interrupt handler thread * Interrupt handler thread
*/ */
...@@ -1259,6 +1284,8 @@ static int irq_thread(void *data) ...@@ -1259,6 +1284,8 @@ static int irq_thread(void *data)
irqreturn_t (*handler_fn)(struct irq_desc *desc, irqreturn_t (*handler_fn)(struct irq_desc *desc,
struct irqaction *action); struct irqaction *action);
irq_thread_set_ready(desc, action);
sched_set_fifo(current); sched_set_fifo(current);
if (force_irqthreads() && test_bit(IRQTF_FORCED_THREAD, if (force_irqthreads() && test_bit(IRQTF_FORCED_THREAD,
...@@ -1683,8 +1710,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) ...@@ -1683,8 +1710,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
} }
if (!shared) { if (!shared) {
init_waitqueue_head(&desc->wait_for_threads);
/* Setup the type (level, edge polarity) if configured: */ /* Setup the type (level, edge polarity) if configured: */
if (new->flags & IRQF_TRIGGER_MASK) { if (new->flags & IRQF_TRIGGER_MASK) {
ret = __irq_set_trigger(desc, ret = __irq_set_trigger(desc,
...@@ -1780,14 +1805,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) ...@@ -1780,14 +1805,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
irq_setup_timings(desc, new); irq_setup_timings(desc, new);
/* wake_up_and_wait_for_irq_thread_ready(desc, new);
* Strictly no need to wake it up, but hung_task complains wake_up_and_wait_for_irq_thread_ready(desc, new->secondary);
* when no hard interrupt wakes the thread up.
*/
if (new->thread)
wake_up_process(new->thread);
if (new->secondary)
wake_up_process(new->secondary->thread);
register_irq_proc(irq, desc); register_irq_proc(irq, desc);
new->dir = NULL; new->dir = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment