]>
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> |
7d828062 TG |
10 | #include <linux/interrupt.h> |
11 | #include <linux/kernel_stat.h> | |
cfefd21e | 12 | #include <linux/syscore_ops.h> |
7d828062 TG |
13 | |
14 | #include "internals.h" | |
15 | ||
cfefd21e TG |
16 | static LIST_HEAD(gc_list); |
17 | static DEFINE_RAW_SPINLOCK(gc_lock); | |
18 | ||
7d828062 TG |
19 | /** |
20 | * irq_gc_noop - NOOP function | |
21 | * @d: irq_data | |
22 | */ | |
23 | void irq_gc_noop(struct irq_data *d) | |
24 | { | |
25 | } | |
26 | ||
27 | /** | |
28 | * irq_gc_mask_disable_reg - Mask chip via disable register | |
29 | * @d: irq_data | |
30 | * | |
31 | * Chip has separate enable/disable registers instead of a single mask | |
32 | * register. | |
33 | */ | |
34 | void irq_gc_mask_disable_reg(struct irq_data *d) | |
35 | { | |
36 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 37 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 38 | u32 mask = d->mask; |
7d828062 TG |
39 | |
40 | irq_gc_lock(gc); | |
cfeaa93f | 41 | irq_reg_writel(mask, gc->reg_base + ct->regs.disable); |
899f0e66 | 42 | *ct->mask_cache &= ~mask; |
7d828062 TG |
43 | irq_gc_unlock(gc); |
44 | } | |
45 | ||
46 | /** | |
47 | * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register | |
48 | * @d: irq_data | |
49 | * | |
50 | * Chip has a single mask register. Values of this register are cached | |
51 | * and protected by gc->lock | |
52 | */ | |
53 | void irq_gc_mask_set_bit(struct irq_data *d) | |
54 | { | |
55 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 56 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 57 | u32 mask = d->mask; |
7d828062 TG |
58 | |
59 | irq_gc_lock(gc); | |
899f0e66 GF |
60 | *ct->mask_cache |= mask; |
61 | irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask); | |
7d828062 TG |
62 | irq_gc_unlock(gc); |
63 | } | |
64 | ||
65 | /** | |
66 | * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register | |
67 | * @d: irq_data | |
68 | * | |
69 | * Chip has a single mask register. Values of this register are cached | |
70 | * and protected by gc->lock | |
71 | */ | |
72 | void irq_gc_mask_clr_bit(struct irq_data *d) | |
73 | { | |
74 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 75 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 76 | u32 mask = d->mask; |
7d828062 TG |
77 | |
78 | irq_gc_lock(gc); | |
899f0e66 GF |
79 | *ct->mask_cache &= ~mask; |
80 | irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask); | |
7d828062 TG |
81 | irq_gc_unlock(gc); |
82 | } | |
83 | ||
84 | /** | |
85 | * irq_gc_unmask_enable_reg - Unmask chip via enable register | |
86 | * @d: irq_data | |
87 | * | |
88 | * Chip has separate enable/disable registers instead of a single mask | |
89 | * register. | |
90 | */ | |
91 | void irq_gc_unmask_enable_reg(struct irq_data *d) | |
92 | { | |
93 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 94 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 95 | u32 mask = d->mask; |
7d828062 TG |
96 | |
97 | irq_gc_lock(gc); | |
cfeaa93f | 98 | irq_reg_writel(mask, gc->reg_base + ct->regs.enable); |
899f0e66 | 99 | *ct->mask_cache |= mask; |
7d828062 TG |
100 | irq_gc_unlock(gc); |
101 | } | |
102 | ||
103 | /** | |
659fb32d | 104 | * irq_gc_ack_set_bit - Ack pending interrupt via setting bit |
7d828062 TG |
105 | * @d: irq_data |
106 | */ | |
659fb32d | 107 | void irq_gc_ack_set_bit(struct irq_data *d) |
7d828062 TG |
108 | { |
109 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 110 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 111 | u32 mask = d->mask; |
7d828062 TG |
112 | |
113 | irq_gc_lock(gc); | |
cfeaa93f | 114 | irq_reg_writel(mask, gc->reg_base + ct->regs.ack); |
7d828062 TG |
115 | irq_gc_unlock(gc); |
116 | } | |
117 | ||
659fb32d SG |
118 | /** |
119 | * irq_gc_ack_clr_bit - Ack pending interrupt via clearing bit | |
120 | * @d: irq_data | |
121 | */ | |
122 | void irq_gc_ack_clr_bit(struct irq_data *d) | |
123 | { | |
124 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 125 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 126 | u32 mask = ~d->mask; |
659fb32d SG |
127 | |
128 | irq_gc_lock(gc); | |
cfeaa93f | 129 | irq_reg_writel(mask, gc->reg_base + ct->regs.ack); |
659fb32d SG |
130 | irq_gc_unlock(gc); |
131 | } | |
132 | ||
7d828062 TG |
133 | /** |
134 | * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt | |
135 | * @d: irq_data | |
136 | */ | |
137 | void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) | |
138 | { | |
139 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 140 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 141 | u32 mask = d->mask; |
7d828062 TG |
142 | |
143 | irq_gc_lock(gc); | |
cfeaa93f GF |
144 | irq_reg_writel(mask, gc->reg_base + ct->regs.mask); |
145 | irq_reg_writel(mask, gc->reg_base + ct->regs.ack); | |
7d828062 TG |
146 | irq_gc_unlock(gc); |
147 | } | |
148 | ||
149 | /** | |
150 | * irq_gc_eoi - EOI interrupt | |
151 | * @d: irq_data | |
152 | */ | |
153 | void irq_gc_eoi(struct irq_data *d) | |
154 | { | |
155 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
cfeaa93f | 156 | struct irq_chip_type *ct = irq_data_get_chip_type(d); |
966dc736 | 157 | u32 mask = d->mask; |
7d828062 TG |
158 | |
159 | irq_gc_lock(gc); | |
cfeaa93f | 160 | irq_reg_writel(mask, gc->reg_base + ct->regs.eoi); |
7d828062 TG |
161 | irq_gc_unlock(gc); |
162 | } | |
163 | ||
164 | /** | |
165 | * irq_gc_set_wake - Set/clr wake bit for an interrupt | |
166 | * @d: irq_data | |
167 | * | |
168 | * For chips where the wake from suspend functionality is not | |
169 | * configured in a separate register and the wakeup active state is | |
170 | * just stored in a bitmask. | |
171 | */ | |
172 | int irq_gc_set_wake(struct irq_data *d, unsigned int on) | |
173 | { | |
174 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
966dc736 | 175 | u32 mask = d->mask; |
7d828062 TG |
176 | |
177 | if (!(mask & gc->wake_enabled)) | |
178 | return -EINVAL; | |
179 | ||
180 | irq_gc_lock(gc); | |
181 | if (on) | |
182 | gc->wake_active |= mask; | |
183 | else | |
184 | gc->wake_active &= ~mask; | |
185 | irq_gc_unlock(gc); | |
186 | return 0; | |
187 | } | |
188 | ||
189 | /** | |
190 | * irq_alloc_generic_chip - Allocate a generic chip and initialize it | |
191 | * @name: Name of the irq chip | |
192 | * @num_ct: Number of irq_chip_type instances associated with this | |
193 | * @irq_base: Interrupt base nr for this chip | |
194 | * @reg_base: Register base address (virtual) | |
195 | * @handler: Default flow handler associated with this chip | |
196 | * | |
197 | * Returns an initialized irq_chip_generic structure. The chip defaults | |
198 | * to the primary (index 0) irq_chip_type and @handler | |
199 | */ | |
200 | struct irq_chip_generic * | |
201 | irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, | |
202 | void __iomem *reg_base, irq_flow_handler_t handler) | |
203 | { | |
204 | struct irq_chip_generic *gc; | |
205 | unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); | |
206 | ||
207 | gc = kzalloc(sz, GFP_KERNEL); | |
208 | if (gc) { | |
209 | raw_spin_lock_init(&gc->lock); | |
210 | gc->num_ct = num_ct; | |
211 | gc->irq_base = irq_base; | |
212 | gc->reg_base = reg_base; | |
213 | gc->chip_types->chip.name = name; | |
214 | gc->chip_types->handler = handler; | |
215 | } | |
216 | return gc; | |
217 | } | |
825de2e9 | 218 | EXPORT_SYMBOL_GPL(irq_alloc_generic_chip); |
7d828062 TG |
219 | |
220 | /* | |
221 | * Separate lockdep class for interrupt chip which can nest irq_desc | |
222 | * lock. | |
223 | */ | |
224 | static struct lock_class_key irq_nested_lock_class; | |
225 | ||
226 | /** | |
227 | * irq_setup_generic_chip - Setup a range of interrupts with a generic chip | |
228 | * @gc: Generic irq chip holding all data | |
229 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | |
230 | * @flags: Flags for initialization | |
231 | * @clr: IRQ_* bits to clear | |
232 | * @set: IRQ_* bits to set | |
233 | * | |
234 | * Set up max. 32 interrupts starting from gc->irq_base. Note, this | |
235 | * initializes all interrupts to the primary irq_chip_type and its | |
236 | * associated handler. | |
237 | */ | |
238 | void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, | |
239 | enum irq_gc_flags flags, unsigned int clr, | |
240 | unsigned int set) | |
241 | { | |
242 | struct irq_chip_type *ct = gc->chip_types; | |
243 | unsigned int i; | |
af80b0fe | 244 | u32 *mskptr = &gc->mask_cache, mskreg = ct->regs.mask; |
7d828062 | 245 | |
cfefd21e TG |
246 | raw_spin_lock(&gc_lock); |
247 | list_add_tail(&gc->list, &gc_list); | |
248 | raw_spin_unlock(&gc_lock); | |
249 | ||
af80b0fe GF |
250 | for (i = 0; i < gc->num_ct; i++) { |
251 | if (flags & IRQ_GC_MASK_CACHE_PER_TYPE) { | |
252 | mskptr = &ct[i].mask_cache_priv; | |
253 | mskreg = ct[i].regs.mask; | |
254 | } | |
255 | ct[i].mask_cache = mskptr; | |
256 | if (flags & IRQ_GC_INIT_MASK_CACHE) | |
257 | *mskptr = irq_reg_readl(gc->reg_base + mskreg); | |
258 | } | |
899f0e66 | 259 | |
7d828062 | 260 | for (i = gc->irq_base; msk; msk >>= 1, i++) { |
1dd75f91 | 261 | if (!(msk & 0x01)) |
7d828062 TG |
262 | continue; |
263 | ||
264 | if (flags & IRQ_GC_INIT_NESTED_LOCK) | |
265 | irq_set_lockdep_class(i, &irq_nested_lock_class); | |
266 | ||
966dc736 TG |
267 | if (!(flags & IRQ_GC_NO_MASK)) { |
268 | struct irq_data *d = irq_get_irq_data(i); | |
269 | ||
270 | d->mask = 1 << (i - gc->irq_base); | |
271 | } | |
7d828062 TG |
272 | irq_set_chip_and_handler(i, &ct->chip, ct->handler); |
273 | irq_set_chip_data(i, gc); | |
274 | irq_modify_status(i, clr, set); | |
275 | } | |
276 | gc->irq_cnt = i - gc->irq_base; | |
277 | } | |
825de2e9 | 278 | EXPORT_SYMBOL_GPL(irq_setup_generic_chip); |
7d828062 TG |
279 | |
280 | /** | |
281 | * irq_setup_alt_chip - Switch to alternative chip | |
282 | * @d: irq_data for this interrupt | |
283 | * @type Flow type to be initialized | |
284 | * | |
285 | * Only to be called from chip->irq_set_type() callbacks. | |
286 | */ | |
287 | int irq_setup_alt_chip(struct irq_data *d, unsigned int type) | |
288 | { | |
289 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | |
290 | struct irq_chip_type *ct = gc->chip_types; | |
291 | unsigned int i; | |
292 | ||
293 | for (i = 0; i < gc->num_ct; i++, ct++) { | |
294 | if (ct->type & type) { | |
295 | d->chip = &ct->chip; | |
296 | irq_data_to_desc(d)->handle_irq = ct->handler; | |
297 | return 0; | |
298 | } | |
299 | } | |
300 | return -EINVAL; | |
301 | } | |
825de2e9 | 302 | EXPORT_SYMBOL_GPL(irq_setup_alt_chip); |
cfefd21e TG |
303 | |
304 | /** | |
305 | * irq_remove_generic_chip - Remove a chip | |
306 | * @gc: Generic irq chip holding all data | |
307 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | |
308 | * @clr: IRQ_* bits to clear | |
309 | * @set: IRQ_* bits to set | |
310 | * | |
311 | * Remove up to 32 interrupts starting from gc->irq_base. | |
312 | */ | |
313 | void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, | |
314 | unsigned int clr, unsigned int set) | |
315 | { | |
316 | unsigned int i = gc->irq_base; | |
317 | ||
318 | raw_spin_lock(&gc_lock); | |
319 | list_del(&gc->list); | |
320 | raw_spin_unlock(&gc_lock); | |
321 | ||
322 | for (; msk; msk >>= 1, i++) { | |
1dd75f91 | 323 | if (!(msk & 0x01)) |
cfefd21e TG |
324 | continue; |
325 | ||
326 | /* Remove handler first. That will mask the irq line */ | |
327 | irq_set_handler(i, NULL); | |
328 | irq_set_chip(i, &no_irq_chip); | |
329 | irq_set_chip_data(i, NULL); | |
330 | irq_modify_status(i, clr, set); | |
331 | } | |
332 | } | |
825de2e9 | 333 | EXPORT_SYMBOL_GPL(irq_remove_generic_chip); |
cfefd21e TG |
334 | |
335 | #ifdef CONFIG_PM | |
336 | static int irq_gc_suspend(void) | |
337 | { | |
338 | struct irq_chip_generic *gc; | |
339 | ||
340 | list_for_each_entry(gc, &gc_list, list) { | |
341 | struct irq_chip_type *ct = gc->chip_types; | |
342 | ||
343 | if (ct->chip.irq_suspend) | |
344 | ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base)); | |
345 | } | |
346 | return 0; | |
347 | } | |
348 | ||
349 | static void irq_gc_resume(void) | |
350 | { | |
351 | struct irq_chip_generic *gc; | |
352 | ||
353 | list_for_each_entry(gc, &gc_list, list) { | |
354 | struct irq_chip_type *ct = gc->chip_types; | |
355 | ||
356 | if (ct->chip.irq_resume) | |
357 | ct->chip.irq_resume(irq_get_irq_data(gc->irq_base)); | |
358 | } | |
359 | } | |
360 | #else | |
361 | #define irq_gc_suspend NULL | |
362 | #define irq_gc_resume NULL | |
363 | #endif | |
364 | ||
365 | static void irq_gc_shutdown(void) | |
366 | { | |
367 | struct irq_chip_generic *gc; | |
368 | ||
369 | list_for_each_entry(gc, &gc_list, list) { | |
370 | struct irq_chip_type *ct = gc->chip_types; | |
371 | ||
372 | if (ct->chip.irq_pm_shutdown) | |
373 | ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base)); | |
374 | } | |
375 | } | |
376 | ||
377 | static struct syscore_ops irq_gc_syscore_ops = { | |
378 | .suspend = irq_gc_suspend, | |
379 | .resume = irq_gc_resume, | |
380 | .shutdown = irq_gc_shutdown, | |
381 | }; | |
382 | ||
383 | static int __init irq_gc_init_ops(void) | |
384 | { | |
385 | register_syscore_ops(&irq_gc_syscore_ops); | |
386 | return 0; | |
387 | } | |
388 | device_initcall(irq_gc_init_ops); |