diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-08-19 23:50:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:52:29 -0400 |
commit | 08678b0841267c1d00d771fe01548d86043d065e (patch) | |
tree | 7debb21f9e9a768ced43077f7376797a0c46f8c0 /kernel/irq/handle.c | |
parent | bfea1238beac9d306eeac081c67de5ca6aec4c7a (diff) |
generic: sparse irqs: use irq_desc() together with dyn_array, instead of irq_desc[]
add CONFIG_HAVE_SPARSE_IRQ to for use condensed array.
Get rid of irq_desc[] array assumptions.
Preallocate 32 irq_desc, and irq_desc() will try to get more.
( No change in functionality is expected anywhere, except the odd build
failure where we missed a code site or where a crossing commit itroduces
new irq_desc[] usage. )
v2: according to Eric, change get_irq_desc() to irq_desc()
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/irq/handle.c')
-rw-r--r-- | kernel/irq/handle.c | 138 |
1 files changed, 125 insertions, 13 deletions
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 6ce3bcc2b8f7..9fc33b3378e6 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
@@ -18,6 +18,14 @@ | |||
18 | 18 | ||
19 | #include "internals.h" | 19 | #include "internals.h" |
20 | 20 | ||
21 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
22 | |||
23 | /* | ||
24 | * lockdep: we want to handle all irq_desc locks as a single lock-class: | ||
25 | */ | ||
26 | static struct lock_class_key irq_desc_lock_class; | ||
27 | #endif | ||
28 | |||
21 | /** | 29 | /** |
22 | * handle_bad_irq - handle spurious and unhandled irqs | 30 | * handle_bad_irq - handle spurious and unhandled irqs |
23 | * @irq: the interrupt number | 31 | * @irq: the interrupt number |
@@ -51,7 +59,8 @@ int nr_irqs = NR_IRQS; | |||
51 | EXPORT_SYMBOL_GPL(nr_irqs); | 59 | EXPORT_SYMBOL_GPL(nr_irqs); |
52 | 60 | ||
53 | #ifdef CONFIG_HAVE_DYN_ARRAY | 61 | #ifdef CONFIG_HAVE_DYN_ARRAY |
54 | static struct irq_desc irq_desc_init __initdata = { | 62 | static struct irq_desc irq_desc_init = { |
63 | .irq = -1U, | ||
55 | .status = IRQ_DISABLED, | 64 | .status = IRQ_DISABLED, |
56 | .chip = &no_irq_chip, | 65 | .chip = &no_irq_chip, |
57 | .handle_irq = handle_bad_irq, | 66 | .handle_irq = handle_bad_irq, |
@@ -62,6 +71,27 @@ static struct irq_desc irq_desc_init __initdata = { | |||
62 | #endif | 71 | #endif |
63 | }; | 72 | }; |
64 | 73 | ||
74 | |||
75 | static void init_one_irq_desc(struct irq_desc *desc) | ||
76 | { | ||
77 | memcpy(desc, &irq_desc_init, sizeof(struct irq_desc)); | ||
78 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
79 | lockdep_set_class(&desc->lock, &irq_desc_lock_class); | ||
80 | #endif | ||
81 | } | ||
82 | |||
83 | #ifdef CONFIG_HAVE_SPARSE_IRQ | ||
84 | static int nr_irq_desc = 32; | ||
85 | |||
86 | static int __init parse_nr_irq_desc(char *arg) | ||
87 | { | ||
88 | if (arg) | ||
89 | nr_irq_desc = simple_strtoul(arg, NULL, 0); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | early_param("nr_irq_desc", parse_nr_irq_desc); | ||
94 | |||
65 | static void __init init_work(void *data) | 95 | static void __init init_work(void *data) |
66 | { | 96 | { |
67 | struct dyn_array *da = data; | 97 | struct dyn_array *da = data; |
@@ -71,12 +101,83 @@ static void __init init_work(void *data) | |||
71 | desc = *da->name; | 101 | desc = *da->name; |
72 | 102 | ||
73 | for (i = 0; i < *da->nr; i++) | 103 | for (i = 0; i < *da->nr; i++) |
74 | memcpy(&desc[i], &irq_desc_init, sizeof(struct irq_desc)); | 104 | init_one_irq_desc(&desc[i]); |
105 | |||
106 | for (i = 1; i < *da->nr; i++) | ||
107 | desc[i-1].next = &desc[i]; | ||
75 | } | 108 | } |
76 | 109 | ||
77 | struct irq_desc *irq_desc; | 110 | static struct irq_desc *sparse_irqs; |
111 | DEFINE_DYN_ARRAY(sparse_irqs, sizeof(struct irq_desc), nr_irq_desc, PAGE_SIZE, init_work); | ||
112 | |||
113 | extern int after_bootmem; | ||
114 | extern void *__alloc_bootmem_nopanic(unsigned long size, | ||
115 | unsigned long align, | ||
116 | unsigned long goal); | ||
117 | struct irq_desc *irq_to_desc(unsigned int irq) | ||
118 | { | ||
119 | struct irq_desc *desc, *desc_pri; | ||
120 | int i; | ||
121 | int count = 0; | ||
122 | |||
123 | BUG_ON(irq == -1U); | ||
124 | |||
125 | desc_pri = desc = &sparse_irqs[0]; | ||
126 | while (desc) { | ||
127 | if (desc->irq == irq) | ||
128 | return desc; | ||
129 | |||
130 | if (desc->irq == -1U) { | ||
131 | desc->irq = irq; | ||
132 | return desc; | ||
133 | } | ||
134 | desc_pri = desc; | ||
135 | desc = desc->next; | ||
136 | count++; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * we run out of pre-allocate ones, allocate more | ||
141 | */ | ||
142 | printk(KERN_DEBUG "try to get more irq_desc %d\n", nr_irq_desc); | ||
143 | |||
144 | if (after_bootmem) | ||
145 | desc = kzalloc(sizeof(struct irq_desc)*nr_irq_desc, GFP_ATOMIC); | ||
146 | else | ||
147 | desc = __alloc_bootmem_nopanic(sizeof(struct irq_desc)*nr_irq_desc, PAGE_SIZE, 0); | ||
148 | |||
149 | if (!desc) | ||
150 | panic("please boot with nr_irq_desc= %d\n", count * 2); | ||
151 | |||
152 | for (i = 0; i < nr_irq_desc; i++) | ||
153 | init_one_irq_desc(&desc[i]); | ||
154 | |||
155 | for (i = 1; i < nr_irq_desc; i++) | ||
156 | desc[i-1].next = &desc[i]; | ||
157 | |||
158 | desc->irq = irq; | ||
159 | desc_pri->next = desc; | ||
160 | |||
161 | return desc; | ||
162 | } | ||
163 | #else | ||
164 | static void __init init_work(void *data) | ||
165 | { | ||
166 | struct dyn_array *da = data; | ||
167 | int i; | ||
168 | struct irq_desc *desc; | ||
169 | |||
170 | desc = *da->name; | ||
171 | |||
172 | for (i = 0; i < *da->nr; i++) | ||
173 | init_one_irq_desc(&desc[i]); | ||
174 | |||
175 | } | ||
176 | static struct irq_desc *irq_desc; | ||
78 | DEFINE_DYN_ARRAY(irq_desc, sizeof(struct irq_desc), nr_irqs, PAGE_SIZE, init_work); | 177 | DEFINE_DYN_ARRAY(irq_desc, sizeof(struct irq_desc), nr_irqs, PAGE_SIZE, init_work); |
79 | 178 | ||
179 | #endif | ||
180 | |||
80 | #else | 181 | #else |
81 | 182 | ||
82 | struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { | 183 | struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { |
@@ -85,12 +186,23 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { | |||
85 | .chip = &no_irq_chip, | 186 | .chip = &no_irq_chip, |
86 | .handle_irq = handle_bad_irq, | 187 | .handle_irq = handle_bad_irq, |
87 | .depth = 1, | 188 | .depth = 1, |
88 | .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock), | 189 | .lock = __SPIN_LOCK_UNLOCKED(sparse_irqs->lock), |
89 | #ifdef CONFIG_SMP | 190 | #ifdef CONFIG_SMP |
90 | .affinity = CPU_MASK_ALL | 191 | .affinity = CPU_MASK_ALL |
91 | #endif | 192 | #endif |
92 | } | 193 | } |
93 | }; | 194 | }; |
195 | |||
196 | #endif | ||
197 | |||
198 | #ifndef CONFIG_HAVE_SPARSE_IRQ | ||
199 | struct irq_desc *irq_to_desc(unsigned int irq) | ||
200 | { | ||
201 | if (irq < nr_irqs) | ||
202 | return &irq_desc[irq]; | ||
203 | |||
204 | return NULL; | ||
205 | } | ||
94 | #endif | 206 | #endif |
95 | 207 | ||
96 | /* | 208 | /* |
@@ -99,7 +211,10 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { | |||
99 | */ | 211 | */ |
100 | static void ack_bad(unsigned int irq) | 212 | static void ack_bad(unsigned int irq) |
101 | { | 213 | { |
102 | print_irq_desc(irq, irq_desc + irq); | 214 | struct irq_desc *desc; |
215 | |||
216 | desc = irq_to_desc(irq); | ||
217 | print_irq_desc(irq, desc); | ||
103 | ack_bad_irq(irq); | 218 | ack_bad_irq(irq); |
104 | } | 219 | } |
105 | 220 | ||
@@ -196,7 +311,7 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action) | |||
196 | */ | 311 | */ |
197 | unsigned int __do_IRQ(unsigned int irq) | 312 | unsigned int __do_IRQ(unsigned int irq) |
198 | { | 313 | { |
199 | struct irq_desc *desc = irq_desc + irq; | 314 | struct irq_desc *desc = irq_to_desc(irq); |
200 | struct irqaction *action; | 315 | struct irqaction *action; |
201 | unsigned int status; | 316 | unsigned int status; |
202 | 317 | ||
@@ -287,19 +402,16 @@ out: | |||
287 | } | 402 | } |
288 | #endif | 403 | #endif |
289 | 404 | ||
290 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
291 | |||
292 | /* | ||
293 | * lockdep: we want to handle all irq_desc locks as a single lock-class: | ||
294 | */ | ||
295 | static struct lock_class_key irq_desc_lock_class; | ||
296 | 405 | ||
406 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
297 | void early_init_irq_lock_class(void) | 407 | void early_init_irq_lock_class(void) |
298 | { | 408 | { |
409 | #ifndef CONFIG_HAVE_DYN_ARRAY | ||
299 | int i; | 410 | int i; |
300 | 411 | ||
301 | for (i = 0; i < nr_irqs; i++) | 412 | for (i = 0; i < nr_irqs; i++) |
302 | lockdep_set_class(&irq_desc[i].lock, &irq_desc_lock_class); | 413 | lockdep_set_class(&irq_desc[i].lock, &irq_desc_lock_class); |
414 | #endif | ||
303 | } | 415 | } |
304 | |||
305 | #endif | 416 | #endif |
417 | |||