tg3 shutdown sequence update
Subsystems (2)
PATCH 1/1 tg3 shutdown sequence update
This patch is only for testing and comment, _not_ for applying. (testers requested)
The attached patch updates the tg3 net driver shutdown sequence to be a bit more correct WRT the documented sequence. Detailed changes:
* bail out of tg3_stop_block ASAP if block is already disabled
* use standard tg3_stop_block to disable RX MAC mode. this adds polling of the the enable bit to the standard code.
* just in case, shut down DMA completion between send data completion shutdown and send DB completion shutdown
* use standard tg3_stop_block to disable TX MAC mode.
* don't bother to disable MAC_MODE_TDE_ENABLE bit manually, TX MAC mode disable does it for us.
* add PCI posting flush for flow-through queues
Does this look ok WRT errata and hardware seen in the field?
One potential concern is that the error handling if tg3_stop_block fails runs through all the blocks unconditionally, and then returns an error.
It does not bail early if some of the stop-block calls fail.
Comments?
Jeff
net/tg3.c renamed from net/tg3.c.~1~ +8 -6
@@ -2367,6 +2367,7 @@unsigned int i;u32 len, entry, base_flags, mss;int would_hit_hwbug; +unsigned long flags; len = (skb->len - skb->data_len);
@@ -2389,12 +2390,12 @@* So we really do need to disable interrupts when taking * tx_lock here. */ -spin_lock_irq (&tp->tx_lock); +spin_lock_irqsave (&tp->tx_lock, flags);/* This is a hard error, log it. */ if (unlikely (TX_BUFFS_AVAIL (tp) <= (skb_shinfo (skb)->nr_frags +1 ))) {netif_stop_queue (dev); -spin_unlock_irq (&tp->tx_lock); +spin_unlock_irqrestore (&tp->tx_lock, flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name);return 1 ;
@@ -2535,7 +2536,7 @@netif_stop_queue (dev); out_unlock: -spin_unlock_irq (&tp->tx_lock); +spin_unlock_irqrestore (&tp->tx_lock, flags); dev->trans_start = jiffies;
@@ -2547,6 +2548,7 @@struct tg3 *tp = dev->priv;dma_addr_t mapping;u32 len, entry, base_flags, mss; +unsigned long flags; len = (skb->len - skb->data_len);
@@ -2569,12 +2571,12 @@* So we really do need to disable interrupts when taking * tx_lock here. */ -spin_lock_irq (&tp->tx_lock); +spin_lock_irqsave (&tp->tx_lock, flags);/* This is a hard error, log it. */ if (unlikely (TX_BUFFS_AVAIL (tp) <= (skb_shinfo (skb)->nr_frags +1 ))) {netif_stop_queue (dev); -spin_unlock_irq (&tp->tx_lock); +spin_unlock_irqrestore (&tp->tx_lock, flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name);return 1 ;
@@ -2665,7 +2667,7 @@if (TX_BUFFS_AVAIL (tp) <= (MAX_SKB_FRAGS +1 ))netif_stop_queue (dev); -spin_unlock_irq (&tp->tx_lock); +spin_unlock_irqrestore (&tp->tx_lock, flags); dev->trans_start = jiffies;
Jeff you're posting the "spin_lock_irqsave(tx_lock)" patch not the one you intended...
Doh! Wrong patch posted... sorry folks...
PATCH 1/1 tg3 shutdown sequence update (try 2)
In reply to Jeff GarzikRe-sending correct patch :)
===== drivers/net/tg3.c 1.41 vs 1.43 =====
drivers/net/tg3.c +11 -31
@@ -3088,6 +3088,9 @@u32 val; val =tr32 (ofs); +if ((val & enable_bit) ==0 ) +return 0 ; + val &= ~enable_bit;tw32 (ofs, val);tr32 (ofs);
@@ -3112,16 +3115,12 @@/* tp->lock is held. */ static int tg3_abort_hw (struct tg3 *tp) { -int i, err; +int err;tg3_disable_ints (tp); - tp->rx_mode &= ~RX_MODE_ENABLE ; -tw32 (MAC_RX_MODE , tp->rx_mode); -tr32 (MAC_RX_MODE ); -udelay (10 ); - - err =tg3_stop_block (tp,RCVBDI_MODE ,RCVBDI_MODE_ENABLE ); + err =tg3_stop_block (tp,MAC_RX_MODE ,RX_MODE_ENABLE ); + err |=tg3_stop_block (tp,RCVBDI_MODE ,RCVBDI_MODE_ENABLE ); err |=tg3_stop_block (tp,RCVLPC_MODE ,RCVLPC_MODE_ENABLE ); err |=tg3_stop_block (tp,RCVLSC_MODE ,RCVLSC_MODE_ENABLE ); err |=tg3_stop_block (tp,RCVDBDI_MODE ,RCVDBDI_MODE_ENABLE );
@@ -3133,40 +3132,21 @@ err |=tg3_stop_block (tp,SNDDATAI_MODE ,SNDDATAI_MODE_ENABLE ); err |=tg3_stop_block (tp,RDMAC_MODE ,RDMAC_MODE_ENABLE ); err |=tg3_stop_block (tp,SNDDATAC_MODE ,SNDDATAC_MODE_ENABLE ); + err |=tg3_stop_block (tp,DMAC_MODE ,DMAC_MODE_ENABLE ); err |=tg3_stop_block (tp,SNDBDC_MODE ,SNDBDC_MODE_ENABLE ); -if (err) - goto out; - - tp->mac_mode &= ~MAC_MODE_TDE_ENABLE ; -tw32 (MAC_MODE , tp->mac_mode); -tr32 (MAC_MODE ); -udelay (40 ); - - tp->tx_mode &= ~TX_MODE_ENABLE ; -tw32 (MAC_TX_MODE , tp->tx_mode); -tr32 (MAC_TX_MODE ); + err |=tg3_stop_block (tp,MAC_TX_MODE ,TX_MODE_ENABLE ); -for (i =0 ; i <MAX_WAIT_CNT ; i++) { -udelay (100 ); -if (!(tr32 (MAC_TX_MODE ) &TX_MODE_ENABLE )) -break ; - } -if (i >=MAX_WAIT_CNT ) { - printk(KERN_ERR PFX "tg3_abort_hw timed out for %s, " -"TX_MODE_ENABLE will not clear MAC_TX_MODE=%08x\n" , - tp->dev->name, tr32(MAC_TX_MODE)); -return -ENODEV ; - } - - err =tg3_stop_block (tp,HOSTCC_MODE ,HOSTCC_MODE_ENABLE ); + err |=tg3_stop_block (tp,HOSTCC_MODE ,HOSTCC_MODE_ENABLE ); err |=tg3_stop_block (tp,WDMAC_MODE ,WDMAC_MODE_ENABLE ); err |=tg3_stop_block (tp,MBFREE_MODE ,MBFREE_MODE_ENABLE );tw32 (FTQ_RESET ,0xffffffff );tw32 (FTQ_RESET ,0x00000000 ); +tr32 (FTQ_RESET ); err |=tg3_stop_block (tp,BUFMGR_MODE ,BUFMGR_MODE_ENABLE ); err |=tg3_stop_block (tp,MEMARB_MODE ,MEMARB_MODE_ENABLE ); +if (err) goto out;