summaryrefslogtreecommitdiffstats
path: root/drivers/net/8139cp.c
diff options
context:
space:
mode:
authorChris Lalancette <clalance@redhat.com>2007-01-16 16:41:44 -0500
committerJeff Garzik <jeff@garzik.org>2007-01-18 11:47:22 -0500
commit553af56775b3f23bf64f87090ab81a62bef2837b (patch)
tree1b8e9c5feb2bdaa2f61adb3a6f87d96f4afd21db /drivers/net/8139cp.c
parent10764889c6355cbb335cf0578ce12427475d1a65 (diff)
downloadlinux-553af56775b3f23bf64f87090ab81a62bef2837b.tar.gz
linux-553af56775b3f23bf64f87090ab81a62bef2837b.tar.bz2
linux-553af56775b3f23bf64f87090ab81a62bef2837b.zip
8139cp: Don't blindly enable interrupts
Similar to this commit: http://kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=d15e9c4d9a75702b30e00cdf95c71c88e3f3f51e It's not safe in cp_start_xmit to blindly call spin_lock_irq and then spin_unlock_irq, since it may very well be the case that cp_start_xmit was called with interrupts already disabled (I came across this bug in the context of netdump in RedHat kernels, but the same issue holds, for example, in netconsole). Therefore, replace all instances of spin_lock_irq and spin_unlock_irq with spin_lock_irqsave and spin_unlock_irqrestore, respectively, in cp_start_xmit(). I tested this against a fully-virtualized Xen guest using netdump, which happens to use the 8139cp driver to talk to the emulated hardware. I don't have a real piece of 8139cp hardware to test on, so someone else will have to do that. Signed-off-by: Chris Lalancette <clalance@redhat.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/8139cp.c')
-rw-r--r--drivers/net/8139cp.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index e2cb19b582a1..6f93a765e564 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -765,17 +765,18 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
struct cp_private *cp = netdev_priv(dev);
unsigned entry;
u32 eor, flags;
+ unsigned long intr_flags;
#if CP_VLAN_TAG_USED
u32 vlan_tag = 0;
#endif
int mss = 0;
- spin_lock_irq(&cp->lock);
+ spin_lock_irqsave(&cp->lock, intr_flags);
/* This is a hard error, log it. */
if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
- spin_unlock_irq(&cp->lock);
+ spin_unlock_irqrestore(&cp->lock, intr_flags);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return 1;
@@ -908,7 +909,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
- spin_unlock_irq(&cp->lock);
+ spin_unlock_irqrestore(&cp->lock, intr_flags);
cpw8(TxPoll, NormalTxPoll);
dev->trans_start = jiffies;