Commit 70a8c581 authored by Jeff Garzik's avatar Jeff Garzik

[netdrvr tg3] fix NAPI deadlock

* do not hold driver spinlock during RX processing in tg3_poll
  (this is the deadlock fix)
* create netif_poll_{en,dis}able to synchronize against dev->poll()
* create __netif_rx_complete to avoid a third irq-save in tg3_poll
* create tg3_netif_{start,stop} as driver-specific helper functions
  which disable and enable NAPI polling and TX queueing.  Note that
  the TX queueing enable/disable is purely advisory, and is not
  intended to prevent any races.
* remove tg3_halt call from tg3_set_power_state, as all callers
  have already called tg3_halt, making it redundant.  Removing this
  function call also eliminates some locking complications.
* use new helper __netif_rx_complete in tg3_poll
* create tg3_reset_task, as a function that runs in process context
  which resets the NIC.  This is needed because tg3_netif_stop()
  calls schedule() in the process of disabling dev->poll.
* schedule tg3_reset_task from tg3_tx_timeout
* schedule tg3_reset_task from tg3_timer
* wrap several tg3_halt...tg3_init_hw sequences with
  tg3_netif_stop...tg3_netif_start.  In addition to synchronizing
  with dev->poll, this additionally fixes bugs where we were not
  calling netif_wake_queue, when we should have been.
* move netif_start_queue call to very bottom of tg3_open
* add missing tg3_netif_{start,stop} to tg3_{suspend,resume},
  further fixing obvious bugs.
