r8152: disable the tasklet by default
[cascardo/linux.git] / drivers / net / usb / r8152.c
index e3d84c3..fd41675 100644 (file)
@@ -486,7 +486,7 @@ struct tally_counter {
        __le64  rx_broadcast;
        __le32  rx_multicast;
        __le16  tx_aborted;
-       __le16  tx_underun;
+       __le16  tx_underrun;
 };
 
 struct rx_desc {
@@ -690,6 +690,9 @@ static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
                }
        }
 
+       if (ret == -ENODEV)
+               set_bit(RTL8152_UNPLUG, &tp->flags);
+
        return ret;
 }
 
@@ -757,6 +760,9 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
        }
 
 error1:
+       if (ret == -ENODEV)
+               set_bit(RTL8152_UNPLUG, &tp->flags);
+
        return ret;
 }
 
@@ -1083,6 +1089,7 @@ static void read_bulk_callback(struct urb *urb)
 
        result = r8152_submit_rx(tp, agg, GFP_ATOMIC);
        if (result == -ENODEV) {
+               set_bit(RTL8152_UNPLUG, &tp->flags);
                netif_device_detach(tp->netdev);
        } else if (result) {
                spin_lock(&tp->rx_lock);
@@ -1162,6 +1169,9 @@ static void intr_callback(struct urb *urb)
        case -ESHUTDOWN:
                netif_device_detach(tp->netdev);
        case -ENOENT:
+       case -EPROTO:
+               netif_info(tp, intr, tp->netdev,
+                          "Stop submitting intr, status %d\n", status);
                return;
        case -EOVERFLOW:
                netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n");
@@ -1187,11 +1197,13 @@ static void intr_callback(struct urb *urb)
 
 resubmit:
        res = usb_submit_urb(urb, GFP_ATOMIC);
-       if (res == -ENODEV)
+       if (res == -ENODEV) {
+               set_bit(RTL8152_UNPLUG, &tp->flags);
                netif_device_detach(tp->netdev);
-       else if (res)
+       } else if (res) {
                netif_err(tp, intr, tp->netdev,
                          "can't resubmit intr, status %d\n", res);
+       }
 }
 
 static inline void *rx_agg_align(void *data)
@@ -1755,6 +1767,7 @@ static void tx_bottom(struct r8152 *tp)
                        struct net_device *netdev = tp->netdev;
 
                        if (res == -ENODEV) {
+                               set_bit(RTL8152_UNPLUG, &tp->flags);
                                netif_device_detach(netdev);
                        } else {
                                struct net_device_stats *stats = &netdev->stats;
@@ -2891,6 +2904,9 @@ static int rtl8152_open(struct net_device *netdev)
        if (res)
                goto out;
 
+       /* set speed to 0 to avoid autoresume try to submit rx */
+       tp->speed = 0;
+
        res = usb_autopm_get_interface(tp->intf);
        if (res < 0) {
                free_all_mem(tp);
@@ -2904,6 +2920,8 @@ static int rtl8152_open(struct net_device *netdev)
                clear_bit(WORK_ENABLE, &tp->flags);
                usb_kill_urb(tp->intr_urb);
                cancel_delayed_work_sync(&tp->schedule);
+
+               /* disable the tx/rx, if the workqueue has enabled them. */
                if (tp->speed & LINK_STATUS)
                        tp->rtl_ops.disable(tp);
        }
@@ -2925,6 +2943,8 @@ static int rtl8152_open(struct net_device *netdev)
                netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
                           res);
                free_all_mem(tp);
+       } else {
+               tasklet_enable(&tp->tl);
        }
 
        mutex_unlock(&tp->control);
@@ -2940,6 +2960,7 @@ static int rtl8152_close(struct net_device *netdev)
        struct r8152 *tp = netdev_priv(netdev);
        int res = 0;
 
+       tasklet_disable(&tp->tl);
        clear_bit(WORK_ENABLE, &tp->flags);
        usb_kill_urb(tp->intr_urb);
        cancel_delayed_work_sync(&tp->schedule);
@@ -2955,14 +2976,9 @@ static int rtl8152_close(struct net_device *netdev)
                 * be disable when autoresume occurs, because the
                 * netif_running() would be false.
                 */
-               if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
-                       rtl_runtime_suspend_enable(tp, false);
-                       clear_bit(SELECTIVE_SUSPEND, &tp->flags);
-               }
+               rtl_runtime_suspend_enable(tp, false);
 
-               tasklet_disable(&tp->tl);
                tp->rtl_ops.down(tp);
-               tasklet_enable(&tp->tl);
 
                mutex_unlock(&tp->control);
 
@@ -3205,7 +3221,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
                netif_device_detach(netdev);
        }
 
-       if (netif_running(netdev)) {
+       if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
                clear_bit(WORK_ENABLE, &tp->flags);
                usb_kill_urb(tp->intr_urb);
                tasklet_disable(&tp->tl);
@@ -3253,6 +3269,8 @@ static int rtl8152_resume(struct usb_interface *intf)
                        set_bit(WORK_ENABLE, &tp->flags);
                }
                usb_submit_urb(tp->intr_urb, GFP_KERNEL);
+       } else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+               clear_bit(SELECTIVE_SUSPEND, &tp->flags);
        }
 
        mutex_unlock(&tp->control);
@@ -3420,7 +3438,7 @@ static void rtl8152_get_ethtool_stats(struct net_device *dev,
        data[9] = le64_to_cpu(tally.rx_broadcast);
        data[10] = le32_to_cpu(tally.rx_multicast);
        data[11] = le16_to_cpu(tally.tx_aborted);
-       data[12] = le16_to_cpu(tally.tx_underun);
+       data[12] = le16_to_cpu(tally.tx_underrun);
 }
 
 static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -3558,11 +3576,33 @@ out:
        return ret;
 }
 
+static int rtl8152_nway_reset(struct net_device *dev)
+{
+       struct r8152 *tp = netdev_priv(dev);
+       int ret;
+
+       ret = usb_autopm_get_interface(tp->intf);
+       if (ret < 0)
+               goto out;
+
+       mutex_lock(&tp->control);
+
+       ret = mii_nway_restart(&tp->mii);
+
+       mutex_unlock(&tp->control);
+
+       usb_autopm_put_interface(tp->intf);
+
+out:
+       return ret;
+}
+
 static struct ethtool_ops ops = {
        .get_drvinfo = rtl8152_get_drvinfo,
        .get_settings = rtl8152_get_settings,
        .set_settings = rtl8152_set_settings,
        .get_link = ethtool_op_get_link,
+       .nway_reset = rtl8152_nway_reset,
        .get_msglevel = rtl8152_get_msglevel,
        .set_msglevel = rtl8152_set_msglevel,
        .get_wol = rtl8152_get_wol,
@@ -3848,12 +3888,15 @@ static int rtl8152_probe(struct usb_interface *intf,
        else
                device_set_wakeup_enable(&udev->dev, false);
 
+       tasklet_disable(&tp->tl);
+
        netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
 
        return 0;
 
 out1:
        usb_set_intfdata(intf, NULL);
+       tasklet_kill(&tp->tl);
 out:
        free_netdev(netdev);
        return ret;