]>
Commit | Line | Data |
---|---|---|
7d828062 TG |
1 | /* |
2 | * Library implementing the most common irq chip callback functions | |
3 | * | |
4 | * Copyright (C) 2011, Thomas Gleixner | |
5 | */ | |
6 | #include <linux/io.h> | |
7 | #include <linux/irq.h> | |
8 | #include <linux/slab.h> | |
6e5fdeed | 9 | #include <linux/export.h> |
088f40b7 | 10 | #include <linux/irqdomain.h> |
7d828062 TG |
11 | #include <linux/interrupt.h> |
12 | #include <linux/kernel_stat.h> | |
cfefd21e | 13 | #include <linux/syscore_ops.h> |
7d828062 TG |
14 | |
15 | #include "internals.h" | |
16 | ||
cfefd21e TG |
17 | static LIST_HEAD(gc_list); |
18 | static DEFINE_RAW_SPINLOCK(gc_lock); | |
19 | ||
7d828062 TG |
20 | /** |
21 | * irq_gc_noop - NOOP function | |
22 | * @d: irq_data | |
23 | */ | |
24 | void irq_gc_noop(struct irq_data *d) | |
25 | { | |
26 | } | |
27 | ||
28 | /** | |
29 | * irq_gc_mask_disable_reg - Mask chip via disable register | |
30 | * @d: irq_data | |
31 | * | |
32 | * Chip has separate enable/disable registers instead of a single mask | |
33 | * register. | |
34 | */ | |
35 | void irq_gc_mask_disable_reg(struct irq_data *d) | |
36 | { | |
37 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 38 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 39 | u32 mask = d->mask; |
7d828062 TG |
40 | |
41 | irq_gc_lock(gc); | |
cfeaa93f | 42 | irq_reg_writel(mask, gc->reg_base + ct->regs.disable); |
899f0e66 | 43 | *ct->mask_cache &= ~mask; |
7d828062 TG |
44 | irq_gc_unlock(gc); |
45 | } | |
46 | ||
47 | /** | |
ccc414f8 | 48 | * irq_gc_mask_set_bit - Mask chip via setting bit in mask register |
7d828062 TG |
49 | * @d: irq_data |
50 | * | |
51 | * Chip has a single mask register. Values of this register are cached | |
52 | * and protected by gc->lock | |
53 | */ | |
54 | void irq_gc_mask_set_bit(struct irq_data *d) | |
55 | { | |
56 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 57 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 58 | u32 mask = d->mask; |
7d828062 TG |
59 | |
60 | irq_gc_lock(gc); | |
899f0e66 GF |
61 | *ct->mask_cache |= mask; |
62 | irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask); | |
7d828062 TG |
63 | irq_gc_unlock(gc); |
64 | } | |
d55f0cc4 | 65 | EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit); |
7d828062 TG |
66 | |
67 | /** | |
ccc414f8 | 68 | * irq_gc_mask_clr_bit - Mask chip via clearing bit in mask register |
7d828062 TG |
69 | * @d: irq_data |
70 | * | |
71 | * Chip has a single mask register. Values of this register are cached | |
72 | * and protected by gc->lock | |
73 | */ | |
74 | void irq_gc_mask_clr_bit(struct irq_data *d) | |
75 | { | |
76 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 77 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 78 | u32 mask = d->mask; |
7d828062 TG |
79 | |
80 | irq_gc_lock(gc); | |
899f0e66 GF |
81 | *ct->mask_cache &= ~mask; |
82 | irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask); | |
7d828062 TG |
83 | irq_gc_unlock(gc); |
84 | } | |
d55f0cc4 | 85 | EXPORT_SYMBOL_GPL(irq_gc_mask_clr_bit); |
7d828062 TG |
86 | |
87 | /** | |
88 | * irq_gc_unmask_enable_reg - Unmask chip via enable register | |
89 | * @d: irq_data | |
90 | * | |
91 | * Chip has separate enable/disable registers instead of a single mask | |
92 | * register. | |
93 | */ | |
94 | void irq_gc_unmask_enable_reg(struct irq_data *d) | |
95 | { | |
96 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 97 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 98 | u32 mask = d->mask; |
7d828062 TG |
99 | |
100 | irq_gc_lock(gc); | |
cfeaa93f | 101 | irq_reg_writel(mask, gc->reg_base + ct->regs.enable); |
899f0e66 | 102 | *ct->mask_cache |= mask; |
7d828062 TG |
103 | irq_gc_unlock(gc); |
104 | } | |
105 | ||
106 | /** | |
659fb32d | 107 | * irq_gc_ack_set_bit - Ack pending interrupt via setting bit |
7d828062 TG |
108 | * @d: irq_data |
109 | */ | |
659fb32d | 110 | void irq_gc_ack_set_bit(struct irq_data *d) |
7d828062 TG |
111 | { |
112 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 113 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 114 | u32 mask = d->mask; |
7d828062 TG |
115 | |
116 | irq_gc_lock(gc); | |
cfeaa93f | 117 | irq_reg_writel(mask, gc->reg_base + ct->regs.ack); |
7d828062 TG |
118 | irq_gc_unlock(gc); |
119 | } | |
d55f0cc4 | 120 | EXPORT_SYMBOL_GPL(irq_gc_ack_set_bit); |
7d828062 | 121 | |
659fb32d SG |
122 | /** |
123 | * irq_gc_ack_clr_bit - Ack pending interrupt via clearing bit | |
124 | * @d: irq_data | |
125 | */ | |
126 | void irq_gc_ack_clr_bit(struct irq_data *d) | |
127 | { | |
128 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 129 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 130 | u32 mask = ~d->mask; |
659fb32d SG |
131 | |
132 | irq_gc_lock(gc); | |
cfeaa93f | 133 | irq_reg_writel(mask, gc->reg_base + ct->regs.ack); |
659fb32d SG |
134 | irq_gc_unlock(gc); |
135 | } | |
136 | ||
7d828062 | 137 | /** |
37074c5a | 138 | * irq_gc_mask_disable_reg_and_ack - Mask and ack pending interrupt |
7d828062 TG |
139 | * @d: irq_data |
140 | */ | |
141 | void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) | |
142 | { | |
143 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 144 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 145 | u32 mask = d->mask; |
7d828062 TG |
146 | |
147 | irq_gc_lock(gc); | |
cfeaa93f GF |
148 | irq_reg_writel(mask, gc->reg_base + ct->regs.mask); |
149 | irq_reg_writel(mask, gc->reg_base + ct->regs.ack); | |
7d828062 TG |
150 | irq_gc_unlock(gc); |
151 | } | |
152 | ||
153 | /** | |
154 | * irq_gc_eoi - EOI interrupt | |
155 | * @d: irq_data | |
156 | */ | |
157 | void irq_gc_eoi(struct irq_data *d) | |
158 | { | |
159 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 160 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 161 | u32 mask = d->mask; |
7d828062 TG |
162 | |
163 | irq_gc_lock(gc); | |
cfeaa93f | 164 | irq_reg_writel(mask, gc->reg_base + ct->regs.eoi); |
7d828062 TG |
165 | irq_gc_unlock(gc); |
166 | } | |
167 | ||
168 | /** | |
169 | * irq_gc_set_wake - Set/clr wake bit for an interrupt | |
ccc414f8 TG |
170 | * @d: irq_data |
171 | * @on: Indicates whether the wake bit should be set or cleared | |
7d828062 TG |
172 | * |
173 | * For chips where the wake from suspend functionality is not | |
174 | * configured in a separate register and the wakeup active state is | |
175 | * just stored in a bitmask. | |
176 | */ | |
177 | int irq_gc_set_wake(struct irq_data *d, unsigned int on) | |
178 | { | |
179 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
966dc736 | 180 | u32 mask = d->mask; |
7d828062 TG |
181 | |
182 | if (!(mask & gc->wake_enabled)) | |
183 | return -EINVAL; | |
184 | ||
185 | irq_gc_lock(gc); | |
186 | if (on) | |
187 | gc->wake_active |= mask; | |
188 | else | |
189 | gc->wake_active &= ~mask; | |
190 | irq_gc_unlock(gc); | |
191 | return 0; | |
192 | } | |
193 | ||
3528d82b TG |
194 | static void |
195 | irq_init_generic_chip(struct irq_chip_generic *gc, const char *name, | |
196 | int num_ct, unsigned int irq_base, | |
197 | void __iomem *reg_base, irq_flow_handler_t handler) | |
198 | { | |
199 | raw_spin_lock_init(&gc->lock); | |
200 | gc->num_ct = num_ct; | |
201 | gc->irq_base = irq_base; | |
202 | gc->reg_base = reg_base; | |
203 | gc->chip_types->chip.name = name; | |
204 | gc->chip_types->handler = handler; | |
205 | } | |
206 | ||
7d828062 TG |
207 | /** |
208 | * irq_alloc_generic_chip - Allocate a generic chip and initialize it | |
209 | * @name: Name of the irq chip | |
210 | * @num_ct: Number of irq_chip_type instances associated with this | |
211 | * @irq_base: Interrupt base nr for this chip | |
212 | * @reg_base: Register base address (virtual) | |
213 | * @handler: Default flow handler associated with this chip | |
214 | * | |
215 | * Returns an initialized irq_chip_generic structure. The chip defaults | |
216 | * to the primary (index 0) irq_chip_type and @handler | |
217 | */ | |
218 | struct irq_chip_generic * | |
219 | irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, | |
220 | void __iomem *reg_base, irq_flow_handler_t handler) | |
221 | { | |
222 | struct irq_chip_generic *gc; | |
223 | unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); | |
224 | ||
225 | gc = kzalloc(sz, GFP_KERNEL); | |
226 | if (gc) { | |
3528d82b TG |
227 | irq_init_generic_chip(gc, name, num_ct, irq_base, reg_base, |
228 | handler); | |
7d828062 TG |
229 | } |
230 | return gc; | |
231 | } | |
825de2e9 | 232 | EXPORT_SYMBOL_GPL(irq_alloc_generic_chip); |
7d828062 | 233 | |
3528d82b TG |
234 | static void |
235 | irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags) | |
236 | { | |
237 | struct irq_chip_type *ct = gc->chip_types; | |
238 | u32 *mskptr = &gc->mask_cache, mskreg = ct->regs.mask; | |
239 | int i; | |
240 | ||
241 | for (i = 0; i < gc->num_ct; i++) { | |
242 | if (flags & IRQ_GC_MASK_CACHE_PER_TYPE) { | |
243 | mskptr = &ct[i].mask_cache_priv; | |
244 | mskreg = ct[i].regs.mask; | |
245 | } | |
246 | ct[i].mask_cache = mskptr; | |
247 | if (flags & IRQ_GC_INIT_MASK_CACHE) | |
248 | *mskptr = irq_reg_readl(gc->reg_base + mskreg); | |
249 | } | |
250 | } | |
251 | ||
088f40b7 TG |
252 | /** |
253 | * irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain | |
254 | * @d: irq domain for which to allocate chips | |
255 | * @irqs_per_chip: Number of interrupts each chip handles | |
256 | * @num_ct: Number of irq_chip_type instances associated with this | |
257 | * @name: Name of the irq chip | |
258 | * @handler: Default flow handler associated with these chips | |
259 | * @clr: IRQ_* bits to clear in the mapping function | |
260 | * @set: IRQ_* bits to set in the mapping function | |
6fff8314 | 261 | * @gcflags: Generic chip specific setup flags |
088f40b7 TG |
262 | */ |
263 | int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, | |
264 | int num_ct, const char *name, | |
265 | irq_flow_handler_t handler, | |
266 | unsigned int clr, unsigned int set, | |
267 | enum irq_gc_flags gcflags) | |
268 | { | |
269 | struct irq_domain_chip_generic *dgc; | |
270 | struct irq_chip_generic *gc; | |
271 | int numchips, sz, i; | |
272 | unsigned long flags; | |
273 | void *tmp; | |
274 | ||
275 | if (d->gc) | |
276 | return -EBUSY; | |
277 | ||
505608d2 | 278 | numchips = DIV_ROUND_UP(d->revmap_size, irqs_per_chip); |
088f40b7 TG |
279 | if (!numchips) |
280 | return -EINVAL; | |
281 | ||
282 | /* Allocate a pointer, generic chip and chiptypes for each chip */ | |
283 | sz = sizeof(*dgc) + numchips * sizeof(gc); | |
284 | sz += numchips * (sizeof(*gc) + num_ct * sizeof(struct irq_chip_type)); | |
285 | ||
286 | tmp = dgc = kzalloc(sz, GFP_KERNEL); | |
287 | if (!dgc) | |
288 | return -ENOMEM; | |
289 | dgc->irqs_per_chip = irqs_per_chip; | |
290 | dgc->num_chips = numchips; | |
291 | dgc->irq_flags_to_set = set; | |
292 | dgc->irq_flags_to_clear = clr; | |
293 | dgc->gc_flags = gcflags; | |
294 | d->gc = dgc; | |
295 | ||
296 | /* Calc pointer to the first generic chip */ | |
297 | tmp += sizeof(*dgc) + numchips * sizeof(gc); | |
298 | for (i = 0; i < numchips; i++) { | |
299 | /* Store the pointer to the generic chip */ | |
300 | dgc->gc[i] = gc = tmp; | |
301 | irq_init_generic_chip(gc, name, num_ct, i * irqs_per_chip, | |
302 | NULL, handler); | |
303 | gc->domain = d; | |
304 | raw_spin_lock_irqsave(&gc_lock, flags); | |
305 | list_add_tail(&gc->list, &gc_list); | |
306 | raw_spin_unlock_irqrestore(&gc_lock, flags); | |
307 | /* Calc pointer to the next generic chip */ | |
308 | tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); | |
309 | } | |
0bb4afb4 | 310 | d->name = name; |
088f40b7 TG |
311 | return 0; |
312 | } | |
313 | EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips); | |
314 | ||
315 | /** | |
316 | * irq_get_domain_generic_chip - Get a pointer to the generic chip of a hw_irq | |
317 | * @d: irq domain pointer | |
318 | * @hw_irq: Hardware interrupt number | |
319 | */ | |
320 | struct irq_chip_generic * | |
321 | irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq) | |
322 | { | |
323 | struct irq_domain_chip_generic *dgc = d->gc; | |
324 | int idx; | |
325 | ||
326 | if (!dgc) | |
327 | return NULL; | |
328 | idx = hw_irq / dgc->irqs_per_chip; | |
329 | if (idx >= dgc->num_chips) | |
330 | return NULL; | |
331 | return dgc->gc[idx]; | |
332 | } | |
333 | EXPORT_SYMBOL_GPL(irq_get_domain_generic_chip); | |
334 | ||
7d828062 TG |
335 | /* |
336 | * Separate lockdep class for interrupt chip which can nest irq_desc | |
337 | * lock. | |
338 | */ | |
339 | static struct lock_class_key irq_nested_lock_class; | |
340 | ||
ccc414f8 | 341 | /* |
088f40b7 TG |
342 | * irq_map_generic_chip - Map a generic chip for an irq domain |
343 | */ | |
a5152c8a BB |
344 | int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, |
345 | irq_hw_number_t hw_irq) | |
088f40b7 TG |
346 | { |
347 | struct irq_data *data = irq_get_irq_data(virq); | |
348 | struct irq_domain_chip_generic *dgc = d->gc; | |
349 | struct irq_chip_generic *gc; | |
350 | struct irq_chip_type *ct; | |
351 | struct irq_chip *chip; | |
352 | unsigned long flags; | |
353 | int idx; | |
354 | ||
355 | if (!d->gc) | |
356 | return -ENODEV; | |
357 | ||
358 | idx = hw_irq / dgc->irqs_per_chip; | |
359 | if (idx >= dgc->num_chips) | |
360 | return -EINVAL; | |
361 | gc = dgc->gc[idx]; | |
362 | ||
363 | idx = hw_irq % dgc->irqs_per_chip; | |
364 | ||
e8bd834f GL |
365 | if (test_bit(idx, &gc->unused)) |
366 | return -ENOTSUPP; | |
367 | ||
088f40b7 TG |
368 | if (test_bit(idx, &gc->installed)) |
369 | return -EBUSY; | |
370 | ||
371 | ct = gc->chip_types; | |
372 | chip = &ct->chip; | |
373 | ||
374 | /* We only init the cache for the first mapping of a generic chip */ | |
375 | if (!gc->installed) { | |
376 | raw_spin_lock_irqsave(&gc->lock, flags); | |
377 | irq_gc_init_mask_cache(gc, dgc->gc_flags); | |
378 | raw_spin_unlock_irqrestore(&gc->lock, flags); | |
379 | } | |
380 | ||
381 | /* Mark the interrupt as installed */ | |
382 | set_bit(idx, &gc->installed); | |
383 | ||
384 | if (dgc->gc_flags & IRQ_GC_INIT_NESTED_LOCK) | |
385 | irq_set_lockdep_class(virq, &irq_nested_lock_class); | |
386 | ||
387 | if (chip->irq_calc_mask) | |
388 | chip->irq_calc_mask(data); | |
389 | else | |
390 | data->mask = 1 << idx; | |
391 | ||
392 | irq_set_chip_and_handler(virq, chip, ct->handler); | |
393 | irq_set_chip_data(virq, gc); | |
394 | irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set); | |
395 | return 0; | |
396 | } | |
a5152c8a | 397 | EXPORT_SYMBOL_GPL(irq_map_generic_chip); |
088f40b7 TG |
398 | |
399 | struct irq_domain_ops irq_generic_chip_ops = { | |
400 | .map = irq_map_generic_chip, | |
401 | .xlate = irq_domain_xlate_onetwocell, | |
402 | }; | |
403 | EXPORT_SYMBOL_GPL(irq_generic_chip_ops); | |
404 | ||
7d828062 TG |
405 | /** |
406 | * irq_setup_generic_chip - Setup a range of interrupts with a generic chip | |
407 | * @gc: Generic irq chip holding all data | |
408 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | |
409 | * @flags: Flags for initialization | |
410 | * @clr: IRQ_* bits to clear | |
411 | * @set: IRQ_* bits to set | |
412 | * | |
413 | * Set up max. 32 interrupts starting from gc->irq_base. Note, this | |
414 | * initializes all interrupts to the primary irq_chip_type and its | |
415 | * associated handler. | |
416 | */ | |
417 | void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, | |
418 | enum irq_gc_flags flags, unsigned int clr, | |
419 | unsigned int set) | |
420 | { | |
421 | struct irq_chip_type *ct = gc->chip_types; | |
d0051816 | 422 | struct irq_chip *chip = &ct->chip; |
7d828062 TG |
423 | unsigned int i; |
424 | ||
cfefd21e TG |
425 | raw_spin_lock(&gc_lock); |
426 | list_add_tail(&gc->list, &gc_list); | |
427 | raw_spin_unlock(&gc_lock); | |
428 | ||
3528d82b | 429 | irq_gc_init_mask_cache(gc, flags); |
899f0e66 | 430 | |
7d828062 | 431 | for (i = gc->irq_base; msk; msk >>= 1, i++) { |
1dd75f91 | 432 | if (!(msk & 0x01)) |
7d828062 TG |
433 | continue; |
434 | ||
435 | if (flags & IRQ_GC_INIT_NESTED_LOCK) | |
436 | irq_set_lockdep_class(i, &irq_nested_lock_class); | |
437 | ||
966dc736 TG |
438 | if (!(flags & IRQ_GC_NO_MASK)) { |
439 | struct irq_data *d = irq_get_irq_data(i); | |
440 | ||
d0051816 TG |
441 | if (chip->irq_calc_mask) |
442 | chip->irq_calc_mask(d); | |
443 | else | |
444 | d->mask = 1 << (i - gc->irq_base); | |
966dc736 | 445 | } |
d0051816 | 446 | irq_set_chip_and_handler(i, chip, ct->handler); |
7d828062 TG |
447 | irq_set_chip_data(i, gc); |
448 | irq_modify_status(i, clr, set); | |
449 | } | |
450 | gc->irq_cnt = i - gc->irq_base; | |
451 | } | |
825de2e9 | 452 | EXPORT_SYMBOL_GPL(irq_setup_generic_chip); |
7d828062 TG |
453 | |
454 | /** | |
455 | * irq_setup_alt_chip - Switch to alternative chip | |
456 | * @d: irq_data for this interrupt | |
ccc414f8 | 457 | * @type: Flow type to be initialized |
7d828062 TG |
458 | * |
459 | * Only to be called from chip->irq_set_type() callbacks. | |
460 | */ | |
461 | int irq_setup_alt_chip(struct irq_data *d, unsigned int type) | |
462 | { | |
463 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
464 | struct irq_chip_type *ct = gc->chip_types; | |
465 | unsigned int i; | |
466 | ||
467 | for (i = 0; i < gc->num_ct; i++, ct++) { | |
468 | if (ct->type & type) { | |
469 | d->chip = &ct->chip; | |
470 | irq_data_to_desc(d)->handle_irq = ct->handler; | |
471 | return 0; | |
472 | } | |
473 | } | |
474 | return -EINVAL; | |
475 | } | |
825de2e9 | 476 | EXPORT_SYMBOL_GPL(irq_setup_alt_chip); |
cfefd21e TG |
477 | |
478 | /** | |
479 | * irq_remove_generic_chip - Remove a chip | |
480 | * @gc: Generic irq chip holding all data | |
481 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | |
482 | * @clr: IRQ_* bits to clear | |
483 | * @set: IRQ_* bits to set | |
484 | * | |
485 | * Remove up to 32 interrupts starting from gc->irq_base. | |
486 | */ | |
487 | void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, | |
488 | unsigned int clr, unsigned int set) | |
489 | { | |
490 | unsigned int i = gc->irq_base; | |
491 | ||
492 | raw_spin_lock(&gc_lock); | |
493 | list_del(&gc->list); | |
494 | raw_spin_unlock(&gc_lock); | |
495 | ||
496 | for (; msk; msk >>= 1, i++) { | |
1dd75f91 | 497 | if (!(msk & 0x01)) |
cfefd21e TG |
498 | continue; |
499 | ||
500 | /* Remove handler first. That will mask the irq line */ | |
501 | irq_set_handler(i, NULL); | |
502 | irq_set_chip(i, &no_irq_chip); | |
503 | irq_set_chip_data(i, NULL); | |
504 | irq_modify_status(i, clr, set); | |
505 | } | |
506 | } | |
825de2e9 | 507 | EXPORT_SYMBOL_GPL(irq_remove_generic_chip); |
cfefd21e | 508 | |
088f40b7 TG |
509 | static struct irq_data *irq_gc_get_irq_data(struct irq_chip_generic *gc) |
510 | { | |
511 | unsigned int virq; | |
512 | ||
513 | if (!gc->domain) | |
514 | return irq_get_irq_data(gc->irq_base); | |
515 | ||
516 | /* | |
517 | * We don't know which of the irqs has been actually | |
518 | * installed. Use the first one. | |
519 | */ | |
520 | if (!gc->installed) | |
521 | return NULL; | |
522 | ||
523 | virq = irq_find_mapping(gc->domain, gc->irq_base + __ffs(gc->installed)); | |
524 | return virq ? irq_get_irq_data(virq) : NULL; | |
525 | } | |
526 | ||
cfefd21e TG |
527 | #ifdef CONFIG_PM |
528 | static int irq_gc_suspend(void) | |
529 | { | |
530 | struct irq_chip_generic *gc; | |
531 | ||
532 | list_for_each_entry(gc, &gc_list, list) { | |
533 | struct irq_chip_type *ct = gc->chip_types; | |
534 | ||
088f40b7 TG |
535 | if (ct->chip.irq_suspend) { |
536 | struct irq_data *data = irq_gc_get_irq_data(gc); | |
537 | ||
538 | if (data) | |
539 | ct->chip.irq_suspend(data); | |
540 | } | |
cfefd21e TG |
541 | } |
542 | return 0; | |
543 | } | |
544 | ||
545 | static void irq_gc_resume(void) | |
546 | { | |
547 | struct irq_chip_generic *gc; | |
548 | ||
549 | list_for_each_entry(gc, &gc_list, list) { | |
550 | struct irq_chip_type *ct = gc->chip_types; | |
551 | ||
088f40b7 TG |
552 | if (ct->chip.irq_resume) { |
553 | struct irq_data *data = irq_gc_get_irq_data(gc); | |
554 | ||
555 | if (data) | |
556 | ct->chip.irq_resume(data); | |
557 | } | |
cfefd21e TG |
558 | } |
559 | } | |
560 | #else | |
561 | #define irq_gc_suspend NULL | |
562 | #define irq_gc_resume NULL | |
563 | #endif | |
564 | ||
565 | static void irq_gc_shutdown(void) | |
566 | { | |
567 | struct irq_chip_generic *gc; | |
568 | ||
569 | list_for_each_entry(gc, &gc_list, list) { | |
570 | struct irq_chip_type *ct = gc->chip_types; | |
571 | ||
088f40b7 TG |
572 | if (ct->chip.irq_pm_shutdown) { |
573 | struct irq_data *data = irq_gc_get_irq_data(gc); | |
574 | ||
575 | if (data) | |
576 | ct->chip.irq_pm_shutdown(data); | |
577 | } | |
cfefd21e TG |
578 | } |
579 | } | |
580 | ||
581 | static struct syscore_ops irq_gc_syscore_ops = { | |
582 | .suspend = irq_gc_suspend, | |
583 | .resume = irq_gc_resume, | |
584 | .shutdown = irq_gc_shutdown, | |
585 | }; | |
586 | ||
587 | static int __init irq_gc_init_ops(void) | |
588 | { | |
589 | register_syscore_ops(&irq_gc_syscore_ops); | |
590 | return 0; | |
591 | } | |
592 | device_initcall(irq_gc_init_ops); |