ksz884x: fix receive polling race condition
authorLennert Buytenhek <buytenh@wantstofly.org>
Tue, 18 Dec 2012 03:57:00 +0000 (03:57 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 19 Dec 2012 20:44:45 +0000 (12:44 -0800)
commit4945106d21926eadaaa1c5465d26d9a0d26a2420
treef0ed2f5271c33a59e227b92360ecfe0fffdba727
parent341abdbe38ca22f351c9db68a69382fa57350066
ksz884x: fix receive polling race condition

The ksz884x driver does receive processing in a custom tasklet, and
seems to be assuming that since it takes its private interface spinlock
with spin_lock_irq(), it won't be running concurrently with its own
interrupt handler, as it cannot be preempted by it, but since its
interrupt handler doesn't do any locking whatsoever, the receive
processing tasklet and interrupt handler can end up running concurrently
on different CPUs.

As a result of this, the ksz884x receive path ends up locking up fairly
easily, when the receive processing tasklet's reenabling of receive
interrupts (due to it being done with polling the receive ring) races
with the interrupt handler's disabling of receive interrupts (due to a
new receive interrupt coming in) resulting in the receive interrupt
being masked but the receive processing tasklet not being scheduled.

Fix this by making the ksz884x interrupt handler take its private
interface spinlock.  This requires upgrading the spin_lock() in the
transmit cleanup tasklet to a spin_lock_irq(), as otherwise the IRQ
handler can preempt transmit cleanup and deadlock the system, but
with those two changes, no more receive lockups have been observed.

Reported-by: Chris Healy <cphealy@gmail.com>
Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
----
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/micrel/ksz884x.c