diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2010-02-24 01:00:34 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-26 05:08:42 -0500 |
commit | dee7399c2d9a1d3b0af5d68d7e0dd922e104a2a8 (patch) | |
tree | 49fe76813eeb051711370d210afea01e15082af6 /drivers/net/tc35815.c | |
parent | 9c5f9c2861909753140ad6a41cdc77cdf20c1dc9 (diff) |
tc35815: Fix double locking on NAPI
Isolate spinlock for tx and rx to resolve double-locking.
This is potential bug while this controller does not exist on any
SMP platforms, but lockdep or rt-preempt reveals this bug.
Reported-by: Ralf Roesch <ralf.roesch@rw-gmbh.de>
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tc35815.c')
-rw-r--r-- | drivers/net/tc35815.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 876f45afbed4..49bd84c0d583 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c | |||
@@ -402,6 +402,7 @@ struct tc35815_local { | |||
402 | * by this lock as well. | 402 | * by this lock as well. |
403 | */ | 403 | */ |
404 | spinlock_t lock; | 404 | spinlock_t lock; |
405 | spinlock_t rx_lock; | ||
405 | 406 | ||
406 | struct mii_bus *mii_bus; | 407 | struct mii_bus *mii_bus; |
407 | struct phy_device *phy_dev; | 408 | struct phy_device *phy_dev; |
@@ -835,6 +836,7 @@ static int __devinit tc35815_init_one(struct pci_dev *pdev, | |||
835 | 836 | ||
836 | INIT_WORK(&lp->restart_work, tc35815_restart_work); | 837 | INIT_WORK(&lp->restart_work, tc35815_restart_work); |
837 | spin_lock_init(&lp->lock); | 838 | spin_lock_init(&lp->lock); |
839 | spin_lock_init(&lp->rx_lock); | ||
838 | lp->pci_dev = pdev; | 840 | lp->pci_dev = pdev; |
839 | lp->chiptype = ent->driver_data; | 841 | lp->chiptype = ent->driver_data; |
840 | 842 | ||
@@ -1186,6 +1188,7 @@ static void tc35815_restart(struct net_device *dev) | |||
1186 | printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name); | 1188 | printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name); |
1187 | } | 1189 | } |
1188 | 1190 | ||
1191 | spin_lock_bh(&lp->rx_lock); | ||
1189 | spin_lock_irq(&lp->lock); | 1192 | spin_lock_irq(&lp->lock); |
1190 | tc35815_chip_reset(dev); | 1193 | tc35815_chip_reset(dev); |
1191 | tc35815_clear_queues(dev); | 1194 | tc35815_clear_queues(dev); |
@@ -1193,6 +1196,7 @@ static void tc35815_restart(struct net_device *dev) | |||
1193 | /* Reconfigure CAM again since tc35815_chip_init() initialize it. */ | 1196 | /* Reconfigure CAM again since tc35815_chip_init() initialize it. */ |
1194 | tc35815_set_multicast_list(dev); | 1197 | tc35815_set_multicast_list(dev); |
1195 | spin_unlock_irq(&lp->lock); | 1198 | spin_unlock_irq(&lp->lock); |
1199 | spin_unlock_bh(&lp->rx_lock); | ||
1196 | 1200 | ||
1197 | netif_wake_queue(dev); | 1201 | netif_wake_queue(dev); |
1198 | } | 1202 | } |
@@ -1211,11 +1215,14 @@ static void tc35815_schedule_restart(struct net_device *dev) | |||
1211 | struct tc35815_local *lp = netdev_priv(dev); | 1215 | struct tc35815_local *lp = netdev_priv(dev); |
1212 | struct tc35815_regs __iomem *tr = | 1216 | struct tc35815_regs __iomem *tr = |
1213 | (struct tc35815_regs __iomem *)dev->base_addr; | 1217 | (struct tc35815_regs __iomem *)dev->base_addr; |
1218 | unsigned long flags; | ||
1214 | 1219 | ||
1215 | /* disable interrupts */ | 1220 | /* disable interrupts */ |
1221 | spin_lock_irqsave(&lp->lock, flags); | ||
1216 | tc_writel(0, &tr->Int_En); | 1222 | tc_writel(0, &tr->Int_En); |
1217 | tc_writel(tc_readl(&tr->DMA_Ctl) | DMA_IntMask, &tr->DMA_Ctl); | 1223 | tc_writel(tc_readl(&tr->DMA_Ctl) | DMA_IntMask, &tr->DMA_Ctl); |
1218 | schedule_work(&lp->restart_work); | 1224 | schedule_work(&lp->restart_work); |
1225 | spin_unlock_irqrestore(&lp->lock, flags); | ||
1219 | } | 1226 | } |
1220 | 1227 | ||
1221 | static void tc35815_tx_timeout(struct net_device *dev) | 1228 | static void tc35815_tx_timeout(struct net_device *dev) |
@@ -1436,7 +1443,9 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit) | |||
1436 | if (status & Int_IntMacTx) { | 1443 | if (status & Int_IntMacTx) { |
1437 | /* Transmit complete. */ | 1444 | /* Transmit complete. */ |
1438 | lp->lstats.tx_ints++; | 1445 | lp->lstats.tx_ints++; |
1446 | spin_lock_irq(&lp->lock); | ||
1439 | tc35815_txdone(dev); | 1447 | tc35815_txdone(dev); |
1448 | spin_unlock_irq(&lp->lock); | ||
1440 | if (ret < 0) | 1449 | if (ret < 0) |
1441 | ret = 0; | 1450 | ret = 0; |
1442 | } | 1451 | } |
@@ -1649,7 +1658,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget) | |||
1649 | int received = 0, handled; | 1658 | int received = 0, handled; |
1650 | u32 status; | 1659 | u32 status; |
1651 | 1660 | ||
1652 | spin_lock(&lp->lock); | 1661 | spin_lock(&lp->rx_lock); |
1653 | status = tc_readl(&tr->Int_Src); | 1662 | status = tc_readl(&tr->Int_Src); |
1654 | do { | 1663 | do { |
1655 | /* BLEx, FDAEx will be cleared later */ | 1664 | /* BLEx, FDAEx will be cleared later */ |
@@ -1667,7 +1676,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget) | |||
1667 | } | 1676 | } |
1668 | status = tc_readl(&tr->Int_Src); | 1677 | status = tc_readl(&tr->Int_Src); |
1669 | } while (status); | 1678 | } while (status); |
1670 | spin_unlock(&lp->lock); | 1679 | spin_unlock(&lp->rx_lock); |
1671 | 1680 | ||
1672 | if (received < budget) { | 1681 | if (received < budget) { |
1673 | napi_complete(napi); | 1682 | napi_complete(napi); |