diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2011-04-03 05:42:53 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2011-04-23 09:56:24 -0400 |
commit | 7d8280624797bbe2f5170bd3c85c75a8c9c74242 (patch) | |
tree | 8028581a9a51eeb3c168409b5645c68b7a32e7dd | |
parent | 7f1b1244e159a8490d7fb13667c6cb7e1e75046b (diff) |
genirq: Implement a generic interrupt chip
Implement a generic interrupt chip, which is configurable and is able
to handle the most common irq chip implementations.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Tested-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Tested-by: Tony Lindgren <tony@atomide.com>
Tested-by; Kevin Hilman <khilman@ti.com>
-rw-r--r-- | include/linux/irq.h | 135 | ||||
-rw-r--r-- | kernel/irq/Makefile | 1 | ||||
-rw-r--r-- | kernel/irq/generic-chip.c | 261 |
3 files changed, 397 insertions, 0 deletions
diff --git a/include/linux/irq.h b/include/linux/irq.h index 39c23786c1db..2ba2f1216790 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -568,6 +568,141 @@ static inline int irq_reserve_irq(unsigned int irq) | |||
568 | return irq_reserve_irqs(irq, 1); | 568 | return irq_reserve_irqs(irq, 1); |
569 | } | 569 | } |
570 | 570 | ||
571 | #ifndef irq_reg_writel | ||
572 | # define irq_reg_writel(val, addr) writel(val, addr) | ||
573 | #endif | ||
574 | #ifndef irq_reg_readl | ||
575 | # define irq_reg_readl(addr) readl(addr) | ||
576 | #endif | ||
577 | |||
578 | /** | ||
579 | * struct irq_chip_regs - register offsets for struct irq_gci | ||
580 | * @enable: Enable register offset to reg_base | ||
581 | * @disable: Disable register offset to reg_base | ||
582 | * @mask: Mask register offset to reg_base | ||
583 | * @ack: Ack register offset to reg_base | ||
584 | * @eoi: Eoi register offset to reg_base | ||
585 | * @type: Type configuration register offset to reg_base | ||
586 | * @polarity: Polarity configuration register offset to reg_base | ||
587 | */ | ||
588 | struct irq_chip_regs { | ||
589 | unsigned long enable; | ||
590 | unsigned long disable; | ||
591 | unsigned long mask; | ||
592 | unsigned long ack; | ||
593 | unsigned long eoi; | ||
594 | unsigned long type; | ||
595 | unsigned long polarity; | ||
596 | }; | ||
597 | |||
598 | /** | ||
599 | * struct irq_chip_type - Generic interrupt chip instance for a flow type | ||
600 | * @chip: The real interrupt chip which provides the callbacks | ||
601 | * @regs: Register offsets for this chip | ||
602 | * @handler: Flow handler associated with this chip | ||
603 | * @type: Chip can handle these flow types | ||
604 | * | ||
605 | * A irq_generic_chip can have several instances of irq_chip_type when | ||
606 | * it requires different functions and register offsets for different | ||
607 | * flow types. | ||
608 | */ | ||
609 | struct irq_chip_type { | ||
610 | struct irq_chip chip; | ||
611 | struct irq_chip_regs regs; | ||
612 | irq_flow_handler_t handler; | ||
613 | u32 type; | ||
614 | }; | ||
615 | |||
616 | /** | ||
617 | * struct irq_chip_generic - Generic irq chip data structure | ||
618 | * @lock: Lock to protect register and cache data access | ||
619 | * @reg_base: Register base address (virtual) | ||
620 | * @irq_base: Interrupt base nr for this chip | ||
621 | * @irq_cnt: Number of interrupts handled by this chip | ||
622 | * @mask_cache: Cached mask register | ||
623 | * @type_cache: Cached type register | ||
624 | * @polarity_cache: Cached polarity register | ||
625 | * @wake_enabled: Interrupt can wakeup from suspend | ||
626 | * @wake_active: Interrupt is marked as an wakeup from suspend source | ||
627 | * @num_ct: Number of available irq_chip_type instances (usually 1) | ||
628 | * @private: Private data for non generic chip callbacks | ||
629 | * @chip_types: Array of interrupt irq_chip_types | ||
630 | * | ||
631 | * Note, that irq_chip_generic can have multiple irq_chip_type | ||
632 | * implementations which can be associated to a particular irq line of | ||
633 | * an irq_chip_generic instance. That allows to share and protect | ||
634 | * state in an irq_chip_generic instance when we need to implement | ||
635 | * different flow mechanisms (level/edge) for it. | ||
636 | */ | ||
637 | struct irq_chip_generic { | ||
638 | raw_spinlock_t lock; | ||
639 | void __iomem *reg_base; | ||
640 | unsigned int irq_base; | ||
641 | unsigned int irq_cnt; | ||
642 | u32 mask_cache; | ||
643 | u32 type_cache; | ||
644 | u32 polarity_cache; | ||
645 | u32 wake_enabled; | ||
646 | u32 wake_active; | ||
647 | unsigned int num_ct; | ||
648 | void *private; | ||
649 | struct irq_chip_type chip_types[0]; | ||
650 | }; | ||
651 | |||
652 | /** | ||
653 | * enum irq_gc_flags - Initialization flags for generic irq chips | ||
654 | * @IRQ_GC_INIT_MASK_CACHE: Initialize the mask_cache by reading mask reg | ||
655 | * @IRQ_GC_INIT_NESTED_LOCK: Set the lock class of the irqs to nested for | ||
656 | * irq chips which need to call irq_set_wake() on | ||
657 | * the parent irq. Usually GPIO implementations | ||
658 | */ | ||
659 | enum irq_gc_flags { | ||
660 | IRQ_GC_INIT_MASK_CACHE = 1 << 0, | ||
661 | IRQ_GC_INIT_NESTED_LOCK = 1 << 1, | ||
662 | }; | ||
663 | |||
664 | /* Generic chip callback functions */ | ||
665 | void irq_gc_noop(struct irq_data *d); | ||
666 | void irq_gc_mask_disable_reg(struct irq_data *d); | ||
667 | void irq_gc_mask_set_bit(struct irq_data *d); | ||
668 | void irq_gc_mask_clr_bit(struct irq_data *d); | ||
669 | void irq_gc_unmask_enable_reg(struct irq_data *d); | ||
670 | void irq_gc_ack(struct irq_data *d); | ||
671 | void irq_gc_mask_disable_reg_and_ack(struct irq_data *d); | ||
672 | void irq_gc_eoi(struct irq_data *d); | ||
673 | int irq_gc_set_wake(struct irq_data *d, unsigned int on); | ||
674 | |||
675 | /* Setup functions for irq_chip_generic */ | ||
676 | struct irq_chip_generic * | ||
677 | irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base, | ||
678 | void __iomem *reg_base, irq_flow_handler_t handler); | ||
679 | void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, | ||
680 | enum irq_gc_flags flags, unsigned int clr, | ||
681 | unsigned int set); | ||
682 | int irq_setup_alt_chip(struct irq_data *d, unsigned int type); | ||
683 | |||
684 | static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d) | ||
685 | { | ||
686 | return container_of(d->chip, struct irq_chip_type, chip); | ||
687 | } | ||
688 | |||
689 | #define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX) | ||
690 | |||
691 | #ifdef CONFIG_SMP | ||
692 | static inline void irq_gc_lock(struct irq_chip_generic *gc) | ||
693 | { | ||
694 | raw_spin_lock(&gc->lock); | ||
695 | } | ||
696 | |||
697 | static inline void irq_gc_unlock(struct irq_chip_generic *gc) | ||
698 | { | ||
699 | raw_spin_unlock(&gc->lock); | ||
700 | } | ||
701 | #else | ||
702 | static inline void irq_gc_lock(struct irq_chip_generic *gc) { } | ||
703 | static inline void irq_gc_unlock(struct irq_chip_generic *gc) { } | ||
704 | #endif | ||
705 | |||
571 | #endif /* CONFIG_GENERIC_HARDIRQS */ | 706 | #endif /* CONFIG_GENERIC_HARDIRQS */ |
572 | 707 | ||
573 | #endif /* !CONFIG_S390 */ | 708 | #endif /* !CONFIG_S390 */ |
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 54329cd7b3ee..e7a13bd3316a 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | 1 | ||
2 | obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o | 2 | obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o |
3 | obj-y += generic-chip.o | ||
3 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o | 4 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o |
4 | obj-$(CONFIG_PROC_FS) += proc.o | 5 | obj-$(CONFIG_PROC_FS) += proc.o |
5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o | 6 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o |
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c new file mode 100644 index 000000000000..eb23e5924260 --- /dev/null +++ b/kernel/irq/generic-chip.c | |||
@@ -0,0 +1,261 @@ | |||
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 | |||
12 | #include "internals.h" | ||
13 | |||
14 | static inline struct irq_chip_regs *cur_regs(struct irq_data *d) | ||
15 | { | ||
16 | return &container_of(d->chip, struct irq_chip_type, chip)->regs; | ||
17 | } | ||
18 | |||
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); | ||
37 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
38 | |||
39 | irq_gc_lock(gc); | ||
40 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->disable); | ||
41 | gc->mask_cache &= ~mask; | ||
42 | irq_gc_unlock(gc); | ||
43 | } | ||
44 | |||
45 | /** | ||
46 | * irq_gc_mask_set_mask_bit - Mask chip via setting bit in mask register | ||
47 | * @d: irq_data | ||
48 | * | ||
49 | * Chip has a single mask register. Values of this register are cached | ||
50 | * and protected by gc->lock | ||
51 | */ | ||
52 | void irq_gc_mask_set_bit(struct irq_data *d) | ||
53 | { | ||
54 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
55 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
56 | |||
57 | irq_gc_lock(gc); | ||
58 | gc->mask_cache |= mask; | ||
59 | irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask); | ||
60 | irq_gc_unlock(gc); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * irq_gc_mask_set_mask_bit - Mask chip via clearing bit in mask register | ||
65 | * @d: irq_data | ||
66 | * | ||
67 | * Chip has a single mask register. Values of this register are cached | ||
68 | * and protected by gc->lock | ||
69 | */ | ||
70 | void irq_gc_mask_clr_bit(struct irq_data *d) | ||
71 | { | ||
72 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
73 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
74 | |||
75 | irq_gc_lock(gc); | ||
76 | gc->mask_cache &= ~mask; | ||
77 | irq_reg_writel(gc->mask_cache, gc->reg_base + cur_regs(d)->mask); | ||
78 | irq_gc_unlock(gc); | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * irq_gc_unmask_enable_reg - Unmask chip via enable register | ||
83 | * @d: irq_data | ||
84 | * | ||
85 | * Chip has separate enable/disable registers instead of a single mask | ||
86 | * register. | ||
87 | */ | ||
88 | void irq_gc_unmask_enable_reg(struct irq_data *d) | ||
89 | { | ||
90 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
91 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
92 | |||
93 | irq_gc_lock(gc); | ||
94 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->enable); | ||
95 | gc->mask_cache |= mask; | ||
96 | irq_gc_unlock(gc); | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * irq_gc_ack - Ack pending interrupt | ||
101 | * @d: irq_data | ||
102 | */ | ||
103 | void irq_gc_ack(struct irq_data *d) | ||
104 | { | ||
105 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
106 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
107 | |||
108 | irq_gc_lock(gc); | ||
109 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); | ||
110 | irq_gc_unlock(gc); | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * irq_gc_mask_disable_reg_and_ack- Mask and ack pending interrupt | ||
115 | * @d: irq_data | ||
116 | */ | ||
117 | void irq_gc_mask_disable_reg_and_ack(struct irq_data *d) | ||
118 | { | ||
119 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
120 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
121 | |||
122 | irq_gc_lock(gc); | ||
123 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->mask); | ||
124 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->ack); | ||
125 | irq_gc_unlock(gc); | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * irq_gc_eoi - EOI interrupt | ||
130 | * @d: irq_data | ||
131 | */ | ||
132 | void irq_gc_eoi(struct irq_data *d) | ||
133 | { | ||
134 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
135 | u32 mask = 1 << (d->irq - gc->irq_base); | ||
136 | |||
137 | irq_gc_lock(gc); | ||
138 | irq_reg_writel(mask, gc->reg_base + cur_regs(d)->eoi); | ||
139 | irq_gc_unlock(gc); | ||
140 | } | ||
141 | |||
142 | /** | ||
143 | * irq_gc_set_wake - Set/clr wake bit for an interrupt | ||
144 | * @d: irq_data | ||
145 | * | ||
146 | * For chips where the wake from suspend functionality is not | ||
147 | * configured in a separate register and the wakeup active state is | ||
148 | * just stored in a bitmask. | ||
149 | */ | ||
150 | int irq_gc_set_wake(struct irq_data *d, unsigned int on) | ||
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 | if (!(mask & gc->wake_enabled)) | ||
156 | return -EINVAL; | ||
157 | |||
158 | irq_gc_lock(gc); | ||
159 | if (on) | ||
160 | gc->wake_active |= mask; | ||
161 | else | ||
162 | gc->wake_active &= ~mask; | ||
163 | irq_gc_unlock(gc); | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * irq_alloc_generic_chip - Allocate a generic chip and initialize it | ||
169 | * @name: Name of the irq chip | ||
170 | * @num_ct: Number of irq_chip_type instances associated with this | ||
171 | * @irq_base: Interrupt base nr for this chip | ||
172 | * @reg_base: Register base address (virtual) | ||
173 | * @handler: Default flow handler associated with this chip | ||
174 | * | ||
175 | * Returns an initialized irq_chip_generic structure. The chip defaults | ||
176 | * to the primary (index 0) irq_chip_type and @handler | ||
177 | */ | ||
178 | struct irq_chip_generic * | ||
179 | irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, | ||
180 | void __iomem *reg_base, irq_flow_handler_t handler) | ||
181 | { | ||
182 | struct irq_chip_generic *gc; | ||
183 | unsigned long sz = sizeof(*gc) + num_ct * sizeof(struct irq_chip_type); | ||
184 | |||
185 | gc = kzalloc(sz, GFP_KERNEL); | ||
186 | if (gc) { | ||
187 | raw_spin_lock_init(&gc->lock); | ||
188 | gc->num_ct = num_ct; | ||
189 | gc->irq_base = irq_base; | ||
190 | gc->reg_base = reg_base; | ||
191 | gc->chip_types->chip.name = name; | ||
192 | gc->chip_types->handler = handler; | ||
193 | } | ||
194 | return gc; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Separate lockdep class for interrupt chip which can nest irq_desc | ||
199 | * lock. | ||
200 | */ | ||
201 | static struct lock_class_key irq_nested_lock_class; | ||
202 | |||
203 | /** | ||
204 | * irq_setup_generic_chip - Setup a range of interrupts with a generic chip | ||
205 | * @gc: Generic irq chip holding all data | ||
206 | * @msk: Bitmask holding the irqs to initialize relative to gc->irq_base | ||
207 | * @flags: Flags for initialization | ||
208 | * @clr: IRQ_* bits to clear | ||
209 | * @set: IRQ_* bits to set | ||
210 | * | ||
211 | * Set up max. 32 interrupts starting from gc->irq_base. Note, this | ||
212 | * initializes all interrupts to the primary irq_chip_type and its | ||
213 | * associated handler. | ||
214 | */ | ||
215 | void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, | ||
216 | enum irq_gc_flags flags, unsigned int clr, | ||
217 | unsigned int set) | ||
218 | { | ||
219 | struct irq_chip_type *ct = gc->chip_types; | ||
220 | unsigned int i; | ||
221 | |||
222 | /* Init mask cache ? */ | ||
223 | if (flags & IRQ_GC_INIT_MASK_CACHE) | ||
224 | gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); | ||
225 | |||
226 | for (i = gc->irq_base; msk; msk >>= 1, i++) { | ||
227 | if (!msk & 0x01) | ||
228 | continue; | ||
229 | |||
230 | if (flags & IRQ_GC_INIT_NESTED_LOCK) | ||
231 | irq_set_lockdep_class(i, &irq_nested_lock_class); | ||
232 | |||
233 | irq_set_chip_and_handler(i, &ct->chip, ct->handler); | ||
234 | irq_set_chip_data(i, gc); | ||
235 | irq_modify_status(i, clr, set); | ||
236 | } | ||
237 | gc->irq_cnt = i - gc->irq_base; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * irq_setup_alt_chip - Switch to alternative chip | ||
242 | * @d: irq_data for this interrupt | ||
243 | * @type Flow type to be initialized | ||
244 | * | ||
245 | * Only to be called from chip->irq_set_type() callbacks. | ||
246 | */ | ||
247 | int irq_setup_alt_chip(struct irq_data *d, unsigned int type) | ||
248 | { | ||
249 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
250 | struct irq_chip_type *ct = gc->chip_types; | ||
251 | unsigned int i; | ||
252 | |||
253 | for (i = 0; i < gc->num_ct; i++, ct++) { | ||
254 | if (ct->type & type) { | ||
255 | d->chip = &ct->chip; | ||
256 | irq_data_to_desc(d)->handle_irq = ct->handler; | ||
257 | return 0; | ||
258 | } | ||
259 | } | ||
260 | return -EINVAL; | ||
261 | } | ||