aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/irqdesc.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2010-09-22 11:09:43 -0400
committerThomas Gleixner <tglx@linutronix.de>2010-10-12 10:39:05 -0400
commit3795de236d67a05994a1a12759db9d4dd9ffc42c (patch)
tree75e5a2a8922e114de60f468494c879ba4f65ebee /kernel/irq/irqdesc.c
parentf303a6dd127b5ec6de90d1cd79ed19820c7e9658 (diff)
genirq: Distangle kernel/irq/handle.c
kernel/irq/handle.c has become a dumpground for random code in random order. Split out the irq descriptor management and the dummy irq_chip implementation into separate files. Cleanup the include maze while at it. No code change. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/irq/irqdesc.c')
-rw-r--r--kernel/irq/irqdesc.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
new file mode 100644
index 000000000000..fbf8cfa00510
--- /dev/null
+++ b/kernel/irq/irqdesc.c
@@ -0,0 +1,269 @@
1/*
2 * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
3 * Copyright (C) 2005-2006, Thomas Gleixner, Russell King
4 *
5 * This file contains the interrupt descriptor management code
6 *
7 * Detailed information is available in Documentation/DocBook/genericirq
8 *
9 */
10#include <linux/irq.h>
11#include <linux/slab.h>
12#include <linux/module.h>
13#include <linux/interrupt.h>
14#include <linux/kernel_stat.h>
15#include <linux/radix-tree.h>
16
17#include "internals.h"
18
19/*
20 * lockdep: we want to handle all irq_desc locks as a single lock-class:
21 */
22struct lock_class_key irq_desc_lock_class;
23
24#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
25static void __init init_irq_default_affinity(void)
26{
27 alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
28 cpumask_setall(irq_default_affinity);
29}
30#else
31static void __init init_irq_default_affinity(void)
32{
33}
34#endif
35
36int nr_irqs = NR_IRQS;
37EXPORT_SYMBOL_GPL(nr_irqs);
38
39#ifdef CONFIG_SPARSE_IRQ
40
41static struct irq_desc irq_desc_init = {
42 .status = IRQ_DISABLED,
43 .handle_irq = handle_bad_irq,
44 .depth = 1,
45 .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
46};
47
48void __ref init_kstat_irqs(struct irq_desc *desc, int node, int nr)
49{
50 void *ptr;
51
52 ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs),
53 GFP_ATOMIC, node);
54
55 /*
56 * don't overwite if can not get new one
57 * init_copy_kstat_irqs() could still use old one
58 */
59 if (ptr) {
60 printk(KERN_DEBUG " alloc kstat_irqs on node %d\n", node);
61 desc->kstat_irqs = ptr;
62 }
63}
64
65static void init_one_irq_desc(int irq, struct irq_desc *desc, int node)
66{
67 memcpy(desc, &irq_desc_init, sizeof(struct irq_desc));
68
69 raw_spin_lock_init(&desc->lock);
70 desc->irq_data.irq = irq;
71#ifdef CONFIG_SMP
72 desc->irq_data.node = node;
73#endif
74 lockdep_set_class(&desc->lock, &irq_desc_lock_class);
75 init_kstat_irqs(desc, node, nr_cpu_ids);
76 if (!desc->kstat_irqs) {
77 printk(KERN_ERR "can not alloc kstat_irqs\n");
78 BUG_ON(1);
79 }
80 if (!alloc_desc_masks(desc, node, false)) {
81 printk(KERN_ERR "can not alloc irq_desc cpumasks\n");
82 BUG_ON(1);
83 }
84 init_desc_masks(desc);
85 arch_init_chip_data(desc, node);
86}
87
88/*
89 * Protect the sparse_irqs:
90 */
91DEFINE_RAW_SPINLOCK(sparse_irq_lock);
92
93static RADIX_TREE(irq_desc_tree, GFP_ATOMIC);
94
95static void set_irq_desc(unsigned int irq, struct irq_desc *desc)
96{
97 radix_tree_insert(&irq_desc_tree, irq, desc);
98}
99
100struct irq_desc *irq_to_desc(unsigned int irq)
101{
102 return radix_tree_lookup(&irq_desc_tree, irq);
103}
104
105void replace_irq_desc(unsigned int irq, struct irq_desc *desc)
106{
107 void **ptr;
108
109 ptr = radix_tree_lookup_slot(&irq_desc_tree, irq);
110 if (ptr)
111 radix_tree_replace_slot(ptr, desc);
112}
113
114static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = {
115 [0 ... NR_IRQS_LEGACY-1] = {
116 .status = IRQ_DISABLED,
117 .handle_irq = handle_bad_irq,
118 .depth = 1,
119 .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
120 }
121};
122
123static unsigned int *kstat_irqs_legacy;
124
125int __init early_irq_init(void)
126{
127 struct irq_desc *desc;
128 int legacy_count;
129 int node;
130 int i;
131
132 init_irq_default_affinity();
133
134 /* initialize nr_irqs based on nr_cpu_ids */
135 arch_probe_nr_irqs();
136 printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d\n", NR_IRQS, nr_irqs);
137
138 desc = irq_desc_legacy;
139 legacy_count = ARRAY_SIZE(irq_desc_legacy);
140 node = first_online_node;
141
142 /* allocate based on nr_cpu_ids */
143 kstat_irqs_legacy = kzalloc_node(NR_IRQS_LEGACY * nr_cpu_ids *
144 sizeof(int), GFP_NOWAIT, node);
145
146 irq_desc_init.irq_data.chip = &no_irq_chip;
147
148 for (i = 0; i < legacy_count; i++) {
149 desc[i].irq_data.irq = i;
150 desc[i].irq_data.chip = &no_irq_chip;
151#ifdef CONFIG_SMP
152 desc[i].irq_data.node = node;
153#endif
154 desc[i].kstat_irqs = kstat_irqs_legacy + i * nr_cpu_ids;
155 lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
156 alloc_desc_masks(&desc[i], node, true);
157 init_desc_masks(&desc[i]);
158 set_irq_desc(i, &desc[i]);
159 }
160
161 return arch_early_irq_init();
162}
163
164struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
165{
166 struct irq_desc *desc;
167 unsigned long flags;
168
169 if (irq >= nr_irqs) {
170 WARN(1, "irq (%d) >= nr_irqs (%d) in irq_to_desc_alloc\n",
171 irq, nr_irqs);
172 return NULL;
173 }
174
175 desc = irq_to_desc(irq);
176 if (desc)
177 return desc;
178
179 raw_spin_lock_irqsave(&sparse_irq_lock, flags);
180
181 /* We have to check it to avoid races with another CPU */
182 desc = irq_to_desc(irq);
183 if (desc)
184 goto out_unlock;
185
186 desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
187
188 printk(KERN_DEBUG " alloc irq_desc for %d on node %d\n", irq, node);
189 if (!desc) {
190 printk(KERN_ERR "can not alloc irq_desc\n");
191 BUG_ON(1);
192 }
193 init_one_irq_desc(irq, desc, node);
194
195 set_irq_desc(irq, desc);
196
197out_unlock:
198 raw_spin_unlock_irqrestore(&sparse_irq_lock, flags);
199
200 return desc;
201}
202
203#else /* !CONFIG_SPARSE_IRQ */
204
205struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
206 [0 ... NR_IRQS-1] = {
207 .status = IRQ_DISABLED,
208 .handle_irq = handle_bad_irq,
209 .depth = 1,
210 .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
211 }
212};
213
214static unsigned int kstat_irqs_all[NR_IRQS][NR_CPUS];
215int __init early_irq_init(void)
216{
217 struct irq_desc *desc;
218 int count;
219 int i;
220
221 init_irq_default_affinity();
222
223 printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS);
224
225 desc = irq_desc;
226 count = ARRAY_SIZE(irq_desc);
227
228 for (i = 0; i < count; i++) {
229 desc[i].irq_data.irq = i;
230 desc[i].irq_data.chip = &no_irq_chip;
231 alloc_desc_masks(&desc[i], 0, true);
232 init_desc_masks(&desc[i]);
233 desc[i].kstat_irqs = kstat_irqs_all[i];
234 }
235 return arch_early_irq_init();
236}
237
238struct irq_desc *irq_to_desc(unsigned int irq)
239{
240 return (irq < NR_IRQS) ? irq_desc + irq : NULL;
241}
242
243struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node)
244{
245 return irq_to_desc(irq);
246}
247#endif /* !CONFIG_SPARSE_IRQ */
248
249void clear_kstat_irqs(struct irq_desc *desc)
250{
251 memset(desc->kstat_irqs, 0, nr_cpu_ids * sizeof(*(desc->kstat_irqs)));
252}
253
254void early_init_irq_lock_class(void)
255{
256 struct irq_desc *desc;
257 int i;
258
259 for_each_irq_desc(i, desc) {
260 lockdep_set_class(&desc->lock, &irq_desc_lock_class);
261 }
262}
263
264unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
265{
266 struct irq_desc *desc = irq_to_desc(irq);
267 return desc ? desc->kstat_irqs[cpu] : 0;
268}
269EXPORT_SYMBOL(kstat_irqs_cpu);