[TG3]: Add tg3_restart_hw()
authorMichael Chan <mchan@broadcom.com>
Tue, 25 Jul 2006 23:37:27 +0000 (16:37 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 25 Jul 2006 23:37:27 +0000 (16:37 -0700)
Add tg3_restart_hw() to handle failures when re-initializing the
device.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/tg3.c

index ce6f3be86da00b77e363d426eb7562c962c35121..1253cec6ebdce43412f2109e757baf4c310863be 100644 (file)
@@ -3590,6 +3590,28 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
 static int tg3_init_hw(struct tg3 *, int);
 static int tg3_halt(struct tg3 *, int, int);
 
+/* Restart hardware after configuration changes, self-test, etc.
+ * Invoked with tp->lock held.
+ */
+static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+{
+       int err;
+
+       err = tg3_init_hw(tp, reset_phy);
+       if (err) {
+               printk(KERN_ERR PFX "%s: Failed to re-initialize device, "
+                      "aborting.\n", tp->dev->name);
+               tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+               tg3_full_unlock(tp);
+               del_timer_sync(&tp->timer);
+               tp->irq_sync = 0;
+               netif_poll_enable(tp->dev);
+               dev_close(tp->dev);
+               tg3_full_lock(tp, 0);
+       }
+       return err;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void tg3_poll_controller(struct net_device *dev)
 {
@@ -3630,13 +3652,15 @@ static void tg3_reset_task(void *_data)
        }
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
-       tg3_init_hw(tp, 1);
+       if (tg3_init_hw(tp, 1))
+               goto out;
 
        tg3_netif_start(tp);
 
        if (restart_timer)
                mod_timer(&tp->timer, jiffies + 1);
 
+out:
        tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
 
        tg3_full_unlock(tp);
@@ -4124,6 +4148,7 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
 static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct tg3 *tp = netdev_priv(dev);
+       int err;
 
        if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
                return -EINVAL;
@@ -4144,13 +4169,14 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 
        tg3_set_mtu(dev, tp, new_mtu);
 
-       tg3_init_hw(tp, 0);
+       err = tg3_restart_hw(tp, 0);
 
-       tg3_netif_start(tp);
+       if (!err)
+               tg3_netif_start(tp);
 
        tg3_full_unlock(tp);
 
-       return 0;
+       return err;
 }
 
 /* Free up pending packets in all rx/tx rings.
@@ -5815,6 +5841,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
 {
        struct tg3 *tp = netdev_priv(dev);
        struct sockaddr *addr = p;
+       int err = 0;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EINVAL;
@@ -5832,9 +5859,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
                tg3_full_lock(tp, 1);
 
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               tg3_init_hw(tp, 0);
-
-               tg3_netif_start(tp);
+               err = tg3_restart_hw(tp, 0);
+               if (!err)
+                       tg3_netif_start(tp);
                tg3_full_unlock(tp);
        } else {
                spin_lock_bh(&tp->lock);
@@ -5842,7 +5869,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
                spin_unlock_bh(&tp->lock);
        }
 
-       return 0;
+       return err;
 }
 
 /* tp->lock is held. */
@@ -7956,7 +7983,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
 static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
        struct tg3 *tp = netdev_priv(dev);
-       int irq_sync = 0;
+       int irq_sync = 0, err = 0;
   
        if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
            (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
@@ -7980,13 +8007,14 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
 
        if (netif_running(dev)) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               tg3_init_hw(tp, 1);
-               tg3_netif_start(tp);
+               err = tg3_restart_hw(tp, 1);
+               if (!err)
+                       tg3_netif_start(tp);
        }
 
        tg3_full_unlock(tp);
   
-       return 0;
+       return err;
 }
   
 static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
@@ -8001,7 +8029,7 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
        struct tg3 *tp = netdev_priv(dev);
-       int irq_sync = 0;
+       int irq_sync = 0, err = 0;
   
        if (netif_running(dev)) {
                tg3_netif_stop(tp);
@@ -8025,13 +8053,14 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 
        if (netif_running(dev)) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               tg3_init_hw(tp, 1);
-               tg3_netif_start(tp);
+               err = tg3_restart_hw(tp, 1);
+               if (!err)
+                       tg3_netif_start(tp);
        }
 
        tg3_full_unlock(tp);
   
-       return 0;
+       return err;
 }
   
 static u32 tg3_get_rx_csum(struct net_device *dev)
@@ -8666,7 +8695,9 @@ static int tg3_test_loopback(struct tg3 *tp)
        if (!netif_running(tp->dev))
                return TG3_LOOPBACK_FAILED;
 
-       tg3_reset_hw(tp, 1);
+       err = tg3_reset_hw(tp, 1);
+       if (err)
+               return TG3_LOOPBACK_FAILED;
 
        if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
                err |= TG3_MAC_LOOPBACK_FAILED;
@@ -8740,8 +8771,8 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                if (netif_running(dev)) {
                        tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-                       tg3_init_hw(tp, 1);
-                       tg3_netif_start(tp);
+                       if (!tg3_restart_hw(tp, 1))
+                               tg3_netif_start(tp);
                }
 
                tg3_full_unlock(tp);
@@ -11699,7 +11730,8 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
                tg3_full_lock(tp, 0);
 
                tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-               tg3_init_hw(tp, 1);
+               if (tg3_restart_hw(tp, 1))
+                       goto out;
 
                tp->timer.expires = jiffies + tp->timer_offset;
                add_timer(&tp->timer);
@@ -11707,6 +11739,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
                netif_device_attach(dev);
                tg3_netif_start(tp);
 
+out:
                tg3_full_unlock(tp);
        }
 
@@ -11733,16 +11766,19 @@ static int tg3_resume(struct pci_dev *pdev)
        tg3_full_lock(tp, 0);
 
        tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-       tg3_init_hw(tp, 1);
+       err = tg3_restart_hw(tp, 1);
+       if (err)
+               goto out;
 
        tp->timer.expires = jiffies + tp->timer_offset;
        add_timer(&tp->timer);
 
        tg3_netif_start(tp);
 
+out:
        tg3_full_unlock(tp);
 
-       return 0;
+       return err;
 }
 
 static struct pci_driver tg3_driver = {