]> git.ipfire.org Git - thirdparty/linux.git/blame - kernel/irq/resend.c
Merge tag 'for-linus-5.1-2' of git://github.com/cminyard/linux-ipmi
[thirdparty/linux.git] / kernel / irq / resend.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
a4633adc 2/*
a4633adc
TG
3 * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
4 * Copyright (C) 2005-2006, Thomas Gleixner
5 *
6 * This file contains the IRQ-resend code
7 *
8 * If the interrupt is waiting to be processed, we try to re-run it.
9 * We can't directly run it from here since the caller might be in an
10 * interrupt-protected region. Not all irq controller chips can
11 * retrigger interrupts at the hardware level, so in those cases
12 * we allow the resending of IRQs via a tasklet.
13 */
14
15#include <linux/irq.h>
16#include <linux/module.h>
17#include <linux/random.h>
18#include <linux/interrupt.h>
19
20#include "internals.h"
21
22#ifdef CONFIG_HARDIRQS_SW_RESEND
23
24/* Bitmap to handle software resend of interrupts: */
c1ee6264 25static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);
a4633adc
TG
26
27/*
28 * Run software resends of IRQ's
29 */
30static void resend_irqs(unsigned long arg)
31{
32 struct irq_desc *desc;
33 int irq;
34
85c0f909
YL
35 while (!bitmap_empty(irqs_resend, nr_irqs)) {
36 irq = find_first_bit(irqs_resend, nr_irqs);
a4633adc 37 clear_bit(irq, irqs_resend);
08678b08 38 desc = irq_to_desc(irq);
6a6de9ef 39 local_irq_disable();
bd0b9ac4 40 desc->handle_irq(desc);
6a6de9ef 41 local_irq_enable();
a4633adc
TG
42 }
43}
44
45/* Tasklet to handle resend: */
46static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);
47
48#endif
49
50/*
51 * IRQ resend
52 *
53 * Is called with interrupts disabled and desc->lock held.
54 */
0798abeb 55void check_irq_resend(struct irq_desc *desc)
a4633adc 56{
2464286a
TG
57 /*
58 * We do not resend level type interrupts. Level type
59 * interrupts are resent by hardware when they are still
d4dc0f90
TG
60 * active. Clear the pending bit so suspend/resume does not
61 * get confused.
2464286a 62 */
d4dc0f90
TG
63 if (irq_settings_is_level(desc)) {
64 desc->istate &= ~IRQS_PENDING;
87923470 65 return;
d4dc0f90 66 }
163ef309
TG
67 if (desc->istate & IRQS_REPLAY)
68 return;
2a0d6fb3 69 if (desc->istate & IRQS_PENDING) {
2a0d6fb3 70 desc->istate &= ~IRQS_PENDING;
163ef309 71 desc->istate |= IRQS_REPLAY;
a4633adc 72
21e2b8c6
TG
73 if (!desc->irq_data.chip->irq_retrigger ||
74 !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
a4633adc 75#ifdef CONFIG_HARDIRQS_SW_RESEND
0798abeb
JL
76 unsigned int irq = irq_desc_get_irq(desc);
77
293a7a0a 78 /*
75a06189
TG
79 * If the interrupt is running in the thread
80 * context of the parent irq we need to be
81 * careful, because we cannot trigger it
82 * directly.
293a7a0a 83 */
75a06189
TG
84 if (irq_settings_is_nested_thread(desc)) {
85 /*
86 * If the parent_irq is valid, we
87 * retrigger the parent, otherwise we
88 * do nothing.
89 */
90 if (!desc->parent_irq)
91 return;
293a7a0a 92 irq = desc->parent_irq;
75a06189 93 }
a4633adc
TG
94 /* Set it pending and activate the softirq: */
95 set_bit(irq, irqs_resend);
96 tasklet_schedule(&resend_tasklet);
97#endif
98 }
99 }
100}