parent 2b7eab5f
......@@ -25,6 +25,7 @@
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/workqueue.h>
#include <asm/system.h>
#include <asm/io.h>
......@@ -228,6 +229,46 @@ static void tg3_enable_ints(struct tg3 *tp)
tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
}
/* these three netif_xxx funcs should be moved into generic net layer */
static void netif_poll_disable(struct net_device *dev)
{
while (test_and_set_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(1);
}
}
static inline void netif_poll_enable(struct net_device *dev)
{
clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
}
/* same as netif_rx_complete, except that local_irq_save(flags)
* has already been issued
*/
static inline void __netif_rx_complete(struct net_device *dev)
{
if (!test_bit(__LINK_STATE_RX_SCHED, &dev->state)) BUG();
list_del(&dev->poll_list);
clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
}
static inline void tg3_netif_stop(struct tg3 *tp)
{
netif_stop_queue(tp->dev);
netif_poll_disable(tp->dev);
}
static inline void tg3_netif_start(struct tg3 *tp)
{
netif_poll_enable(tp->dev);
netif_wake_queue(tp->dev);
/* NOTE: unconditional netif_wake_queue is only appropriate
* so long as all callers are assured to have free tx slots
* (such as after tg3_init_hw)
*/
}
static void tg3_switch_clocks(struct tg3 *tp)
{
if (tr32(TG3PCI_CLOCK_CTRL) & CLOCK_CTRL_44MHZ_CORE) {
......@@ -387,7 +428,6 @@ static int tg3_phy_reset(struct tg3 *tp, int force)
}
static int tg3_setup_phy(struct tg3 *);
static int tg3_halt(struct tg3 *);
static int tg3_set_power_state(struct tg3 *tp, int state)
{
......@@ -458,8 +498,6 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
tg3_setup_phy(tp);
}
tg3_halt(tp);
pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps);
if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) {
......@@ -2044,7 +2082,12 @@ static int tg3_poll(struct net_device *netdev, int *budget)
spin_unlock(&tp->tx_lock);
}
/* run RX thread, within the bounds set by NAPI */
spin_unlock_irqrestore(&tp->lock, flags);
/* run RX thread, within the bounds set by NAPI.
* All RX "locking" is done by ensuring outside
* code synchronizes with dev->poll()
*/
done = 1;
if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
int orig_budget = *budget;
......@@ -2064,11 +2107,11 @@ static int tg3_poll(struct net_device *netdev, int *budget)
/* if no more work, tell net stack and NIC we're done */
if (done) {
netif_rx_complete(netdev);
spin_lock_irqsave(&tp->lock, flags);
__netif_rx_complete(netdev);
tg3_enable_ints(tp);
}
spin_unlock_irqrestore(&tp->lock, flags);
}
return (done ? 0 : 1);
}
......@@ -2136,17 +2179,21 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void tg3_init_rings(struct tg3 *);
static int tg3_init_hw(struct tg3 *);
static int tg3_halt(struct tg3 *);
static void tg3_tx_timeout(struct net_device *dev)
static void tg3_reset_task(void *_data)
{
struct tg3 *tp = dev->priv;
struct tg3 *tp = _data;
unsigned int restart_timer;
printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
dev->name);
tg3_netif_stop(tp);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
tg3_halt(tp);
tg3_init_rings(tp);
tg3_init_hw(tp);
......@@ -2154,7 +2201,20 @@ static void tg3_tx_timeout(struct net_device *dev)
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
netif_wake_queue(dev);
tg3_netif_start(tp);
if (restart_timer)
mod_timer(&tp->timer, jiffies + 1);
}
static void tg3_tx_timeout(struct net_device *dev)
{
struct tg3 *tp = dev->priv;
printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
dev->name);
schedule_work(&tp->reset_task);
}
#if !PCI_DMA_BUS_IS_PHYS
......@@ -2686,6 +2746,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
tg3_netif_stop(tp);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
......@@ -2698,6 +2759,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
tg3_netif_start(tp);
return 0;
}
......@@ -4408,9 +4470,11 @@ static void tg3_timer(unsigned long __opaque)
}
if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
tg3_halt(tp);
tg3_init_rings(tp);
tg3_init_hw(tp);
tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER;
spin_unlock(&tp->tx_lock);
spin_unlock_irqrestore(&tp->lock, flags);
schedule_work(&tp->reset_task);
return;
}
/* This part only runs once per second. */
......@@ -4541,8 +4605,6 @@ static int tg3_open(struct net_device *dev)
return err;
}
netif_start_queue(dev);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
......@@ -4551,6 +4613,8 @@ static int tg3_open(struct net_device *dev)
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
netif_start_queue(dev);
return 0;
}
......@@ -5316,6 +5380,7 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
(ering.tx_pending > TG3_TX_RING_SIZE - 1))
return -EINVAL;
tg3_netif_stop(tp);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
......@@ -5329,6 +5394,7 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
netif_wake_queue(tp->dev);
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
tg3_netif_start(tp);
return 0;
}
......@@ -5351,6 +5417,7 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
if (copy_from_user(&epause, useraddr, sizeof(epause)))
return -EFAULT;
tg3_netif_stop(tp);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
if (epause.autoneg)
......@@ -5370,6 +5437,7 @@ static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
tg3_init_hw(tp);
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
tg3_netif_start(tp);
return 0;
}
......@@ -6724,6 +6792,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
spin_lock_init(&tp->lock);
spin_lock_init(&tp->tx_lock);
spin_lock_init(&tp->indirect_lock);
PREPARE_WORK(&tp->reset_task, tg3_reset_task, tp);
tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
if (tp->regs == 0UL) {
......@@ -6865,6 +6934,8 @@ static int tg3_suspend(struct pci_dev *pdev, u32 state)
if (!netif_running(dev))
return 0;
tg3_netif_stop(tp);
spin_lock_irq(&tp->lock);
spin_lock(&tp->tx_lock);
tg3_disable_ints(tp);
......@@ -6891,6 +6962,7 @@ static int tg3_suspend(struct pci_dev *pdev, u32 state)
spin_unlock_irq(&tp->lock);
netif_device_attach(dev);
tg3_netif_start(tp);
}
return err;
......@@ -6921,6 +6993,8 @@ static int tg3_resume(struct pci_dev *pdev)
spin_unlock(&tp->tx_lock);
spin_unlock_irq(&tp->lock);
tg3_netif_start(tp);
return 0;
}
......
......@@ -1821,6 +1821,8 @@ struct tg3 {
#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
#define TG3_FLAG_SPLIT_MODE 0x40000000
#define TG3_FLAG_INIT_COMPLETE 0x80000000
u32 tg3_flags2;
#define TG3_FLG2_RESTART_TIMER 0x00000001
u32 split_mode_max_reqs;
#define SPLIT_MODE_5704_MAX_REQ 3
......@@ -1889,6 +1891,7 @@ struct tg3 {
struct tg3_hw_stats *hw_stats;
dma_addr_t stats_mapping;
struct work_struct reset_task;
};
#endif /* !(_T3_H) */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment