diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/sky2.c | 25 |
1 files changed, 9 insertions, 16 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 301f8a6f8c08..4944fcc6b076 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1741,8 +1741,12 @@ mapping_error: /* * Free ring elements from starting at tx_cons until "done" * - * NB: the hardware will tell us about partial completion of multi-part + * NB: + * 1. The hardware will tell us about partial completion of multi-part * buffers so make sure not to free skb to early. + * 2. This may run in parallel start_xmit because the it only + * looks at the tail of the queue of FIFO (tx_cons), not + * the head (tx_prod) */ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) { @@ -1800,16 +1804,6 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) netif_wake_queue(dev); } -/* Cleanup all untransmitted buffers, assume transmitter not running */ -static void sky2_tx_clean(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - netif_tx_lock_bh(dev); - sky2_tx_complete(sky2, sky2->tx_prod); - netif_tx_unlock_bh(dev); -} - static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) { /* Disable Force Sync bit and Enable Alloc bit */ @@ -1901,7 +1895,9 @@ static int sky2_down(struct net_device *dev) sky2_tx_reset(hw, port); - sky2_tx_clean(dev); + /* Free any pending frames stuck in HW queue */ + sky2_tx_complete(sky2, sky2->tx_prod); + sky2_rx_clean(sky2); pci_free_consistent(hw->pdev, RX_LE_BYTES, @@ -2378,11 +2374,8 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) { struct sky2_port *sky2 = netdev_priv(dev); - if (likely(netif_running(dev) && !sky2->restarting)) { - netif_tx_lock(dev); + if (likely(netif_running(dev) && !sky2->restarting)) sky2_tx_complete(sky2, last); - netif_tx_unlock(dev); - } } static inline void sky2_skb_rx(const struct sky2_port *sky2, |