2010-12-16 09:05:48

by Jean-Michel Hautbois

[permalink] [raw]
Subject: Unbalanced enable for IRQ => phy_change

Hi !

I am currently using a MPC8548 PowerPC board, and I have encountered
the following problem :
[   19.867849] Unbalanced enable for IRQ 48
[   19.867855] ------------[ cut here ]------------
[   19.873819] Badness at /.../kernel/irq/manage.c:174
[   19.873823] NIP: c0044acc LR: c0044acc CTR: c0018480
[   19.873828] REGS: dfc2be60 TRAP: 0700   Tainted: P
(2.6.24.7_http://www.men.de_1.1)
[   19.873831] MSR: 00021000 <ME>  CR: 24000022  XER: 00000000
[   19.873839] TASK = dfc204e0[5] 'events/0' THREAD: dfc2a000
[   19.873842] GPR00: c0044acc dfc2bf10 dfc204e0 0000002f 00021000
00000000 00000000 00000000
[   19.873854] GPR08: 00000034 ffffffff 0000574e de821b20 24000024
100607bc 00008000 00001020
[   19.873865] GPR16: c0447b44 c0447b2c 00fff018 033327d2 00000008
c044b2c8 c048d1a8 c044b300
[   19.873877] GPR24: dfc206a0 dfc204e0 dfc01f30 dfc2a000 00029000
c04cb714 00000030 c04cb6e4
[   19.873890] NIP [c0044acc] enable_irq+0x6c/0xdc
[   19.873903] LR [c0044acc] enable_irq+0x6c/0xdc
[   19.873908] Call Trace:
[   19.873911] [dfc2bf10] [c0044acc] enable_irq+0x6c/0xdc (unreliable)
[   19.873919] [dfc2bf30] [c0217868] phy_change+0x74/0xe4
[   19.873926] [dfc2bf50] [c002fb2c] run_workqueue+0xc4/0x15c
[   19.873933] [dfc2bf90] [c002ffb0] worker_thread+0x74/0xd4
[   19.873940] [dfc2bfd0] [c0034360] kthread+0x48/0x84
[   19.873946] [dfc2bff0] [c00047bc] kernel_thread+0x44/0x60
[   19.873953] Instruction dump:
[   19.873957] 7fe04a14 3bbf0030 7fa3eb78 483a9461 813f001c 7c7c1b78
2f890000 409e0038
[   19.873968] 3c60c045 7fc4f378 3863f1d4 4bfd9129 <0fe00000> 7fa3eb78
7f84e378 483a91a5


When looking at the phy_change function in drivers/net/phy/phy.c I
have noticed something quite strange :
We are calling phy_disable_interrupts() and after some operations, enable_irq().
The first thing I thought about is why aren't we calling
disable_irq/enable_irq or phy_disable_interrupts/phy_enable_interrupts
but a mix ?

Next, I took a more deep look at phy_disable_interrupts() and
sepcifically at the phy_config_interrupt() function :

       int err = 0;

       phydev->interrupts = interrupts;
       if (phydev->drv->config_intr)
               err = phydev->drv->config_intr(phydev);

       return err;

If phydev->drv->config_intr is not implemented (this is my use case :
I am using the drivers/net/gianfar.c driver), then, nothing will be
done, and there is no disable_irq() call.

I don't know what is better : using disable_irq/enable_irq or the phy
specific functions, but I think that we should avoid using a mix...
Am I wrong ?

Thanks in advance,
Regards,
JM