aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/irq.h11
-rw-r--r--kernel/irq/generic-chip.c93
2 files changed, 104 insertions, 0 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 2ba2f1216790..8b4538446636 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -280,6 +280,9 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d)
280 * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips 280 * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips
281 * @irq_cpu_online: configure an interrupt source for a secondary CPU 281 * @irq_cpu_online: configure an interrupt source for a secondary CPU
282 * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU 282 * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU
283 * @irq_suspend: function called from core code on suspend once per chip
284 * @irq_resume: function called from core code on resume once per chip
285 * @irq_pm_shutdown: function called from core code on shutdown once per chip
283 * @irq_print_chip: optional to print special chip info in show_interrupts 286 * @irq_print_chip: optional to print special chip info in show_interrupts
284 * @flags: chip specific flags 287 * @flags: chip specific flags
285 * 288 *
@@ -309,6 +312,10 @@ struct irq_chip {
309 void (*irq_cpu_online)(struct irq_data *data); 312 void (*irq_cpu_online)(struct irq_data *data);
310 void (*irq_cpu_offline)(struct irq_data *data); 313 void (*irq_cpu_offline)(struct irq_data *data);
311 314
315 void (*irq_suspend)(struct irq_data *data);
316 void (*irq_resume)(struct irq_data *data);
317 void (*irq_pm_shutdown)(struct irq_data *data);
318
312 void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); 319 void (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
313 320
314 unsigned long flags; 321 unsigned long flags;
@@ -626,6 +633,7 @@ struct irq_chip_type {
626 * @wake_active: Interrupt is marked as an wakeup from suspend source 633 * @wake_active: Interrupt is marked as an wakeup from suspend source
627 * @num_ct: Number of available irq_chip_type instances (usually 1) 634 * @num_ct: Number of available irq_chip_type instances (usually 1)
628 * @private: Private data for non generic chip callbacks 635 * @private: Private data for non generic chip callbacks
636 * @list: List head for keeping track of instances
629 * @chip_types: Array of interrupt irq_chip_types 637 * @chip_types: Array of interrupt irq_chip_types
630 * 638 *
631 * Note, that irq_chip_generic can have multiple irq_chip_type 639 * Note, that irq_chip_generic can have multiple irq_chip_type
@@ -646,6 +654,7 @@ struct irq_chip_generic {
646 u32 wake_active; 654 u32 wake_active;
647 unsigned int num_ct; 655 unsigned int num_ct;
648 void *private; 656 void *private;
657 struct list_head list;
649 struct irq_chip_type chip_types[0]; 658 struct irq_chip_type chip_types[0];
650}; 659};
651 660
@@ -680,6 +689,8 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
680 enum irq_gc_flags flags, unsigned int clr, 689 enum irq_gc_flags flags, unsigned int clr,
681 unsigned int set); 690 unsigned int set);
682int irq_setup_alt_chip(struct irq_data *d, unsigned int type); 691int irq_setup_alt_chip(struct irq_data *d, unsigned int type);
692void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
693 unsigned int clr, unsigned int set);
683 694
684static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d) 695static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d)
685{ 696{
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index eb23e5924260..31a9db711906 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -8,9 +8,13 @@
8#include <linux/slab.h> 8#include <linux/slab.h>
9#include <linux/interrupt.h> 9#include <linux/interrupt.h>
10#include <linux/kernel_stat.h> 10#include <linux/kernel_stat.h>
11#include <linux/syscore_ops.h>
11 12
12#include "internals.h" 13#include "internals.h"
13 14
15static LIST_HEAD(gc_list);
16static DEFINE_RAW_SPINLOCK(gc_lock);
17
14static inline struct irq_chip_regs *cur_regs(struct irq_data *d) 18static inline struct irq_chip_regs *cur_regs(struct irq_data *d)
15{ 19{
16 return &container_of(d->chip, struct irq_chip_type, chip)->regs; 20 return &container_of(d->chip, struct irq_chip_type, chip)->regs;
@@ -219,6 +223,10 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
219 struct irq_chip_type *ct = gc->chip_types; 223 struct irq_chip_type *ct = gc->chip_types;
220 unsigned int i; 224 unsigned int i;
221 225
226 raw_spin_lock(&gc_lock);
227 list_add_tail(&gc->list, &gc_list);
228 raw_spin_unlock(&gc_lock);
229
222 /* Init mask cache ? */ 230 /* Init mask cache ? */
223 if (flags & IRQ_GC_INIT_MASK_CACHE) 231 if (flags & IRQ_GC_INIT_MASK_CACHE)
224 gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); 232 gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask);
@@ -259,3 +267,88 @@ int irq_setup_alt_chip(struct irq_data *d, unsigned int type)
259 } 267 }
260 return -EINVAL; 268 return -EINVAL;
261} 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 */
280void 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
302static 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
315static 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
331static 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
343static struct syscore_ops irq_gc_syscore_ops = {
344 .suspend = irq_gc_suspend,
345 .resume = irq_gc_resume,
346 .shutdown = irq_gc_shutdown,
347};
348
349static int __init irq_gc_init_ops(void)
350{
351 register_syscore_ops(&irq_gc_syscore_ops);
352 return 0;
353}
354device_initcall(irq_gc_init_ops);