When an interrupt controller uses a function such as handle_level_irq() as an interrupt handler and the controller implements the irq_disable() callback, the following scenario will appear in the i2c-hid driver in the sleep scenario: in the sleep flow, while the user is still triggering the i2c-hid interrupt, we get the following function call: handle_level_irq() -> mask_ack_irq() -> mask_irq() i2c_hid_core_suspend() -> disable_irq() -> __irq_disable() -> irq_state_set_disabled() -> irq_state_set_masked() irq_thread_fn() -> irq_finalize_oneshot() -> if (!desc->threads_oneshot && !irqd_irq_disabled() && irqd_irq_masked()) unmask_threaded_irq() -> unmask_irq() That is, when __irq_disable() is called between mask_irq() and irq_finalize_oneshot(), the code in irq_finalize_oneshot() will cause the !irqd_irq_disabled() fails to enter the unmask_irq() branch, which causes mask_irq/unmask_irq to be called unpaired and the i2c-hid interrupt to be masked. Since mask_irq/unmask_irq and irq_disabled() belong to two different hardware registers or policies, the !irqd_irq_disabled() assertion may not be used to determine whether unmask_irq() needs to be called. Cc: stable@xxxxxxxxxxxxxxx Signed-off-by: xiongxin <xiongxin@xxxxxxxxxx> Signed-off-by: Riwen Lu <luriwen@xxxxxxxxxx> diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 1782f90cd8c6..9160fc9170b3 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1120,8 +1120,7 @@ static void irq_finalize_oneshot(struct irq_desc *desc, desc->threads_oneshot &= ~action->thread_mask; - if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && - irqd_irq_masked(&desc->irq_data)) + if (!desc->threads_oneshot && irqd_irq_masked(&desc->irq_data)) unmask_threaded_irq(desc); out_unlock: -- 2.34.1