Commit 950d0a10d12578a270f3dfa9fd76fe5c2deb343f
Exists in
master
and in
4 other branches
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
…/git/tip/linux-2.6-tip * 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: irq: Track the owner of irq descriptor irq: Always set IRQF_ONESHOT if no primary handler is specified genirq: Fix wrong bit operation
Showing 5 changed files Side-by-side Diff
include/linux/irq.h
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 | #include <linux/errno.h> |
24 | 24 | #include <linux/topology.h> |
25 | 25 | #include <linux/wait.h> |
26 | +#include <linux/module.h> | |
26 | 27 | |
27 | 28 | #include <asm/irq.h> |
28 | 29 | #include <asm/ptrace.h> |
... | ... | @@ -547,7 +548,15 @@ |
547 | 548 | return d->msi_desc; |
548 | 549 | } |
549 | 550 | |
550 | -int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node); | |
551 | +int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, | |
552 | + struct module *owner); | |
553 | + | |
554 | +static inline int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, | |
555 | + int node) | |
556 | +{ | |
557 | + return __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE); | |
558 | +} | |
559 | + | |
551 | 560 | void irq_free_descs(unsigned int irq, unsigned int cnt); |
552 | 561 | int irq_reserve_irqs(unsigned int from, unsigned int cnt); |
553 | 562 |
include/linux/irqdesc.h
kernel/irq/generic-chip.c
... | ... | @@ -246,7 +246,7 @@ |
246 | 246 | gc->mask_cache = irq_reg_readl(gc->reg_base + ct->regs.mask); |
247 | 247 | |
248 | 248 | for (i = gc->irq_base; msk; msk >>= 1, i++) { |
249 | - if (!msk & 0x01) | |
249 | + if (!(msk & 0x01)) | |
250 | 250 | continue; |
251 | 251 | |
252 | 252 | if (flags & IRQ_GC_INIT_NESTED_LOCK) |
... | ... | @@ -301,7 +301,7 @@ |
301 | 301 | raw_spin_unlock(&gc_lock); |
302 | 302 | |
303 | 303 | for (; msk; msk >>= 1, i++) { |
304 | - if (!msk & 0x01) | |
304 | + if (!(msk & 0x01)) | |
305 | 305 | continue; |
306 | 306 | |
307 | 307 | /* Remove handler first. That will mask the irq line */ |
kernel/irq/irqdesc.c
... | ... | @@ -70,7 +70,8 @@ |
70 | 70 | static inline int desc_node(struct irq_desc *desc) { return 0; } |
71 | 71 | #endif |
72 | 72 | |
73 | -static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node) | |
73 | +static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node, | |
74 | + struct module *owner) | |
74 | 75 | { |
75 | 76 | int cpu; |
76 | 77 | |
... | ... | @@ -86,6 +87,7 @@ |
86 | 87 | desc->irq_count = 0; |
87 | 88 | desc->irqs_unhandled = 0; |
88 | 89 | desc->name = NULL; |
90 | + desc->owner = owner; | |
89 | 91 | for_each_possible_cpu(cpu) |
90 | 92 | *per_cpu_ptr(desc->kstat_irqs, cpu) = 0; |
91 | 93 | desc_smp_init(desc, node); |
... | ... | @@ -128,7 +130,7 @@ |
128 | 130 | static inline void free_masks(struct irq_desc *desc) { } |
129 | 131 | #endif |
130 | 132 | |
131 | -static struct irq_desc *alloc_desc(int irq, int node) | |
133 | +static struct irq_desc *alloc_desc(int irq, int node, struct module *owner) | |
132 | 134 | { |
133 | 135 | struct irq_desc *desc; |
134 | 136 | gfp_t gfp = GFP_KERNEL; |
... | ... | @@ -147,7 +149,7 @@ |
147 | 149 | raw_spin_lock_init(&desc->lock); |
148 | 150 | lockdep_set_class(&desc->lock, &irq_desc_lock_class); |
149 | 151 | |
150 | - desc_set_defaults(irq, desc, node); | |
152 | + desc_set_defaults(irq, desc, node, owner); | |
151 | 153 | |
152 | 154 | return desc; |
153 | 155 | |
154 | 156 | |
... | ... | @@ -173,13 +175,14 @@ |
173 | 175 | kfree(desc); |
174 | 176 | } |
175 | 177 | |
176 | -static int alloc_descs(unsigned int start, unsigned int cnt, int node) | |
178 | +static int alloc_descs(unsigned int start, unsigned int cnt, int node, | |
179 | + struct module *owner) | |
177 | 180 | { |
178 | 181 | struct irq_desc *desc; |
179 | 182 | int i; |
180 | 183 | |
181 | 184 | for (i = 0; i < cnt; i++) { |
182 | - desc = alloc_desc(start + i, node); | |
185 | + desc = alloc_desc(start + i, node, owner); | |
183 | 186 | if (!desc) |
184 | 187 | goto err; |
185 | 188 | mutex_lock(&sparse_irq_lock); |
... | ... | @@ -227,7 +230,7 @@ |
227 | 230 | nr_irqs = initcnt; |
228 | 231 | |
229 | 232 | for (i = 0; i < initcnt; i++) { |
230 | - desc = alloc_desc(i, node); | |
233 | + desc = alloc_desc(i, node, NULL); | |
231 | 234 | set_bit(i, allocated_irqs); |
232 | 235 | irq_insert_desc(i, desc); |
233 | 236 | } |
... | ... | @@ -261,7 +264,7 @@ |
261 | 264 | alloc_masks(&desc[i], GFP_KERNEL, node); |
262 | 265 | raw_spin_lock_init(&desc[i].lock); |
263 | 266 | lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); |
264 | - desc_set_defaults(i, &desc[i], node); | |
267 | + desc_set_defaults(i, &desc[i], node, NULL); | |
265 | 268 | } |
266 | 269 | return arch_early_irq_init(); |
267 | 270 | } |
268 | 271 | |
... | ... | @@ -276,8 +279,16 @@ |
276 | 279 | dynamic_irq_cleanup(irq); |
277 | 280 | } |
278 | 281 | |
279 | -static inline int alloc_descs(unsigned int start, unsigned int cnt, int node) | |
282 | +static inline int alloc_descs(unsigned int start, unsigned int cnt, int node, | |
283 | + struct module *owner) | |
280 | 284 | { |
285 | + u32 i; | |
286 | + | |
287 | + for (i = 0; i < cnt; i++) { | |
288 | + struct irq_desc *desc = irq_to_desc(start + i); | |
289 | + | |
290 | + desc->owner = owner; | |
291 | + } | |
281 | 292 | return start; |
282 | 293 | } |
283 | 294 | |
... | ... | @@ -337,7 +348,8 @@ |
337 | 348 | * Returns the first irq number or error code |
338 | 349 | */ |
339 | 350 | int __ref |
340 | -irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node) | |
351 | +__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, | |
352 | + struct module *owner) | |
341 | 353 | { |
342 | 354 | int start, ret; |
343 | 355 | |
344 | 356 | |
... | ... | @@ -366,13 +378,13 @@ |
366 | 378 | |
367 | 379 | bitmap_set(allocated_irqs, start, cnt); |
368 | 380 | mutex_unlock(&sparse_irq_lock); |
369 | - return alloc_descs(start, cnt, node); | |
381 | + return alloc_descs(start, cnt, node, owner); | |
370 | 382 | |
371 | 383 | err: |
372 | 384 | mutex_unlock(&sparse_irq_lock); |
373 | 385 | return ret; |
374 | 386 | } |
375 | -EXPORT_SYMBOL_GPL(irq_alloc_descs); | |
387 | +EXPORT_SYMBOL_GPL(__irq_alloc_descs); | |
376 | 388 | |
377 | 389 | /** |
378 | 390 | * irq_reserve_irqs - mark irqs allocated |
... | ... | @@ -440,7 +452,7 @@ |
440 | 452 | unsigned long flags; |
441 | 453 | |
442 | 454 | raw_spin_lock_irqsave(&desc->lock, flags); |
443 | - desc_set_defaults(irq, desc, desc_node(desc)); | |
455 | + desc_set_defaults(irq, desc, desc_node(desc), NULL); | |
444 | 456 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
445 | 457 | } |
446 | 458 |
kernel/irq/manage.c
... | ... | @@ -883,6 +883,8 @@ |
883 | 883 | |
884 | 884 | if (desc->irq_data.chip == &no_irq_chip) |
885 | 885 | return -ENOSYS; |
886 | + if (!try_module_get(desc->owner)) | |
887 | + return -ENODEV; | |
886 | 888 | /* |
887 | 889 | * Some drivers like serial.c use request_irq() heavily, |
888 | 890 | * so we have to be careful not to interfere with a |
... | ... | @@ -906,8 +908,10 @@ |
906 | 908 | */ |
907 | 909 | nested = irq_settings_is_nested_thread(desc); |
908 | 910 | if (nested) { |
909 | - if (!new->thread_fn) | |
910 | - return -EINVAL; | |
911 | + if (!new->thread_fn) { | |
912 | + ret = -EINVAL; | |
913 | + goto out_mput; | |
914 | + } | |
911 | 915 | /* |
912 | 916 | * Replace the primary handler which was provided from |
913 | 917 | * the driver for non nested interrupt handling by the |
... | ... | @@ -929,8 +933,10 @@ |
929 | 933 | |
930 | 934 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, |
931 | 935 | new->name); |
932 | - if (IS_ERR(t)) | |
933 | - return PTR_ERR(t); | |
936 | + if (IS_ERR(t)) { | |
937 | + ret = PTR_ERR(t); | |
938 | + goto out_mput; | |
939 | + } | |
934 | 940 | /* |
935 | 941 | * We keep the reference to the task struct even if |
936 | 942 | * the thread dies to avoid that the interrupt code |
... | ... | @@ -1095,6 +1101,8 @@ |
1095 | 1101 | kthread_stop(t); |
1096 | 1102 | put_task_struct(t); |
1097 | 1103 | } |
1104 | +out_mput: | |
1105 | + module_put(desc->owner); | |
1098 | 1106 | return ret; |
1099 | 1107 | } |
1100 | 1108 | |
... | ... | @@ -1203,6 +1211,7 @@ |
1203 | 1211 | put_task_struct(action->thread); |
1204 | 1212 | } |
1205 | 1213 | |
1214 | + module_put(desc->owner); | |
1206 | 1215 | return action; |
1207 | 1216 | } |
1208 | 1217 | |
... | ... | @@ -1322,6 +1331,7 @@ |
1322 | 1331 | if (!thread_fn) |
1323 | 1332 | return -EINVAL; |
1324 | 1333 | handler = irq_default_primary_handler; |
1334 | + irqflags |= IRQF_ONESHOT; | |
1325 | 1335 | } |
1326 | 1336 | |
1327 | 1337 | action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); |