Blame view
kernel/irq/chip.c
18.7 KB
dd87eb3a2
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * linux/kernel/irq/chip.c * * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar * Copyright (C) 2005-2006, Thomas Gleixner, Russell King * * This file contains the core interrupt handling code, for irq-chip * based architectures. * * Detailed information is available in Documentation/DocBook/genericirq */ #include <linux/irq.h> |
7fe3730de
|
14 |
#include <linux/msi.h> |
dd87eb3a2
|
15 16 17 |
#include <linux/module.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> |
f069686e4
|
18 |
#include <trace/events/irq.h> |
dd87eb3a2
|
19 |
#include "internals.h" |
3a16d7136
|
20 |
/** |
a0cd9ca2b
|
21 |
* irq_set_chip - set the irq chip for an irq |
dd87eb3a2
|
22 23 24 |
* @irq: irq number * @chip: pointer to irq chip description structure */ |
a0cd9ca2b
|
25 |
int irq_set_chip(unsigned int irq, struct irq_chip *chip) |
dd87eb3a2
|
26 |
{ |
dd87eb3a2
|
27 |
unsigned long flags; |
31d9d9b6d
|
28 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
dd87eb3a2
|
29 |
|
02725e747
|
30 |
if (!desc) |
dd87eb3a2
|
31 |
return -EINVAL; |
dd87eb3a2
|
32 33 34 |
if (!chip) chip = &no_irq_chip; |
6b8ff3120
|
35 |
desc->irq_data.chip = chip; |
02725e747
|
36 |
irq_put_desc_unlock(desc, flags); |
d72274e58
|
37 38 39 40 41 42 |
/* * For !CONFIG_SPARSE_IRQ make the irq show up in * allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is * already marked, and this call is harmless. */ irq_reserve_irq(irq); |
dd87eb3a2
|
43 44 |
return 0; } |
a0cd9ca2b
|
45 |
EXPORT_SYMBOL(irq_set_chip); |
dd87eb3a2
|
46 47 |
/** |
a0cd9ca2b
|
48 |
* irq_set_type - set the irq trigger type for an irq |
dd87eb3a2
|
49 |
* @irq: irq number |
0c5d1eb77
|
50 |
* @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h |
dd87eb3a2
|
51 |
*/ |
a0cd9ca2b
|
52 |
int irq_set_irq_type(unsigned int irq, unsigned int type) |
dd87eb3a2
|
53 |
{ |
dd87eb3a2
|
54 |
unsigned long flags; |
31d9d9b6d
|
55 |
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); |
02725e747
|
56 |
int ret = 0; |
dd87eb3a2
|
57 |
|
02725e747
|
58 59 |
if (!desc) return -EINVAL; |
dd87eb3a2
|
60 |
|
f2b662da8
|
61 |
type &= IRQ_TYPE_SENSE_MASK; |
a09b659cd
|
62 |
ret = __irq_set_trigger(desc, irq, type); |
02725e747
|
63 |
irq_put_desc_busunlock(desc, flags); |
dd87eb3a2
|
64 65 |
return ret; } |
a0cd9ca2b
|
66 |
EXPORT_SYMBOL(irq_set_irq_type); |
dd87eb3a2
|
67 68 |
/** |
a0cd9ca2b
|
69 |
* irq_set_handler_data - set irq handler data for an irq |
dd87eb3a2
|
70 71 72 73 74 |
* @irq: Interrupt number * @data: Pointer to interrupt specific data * * Set the hardware irq controller data for an irq */ |
a0cd9ca2b
|
75 |
int irq_set_handler_data(unsigned int irq, void *data) |
dd87eb3a2
|
76 |
{ |
dd87eb3a2
|
77 |
unsigned long flags; |
31d9d9b6d
|
78 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
dd87eb3a2
|
79 |
|
02725e747
|
80 |
if (!desc) |
dd87eb3a2
|
81 |
return -EINVAL; |
6b8ff3120
|
82 |
desc->irq_data.handler_data = data; |
02725e747
|
83 |
irq_put_desc_unlock(desc, flags); |
dd87eb3a2
|
84 85 |
return 0; } |
a0cd9ca2b
|
86 |
EXPORT_SYMBOL(irq_set_handler_data); |
dd87eb3a2
|
87 88 |
/** |
a0cd9ca2b
|
89 |
* irq_set_msi_desc - set MSI descriptor data for an irq |
5b912c108
|
90 |
* @irq: Interrupt number |
472900b8b
|
91 |
* @entry: Pointer to MSI descriptor data |
5b912c108
|
92 |
* |
24b26d421
|
93 |
* Set the MSI descriptor entry for an irq |
5b912c108
|
94 |
*/ |
a0cd9ca2b
|
95 |
int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) |
5b912c108
|
96 |
{ |
5b912c108
|
97 |
unsigned long flags; |
31d9d9b6d
|
98 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); |
5b912c108
|
99 |
|
02725e747
|
100 |
if (!desc) |
5b912c108
|
101 |
return -EINVAL; |
6b8ff3120
|
102 |
desc->irq_data.msi_desc = entry; |
7fe3730de
|
103 104 |
if (entry) entry->irq = irq; |
02725e747
|
105 |
irq_put_desc_unlock(desc, flags); |
5b912c108
|
106 107 108 109 |
return 0; } /** |
a0cd9ca2b
|
110 |
* irq_set_chip_data - set irq chip data for an irq |
dd87eb3a2
|
111 112 113 114 115 |
* @irq: Interrupt number * @data: Pointer to chip specific data * * Set the hardware irq chip data for an irq */ |
a0cd9ca2b
|
116 |
int irq_set_chip_data(unsigned int irq, void *data) |
dd87eb3a2
|
117 |
{ |
dd87eb3a2
|
118 |
unsigned long flags; |
31d9d9b6d
|
119 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
dd87eb3a2
|
120 |
|
02725e747
|
121 |
if (!desc) |
dd87eb3a2
|
122 |
return -EINVAL; |
6b8ff3120
|
123 |
desc->irq_data.chip_data = data; |
02725e747
|
124 |
irq_put_desc_unlock(desc, flags); |
dd87eb3a2
|
125 126 |
return 0; } |
a0cd9ca2b
|
127 |
EXPORT_SYMBOL(irq_set_chip_data); |
dd87eb3a2
|
128 |
|
f303a6dd1
|
129 130 131 132 133 134 135 |
struct irq_data *irq_get_irq_data(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); return desc ? &desc->irq_data : NULL; } EXPORT_SYMBOL_GPL(irq_get_irq_data); |
c1594b77e
|
136 137 |
static void irq_state_clr_disabled(struct irq_desc *desc) { |
801a0e9ae
|
138 |
irqd_clear(&desc->irq_data, IRQD_IRQ_DISABLED); |
c1594b77e
|
139 140 141 142 |
} static void irq_state_set_disabled(struct irq_desc *desc) { |
801a0e9ae
|
143 |
irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED); |
c1594b77e
|
144 |
} |
6e40262ea
|
145 146 |
static void irq_state_clr_masked(struct irq_desc *desc) { |
32f4125eb
|
147 |
irqd_clear(&desc->irq_data, IRQD_IRQ_MASKED); |
6e40262ea
|
148 149 150 151 |
} static void irq_state_set_masked(struct irq_desc *desc) { |
32f4125eb
|
152 |
irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); |
6e40262ea
|
153 |
} |
b4bc724e8
|
154 |
int irq_startup(struct irq_desc *desc, bool resend) |
469992386
|
155 |
{ |
b4bc724e8
|
156 |
int ret = 0; |
c1594b77e
|
157 |
irq_state_clr_disabled(desc); |
469992386
|
158 |
desc->depth = 0; |
3aae994fb
|
159 |
if (desc->irq_data.chip->irq_startup) { |
b4bc724e8
|
160 |
ret = desc->irq_data.chip->irq_startup(&desc->irq_data); |
6e40262ea
|
161 |
irq_state_clr_masked(desc); |
b4bc724e8
|
162 163 |
} else { irq_enable(desc); |
3aae994fb
|
164 |
} |
b4bc724e8
|
165 166 167 |
if (resend) check_irq_resend(desc, desc->irq_data.irq); return ret; |
469992386
|
168 169 170 171 |
} void irq_shutdown(struct irq_desc *desc) { |
c1594b77e
|
172 |
irq_state_set_disabled(desc); |
469992386
|
173 |
desc->depth = 1; |
50f7c0327
|
174 175 |
if (desc->irq_data.chip->irq_shutdown) desc->irq_data.chip->irq_shutdown(&desc->irq_data); |
ed585a651
|
176 |
else if (desc->irq_data.chip->irq_disable) |
50f7c0327
|
177 178 179 |
desc->irq_data.chip->irq_disable(&desc->irq_data); else desc->irq_data.chip->irq_mask(&desc->irq_data); |
6e40262ea
|
180 |
irq_state_set_masked(desc); |
469992386
|
181 |
} |
87923470c
|
182 183 |
void irq_enable(struct irq_desc *desc) { |
c1594b77e
|
184 |
irq_state_clr_disabled(desc); |
50f7c0327
|
185 186 187 188 |
if (desc->irq_data.chip->irq_enable) desc->irq_data.chip->irq_enable(&desc->irq_data); else desc->irq_data.chip->irq_unmask(&desc->irq_data); |
6e40262ea
|
189 |
irq_state_clr_masked(desc); |
dd87eb3a2
|
190 |
} |
50f7c0327
|
191 |
void irq_disable(struct irq_desc *desc) |
89d694b9d
|
192 |
{ |
c1594b77e
|
193 |
irq_state_set_disabled(desc); |
50f7c0327
|
194 195 |
if (desc->irq_data.chip->irq_disable) { desc->irq_data.chip->irq_disable(&desc->irq_data); |
a61d82580
|
196 |
irq_state_set_masked(desc); |
50f7c0327
|
197 |
} |
89d694b9d
|
198 |
} |
31d9d9b6d
|
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu) { if (desc->irq_data.chip->irq_enable) desc->irq_data.chip->irq_enable(&desc->irq_data); else desc->irq_data.chip->irq_unmask(&desc->irq_data); cpumask_set_cpu(cpu, desc->percpu_enabled); } void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu) { if (desc->irq_data.chip->irq_disable) desc->irq_data.chip->irq_disable(&desc->irq_data); else desc->irq_data.chip->irq_mask(&desc->irq_data); cpumask_clear_cpu(cpu, desc->percpu_enabled); } |
9205e31d1
|
216 |
static inline void mask_ack_irq(struct irq_desc *desc) |
dd87eb3a2
|
217 |
{ |
9205e31d1
|
218 219 |
if (desc->irq_data.chip->irq_mask_ack) desc->irq_data.chip->irq_mask_ack(&desc->irq_data); |
dd87eb3a2
|
220 |
else { |
e2c0f8ff0
|
221 |
desc->irq_data.chip->irq_mask(&desc->irq_data); |
22a49163e
|
222 223 |
if (desc->irq_data.chip->irq_ack) desc->irq_data.chip->irq_ack(&desc->irq_data); |
dd87eb3a2
|
224 |
} |
6e40262ea
|
225 |
irq_state_set_masked(desc); |
0b1adaa03
|
226 |
} |
d4d5e0896
|
227 |
void mask_irq(struct irq_desc *desc) |
0b1adaa03
|
228 |
{ |
e2c0f8ff0
|
229 230 |
if (desc->irq_data.chip->irq_mask) { desc->irq_data.chip->irq_mask(&desc->irq_data); |
6e40262ea
|
231 |
irq_state_set_masked(desc); |
0b1adaa03
|
232 233 |
} } |
d4d5e0896
|
234 |
void unmask_irq(struct irq_desc *desc) |
0b1adaa03
|
235 |
{ |
0eda58b7f
|
236 237 |
if (desc->irq_data.chip->irq_unmask) { desc->irq_data.chip->irq_unmask(&desc->irq_data); |
6e40262ea
|
238 |
irq_state_clr_masked(desc); |
0b1adaa03
|
239 |
} |
dd87eb3a2
|
240 |
} |
399b5da29
|
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
/* * handle_nested_irq - Handle a nested irq from a irq thread * @irq: the interrupt number * * Handle interrupts which are nested into a threaded interrupt * handler. The handler function is called inside the calling * threads context. */ void handle_nested_irq(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); struct irqaction *action; irqreturn_t action_ret; might_sleep(); |
239007b84
|
256 |
raw_spin_lock_irq(&desc->lock); |
399b5da29
|
257 258 259 260 |
kstat_incr_irqs_this_cpu(irq, desc); action = desc->action; |
23812b9d9
|
261 262 |
if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) { desc->istate |= IRQS_PENDING; |
399b5da29
|
263 |
goto out_unlock; |
23812b9d9
|
264 |
} |
399b5da29
|
265 |
|
32f4125eb
|
266 |
irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
239007b84
|
267 |
raw_spin_unlock_irq(&desc->lock); |
399b5da29
|
268 269 270 271 |
action_ret = action->thread_fn(action->irq, action->dev_id); if (!noirqdebug) note_interrupt(irq, desc, action_ret); |
239007b84
|
272 |
raw_spin_lock_irq(&desc->lock); |
32f4125eb
|
273 |
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
399b5da29
|
274 275 |
out_unlock: |
239007b84
|
276 |
raw_spin_unlock_irq(&desc->lock); |
399b5da29
|
277 278 |
} EXPORT_SYMBOL_GPL(handle_nested_irq); |
fe200ae48
|
279 280 |
static bool irq_check_poll(struct irq_desc *desc) { |
6954b75b4
|
281 |
if (!(desc->istate & IRQS_POLL_INPROGRESS)) |
fe200ae48
|
282 283 284 |
return false; return irq_wait_for_poll(desc); } |
dd87eb3a2
|
285 286 287 288 |
/** * handle_simple_irq - Simple and software-decoded IRQs. * @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2
|
289 290 291 292 293 294 295 296 |
* * Simple interrupts are either sent from a demultiplexing interrupt * handler or come from hardware, where no interrupt hardware control * is necessary. * * Note: The caller is expected to handle the ack, clear, mask and * unmask issues if necessary. */ |
7ad5b3a50
|
297 |
void |
7d12e780e
|
298 |
handle_simple_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2
|
299 |
{ |
239007b84
|
300 |
raw_spin_lock(&desc->lock); |
dd87eb3a2
|
301 |
|
32f4125eb
|
302 |
if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
fe200ae48
|
303 304 |
if (!irq_check_poll(desc)) goto out_unlock; |
163ef3091
|
305 |
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a507
|
306 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2
|
307 |
|
23812b9d9
|
308 309 |
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { desc->istate |= IRQS_PENDING; |
dd87eb3a2
|
310 |
goto out_unlock; |
23812b9d9
|
311 |
} |
dd87eb3a2
|
312 |
|
107781e72
|
313 |
handle_irq_event(desc); |
dd87eb3a2
|
314 |
|
dd87eb3a2
|
315 |
out_unlock: |
239007b84
|
316 |
raw_spin_unlock(&desc->lock); |
dd87eb3a2
|
317 |
} |
edf76f830
|
318 |
EXPORT_SYMBOL_GPL(handle_simple_irq); |
dd87eb3a2
|
319 |
|
ac5637611
|
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
/* * Called unconditionally from handle_level_irq() and only for oneshot * interrupts from handle_fasteoi_irq() */ static void cond_unmask_irq(struct irq_desc *desc) { /* * We need to unmask in the following cases: * - Standard level irq (IRQF_ONESHOT is not set) * - Oneshot irq which did not wake the thread (caused by a * spurious interrupt or a primary handler handling it * completely). */ if (!irqd_irq_disabled(&desc->irq_data) && irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) unmask_irq(desc); } |
dd87eb3a2
|
337 338 339 340 |
/** * handle_level_irq - Level type irq handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2
|
341 342 343 344 345 346 |
* * Level type interrupts are active as long as the hardware line has * the active level. This may require to mask the interrupt and unmask * it after the associated handler has acknowledged the device, so the * interrupt line is back to inactive. */ |
7ad5b3a50
|
347 |
void |
7d12e780e
|
348 |
handle_level_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2
|
349 |
{ |
239007b84
|
350 |
raw_spin_lock(&desc->lock); |
9205e31d1
|
351 |
mask_ack_irq(desc); |
dd87eb3a2
|
352 |
|
32f4125eb
|
353 |
if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
fe200ae48
|
354 355 |
if (!irq_check_poll(desc)) goto out_unlock; |
163ef3091
|
356 |
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a507
|
357 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2
|
358 359 360 361 362 |
/* * If its disabled or no action available * keep it masked and get out of here */ |
d4dc0f90d
|
363 364 |
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { desc->istate |= IRQS_PENDING; |
86998aa65
|
365 |
goto out_unlock; |
d4dc0f90d
|
366 |
} |
dd87eb3a2
|
367 |
|
1529866c6
|
368 |
handle_irq_event(desc); |
b25c340c1
|
369 |
|
ac5637611
|
370 |
cond_unmask_irq(desc); |
86998aa65
|
371 |
out_unlock: |
239007b84
|
372 |
raw_spin_unlock(&desc->lock); |
dd87eb3a2
|
373 |
} |
14819ea1e
|
374 |
EXPORT_SYMBOL_GPL(handle_level_irq); |
dd87eb3a2
|
375 |
|
781295762
|
376 377 378 379 380 381 382 383 384 |
#ifdef CONFIG_IRQ_PREFLOW_FASTEOI static inline void preflow_handler(struct irq_desc *desc) { if (desc->preflow_handler) desc->preflow_handler(&desc->irq_data); } #else static inline void preflow_handler(struct irq_desc *desc) { } #endif |
dd87eb3a2
|
385 |
/** |
47c2a3aa4
|
386 |
* handle_fasteoi_irq - irq handler for transparent controllers |
dd87eb3a2
|
387 388 |
* @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2
|
389 |
* |
47c2a3aa4
|
390 |
* Only a single callback will be issued to the chip: an ->eoi() |
dd87eb3a2
|
391 392 393 394 |
* call when the interrupt has been serviced. This enables support * for modern forms of interrupt handlers, which handle the flow * details in hardware, transparently. */ |
7ad5b3a50
|
395 |
void |
7d12e780e
|
396 |
handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2
|
397 |
{ |
239007b84
|
398 |
raw_spin_lock(&desc->lock); |
dd87eb3a2
|
399 |
|
32f4125eb
|
400 |
if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
fe200ae48
|
401 402 |
if (!irq_check_poll(desc)) goto out; |
dd87eb3a2
|
403 |
|
163ef3091
|
404 |
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a507
|
405 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2
|
406 407 408 |
/* * If its disabled or no action available |
76d216014
|
409 |
* then mask it and get out of here: |
dd87eb3a2
|
410 |
*/ |
32f4125eb
|
411 |
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { |
2a0d6fb33
|
412 |
desc->istate |= IRQS_PENDING; |
e2c0f8ff0
|
413 |
mask_irq(desc); |
dd87eb3a2
|
414 |
goto out; |
98bb244b6
|
415 |
} |
c69e3758f
|
416 417 418 |
if (desc->istate & IRQS_ONESHOT) mask_irq(desc); |
781295762
|
419 |
preflow_handler(desc); |
a7ae4de5c
|
420 |
handle_irq_event(desc); |
77694b408
|
421 |
|
ac5637611
|
422 423 |
if (desc->istate & IRQS_ONESHOT) cond_unmask_irq(desc); |
77694b408
|
424 |
out_eoi: |
0c5c15572
|
425 |
desc->irq_data.chip->irq_eoi(&desc->irq_data); |
77694b408
|
426 |
out_unlock: |
239007b84
|
427 |
raw_spin_unlock(&desc->lock); |
77694b408
|
428 429 430 431 432 |
return; out: if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) goto out_eoi; goto out_unlock; |
dd87eb3a2
|
433 434 435 436 437 438 |
} /** * handle_edge_irq - edge type IRQ handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2
|
439 440 |
* * Interrupt occures on the falling and/or rising edge of a hardware |
25985edce
|
441 |
* signal. The occurrence is latched into the irq controller hardware |
dd87eb3a2
|
442 443 |
* and must be acked in order to be reenabled. After the ack another * interrupt can happen on the same source even before the first one |
dfff0615d
|
444 |
* is handled by the associated event handler. If this happens it |
dd87eb3a2
|
445 446 447 448 449 450 |
* might be necessary to disable (mask) the interrupt depending on the * controller hardware. This requires to reenable the interrupt inside * of the loop which handles the interrupts which have arrived while * the handler was running. If all pending interrupts are handled, the * loop is left. */ |
7ad5b3a50
|
451 |
void |
7d12e780e
|
452 |
handle_edge_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2
|
453 |
{ |
239007b84
|
454 |
raw_spin_lock(&desc->lock); |
dd87eb3a2
|
455 |
|
163ef3091
|
456 |
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
dd87eb3a2
|
457 458 459 460 461 |
/* * If we're currently running this IRQ, or its disabled, * we shouldn't process the IRQ. Mark it pending, handle * the necessary masking and go out */ |
32f4125eb
|
462 463 |
if (unlikely(irqd_irq_disabled(&desc->irq_data) || irqd_irq_inprogress(&desc->irq_data) || !desc->action)) { |
fe200ae48
|
464 |
if (!irq_check_poll(desc)) { |
2a0d6fb33
|
465 |
desc->istate |= IRQS_PENDING; |
fe200ae48
|
466 467 468 |
mask_ack_irq(desc); goto out_unlock; } |
dd87eb3a2
|
469 |
} |
d6c88a507
|
470 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2
|
471 472 |
/* Start handling the irq */ |
22a49163e
|
473 |
desc->irq_data.chip->irq_ack(&desc->irq_data); |
dd87eb3a2
|
474 |
|
dd87eb3a2
|
475 |
do { |
a60a5dc2d
|
476 |
if (unlikely(!desc->action)) { |
e2c0f8ff0
|
477 |
mask_irq(desc); |
dd87eb3a2
|
478 479 480 481 482 483 484 485 |
goto out_unlock; } /* * When another irq arrived while we were handling * one, we could have masked the irq. * Renable it, if it was not disabled in meantime. */ |
2a0d6fb33
|
486 |
if (unlikely(desc->istate & IRQS_PENDING)) { |
32f4125eb
|
487 488 |
if (!irqd_irq_disabled(&desc->irq_data) && irqd_irq_masked(&desc->irq_data)) |
c1594b77e
|
489 |
unmask_irq(desc); |
dd87eb3a2
|
490 |
} |
a60a5dc2d
|
491 |
handle_irq_event(desc); |
dd87eb3a2
|
492 |
|
2a0d6fb33
|
493 |
} while ((desc->istate & IRQS_PENDING) && |
32f4125eb
|
494 |
!irqd_irq_disabled(&desc->irq_data)); |
dd87eb3a2
|
495 |
|
dd87eb3a2
|
496 |
out_unlock: |
239007b84
|
497 |
raw_spin_unlock(&desc->lock); |
dd87eb3a2
|
498 |
} |
3911ff30f
|
499 |
EXPORT_SYMBOL(handle_edge_irq); |
dd87eb3a2
|
500 |
|
0521c8fbb
|
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
#ifdef CONFIG_IRQ_EDGE_EOI_HANDLER /** * handle_edge_eoi_irq - edge eoi type IRQ handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq * * Similar as the above handle_edge_irq, but using eoi and w/o the * mask/unmask logic. */ void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); raw_spin_lock(&desc->lock); desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); /* * If we're currently running this IRQ, or its disabled, * we shouldn't process the IRQ. Mark it pending, handle * the necessary masking and go out */ if (unlikely(irqd_irq_disabled(&desc->irq_data) || irqd_irq_inprogress(&desc->irq_data) || !desc->action)) { if (!irq_check_poll(desc)) { desc->istate |= IRQS_PENDING; goto out_eoi; } } kstat_incr_irqs_this_cpu(irq, desc); do { if (unlikely(!desc->action)) goto out_eoi; handle_irq_event(desc); } while ((desc->istate & IRQS_PENDING) && !irqd_irq_disabled(&desc->irq_data)); |
ac0e0447b
|
539 |
out_eoi: |
0521c8fbb
|
540 541 542 543 |
chip->irq_eoi(&desc->irq_data); raw_spin_unlock(&desc->lock); } #endif |
dd87eb3a2
|
544 |
/** |
24b26d421
|
545 |
* handle_percpu_irq - Per CPU local irq handler |
dd87eb3a2
|
546 547 |
* @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2
|
548 549 550 |
* * Per CPU interrupts on SMP machines without locking requirements */ |
7ad5b3a50
|
551 |
void |
7d12e780e
|
552 |
handle_percpu_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2
|
553 |
{ |
35e857cbe
|
554 |
struct irq_chip *chip = irq_desc_get_chip(desc); |
dd87eb3a2
|
555 |
|
d6c88a507
|
556 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2
|
557 |
|
849f061c2
|
558 559 |
if (chip->irq_ack) chip->irq_ack(&desc->irq_data); |
dd87eb3a2
|
560 |
|
849f061c2
|
561 |
handle_irq_event_percpu(desc, desc->action); |
dd87eb3a2
|
562 |
|
849f061c2
|
563 564 |
if (chip->irq_eoi) chip->irq_eoi(&desc->irq_data); |
dd87eb3a2
|
565 |
} |
31d9d9b6d
|
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 |
/** * handle_percpu_devid_irq - Per CPU local irq handler with per cpu dev ids * @irq: the interrupt number * @desc: the interrupt description structure for this irq * * Per CPU interrupts on SMP machines without locking requirements. Same as * handle_percpu_irq() above but with the following extras: * * action->percpu_dev_id is a pointer to percpu variables which * contain the real device id for the cpu on which this handler is * called */ void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct irqaction *action = desc->action; void *dev_id = __this_cpu_ptr(action->percpu_dev_id); irqreturn_t res; kstat_incr_irqs_this_cpu(irq, desc); if (chip->irq_ack) chip->irq_ack(&desc->irq_data); trace_irq_handler_entry(irq, action); res = action->handler(irq, dev_id); trace_irq_handler_exit(irq, action, res); if (chip->irq_eoi) chip->irq_eoi(&desc->irq_data); } |
dd87eb3a2
|
597 |
void |
3836ca08a
|
598 |
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, |
a460e745e
|
599 |
const char *name) |
dd87eb3a2
|
600 |
{ |
dd87eb3a2
|
601 |
unsigned long flags; |
31d9d9b6d
|
602 |
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); |
dd87eb3a2
|
603 |
|
02725e747
|
604 |
if (!desc) |
dd87eb3a2
|
605 |
return; |
dd87eb3a2
|
606 |
|
091738a26
|
607 |
if (!handle) { |
dd87eb3a2
|
608 |
handle = handle_bad_irq; |
091738a26
|
609 610 |
} else { if (WARN_ON(desc->irq_data.chip == &no_irq_chip)) |
02725e747
|
611 |
goto out; |
f8b5473fc
|
612 |
} |
dd87eb3a2
|
613 |
|
dd87eb3a2
|
614 615 |
/* Uninstall? */ if (handle == handle_bad_irq) { |
6b8ff3120
|
616 |
if (desc->irq_data.chip != &no_irq_chip) |
9205e31d1
|
617 |
mask_ack_irq(desc); |
801a0e9ae
|
618 |
irq_state_set_disabled(desc); |
dd87eb3a2
|
619 620 621 |
desc->depth = 1; } desc->handle_irq = handle; |
a460e745e
|
622 |
desc->name = name; |
dd87eb3a2
|
623 624 |
if (handle != handle_bad_irq && is_chained) { |
1ccb4e612
|
625 626 |
irq_settings_set_noprobe(desc); irq_settings_set_norequest(desc); |
7f1b1244e
|
627 |
irq_settings_set_nothread(desc); |
b4bc724e8
|
628 |
irq_startup(desc, true); |
dd87eb3a2
|
629 |
} |
02725e747
|
630 631 |
out: irq_put_desc_busunlock(desc, flags); |
dd87eb3a2
|
632 |
} |
3836ca08a
|
633 |
EXPORT_SYMBOL_GPL(__irq_set_handler); |
dd87eb3a2
|
634 635 |
void |
3836ca08a
|
636 |
irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, |
a460e745e
|
637 |
irq_flow_handler_t handle, const char *name) |
dd87eb3a2
|
638 |
{ |
35e857cbe
|
639 |
irq_set_chip(irq, chip); |
3836ca08a
|
640 |
__irq_set_handler(irq, handle, 0, name); |
dd87eb3a2
|
641 |
} |
46f4f8f66
|
642 |
|
442471848
|
643 |
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) |
46f4f8f66
|
644 |
{ |
46f4f8f66
|
645 |
unsigned long flags; |
31d9d9b6d
|
646 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
46f4f8f66
|
647 |
|
442471848
|
648 |
if (!desc) |
46f4f8f66
|
649 |
return; |
a005677b3
|
650 |
irq_settings_clr_and_set(desc, clr, set); |
876dbd4cc
|
651 |
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU | |
e1ef82414
|
652 |
IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT); |
a005677b3
|
653 654 655 656 |
if (irq_settings_has_no_balance_set(desc)) irqd_set(&desc->irq_data, IRQD_NO_BALANCING); if (irq_settings_is_per_cpu(desc)) irqd_set(&desc->irq_data, IRQD_PER_CPU); |
e1ef82414
|
657 658 |
if (irq_settings_can_move_pcntxt(desc)) irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT); |
0ef5ca1e1
|
659 660 |
if (irq_settings_is_level(desc)) irqd_set(&desc->irq_data, IRQD_LEVEL); |
a005677b3
|
661 |
|
876dbd4cc
|
662 |
irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc)); |
02725e747
|
663 |
irq_put_desc_unlock(desc, flags); |
46f4f8f66
|
664 |
} |
edf76f830
|
665 |
EXPORT_SYMBOL_GPL(irq_modify_status); |
0fdb4b259
|
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 |
/** * irq_cpu_online - Invoke all irq_cpu_online functions. * * Iterate through all irqs and invoke the chip.irq_cpu_online() * for each. */ void irq_cpu_online(void) { struct irq_desc *desc; struct irq_chip *chip; unsigned long flags; unsigned int irq; for_each_active_irq(irq) { desc = irq_to_desc(irq); if (!desc) continue; raw_spin_lock_irqsave(&desc->lock, flags); chip = irq_data_get_irq_chip(&desc->irq_data); |
b3d422329
|
688 689 |
if (chip && chip->irq_cpu_online && (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) || |
32f4125eb
|
690 |
!irqd_irq_disabled(&desc->irq_data))) |
0fdb4b259
|
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 |
chip->irq_cpu_online(&desc->irq_data); raw_spin_unlock_irqrestore(&desc->lock, flags); } } /** * irq_cpu_offline - Invoke all irq_cpu_offline functions. * * Iterate through all irqs and invoke the chip.irq_cpu_offline() * for each. */ void irq_cpu_offline(void) { struct irq_desc *desc; struct irq_chip *chip; unsigned long flags; unsigned int irq; for_each_active_irq(irq) { desc = irq_to_desc(irq); if (!desc) continue; raw_spin_lock_irqsave(&desc->lock, flags); chip = irq_data_get_irq_chip(&desc->irq_data); |
b3d422329
|
718 719 |
if (chip && chip->irq_cpu_offline && (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) || |
32f4125eb
|
720 |
!irqd_irq_disabled(&desc->irq_data))) |
0fdb4b259
|
721 722 723 724 725 |
chip->irq_cpu_offline(&desc->irq_data); raw_spin_unlock_irqrestore(&desc->lock, flags); } } |