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