If a irq is already disabled, irq_shutdown may try to disable it again, for example: devm_request_irq->irq_startup->irq_enable disable_irq <-- disabled devm_free_irq->irq_shutdown <-- disable it again
This would confuse some chips which require balanced irq enable and disable, for example pinctrl-rockchip & pinctrl-nomadik. Add a state check before calling irq_disable to prevent that. v2: Rewrite commit message. v3: Rewrite commit message and not skip irq_shutdown. Signed-off-by: Jeffy Chen <jeffy.c...@rock-chips.com> --- Changes in v3: Rewrite commit message and not skip irq_shutdown. Changes in v2: Rewrite commit message. kernel/irq/chip.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 686be4b..0ac0c56 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -206,13 +206,23 @@ int irq_startup(struct irq_desc *desc, bool resend) void irq_shutdown(struct irq_desc *desc) { + int irq_disabled = irqd_irq_disabled(&desc->irq_data); + irq_state_set_disabled(desc); desc->depth = 1; if (desc->irq_data.chip->irq_shutdown) desc->irq_data.chip->irq_shutdown(&desc->irq_data); - else if (desc->irq_data.chip->irq_disable) + /* + * 1/ Some chips may require balanced irq enable &_disable. + * 2/ Due to the lazy disable approach, a irq could be + * disabled but unmasked. + * + * So if this irq is already disabled, let's mask it instead + * of trying to call irq_disable again. + */ + else if (desc->irq_data.chip->irq_disable && !irq_disabled) desc->irq_data.chip->irq_disable(&desc->irq_data); - else + else if (desc->irq_data.chip->irq_mask) desc->irq_data.chip->irq_mask(&desc->irq_data); irq_domain_deactivate_irq(&desc->irq_data); irq_state_set_masked(desc); -- 2.1.4