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