Merge tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[deliverable/linux.git] / drivers / net / usb / r8152.c
index e9654a6853818933334488c28a98dbb3073a84cf..f41a8ad4740e28ee36d046804b2e987c65805935 100644 (file)
@@ -613,7 +613,7 @@ struct r8152 {
        struct list_head rx_done, tx_free;
        struct sk_buff_head tx_queue, rx_queue;
        spinlock_t rx_lock, tx_lock;
-       struct delayed_work schedule;
+       struct delayed_work schedule, hw_phy_work;
        struct mii_if_info mii;
        struct mutex control;   /* use for hw setting */
 #ifdef CONFIG_PM_SLEEP
@@ -630,6 +630,7 @@ struct r8152 {
                int (*eee_get)(struct r8152 *, struct ethtool_eee *);
                int (*eee_set)(struct r8152 *, struct ethtool_eee *);
                bool (*in_nway)(struct r8152 *);
+               void (*hw_phy_cfg)(struct r8152 *);
                void (*autosuspend_en)(struct r8152 *tp, bool enable);
        } rtl_ops;
 
@@ -639,8 +640,11 @@ struct r8152 {
        u32 tx_qlen;
        u32 coalesce;
        u16 ocp_base;
+       u16 speed;
        u8 *intr_buff;
        u8 version;
+       u8 duplex;
+       u8 autoneg;
 };
 
 enum rtl_version {
@@ -1820,7 +1824,7 @@ static int rx_bottom(struct r8152 *tp, int budget)
                        pkt_len -= CRC_SIZE;
                        rx_data += sizeof(struct rx_desc);
 
-                       skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
+                       skb = napi_alloc_skb(&tp->napi, pkt_len);
                        if (!skb) {
                                stats->rx_dropped++;
                                goto find_next_rx;
@@ -2512,27 +2516,6 @@ static void rtl8153_runtime_enable(struct r8152 *tp, bool enable)
        }
 }
 
-static void rtl_phy_reset(struct r8152 *tp)
-{
-       u16 data;
-       int i;
-
-       data = r8152_mdio_read(tp, MII_BMCR);
-
-       /* don't reset again before the previous one complete */
-       if (data & BMCR_RESET)
-               return;
-
-       data |= BMCR_RESET;
-       r8152_mdio_write(tp, MII_BMCR, data);
-
-       for (i = 0; i < 50; i++) {
-               msleep(20);
-               if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
-                       break;
-       }
-}
-
 static void r8153_teredo_off(struct r8152 *tp)
 {
        u32 ocp_data;
@@ -2600,8 +2583,6 @@ static void r8152b_exit_oob(struct r8152 *tp)
 
        rxdy_gated_en(tp, true);
        r8153_teredo_off(tp);
-       r8152b_hw_phy_cfg(tp);
-
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
 
@@ -2779,8 +2760,6 @@ static void r8153_first_init(struct r8152 *tp)
        ocp_data &= ~RCR_ACPT_ALL;
        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
 
-       r8153_hw_phy_cfg(tp);
-
        rtl8152_nic_reset(tp);
        rtl_reset_bmu(tp);
 
@@ -2916,7 +2895,6 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
        u16 bmcr, anar, gbcr;
        int ret = 0;
 
-       cancel_delayed_work_sync(&tp->schedule);
        anar = r8152_mdio_read(tp, MII_ADVERTISE);
        anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
                  ADVERTISE_100HALF | ADVERTISE_100FULL);
@@ -2976,7 +2954,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
                bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
        }
 
-       if (test_bit(PHY_RESET, &tp->flags))
+       if (test_and_clear_bit(PHY_RESET, &tp->flags))
                bmcr |= BMCR_RESET;
 
        if (tp->mii.supports_gmii)
@@ -2985,7 +2963,7 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
        r8152_mdio_write(tp, MII_ADVERTISE, anar);
        r8152_mdio_write(tp, MII_BMCR, bmcr);
 
