Blame view
kernel/irq/chip.c
18 KB
dd87eb3a2 [PATCH] genirq: a... |
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 MSI: arch must co... |
14 |
#include <linux/msi.h> |
dd87eb3a2 [PATCH] genirq: a... |
15 16 17 18 19 |
#include <linux/module.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> #include "internals.h" |
3a16d7136 [PATCH] genirq: i... |
20 |
/** |
a0cd9ca2b genirq: Namespace... |
21 |
* irq_set_chip - set the irq chip for an irq |
dd87eb3a2 [PATCH] genirq: a... |
22 23 24 |
* @irq: irq number * @chip: pointer to irq chip description structure */ |
a0cd9ca2b genirq: Namespace... |
25 |
int irq_set_chip(unsigned int irq, struct irq_chip *chip) |
dd87eb3a2 [PATCH] genirq: a... |
26 |
{ |
dd87eb3a2 [PATCH] genirq: a... |
27 |
unsigned long flags; |
31d9d9b6d genirq: Add suppo... |
28 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
dd87eb3a2 [PATCH] genirq: a... |
29 |
|
02725e747 genirq: Use irq_g... |
30 |
if (!desc) |
dd87eb3a2 [PATCH] genirq: a... |
31 |
return -EINVAL; |
dd87eb3a2 [PATCH] genirq: a... |
32 33 34 |
if (!chip) chip = &no_irq_chip; |
6b8ff3120 genirq: Convert c... |
35 |
desc->irq_data.chip = chip; |
02725e747 genirq: Use irq_g... |
36 |
irq_put_desc_unlock(desc, flags); |
d72274e58 genirq: Reserve t... |
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 [PATCH] genirq: a... |
43 44 |
return 0; } |
a0cd9ca2b genirq: Namespace... |
45 |
EXPORT_SYMBOL(irq_set_chip); |
dd87eb3a2 [PATCH] genirq: a... |
46 47 |
/** |
a0cd9ca2b genirq: Namespace... |
48 |
* irq_set_type - set the irq trigger type for an irq |
dd87eb3a2 [PATCH] genirq: a... |
49 |
* @irq: irq number |
0c5d1eb77 genirq: record tr... |
50 |
* @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h |
dd87eb3a2 [PATCH] genirq: a... |
51 |
*/ |
a0cd9ca2b genirq: Namespace... |
52 |
int irq_set_irq_type(unsigned int irq, unsigned int type) |
dd87eb3a2 [PATCH] genirq: a... |
53 |
{ |
dd87eb3a2 [PATCH] genirq: a... |
54 |
unsigned long flags; |
31d9d9b6d genirq: Add suppo... |
55 |
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); |
02725e747 genirq: Use irq_g... |
56 |
int ret = 0; |
dd87eb3a2 [PATCH] genirq: a... |
57 |
|
02725e747 genirq: Use irq_g... |
58 59 |
if (!desc) return -EINVAL; |
dd87eb3a2 [PATCH] genirq: a... |
60 |
|
f2b662da8 genirq: record IR... |
61 |
type &= IRQ_TYPE_SENSE_MASK; |
02725e747 genirq: Use irq_g... |
62 63 64 |
if (type != IRQ_TYPE_NONE) ret = __irq_set_trigger(desc, irq, type); irq_put_desc_busunlock(desc, flags); |
dd87eb3a2 [PATCH] genirq: a... |
65 66 |
return ret; } |
a0cd9ca2b genirq: Namespace... |
67 |
EXPORT_SYMBOL(irq_set_irq_type); |
dd87eb3a2 [PATCH] genirq: a... |
68 69 |
/** |
a0cd9ca2b genirq: Namespace... |
70 |
* irq_set_handler_data - set irq handler data for an irq |
dd87eb3a2 [PATCH] genirq: a... |
71 72 73 74 75 |
* @irq: Interrupt number * @data: Pointer to interrupt specific data * * Set the hardware irq controller data for an irq */ |
a0cd9ca2b genirq: Namespace... |
76 |
int irq_set_handler_data(unsigned int irq, void *data) |
dd87eb3a2 [PATCH] genirq: a... |
77 |
{ |
dd87eb3a2 [PATCH] genirq: a... |
78 |
unsigned long flags; |
31d9d9b6d genirq: Add suppo... |
79 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
dd87eb3a2 [PATCH] genirq: a... |
80 |
|
02725e747 genirq: Use irq_g... |
81 |
if (!desc) |
dd87eb3a2 [PATCH] genirq: a... |
82 |
return -EINVAL; |
6b8ff3120 genirq: Convert c... |
83 |
desc->irq_data.handler_data = data; |
02725e747 genirq: Use irq_g... |
84 |
irq_put_desc_unlock(desc, flags); |
dd87eb3a2 [PATCH] genirq: a... |
85 86 |
return 0; } |
a0cd9ca2b genirq: Namespace... |
87 |
EXPORT_SYMBOL(irq_set_handler_data); |
dd87eb3a2 [PATCH] genirq: a... |
88 89 |
/** |
a0cd9ca2b genirq: Namespace... |
90 |
* irq_set_msi_desc - set MSI descriptor data for an irq |
5b912c108 msi: Kill the msi... |
91 |
* @irq: Interrupt number |
472900b8b [PATCH] IRQ kerne... |
92 |
* @entry: Pointer to MSI descriptor data |
5b912c108 msi: Kill the msi... |
93 |
* |
24b26d421 irq: Fix docbook ... |
94 |
* Set the MSI descriptor entry for an irq |
5b912c108 msi: Kill the msi... |
95 |
*/ |
a0cd9ca2b genirq: Namespace... |
96 |
int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) |
5b912c108 msi: Kill the msi... |
97 |
{ |
5b912c108 msi: Kill the msi... |
98 |
unsigned long flags; |
31d9d9b6d genirq: Add suppo... |
99 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); |
5b912c108 msi: Kill the msi... |
100 |
|
02725e747 genirq: Use irq_g... |
101 |
if (!desc) |
5b912c108 msi: Kill the msi... |
102 |
return -EINVAL; |
6b8ff3120 genirq: Convert c... |
103 |
desc->irq_data.msi_desc = entry; |
7fe3730de MSI: arch must co... |
104 105 |
if (entry) entry->irq = irq; |
02725e747 genirq: Use irq_g... |
106 |
irq_put_desc_unlock(desc, flags); |
5b912c108 msi: Kill the msi... |
107 108 109 110 |
return 0; } /** |
a0cd9ca2b genirq: Namespace... |
111 |
* irq_set_chip_data - set irq chip data for an irq |
dd87eb3a2 [PATCH] genirq: a... |
112 113 114 115 116 |
* @irq: Interrupt number * @data: Pointer to chip specific data * * Set the hardware irq chip data for an irq */ |
a0cd9ca2b genirq: Namespace... |
117 |
int irq_set_chip_data(unsigned int irq, void *data) |
dd87eb3a2 [PATCH] genirq: a... |
118 |
{ |
dd87eb3a2 [PATCH] genirq: a... |
119 |
unsigned long flags; |
31d9d9b6d genirq: Add suppo... |
120 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
dd87eb3a2 [PATCH] genirq: a... |
121 |
|
02725e747 genirq: Use irq_g... |
122 |
if (!desc) |
dd87eb3a2 [PATCH] genirq: a... |
123 |
return -EINVAL; |
6b8ff3120 genirq: Convert c... |
124 |
desc->irq_data.chip_data = data; |
02725e747 genirq: Use irq_g... |
125 |
irq_put_desc_unlock(desc, flags); |
dd87eb3a2 [PATCH] genirq: a... |
126 127 |
return 0; } |
a0cd9ca2b genirq: Namespace... |
128 |
EXPORT_SYMBOL(irq_set_chip_data); |
dd87eb3a2 [PATCH] genirq: a... |
129 |
|
f303a6dd1 genirq: Sanitize ... |
130 131 132 133 134 135 136 |
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 genirq: Move IRQ_... |
137 138 |
static void irq_state_clr_disabled(struct irq_desc *desc) { |
801a0e9ae genirq: Add irq d... |
139 |
irqd_clear(&desc->irq_data, IRQD_IRQ_DISABLED); |
c1594b77e genirq: Move IRQ_... |
140 141 142 143 |
} static void irq_state_set_disabled(struct irq_desc *desc) { |
801a0e9ae genirq: Add irq d... |
144 |
irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED); |
c1594b77e genirq: Move IRQ_... |
145 |
} |
6e40262ea genirq: Move IRQ_... |
146 147 |
static void irq_state_clr_masked(struct irq_desc *desc) { |
32f4125eb genirq: Move INPR... |
148 |
irqd_clear(&desc->irq_data, IRQD_IRQ_MASKED); |
6e40262ea genirq: Move IRQ_... |
149 150 151 152 |
} static void irq_state_set_masked(struct irq_desc *desc) { |
32f4125eb genirq: Move INPR... |
153 |
irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); |
6e40262ea genirq: Move IRQ_... |
154 |
} |
469992386 genirq: Consolida... |
155 156 |
int irq_startup(struct irq_desc *desc) { |
c1594b77e genirq: Move IRQ_... |
157 |
irq_state_clr_disabled(desc); |
469992386 genirq: Consolida... |
158 |
desc->depth = 0; |
3aae994fb genirq: Consolida... |
159 160 |
if (desc->irq_data.chip->irq_startup) { int ret = desc->irq_data.chip->irq_startup(&desc->irq_data); |
6e40262ea genirq: Move IRQ_... |
161 |
irq_state_clr_masked(desc); |
3aae994fb genirq: Consolida... |
162 163 |
return ret; } |
469992386 genirq: Consolida... |
164 |
|
87923470c genirq: Consolida... |
165 |
irq_enable(desc); |
469992386 genirq: Consolida... |
166 167 168 169 170 |
return 0; } void irq_shutdown(struct irq_desc *desc) { |
c1594b77e genirq: Move IRQ_... |
171 |
irq_state_set_disabled(desc); |
469992386 genirq: Consolida... |
172 |
desc->depth = 1; |
50f7c0327 genirq: Remove de... |
173 174 |
if (desc->irq_data.chip->irq_shutdown) desc->irq_data.chip->irq_shutdown(&desc->irq_data); |
ed585a651 genirq: Make irq_... |
175 |
else if (desc->irq_data.chip->irq_disable) |
50f7c0327 genirq: Remove de... |
176 177 178 |
desc->irq_data.chip->irq_disable(&desc->irq_data); else desc->irq_data.chip->irq_mask(&desc->irq_data); |
6e40262ea genirq: Move IRQ_... |
179 |
irq_state_set_masked(desc); |
469992386 genirq: Consolida... |
180 |
} |
87923470c genirq: Consolida... |
181 182 |
void irq_enable(struct irq_desc *desc) { |
c1594b77e genirq: Move IRQ_... |
183 |
irq_state_clr_disabled(desc); |
50f7c0327 genirq: Remove de... |
184 185 186 187 |
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 genirq: Move IRQ_... |
188 |
irq_state_clr_masked(desc); |
dd87eb3a2 [PATCH] genirq: a... |
189 |
} |
50f7c0327 genirq: Remove de... |
190 |
void irq_disable(struct irq_desc *desc) |
89d694b9d genirq: do not le... |
191 |
{ |
c1594b77e genirq: Move IRQ_... |
192 |
irq_state_set_disabled(desc); |
50f7c0327 genirq: Remove de... |
193 194 |
if (desc->irq_data.chip->irq_disable) { desc->irq_data.chip->irq_disable(&desc->irq_data); |
a61d82580 genirq: Fix mispl... |
195 |
irq_state_set_masked(desc); |
50f7c0327 genirq: Remove de... |
196 |
} |
89d694b9d genirq: do not le... |
197 |
} |
31d9d9b6d genirq: Add suppo... |
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
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 genirq: Provide c... |
215 |
static inline void mask_ack_irq(struct irq_desc *desc) |
dd87eb3a2 [PATCH] genirq: a... |
216 |
{ |
9205e31d1 genirq: Provide c... |
217 218 |
if (desc->irq_data.chip->irq_mask_ack) desc->irq_data.chip->irq_mask_ack(&desc->irq_data); |
dd87eb3a2 [PATCH] genirq: a... |
219 |
else { |
e2c0f8ff0 genirq: Provide c... |
220 |
desc->irq_data.chip->irq_mask(&desc->irq_data); |
22a49163e genirq: Provide c... |
221 222 |
if (desc->irq_data.chip->irq_ack) desc->irq_data.chip->irq_ack(&desc->irq_data); |
dd87eb3a2 [PATCH] genirq: a... |
223 |
} |
6e40262ea genirq: Move IRQ_... |
224 |
irq_state_set_masked(desc); |
0b1adaa03 genirq: Prevent o... |
225 |
} |
d4d5e0896 genirq: Add IRQCH... |
226 |
void mask_irq(struct irq_desc *desc) |
0b1adaa03 genirq: Prevent o... |
227 |
{ |
e2c0f8ff0 genirq: Provide c... |
228 229 |
if (desc->irq_data.chip->irq_mask) { desc->irq_data.chip->irq_mask(&desc->irq_data); |
6e40262ea genirq: Move IRQ_... |
230 |
irq_state_set_masked(desc); |
0b1adaa03 genirq: Prevent o... |
231 232 |
} } |
d4d5e0896 genirq: Add IRQCH... |
233 |
void unmask_irq(struct irq_desc *desc) |
0b1adaa03 genirq: Prevent o... |
234 |
{ |
0eda58b7f genirq: Provide c... |
235 236 |
if (desc->irq_data.chip->irq_unmask) { desc->irq_data.chip->irq_unmask(&desc->irq_data); |
6e40262ea genirq: Move IRQ_... |
237 |
irq_state_clr_masked(desc); |
0b1adaa03 genirq: Prevent o... |
238 |
} |
dd87eb3a2 [PATCH] genirq: a... |
239 |
} |
399b5da29 genirq: Support n... |
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
/* * 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 genirq: Convert i... |
255 |
raw_spin_lock_irq(&desc->lock); |
399b5da29 genirq: Support n... |
256 257 258 259 |
kstat_incr_irqs_this_cpu(irq, desc); action = desc->action; |
32f4125eb genirq: Move INPR... |
260 |
if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) |
399b5da29 genirq: Support n... |
261 |
goto out_unlock; |
32f4125eb genirq: Move INPR... |
262 |
irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
239007b84 genirq: Convert i... |
263 |
raw_spin_unlock_irq(&desc->lock); |
399b5da29 genirq: Support n... |
264 265 266 267 |
action_ret = action->thread_fn(action->irq, action->dev_id); if (!noirqdebug) note_interrupt(irq, desc, action_ret); |
239007b84 genirq: Convert i... |
268 |
raw_spin_lock_irq(&desc->lock); |
32f4125eb genirq: Move INPR... |
269 |
irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); |
399b5da29 genirq: Support n... |
270 271 |
out_unlock: |
239007b84 genirq: Convert i... |
272 |
raw_spin_unlock_irq(&desc->lock); |
399b5da29 genirq: Support n... |
273 274 |
} EXPORT_SYMBOL_GPL(handle_nested_irq); |
fe200ae48 genirq: Mark poll... |
275 276 |
static bool irq_check_poll(struct irq_desc *desc) { |
6954b75b4 genirq: Move IRQ_... |
277 |
if (!(desc->istate & IRQS_POLL_INPROGRESS)) |
fe200ae48 genirq: Mark poll... |
278 279 280 |
return false; return irq_wait_for_poll(desc); } |
dd87eb3a2 [PATCH] genirq: a... |
281 282 283 284 |
/** * handle_simple_irq - Simple and software-decoded IRQs. * @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2 [PATCH] genirq: a... |
285 286 287 288 289 290 291 292 |
* * 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 kernel: remove fa... |
293 |
void |
7d12e780e IRQ: Maintain reg... |
294 |
handle_simple_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2 [PATCH] genirq: a... |
295 |
{ |
239007b84 genirq: Convert i... |
296 |
raw_spin_lock(&desc->lock); |
dd87eb3a2 [PATCH] genirq: a... |
297 |
|
32f4125eb genirq: Move INPR... |
298 |
if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
fe200ae48 genirq: Mark poll... |
299 300 |
if (!irq_check_poll(desc)) goto out_unlock; |
163ef3091 genirq: Move IRQ_... |
301 |
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a507 genirq: revert dy... |
302 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2 [PATCH] genirq: a... |
303 |
|
32f4125eb genirq: Move INPR... |
304 |
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) |
dd87eb3a2 [PATCH] genirq: a... |
305 |
goto out_unlock; |
107781e72 genirq: Use handl... |
306 |
handle_irq_event(desc); |
dd87eb3a2 [PATCH] genirq: a... |
307 |
|
dd87eb3a2 [PATCH] genirq: a... |
308 |
out_unlock: |
239007b84 genirq: Convert i... |
309 |
raw_spin_unlock(&desc->lock); |
dd87eb3a2 [PATCH] genirq: a... |
310 |
} |
edf76f830 irq: Export funct... |
311 |
EXPORT_SYMBOL_GPL(handle_simple_irq); |
dd87eb3a2 [PATCH] genirq: a... |
312 313 314 315 316 |
/** * handle_level_irq - Level type irq handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2 [PATCH] genirq: a... |
317 318 319 320 321 322 |
* * 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 kernel: remove fa... |
323 |
void |
7d12e780e IRQ: Maintain reg... |
324 |
handle_level_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2 [PATCH] genirq: a... |
325 |
{ |
239007b84 genirq: Convert i... |
326 |
raw_spin_lock(&desc->lock); |
9205e31d1 genirq: Provide c... |
327 |
mask_ack_irq(desc); |
dd87eb3a2 [PATCH] genirq: a... |
328 |
|
32f4125eb genirq: Move INPR... |
329 |
if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
fe200ae48 genirq: Mark poll... |
330 331 |
if (!irq_check_poll(desc)) goto out_unlock; |
163ef3091 genirq: Move IRQ_... |
332 |
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a507 genirq: revert dy... |
333 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2 [PATCH] genirq: a... |
334 335 336 337 338 |
/* * If its disabled or no action available * keep it masked and get out of here */ |
32f4125eb genirq: Move INPR... |
339 |
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) |
86998aa65 [PATCH] genirq co... |
340 |
goto out_unlock; |
dd87eb3a2 [PATCH] genirq: a... |
341 |
|
1529866c6 genirq: Use handl... |
342 |
handle_irq_event(desc); |
b25c340c1 genirq: Add onesh... |
343 |
|
32f4125eb genirq: Move INPR... |
344 |
if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) |
0eda58b7f genirq: Provide c... |
345 |
unmask_irq(desc); |
86998aa65 [PATCH] genirq co... |
346 |
out_unlock: |
239007b84 genirq: Convert i... |
347 |
raw_spin_unlock(&desc->lock); |
dd87eb3a2 [PATCH] genirq: a... |
348 |
} |
14819ea1e irq: export __set... |
349 |
EXPORT_SYMBOL_GPL(handle_level_irq); |
dd87eb3a2 [PATCH] genirq: a... |
350 |
|
781295762 genirq: Add prefl... |
351 352 353 354 355 356 357 358 359 |
#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 [PATCH] genirq: a... |
360 |
/** |
47c2a3aa4 [PATCH] genirq: a... |
361 |
* handle_fasteoi_irq - irq handler for transparent controllers |
dd87eb3a2 [PATCH] genirq: a... |
362 363 |
* @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2 [PATCH] genirq: a... |
364 |
* |
47c2a3aa4 [PATCH] genirq: a... |
365 |
* Only a single callback will be issued to the chip: an ->eoi() |
dd87eb3a2 [PATCH] genirq: a... |
366 367 368 369 |
* 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 kernel: remove fa... |
370 |
void |
7d12e780e IRQ: Maintain reg... |
371 |
handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2 [PATCH] genirq: a... |
372 |
{ |
239007b84 genirq: Convert i... |
373 |
raw_spin_lock(&desc->lock); |
dd87eb3a2 [PATCH] genirq: a... |
374 |
|
32f4125eb genirq: Move INPR... |
375 |
if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
fe200ae48 genirq: Mark poll... |
376 377 |
if (!irq_check_poll(desc)) goto out; |
dd87eb3a2 [PATCH] genirq: a... |
378 |
|
163ef3091 genirq: Move IRQ_... |
379 |
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
d6c88a507 genirq: revert dy... |
380 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2 [PATCH] genirq: a... |
381 382 383 |
/* * If its disabled or no action available |
76d216014 [PATCH] genirq: d... |
384 |
* then mask it and get out of here: |
dd87eb3a2 [PATCH] genirq: a... |
385 |
*/ |
32f4125eb genirq: Move INPR... |
386 |
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { |
2a0d6fb33 genirq: Move IRQ_... |
387 |
desc->istate |= IRQS_PENDING; |
e2c0f8ff0 genirq: Provide c... |
388 |
mask_irq(desc); |
dd87eb3a2 [PATCH] genirq: a... |
389 |
goto out; |
98bb244b6 [PATCH] genirq: f... |
390 |
} |
c69e3758f genirq: Fixup fas... |
391 392 393 |
if (desc->istate & IRQS_ONESHOT) mask_irq(desc); |
781295762 genirq: Add prefl... |
394 |
preflow_handler(desc); |
a7ae4de5c genirq: Use handl... |
395 |
handle_irq_event(desc); |
77694b408 genirq; Add faste... |
396 397 |
out_eoi: |
0c5c15572 genirq: Provide c... |
398 |
desc->irq_data.chip->irq_eoi(&desc->irq_data); |
77694b408 genirq; Add faste... |
399 |
out_unlock: |
239007b84 genirq: Convert i... |
400 |
raw_spin_unlock(&desc->lock); |
77694b408 genirq; Add faste... |
401 402 403 404 405 |
return; out: if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) goto out_eoi; goto out_unlock; |
dd87eb3a2 [PATCH] genirq: a... |
406 407 408 409 410 411 |
} /** * handle_edge_irq - edge type IRQ handler * @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2 [PATCH] genirq: a... |
412 413 |
* * Interrupt occures on the falling and/or rising edge of a hardware |
25985edce Fix common misspe... |
414 |
* signal. The occurrence is latched into the irq controller hardware |
dd87eb3a2 [PATCH] genirq: a... |
415 416 |
* 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 tree-wide: fix ty... |
417 |
* is handled by the associated event handler. If this happens it |
dd87eb3a2 [PATCH] genirq: a... |
418 419 420 421 422 423 |
* 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 kernel: remove fa... |
424 |
void |
7d12e780e IRQ: Maintain reg... |
425 |
handle_edge_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2 [PATCH] genirq: a... |
426 |
{ |
239007b84 genirq: Convert i... |
427 |
raw_spin_lock(&desc->lock); |
dd87eb3a2 [PATCH] genirq: a... |
428 |
|
163ef3091 genirq: Move IRQ_... |
429 |
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); |
dd87eb3a2 [PATCH] genirq: a... |
430 431 432 433 434 |
/* * 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 genirq: Move INPR... |
435 436 |
if (unlikely(irqd_irq_disabled(&desc->irq_data) || irqd_irq_inprogress(&desc->irq_data) || !desc->action)) { |
fe200ae48 genirq: Mark poll... |
437 |
if (!irq_check_poll(desc)) { |
2a0d6fb33 genirq: Move IRQ_... |
438 |
desc->istate |= IRQS_PENDING; |
fe200ae48 genirq: Mark poll... |
439 440 441 |
mask_ack_irq(desc); goto out_unlock; } |
dd87eb3a2 [PATCH] genirq: a... |
442 |
} |
d6c88a507 genirq: revert dy... |
443 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2 [PATCH] genirq: a... |
444 445 |
/* Start handling the irq */ |
22a49163e genirq: Provide c... |
446 |
desc->irq_data.chip->irq_ack(&desc->irq_data); |
dd87eb3a2 [PATCH] genirq: a... |
447 |
|
dd87eb3a2 [PATCH] genirq: a... |
448 |
do { |
a60a5dc2d genirq: Use handl... |
449 |
if (unlikely(!desc->action)) { |
e2c0f8ff0 genirq: Provide c... |
450 |
mask_irq(desc); |
dd87eb3a2 [PATCH] genirq: a... |
451 452 453 454 455 456 457 458 |
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 genirq: Move IRQ_... |
459 |
if (unlikely(desc->istate & IRQS_PENDING)) { |
32f4125eb genirq: Move INPR... |
460 461 |
if (!irqd_irq_disabled(&desc->irq_data) && irqd_irq_masked(&desc->irq_data)) |
c1594b77e genirq: Move IRQ_... |
462 |
unmask_irq(desc); |
dd87eb3a2 [PATCH] genirq: a... |
463 |
} |
a60a5dc2d genirq: Use handl... |
464 |
handle_irq_event(desc); |
dd87eb3a2 [PATCH] genirq: a... |
465 |
|
2a0d6fb33 genirq: Move IRQ_... |
466 |
} while ((desc->istate & IRQS_PENDING) && |
32f4125eb genirq: Move INPR... |
467 |
!irqd_irq_disabled(&desc->irq_data)); |
dd87eb3a2 [PATCH] genirq: a... |
468 |
|
dd87eb3a2 [PATCH] genirq: a... |
469 |
out_unlock: |
239007b84 genirq: Convert i... |
470 |
raw_spin_unlock(&desc->lock); |
dd87eb3a2 [PATCH] genirq: a... |
471 |
} |
0521c8fbb genirq: Provide e... |
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
#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 genirq: fix CONFI... |
510 |
out_eoi: |
0521c8fbb genirq: Provide e... |
511 512 513 514 |
chip->irq_eoi(&desc->irq_data); raw_spin_unlock(&desc->lock); } #endif |
dd87eb3a2 [PATCH] genirq: a... |
515 |
/** |
24b26d421 irq: Fix docbook ... |
516 |
* handle_percpu_irq - Per CPU local irq handler |
dd87eb3a2 [PATCH] genirq: a... |
517 518 |
* @irq: the interrupt number * @desc: the interrupt description structure for this irq |
dd87eb3a2 [PATCH] genirq: a... |
519 520 521 |
* * Per CPU interrupts on SMP machines without locking requirements */ |
7ad5b3a50 kernel: remove fa... |
522 |
void |
7d12e780e IRQ: Maintain reg... |
523 |
handle_percpu_irq(unsigned int irq, struct irq_desc *desc) |
dd87eb3a2 [PATCH] genirq: a... |
524 |
{ |
35e857cbe genirq: Fixup cor... |
525 |
struct irq_chip *chip = irq_desc_get_chip(desc); |
dd87eb3a2 [PATCH] genirq: a... |
526 |
|
d6c88a507 genirq: revert dy... |
527 |
kstat_incr_irqs_this_cpu(irq, desc); |
dd87eb3a2 [PATCH] genirq: a... |
528 |
|
849f061c2 genirq: Use handl... |
529 530 |
if (chip->irq_ack) chip->irq_ack(&desc->irq_data); |
dd87eb3a2 [PATCH] genirq: a... |
531 |
|
849f061c2 genirq: Use handl... |
532 |
handle_irq_event_percpu(desc, desc->action); |
dd87eb3a2 [PATCH] genirq: a... |
533 |
|
849f061c2 genirq: Use handl... |
534 535 |
if (chip->irq_eoi) chip->irq_eoi(&desc->irq_data); |
dd87eb3a2 [PATCH] genirq: a... |
536 |
} |
31d9d9b6d genirq: Add suppo... |
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 |
/** * 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 [PATCH] genirq: a... |
568 |
void |
3836ca08a genirq: Consolida... |
569 |
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, |
a460e745e [PATCH] genirq: c... |
570 |
const char *name) |
dd87eb3a2 [PATCH] genirq: a... |
571 |
{ |
dd87eb3a2 [PATCH] genirq: a... |
572 |
unsigned long flags; |
31d9d9b6d genirq: Add suppo... |
573 |
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); |
dd87eb3a2 [PATCH] genirq: a... |
574 |
|
02725e747 genirq: Use irq_g... |
575 |
if (!desc) |
dd87eb3a2 [PATCH] genirq: a... |
576 |
return; |
dd87eb3a2 [PATCH] genirq: a... |
577 |
|
091738a26 genirq: Remove re... |
578 |
if (!handle) { |
dd87eb3a2 [PATCH] genirq: a... |
579 |
handle = handle_bad_irq; |
091738a26 genirq: Remove re... |
580 581 |
} else { if (WARN_ON(desc->irq_data.chip == &no_irq_chip)) |
02725e747 genirq: Use irq_g... |
582 |
goto out; |
f8b5473fc [ARM] 3690/1: gen... |
583 |
} |
dd87eb3a2 [PATCH] genirq: a... |
584 |
|
dd87eb3a2 [PATCH] genirq: a... |
585 586 |
/* Uninstall? */ if (handle == handle_bad_irq) { |
6b8ff3120 genirq: Convert c... |
587 |
if (desc->irq_data.chip != &no_irq_chip) |
9205e31d1 genirq: Provide c... |
588 |
mask_ack_irq(desc); |
801a0e9ae genirq: Add irq d... |
589 |
irq_state_set_disabled(desc); |
dd87eb3a2 [PATCH] genirq: a... |
590 591 592 |
desc->depth = 1; } desc->handle_irq = handle; |
a460e745e [PATCH] genirq: c... |
593 |
desc->name = name; |
dd87eb3a2 [PATCH] genirq: a... |
594 595 |
if (handle != handle_bad_irq && is_chained) { |
1ccb4e612 genirq: Wrap the ... |
596 597 |
irq_settings_set_noprobe(desc); irq_settings_set_norequest(desc); |
7f1b1244e genirq: Support p... |
598 |
irq_settings_set_nothread(desc); |
469992386 genirq: Consolida... |
599 |
irq_startup(desc); |
dd87eb3a2 [PATCH] genirq: a... |
600 |
} |
02725e747 genirq: Use irq_g... |
601 602 |
out: irq_put_desc_busunlock(desc, flags); |
dd87eb3a2 [PATCH] genirq: a... |
603 |
} |
3836ca08a genirq: Consolida... |
604 |
EXPORT_SYMBOL_GPL(__irq_set_handler); |
dd87eb3a2 [PATCH] genirq: a... |
605 606 |
void |
3836ca08a genirq: Consolida... |
607 |
irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, |
a460e745e [PATCH] genirq: c... |
608 |
irq_flow_handler_t handle, const char *name) |
dd87eb3a2 [PATCH] genirq: a... |
609 |
{ |
35e857cbe genirq: Fixup cor... |
610 |
irq_set_chip(irq, chip); |
3836ca08a genirq: Consolida... |
611 |
__irq_set_handler(irq, handle, 0, name); |
dd87eb3a2 [PATCH] genirq: a... |
612 |
} |
46f4f8f66 IRQ_NOPROBE helpe... |
613 |
|
442471848 genirq: Provide s... |
614 |
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) |
46f4f8f66 IRQ_NOPROBE helpe... |
615 |
{ |
46f4f8f66 IRQ_NOPROBE helpe... |
616 |
unsigned long flags; |
31d9d9b6d genirq: Add suppo... |
617 |
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); |
46f4f8f66 IRQ_NOPROBE helpe... |
618 |
|
442471848 genirq: Provide s... |
619 |
if (!desc) |
46f4f8f66 IRQ_NOPROBE helpe... |
620 |
return; |
a005677b3 genirq: Mirror IR... |
621 |
irq_settings_clr_and_set(desc, clr, set); |
876dbd4cc genirq: Mirror ir... |
622 |
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU | |
e1ef82414 genirq: Reflect I... |
623 |
IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT); |
a005677b3 genirq: Mirror IR... |
624 625 626 627 |
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 genirq: Reflect I... |
628 629 |
if (irq_settings_can_move_pcntxt(desc)) irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT); |
0ef5ca1e1 genirq; Fix clean... |
630 631 |
if (irq_settings_is_level(desc)) irqd_set(&desc->irq_data, IRQD_LEVEL); |
a005677b3 genirq: Mirror IR... |
632 |
|
876dbd4cc genirq: Mirror ir... |
633 |
irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc)); |
02725e747 genirq: Use irq_g... |
634 |
irq_put_desc_unlock(desc, flags); |
46f4f8f66 IRQ_NOPROBE helpe... |
635 |
} |
edf76f830 irq: Export funct... |
636 |
EXPORT_SYMBOL_GPL(irq_modify_status); |
0fdb4b259 genirq: Add chip ... |
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
/** * 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 genirq: Add chip ... |
659 660 |
if (chip && chip->irq_cpu_online && (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) || |
32f4125eb genirq: Move INPR... |
661 |
!irqd_irq_disabled(&desc->irq_data))) |
0fdb4b259 genirq: Add chip ... |
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 |
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 genirq: Add chip ... |
689 690 |
if (chip && chip->irq_cpu_offline && (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) || |
32f4125eb genirq: Move INPR... |
691 |
!irqd_irq_disabled(&desc->irq_data))) |
0fdb4b259 genirq: Add chip ... |
692 693 694 695 696 |
chip->irq_cpu_offline(&desc->irq_data); raw_spin_unlock_irqrestore(&desc->lock, flags); } } |