diff options
Diffstat (limited to 'kernel/irq/generic-chip.c')
-rw-r--r-- | kernel/irq/generic-chip.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c new file mode 100644 index 000000000000..31a9db711906 --- /dev/null +++ b/kernel/irq/generic-chip.c | |||
@@ -0,0 +1,354 @@ | |||
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 - Ack pending interrupt | ||
105 | * @d: irq_data | ||
106 | */ | ||
107 | void irq_gc_ack(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_mask_disable_reg_and_ack- Mask and ack pending interrupt | ||
119 | * @d: irq_data | ||
120 | */ | ||
121 | void irq_gc_mask_disable_reg_and_ack(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)->mask); | ||
128 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); | ||
129 | irq_gc_unlock(gc); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * irq_gc_eoi - EOI interrupt | ||
134 | * @d: irq_data | ||
135 | */ | ||
136 | void irq_gc_eoi(struct irq_data *d) | ||
137 | { | ||
138 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
139 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
140 | |||
141 | irq_gc_lock(gc); | ||
142 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi); | ||
143 | irq_gc_unlock(gc); | ||
144 | } | ||
145 | |||
146 | /** | ||
147 | * irq_gc_set_wake - Set/clr wake bit for an interrupt | ||
148 | * @d: irq_data | ||
149 | * | ||
150 | * For chips where the wake from suspend functionality is not | ||
151 | * configured in a separate register and the wakeup active state is | ||
152 | * just stored in a bitmask. | ||
153 | */ | ||
154 | int irq_gc_set_wake(struct irq_data *d, unsigned int on) | ||
155 | { | ||
156 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
157 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
158 | |||
159 | if (!(mask & gc->wake_enabled)) | ||
160 | return -EINVAL; | ||
161 | |||
162 | irq_gc_lock(gc); | ||
163 | if (on) | ||
164 | gc->wake_active |= mask; | ||
165 | else | ||
166 | gc->wake_active &= ~mask; | ||
167 | irq_gc_unlock(gc); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * irq_alloc_generic_chip - Allocate a generic chip and initialize it | ||
173 | * @name: Name of the irq chip | ||
174 | * @num_ct: Number of irq_chip_type instances associated with this | ||
175 | * @irq_base: Interrupt base nr for this chip | ||
176 | * @reg_base: Register base address (virtual) | ||
177 | * @handler: Default flow handler associated with this chip | ||
178 | * | ||
179 | * Returns an initialized irq_chip_generic structure. The chip defaults | ||
180 | * to the primary (index 0) irq_chip_type and @handler | ||
181 | */ | ||
182 | struct irq_chip_generic * | ||
183 | irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, | ||
184 | void __iomem *reg_base, irq_flow_handler_t handler) | ||
185 | { | ||
186 | struct irq_chip_generic *gc; | ||
187 | unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); | ||
188 | |||
189 | gc = kzalloc(sz, GFP_KERNEL); | ||
190 | if (gc) { | ||
191 | raw_spin_lock_init(&gc->lock); | ||
192 | gc->num_ct = num_ct; | ||
193 | gc->irq_base = irq_base; | ||
194 | gc->reg_base = reg_base; | ||
195 | gc->chip_types->chip.name = name; | ||
196 | gc->chip_types->handler = handler; | ||
197 | } | ||
198 | return gc; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Separate lockdep class for interrupt chip which can nest irq_desc | ||
203 | * lock. | ||
204 | */ | ||
205 | static struct lock_class_key irq_nested_lock_class; | ||
206 | |||
207 | /** | ||
208 | * irq_setup_generic_chip - Setup a range of interrupts with a generic chip | ||
209 | * @gc: Generic irq chip holding all data | ||
210 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | ||
211 | * @flags: Flags for initialization | ||
212 | * @clr: IRQ_* bits to clear | ||
213 | * @set: IRQ_* bits to set | ||
214 | * | ||
215 | * Set up max. 32 interrupts starting from gc->irq_base. Note, this | ||
216 | * initializes all interrupts to the primary irq_chip_type and its | ||
217 | * associated handler. | ||
218 | */ | ||
219 | void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, | ||
220 | enum irq_gc_flags flags, unsigned int clr, | ||
221 | unsigned int set) | ||
222 | { | ||
223 | struct irq_chip_type *ct = gc->chip_types; | ||
224 | unsigned int i; | ||
225 | |||
226 | raw_spin_lock(&gc_lock); | ||
227 | list_add_tail(&gc->list, &gc_list); | ||
228 | raw_spin_unlock(&gc_lock); | ||
229 | |||
230 | /* Init mask cache ? */ | ||
231 | if (flags & IRQ_GC_INIT_MASK_CACHE) | ||
232 | gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); | ||
233 | |||
234 | for (i = gc->irq_base; msk; msk >>= 1, i++) { | ||
235 | if (!msk & 0x01) | ||
236 | continue; | ||
237 | |||
238 | if (flags & IRQ_GC_INIT_NESTED_LOCK) | ||
239 | irq_set_lockdep_class(i, &irq_nested_lock_class); | ||
240 | |||
241 | irq_set_chip_and_handler(i, &ct->chip, ct->handler); | ||
242 | irq_set_chip_data(i, gc); | ||
243 | irq_modify_status(i, clr, set); | ||
244 | } | ||
245 | gc->irq_cnt = i - gc->irq_base; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * irq_setup_alt_chip - Switch to alternative chip | ||
250 | * @d: irq_data for this interrupt | ||
251 | * @type Flow type to be initialized | ||
252 | * | ||
253 | * Only to be called from chip->irq_set_type() callbacks. | ||
254 | */ | ||
255 | int irq_setup_alt_chip(struct irq_data *d, unsigned int type) | ||
256 | { | ||
257 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
258 | struct irq_chip_type *ct = gc->chip_types; | ||
259 | unsigned int i; | ||
260 | |||
261 | for (i = 0; i < gc->num_ct; i++, ct++) { | ||
262 | if (ct->type & type) { | ||
263 | d->chip = &ct->chip; | ||
264 | irq_data_to_desc(d)->handle_irq = ct->handler; | ||
265 | return 0; | ||
266 | } | ||
267 | } | ||
268 | return -EINVAL; | ||
269 | } | ||
270 | |||
271 | /** | ||
272 | * irq_remove_generic_chip - Remove a chip | ||
273 | * @gc: Generic irq chip holding all data | ||
274 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | ||
275 | * @clr: IRQ_* bits to clear | ||
276 | * @set: IRQ_* bits to set | ||
277 | * | ||
278 | * Remove up to 32 interrupts starting from gc->irq_base. | ||
279 | */ | ||
280 | void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, | ||
281 | unsigned int clr, unsigned int set) | ||
282 | { | ||
283 | unsigned int i = gc->irq_base; | ||
284 | |||
285 | raw_spin_lock(&gc_lock); | ||
286 | list_del(&gc->list); | ||
287 | raw_spin_unlock(&gc_lock); | ||
288 | |||
289 | for (; msk; msk >>= 1, i++) { | ||
290 | if (!msk & 0x01) | ||
291 | continue; | ||
292 | |||
293 | /* Remove handler first. That will mask the irq line */ | ||
294 | irq_set_handler(i, NULL); | ||
295 | irq_set_chip(i, &no_irq_chip); | ||
296 | irq_set_chip_data(i, NULL); | ||
297 | irq_modify_status(i, clr, set); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | #ifdef CONFIG_PM | ||
302 | static int irq_gc_suspend(void) | ||
303 | { | ||
304 | struct irq_chip_generic *gc; | ||
305 | |||
306 | list_for_each_entry(gc, &gc_list, list) { | ||
307 | struct irq_chip_type *ct = gc->chip_types; | ||
308 | |||
309 | if (ct->chip.irq_suspend) | ||
310 | ct->chip.irq_suspend(irq_get_irq_data(gc->irq_base)); | ||
311 | } | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static void irq_gc_resume(void) | ||
316 | { | ||
317 | struct irq_chip_generic *gc; | ||
318 | |||
319 | list_for_each_entry(gc, &gc_list, list) { | ||
320 | struct irq_chip_type *ct = gc->chip_types; | ||
321 | |||
322 | if (ct->chip.irq_resume) | ||
323 | ct->chip.irq_resume(irq_get_irq_data(gc->irq_base)); | ||
324 | } | ||
325 | } | ||
326 | #else | ||
327 | #define irq_gc_suspend NULL | ||
328 | #define irq_gc_resume NULL | ||
329 | #endif | ||
330 | |||
331 | static void irq_gc_shutdown(void) | ||
332 | { | ||
333 | struct irq_chip_generic *gc; | ||
334 | |||
335 | list_for_each_entry(gc, &gc_list, list) { | ||
336 | struct irq_chip_type *ct = gc->chip_types; | ||
337 | |||
338 | if (ct->chip.irq_pm_shutdown) | ||
339 | ct->chip.irq_pm_shutdown(irq_get_irq_data(gc->irq_base)); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static struct syscore_ops irq_gc_syscore_ops = { | ||
344 | .suspend = irq_gc_suspend, | ||
345 | .resume = irq_gc_resume, | ||
346 | .shutdown = irq_gc_shutdown, | ||
347 | }; | ||
348 | |||
349 | static int __init irq_gc_init_ops(void) | ||
350 | { | ||
351 | register_syscore_ops(&irq_gc_syscore_ops); | ||
352 | return 0; | ||
353 | } | ||
354 | device_initcall(irq_gc_init_ops); | ||