diff options
author | Anton Vorontsov <avorontsov@ru.mvista.com> | 2008-08-21 14:58:28 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-08-22 02:07:21 -0400 |
commit | 377bf1e4ac2d894791733270604594c7c851ef83 (patch) | |
tree | 955bb2e540d8ae5b5290982dcadb3ff18673ba2c /kernel/irq/manage.c | |
parent | 8d00a6c8f6b08e7167bc03bf955cdc7e47c5132e (diff) |
genirq: fix irq_desc->depth handling with DEBUG_SHIRQ
When DEBUG_SHIRQ is selected, a spurious IRQ is issued before
the setup_irq() initializes the desc->depth. An IRQ handler may
call disable_irq_nosync(), but then setup_irq() will overwrite
desc->depth, and upon enable_irq() we'll catch this WARN:
------------[ cut here ]------------
Badness at kernel/irq/manage.c:180
NIP: c0061ab8 LR: c0061f10 CTR: 00000000
REGS: cf83be50 TRAP: 0700 Not tainted (2.6.27-rc3-23450-g74919b0)
MSR: 00021032 <ME,IR,DR> CR: 22042022 XER: 20000000
TASK = cf829100[5] 'events/0' THREAD: cf83a000
GPR00: c0061f10 cf83bf00 cf829100 c038e674 00000016 00000000 cf83bef8 00000038
GPR08: c0298910 00000000 c0310d28 cf83a000 00000c9c 1001a1a8 0fffe000 00800000
GPR16: ffffffff 00000000 007fff00 00000000 007ffeb0 c03320a0 c031095c c0310924
GPR24: cf8292ec cf807190 cf83a000 00009032 c038e6a4 c038e674 cf99b1cc c038e674
NIP [c0061ab8] __enable_irq+0x20/0x80
LR [c0061f10] enable_irq+0x50/0x70
Call Trace:
[cf83bf00] [c038e674] irq_desc+0x630/0x9000 (unreliable)
[cf83bf10] [c0061f10] enable_irq+0x50/0x70
[cf83bf30] [c01abe94] phy_change+0x68/0x108
[cf83bf50] [c0046394] run_workqueue+0xc4/0x16c
[cf83bf90] [c0046834] worker_thread+0x74/0xd4
[cf83bfd0] [c004ab7c] kthread+0x48/0x84
[cf83bff0] [c00135e0] kernel_thread+0x44/0x60
Instruction dump:
4e800020 3d20c031 38a94214 4bffffcc 9421fff0 7c0802a6 93e1000c 7c7f1b78
90010014 8123001c 2f890000 409e001c <0fe00000> 80010014 83e1000c 38210010
That trace corresponds to this line:
WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
The patch fixes the problem by moving the SHIRQ code below the
setup_irq().
Unfortunately we can't easily move the SHIRQ code inside the
setup_irq(), since it grabs a spinlock, so to prvent a 'real'
IRQ from interfere us we should disable that IRQ.
p.s. The driver in question is drivers/net/phy/phy.c.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r-- | kernel/irq/manage.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 77a51be36010..ae1b684e048c 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -596,26 +596,29 @@ int request_irq(unsigned int irq, irq_handler_t handler, | |||
596 | action->next = NULL; | 596 | action->next = NULL; |
597 | action->dev_id = dev_id; | 597 | action->dev_id = dev_id; |
598 | 598 | ||
599 | retval = setup_irq(irq, action); | ||
600 | if (retval) | ||
601 | kfree(action); | ||
602 | |||
599 | #ifdef CONFIG_DEBUG_SHIRQ | 603 | #ifdef CONFIG_DEBUG_SHIRQ |
600 | if (irqflags & IRQF_SHARED) { | 604 | if (irqflags & IRQF_SHARED) { |
601 | /* | 605 | /* |
602 | * It's a shared IRQ -- the driver ought to be prepared for it | 606 | * It's a shared IRQ -- the driver ought to be prepared for it |
603 | * to happen immediately, so let's make sure.... | 607 | * to happen immediately, so let's make sure.... |
604 | * We do this before actually registering it, to make sure that | 608 | * We disable the irq to make sure that a 'real' IRQ doesn't |
605 | * a 'real' IRQ doesn't run in parallel with our fake | 609 | * run in parallel with our fake. |
606 | */ | 610 | */ |
607 | unsigned long flags; | 611 | unsigned long flags; |
608 | 612 | ||
613 | disable_irq(irq); | ||
609 | local_irq_save(flags); | 614 | local_irq_save(flags); |
615 | |||
610 | handler(irq, dev_id); | 616 | handler(irq, dev_id); |
617 | |||
611 | local_irq_restore(flags); | 618 | local_irq_restore(flags); |
619 | enable_irq(irq); | ||
612 | } | 620 | } |
613 | #endif | 621 | #endif |
614 | |||
615 | retval = setup_irq(irq, action); | ||
616 | if (retval) | ||
617 | kfree(action); | ||
618 | |||
619 | return retval; | 622 | return retval; |
620 | } | 623 | } |
621 | EXPORT_SYMBOL(request_irq); | 624 | EXPORT_SYMBOL(request_irq); |