-       if (test_and_clear_bit(PHY_RESET, &tp->flags)) {
+       if (bmcr & BMCR_RESET) {
                int i;
 
                for (i = 0; i < 50; i++) {
@@ -3135,15 +3113,33 @@ static void rtl_work_func_t(struct work_struct *work)
            netif_carrier_ok(tp->netdev))
                napi_schedule(&tp->napi);
 
-       if (test_and_clear_bit(PHY_RESET, &tp->flags))
-               rtl_phy_reset(tp);
-
        mutex_unlock(&tp->control);
 
 out1:
        usb_autopm_put_interface(tp->intf);
 }
 
+static void rtl_hw_phy_work_func_t(struct work_struct *work)
+{
+       struct r8152 *tp = container_of(work, struct r8152, hw_phy_work.work);
+
+       if (test_bit(RTL8152_UNPLUG, &tp->flags))
+               return;
+
+       if (usb_autopm_get_interface(tp->intf) < 0)
+               return;
+
+       mutex_lock(&tp->control);
+
+       tp->rtl_ops.hw_phy_cfg(tp);
+
+       rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex);
+
+       mutex_unlock(&tp->control);
+
+       usb_autopm_put_interface(tp->intf);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int rtl_notifier(struct notifier_block *nb, unsigned long action,
                        void *data)
@@ -3180,8 +3176,6 @@ static int rtl8152_open(struct net_device *netdev)
        if (res)
                goto out;
 
-       netif_carrier_off(netdev);
-
        res = usb_autopm_get_interface(tp->intf);
        if (res < 0) {
                free_all_mem(tp);
@@ -3192,9 +3186,6 @@ static int rtl8152_open(struct net_device *netdev)
 
        tp->rtl_ops.up(tp);
 
-       rtl8152_set_speed(tp, AUTONEG_ENABLE,
-                         tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
-                         DUPLEX_FULL);
        netif_carrier_off(netdev);
        netif_start_queue(netdev);
        set_bit(WORK_ENABLE, &tp->flags);
@@ -3618,6 +3609,7 @@ static int rtl8152_resume(struct usb_interface *intf)
 
        if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
                tp->rtl_ops.init(tp);
+               queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
                netif_device_attach(tp->netdev);
        }
 
@@ -3632,10 +3624,6 @@ static int rtl8152_resume(struct usb_interface *intf)
                        napi_enable(&tp->napi);
                } else {
                        tp->rtl_ops.up(tp);
-                       rtl8152_set_speed(tp, AUTONEG_ENABLE,
-                                         tp->mii.supports_gmii ?
-                                         SPEED_1000 : SPEED_100,
-                                         DUPLEX_FULL);
                        netif_carrier_off(tp->netdev);
                        set_bit(WORK_ENABLE, &tp->flags);
                }
@@ -3765,6 +3753,11 @@ static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        mutex_lock(&tp->control);
 
        ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
+       if (!ret) {
+               tp->autoneg = cmd->autoneg;
+               tp->speed = cmd->speed;
+               tp->duplex = cmd->duplex;
+       }
 
        mutex_unlock(&tp->control);
 
@@ -4222,6 +4215,7 @@ static int rtl_ops_init(struct r8152 *tp)
                ops->eee_get            = r8152_get_eee;
                ops->eee_set            = r8152_set_eee;
                ops->in_nway            = rtl8152_in_nway;
+               ops->hw_phy_cfg         = r8152b_hw_phy_cfg;
                ops->autosuspend_en     = rtl_runtime_suspend_enable;
                break;
 
@@ -4238,6 +4232,7 @@ static int rtl_ops_init(struct r8152 *tp)
                ops->eee_get            = r8153_get_eee;
                ops->eee_set            = r8153_set_eee;
                ops->in_nway            = rtl8153_in_nway;
+               ops->hw_phy_cfg         = r8153_hw_phy_cfg;
                ops->autosuspend_en     = rtl8153_runtime_enable;
                break;
 
@@ -4285,6 +4280,7 @@ static int rtl8152_probe(struct usb_interface *intf,
 
        mutex_init(&tp->control);
        INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
+       INIT_DELAYED_WORK(&tp->hw_phy_work, rtl_hw_phy_work_func_t);
 
        netdev->netdev_ops = &rtl8152_netdev_ops;
        netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
@@ -4324,9 +4320,14 @@ static int rtl8152_probe(struct usb_interface *intf,
                break;
        }
 
+       tp->autoneg = AUTONEG_ENABLE;
+       tp->speed = tp->mii.supports_gmii ? SPEED_1000 : SPEED_100;
+       tp->duplex = DUPLEX_FULL;
+
        intf->needs_remote_wakeup = 1;
 
        tp->rtl_ops.init(tp);
+       queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0);
        set_ethernet_addr(tp);
 
        usb_set_intfdata(intf, tp);
@@ -4372,6 +4373,7 @@ static void rtl8152_disconnect(struct usb_interface *intf)
 
                netif_napi_del(&tp->napi);
                unregister_netdev(tp->netdev);
+               cancel_delayed_work_sync(&tp->hw_phy_work);
                tp->rtl_ops.unload(tp);
                free_netdev(tp->netdev);
        }
This page took 0.03024 seconds and 5 git commands to generate.