mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-28 21:13:06 +00:00
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
This commit is contained in:
@@ -29,12 +29,14 @@ extern struct irqaction chained_action;
|
||||
* IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed
|
||||
* IRQTF_AFFINITY - irq thread is requested to adjust affinity
|
||||
* IRQTF_FORCED_THREAD - irq action is force threaded
|
||||
* IRQTF_READY - signals that irq thread is ready
|
||||
*/
|
||||
enum {
|
||||
IRQTF_RUNTHREAD,
|
||||
IRQTF_WARNED,
|
||||
IRQTF_AFFINITY,
|
||||
IRQTF_FORCED_THREAD,
|
||||
IRQTF_READY,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
mutex_init(&desc->request_mutex);
|
||||
init_rcu_head(&desc->rcu);
|
||||
init_waitqueue_head(&desc->wait_for_threads);
|
||||
|
||||
desc_set_defaults(irq, desc, node, affinity, owner);
|
||||
irqd_set(&desc->irq_data, flags);
|
||||
@@ -575,6 +576,7 @@ int __init early_irq_init(void)
|
||||
raw_spin_lock_init(&desc[i].lock);
|
||||
lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
|
||||
mutex_init(&desc[i].request_mutex);
|
||||
init_waitqueue_head(&desc[i].wait_for_threads);
|
||||
desc_set_defaults(i, &desc[i], node, NULL, NULL);
|
||||
}
|
||||
return arch_early_irq_init();
|
||||
|
||||
@@ -1248,6 +1248,31 @@ static void irq_wake_secondary(struct irq_desc *desc, struct irqaction *action)
|
||||
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
|
||||
*/
|
||||
@@ -1259,6 +1284,8 @@ static int irq_thread(void *data)
|
||||
irqreturn_t (*handler_fn)(struct irq_desc *desc,
|
||||
struct irqaction *action);
|
||||
|
||||
irq_thread_set_ready(desc, action);
|
||||
|
||||
sched_set_fifo(current);
|
||||
|
||||
if (force_irqthreads() && test_bit(IRQTF_FORCED_THREAD,
|
||||
@@ -1683,8 +1710,6 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
|
||||
}
|
||||
|
||||
if (!shared) {
|
||||
init_waitqueue_head(&desc->wait_for_threads);
|
||||
|
||||
/* Setup the type (level, edge polarity) if configured: */
|
||||
if (new->flags & IRQF_TRIGGER_MASK) {
|
||||
ret = __irq_set_trigger(desc,
|
||||
@@ -1780,14 +1805,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
|
||||
|
||||
irq_setup_timings(desc, new);
|
||||
|
||||
/*
|
||||
* Strictly no need to wake it up, but hung_task complains
|
||||
* 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);
|
||||
wake_up_and_wait_for_irq_thread_ready(desc, new);
|
||||
wake_up_and_wait_for_irq_thread_ready(desc, new->secondary);
|
||||
|
||||
register_irq_proc(irq, desc);
|
||||
new->dir = NULL;
|
||||
|
||||
Reference in New Issue
Block a user