1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
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 | /* hlist_head to handle software resend of interrupts: */ |
25 | static HLIST_HEAD(irq_resend_list); |
26 | static DEFINE_RAW_SPINLOCK(irq_resend_lock); |
27 | |
28 | /* |
29 | * Run software resends of IRQ's |
30 | */ |
31 | static void resend_irqs(struct tasklet_struct *unused) |
32 | { |
33 | struct irq_desc *desc; |
34 | |
35 | raw_spin_lock_irq(&irq_resend_lock); |
36 | while (!hlist_empty(h: &irq_resend_list)) { |
37 | desc = hlist_entry(irq_resend_list.first, struct irq_desc, |
38 | resend_node); |
39 | hlist_del_init(n: &desc->resend_node); |
40 | raw_spin_unlock(&irq_resend_lock); |
41 | desc->handle_irq(desc); |
42 | raw_spin_lock(&irq_resend_lock); |
43 | } |
44 | raw_spin_unlock_irq(&irq_resend_lock); |
45 | } |
46 | |
47 | /* Tasklet to handle resend: */ |
48 | static DECLARE_TASKLET(resend_tasklet, resend_irqs); |
49 | |
50 | static int irq_sw_resend(struct irq_desc *desc) |
51 | { |
52 | /* |
53 | * Validate whether this interrupt can be safely injected from |
54 | * non interrupt context |
55 | */ |
56 | if (handle_enforce_irqctx(data: &desc->irq_data)) |
57 | return -EINVAL; |
58 | |
59 | /* |
60 | * If the interrupt is running in the thread context of the parent |
61 | * irq we need to be careful, because we cannot trigger it |
62 | * directly. |
63 | */ |
64 | if (irq_settings_is_nested_thread(desc)) { |
65 | /* |
66 | * If the parent_irq is valid, we retrigger the parent, |
67 | * otherwise we do nothing. |
68 | */ |
69 | if (!desc->parent_irq) |
70 | return -EINVAL; |
71 | |
72 | desc = irq_to_desc(irq: desc->parent_irq); |
73 | if (!desc) |
74 | return -EINVAL; |
75 | } |
76 | |
77 | /* Add to resend_list and activate the softirq: */ |
78 | raw_spin_lock(&irq_resend_lock); |
79 | if (hlist_unhashed(h: &desc->resend_node)) |
80 | hlist_add_head(n: &desc->resend_node, h: &irq_resend_list); |
81 | raw_spin_unlock(&irq_resend_lock); |
82 | tasklet_schedule(t: &resend_tasklet); |
83 | return 0; |
84 | } |
85 | |
86 | void clear_irq_resend(struct irq_desc *desc) |
87 | { |
88 | raw_spin_lock(&irq_resend_lock); |
89 | hlist_del_init(n: &desc->resend_node); |
90 | raw_spin_unlock(&irq_resend_lock); |
91 | } |
92 | |
93 | void irq_resend_init(struct irq_desc *desc) |
94 | { |
95 | INIT_HLIST_NODE(h: &desc->resend_node); |
96 | } |
97 | #else |
98 | void clear_irq_resend(struct irq_desc *desc) {} |
99 | void irq_resend_init(struct irq_desc *desc) {} |
100 | |
101 | static int irq_sw_resend(struct irq_desc *desc) |
102 | { |
103 | return -EINVAL; |
104 | } |
105 | #endif |
106 | |
107 | static int try_retrigger(struct irq_desc *desc) |
108 | { |
109 | if (desc->irq_data.chip->irq_retrigger) |
110 | return desc->irq_data.chip->irq_retrigger(&desc->irq_data); |
111 | |
112 | #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY |
113 | return irq_chip_retrigger_hierarchy(data: &desc->irq_data); |
114 | #else |
115 | return 0; |
116 | #endif |
117 | } |
118 | |
119 | /* |
120 | * IRQ resend |
121 | * |
122 | * Is called with interrupts disabled and desc->lock held. |
123 | */ |
124 | int check_irq_resend(struct irq_desc *desc, bool inject) |
125 | { |
126 | int err = 0; |
127 | |
128 | /* |
129 | * We do not resend level type interrupts. Level type interrupts |
130 | * are resent by hardware when they are still active. Clear the |
131 | * pending bit so suspend/resume does not get confused. |
132 | */ |
133 | if (irq_settings_is_level(desc)) { |
134 | desc->istate &= ~IRQS_PENDING; |
135 | return -EINVAL; |
136 | } |
137 | |
138 | if (desc->istate & IRQS_REPLAY) |
139 | return -EBUSY; |
140 | |
141 | if (!(desc->istate & IRQS_PENDING) && !inject) |
142 | return 0; |
143 | |
144 | desc->istate &= ~IRQS_PENDING; |
145 | |
146 | if (!try_retrigger(desc)) |
147 | err = irq_sw_resend(desc); |
148 | |
149 | /* If the retrigger was successful, mark it with the REPLAY bit */ |
150 | if (!err) |
151 | desc->istate |= IRQS_REPLAY; |
152 | return err; |
153 | } |
154 | |
155 | #ifdef CONFIG_GENERIC_IRQ_INJECTION |
156 | /** |
157 | * irq_inject_interrupt - Inject an interrupt for testing/error injection |
158 | * @irq: The interrupt number |
159 | * |
160 | * This function must only be used for debug and testing purposes! |
161 | * |
162 | * Especially on x86 this can cause a premature completion of an interrupt |
163 | * affinity change causing the interrupt line to become stale. Very |
164 | * unlikely, but possible. |
165 | * |
166 | * The injection can fail for various reasons: |
167 | * - Interrupt is not activated |
168 | * - Interrupt is NMI type or currently replaying |
169 | * - Interrupt is level type |
170 | * - Interrupt does not support hardware retrigger and software resend is |
171 | * either not enabled or not possible for the interrupt. |
172 | */ |
173 | int irq_inject_interrupt(unsigned int irq) |
174 | { |
175 | struct irq_desc *desc; |
176 | unsigned long flags; |
177 | int err; |
178 | |
179 | /* Try the state injection hardware interface first */ |
180 | if (!irq_set_irqchip_state(irq, which: IRQCHIP_STATE_PENDING, state: true)) |
181 | return 0; |
182 | |
183 | /* That failed, try via the resend mechanism */ |
184 | desc = irq_get_desc_buslock(irq, flags: &flags, check: 0); |
185 | if (!desc) |
186 | return -EINVAL; |
187 | |
188 | /* |
189 | * Only try to inject when the interrupt is: |
190 | * - not NMI type |
191 | * - activated |
192 | */ |
193 | if ((desc->istate & IRQS_NMI) || !irqd_is_activated(d: &desc->irq_data)) |
194 | err = -EINVAL; |
195 | else |
196 | err = check_irq_resend(desc, inject: true); |
197 | |
198 | irq_put_desc_busunlock(desc, flags); |
199 | return err; |
200 | } |
201 | EXPORT_SYMBOL_GPL(irq_inject_interrupt); |
202 | #endif |
203 | |