[PATCH] sky2: Avoid transmitting during sky2_restart()
From: Mike McCormack <hidden>
Date: 2009-07-22 12:39:23
Subsystem:
networking drivers, the rest · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Hi Stephen, I've improved this patch a little to stop the transmit queue before starting to return NETDEV_TX_BUSY in sky2_xmit_frame(). If you have any suggestions for how to get rid of the SKY2_HW_RESTARTING state please let me know. As far as I can tell, the queue cannot be stopped during a restart using netif_stop_queue and netif_tx_lock, as those functions are used elsewhere in the code. thanks, Mike --- Block the transmit queue during sky2_restart(). Don't free transmit packets in sky2_status_intr() during restart, as they'll be free'd in sky2_tx_clean() Signed-off-by: Mike McCormack <redacted> --- drivers/net/sky2.c | 19 ++++++++++++++++++- drivers/net/sky2.h | 1 + 2 files changed, 19 insertions(+), 1 deletions(-)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 661abd0..826d764 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c@@ -1533,6 +1533,8 @@ static inline int tx_dist(unsigned tail, unsigned head) /* Number of list elements available for next tx */ static inline int tx_avail(const struct sky2_port *sky2) { + if (unlikely(sky2->hw->flags & SKY2_HW_RESTARTING)) + return 0; return sky2->tx_pending - tx_dist(sky2->tx_cons, sky2->tx_prod); }
@@ -2359,7 +2361,8 @@ static inline void sky2_tx_done(structnet_device *dev, u16 last)
{
struct sky2_port *sky2 = netdev_priv(dev);
- if (netif_running(dev)) {
+ if (netif_running(dev) &&
+ !(sky2->hw->flags & SKY2_HW_RESTARTING)) {
netif_tx_lock(dev);
sky2_tx_complete(sky2, last);
netif_tx_unlock(dev);@@ -3074,6 +3077,17 @@ static void sky2_restart(struct work_struct *work) int i, err; rtnl_lock(); + + /* stop transmit queues */ + napi_disable(&hw->napi); + for (i = 0; i < hw->ports; i++) { + dev = hw->dev[i]; + if (netif_running(dev)) + netif_stop_queue(dev); + } + hw->flags |= SKY2_HW_RESTARTING; + napi_enable (&hw->napi); + for (i = 0; i < hw->ports; i++) { dev = hw->dev[i]; if (netif_running(dev))
@@ -3085,6 +3099,7 @@ static void sky2_restart(struct work_struct *work) sky2_reset(hw); sky2_write32(hw, B0_IMSK, Y2_IS_BASE); napi_enable(&hw->napi); + hw->flags &= ~SKY2_HW_RESTARTING; for (i = 0; i < hw->ports; i++) { dev = hw->dev[i];
@@ -3095,6 +3110,8 @@ static void sky2_restart(struct work_struct *work) dev->name, err); dev_close(dev); } + else + netif_wake_queue(dev); } }
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index b5549c9..e71c161 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h@@ -2073,6 +2073,7 @@ struct sky2_hw { #define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ #define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ #define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ +#define SKY2_HW_RESTARTING 0x00000100 /* true while restarting */ u8 chip_id; u8 chip_rev;
--
1.5.6.5