Commit 5a14251f authored by Jeb J. Cramer's avatar Jeb J. Cramer Committed by Jeff Garzik

[E1000] Added Tx FIFO flush routine

* Added method to flush Tx FIFO after link disconnect; the hardware
  hangs on to Tx skb's that were in flight prior to link loss
parent 8bf752eb
...@@ -1246,6 +1246,40 @@ e1000_set_multi(struct net_device *netdev) ...@@ -1246,6 +1246,40 @@ e1000_set_multi(struct net_device *netdev)
e1000_leave_82542_rst(adapter); e1000_leave_82542_rst(adapter);
} }
static void
e1000_tx_flush(struct e1000_adapter *adapter)
{
uint32_t ctrl, tctl, txcw, icr;
e1000_irq_disable(adapter);
if(adapter->hw.mac_type < e1000_82543) {
/* Transmit Unit Reset */
tctl = E1000_READ_REG(&adapter->hw, TCTL);
E1000_WRITE_REG(&adapter->hw, TCTL, tctl | E1000_TCTL_RST);
E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
e1000_clean_tx_ring(adapter);
e1000_configure_tx(adapter);
} else {
txcw = E1000_READ_REG(&adapter->hw, TXCW);
E1000_WRITE_REG(&adapter->hw, TXCW, txcw & ~E1000_TXCW_ANE);
ctrl = E1000_READ_REG(&adapter->hw, CTRL);
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl | E1000_CTRL_SLU |
E1000_CTRL_ILOS);
mdelay(10);
e1000_clean_tx_irq(adapter);
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
E1000_WRITE_REG(&adapter->hw, TXCW, txcw);
/* clear the link status change interrupts this caused */
icr = E1000_READ_REG(&adapter->hw, ICR);
}
e1000_irq_enable(adapter);
}
/* need to wait a few seconds after link up to get diagnostic information from the phy */ /* need to wait a few seconds after link up to get diagnostic information from the phy */
...@@ -1348,6 +1382,15 @@ e1000_watchdog(unsigned long data) ...@@ -1348,6 +1382,15 @@ e1000_watchdog(unsigned long data)
e1000_update_stats(adapter); e1000_update_stats(adapter);
e1000_update_adaptive(&adapter->hw); e1000_update_adaptive(&adapter->hw);
if(!netif_carrier_ok(netdev)) {
if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) {
unsigned long flags;
spin_lock_irqsave(&netdev->xmit_lock, flags);
e1000_tx_flush(adapter);
spin_unlock_irqrestore(&netdev->xmit_lock, flags);
}
}
/* Cause software interrupt to ensure rx ring is cleaned */ /* Cause software interrupt to ensure rx ring is cleaned */
E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0); E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0);
......
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