diff options
Diffstat (limited to 'drivers/net/usb/r8152.c')
-rw-r--r-- | drivers/net/usb/r8152.c | 207 |
1 files changed, 134 insertions, 73 deletions
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 986243c932cc..ddc62cb69be8 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -32,7 +32,7 @@ #define NETNEXT_VERSION "08" /* Information for net */ -#define NET_VERSION "8" +#define NET_VERSION "9" #define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" @@ -501,6 +501,8 @@ enum rtl_register_content { #define RTL8153_RMS RTL8153_MAX_PACKET #define RTL8152_TX_TIMEOUT (5 * HZ) #define RTL8152_NAPI_WEIGHT 64 +#define rx_reserved_size(x) ((x) + VLAN_ETH_HLEN + CRC_SIZE + \ + sizeof(struct rx_desc) + RX_ALIGN) /* rtl8152 flags */ enum rtl8152_flags { @@ -515,6 +517,7 @@ enum rtl8152_flags { /* Define these values to match your device */ #define VENDOR_ID_REALTEK 0x0bda +#define VENDOR_ID_MICROSOFT 0x045e #define VENDOR_ID_SAMSUNG 0x04e8 #define VENDOR_ID_LENOVO 0x17ef #define VENDOR_ID_NVIDIA 0x0955 @@ -1292,6 +1295,7 @@ static void intr_callback(struct urb *urb) } } else { if (netif_carrier_ok(tp->netdev)) { + netif_stop_queue(tp->netdev); set_bit(RTL8152_LINK_CHG, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } @@ -1362,6 +1366,7 @@ static int alloc_all_mem(struct r8152 *tp) spin_lock_init(&tp->rx_lock); spin_lock_init(&tp->tx_lock); INIT_LIST_HEAD(&tp->tx_free); + INIT_LIST_HEAD(&tp->rx_done); skb_queue_head_init(&tp->tx_queue); skb_queue_head_init(&tp->rx_queue); @@ -1761,6 +1766,7 @@ static int rx_bottom(struct r8152 *tp, int budget) unsigned long flags; struct list_head *cursor, *next, rx_queue; int ret = 0, work_done = 0; + struct napi_struct *napi = &tp->napi; if (!skb_queue_empty(&tp->rx_queue)) { while (work_done < budget) { @@ -1773,7 +1779,7 @@ static int rx_bottom(struct r8152 *tp, int budget) break; pkt_len = skb->len; - napi_gro_receive(&tp->napi, skb); + napi_gro_receive(napi, skb); work_done++; stats->rx_packets++; stats->rx_bytes += pkt_len; @@ -1823,7 +1829,7 @@ static int rx_bottom(struct r8152 *tp, int budget) pkt_len -= CRC_SIZE; rx_data += sizeof(struct rx_desc); - skb = napi_alloc_skb(&tp->napi, pkt_len); + skb = napi_alloc_skb(napi, pkt_len); if (!skb) { stats->rx_dropped++; goto find_next_rx; @@ -1835,7 +1841,7 @@ static int rx_bottom(struct r8152 *tp, int budget) skb->protocol = eth_type_trans(skb, netdev); rtl_rx_vlan_tag(rx_desc, skb); if (work_done < budget) { - napi_gro_receive(&tp->napi, skb); + napi_gro_receive(napi, skb); work_done++; stats->rx_packets++; stats->rx_bytes += pkt_len; @@ -2252,8 +2258,7 @@ static void r8153_set_rx_early_timeout(struct r8152 *tp) static void r8153_set_rx_early_size(struct r8152 *tp) { - u32 mtu = tp->netdev->mtu; - u32 ocp_data = (agg_buf_sz - mtu - VLAN_ETH_HLEN - VLAN_HLEN) / 8; + u32 ocp_data = (agg_buf_sz - rx_reserved_size(tp->netdev->mtu)) / 4; ocp_write_word(tp, MCU_TYPE_USB, USB_RX_EARLY_SIZE, ocp_data); } @@ -2898,7 +2903,8 @@ static void r8153_first_init(struct r8152 *tp) rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); + ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + CRC_SIZE; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); @@ -2950,7 +2956,8 @@ static void r8153_enter_oob(struct r8152 *tp) usleep_range(1000, 2000); } - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); + ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + CRC_SIZE; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); ocp_data &= ~TEREDO_WAKE_MASK; @@ -3150,6 +3157,7 @@ static bool rtl8153_in_nway(struct r8152 *tp) static void set_carrier(struct r8152 *tp) { struct net_device *netdev = tp->netdev; + struct napi_struct *napi = &tp->napi; u8 speed; speed = rtl8152_get_speed(tp); @@ -3159,19 +3167,22 @@ static void set_carrier(struct r8152 *tp) tp->rtl_ops.enable(tp); set_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_stop_queue(netdev); - napi_disable(&tp->napi); + napi_disable(napi); netif_carrier_on(netdev); rtl_start_rx(tp); napi_enable(&tp->napi); netif_wake_queue(netdev); netif_info(tp, link, netdev, "carrier on\n"); + } else if (netif_queue_stopped(netdev) && + skb_queue_len(&tp->tx_queue) < tp->tx_qlen) { + netif_wake_queue(netdev); } } else { if (netif_carrier_ok(netdev)) { netif_carrier_off(netdev); - napi_disable(&tp->napi); + napi_disable(napi); tp->rtl_ops.disable(tp); - napi_enable(&tp->napi); + napi_enable(napi); netif_info(tp, link, netdev, "carrier off\n"); } } @@ -3633,11 +3644,13 @@ static int rtl8152_runtime_suspend(struct r8152 *tp) tp->rtl_ops.autosuspend_en(tp, true); if (netif_carrier_ok(netdev)) { - napi_disable(&tp->napi); + struct napi_struct *napi = &tp->napi; + + napi_disable(napi); rtl_stop_rx(tp); rxdy_gated_en(tp, false); ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr); - napi_enable(&tp->napi); + napi_enable(napi); } } @@ -3653,12 +3666,14 @@ static int rtl8152_system_suspend(struct r8152 *tp) netif_device_detach(netdev); if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { + struct napi_struct *napi = &tp->napi; + clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); - napi_disable(&tp->napi); + napi_disable(napi); cancel_delayed_work_sync(&tp->schedule); tp->rtl_ops.down(tp); - napi_enable(&tp->napi); + napi_enable(napi); } return ret; @@ -3684,35 +3699,46 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) static int rtl8152_resume(struct usb_interface *intf) { struct r8152 *tp = usb_get_intfdata(intf); + struct net_device *netdev = tp->netdev; mutex_lock(&tp->control); 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); + netif_device_attach(netdev); } - if (netif_running(tp->netdev) && tp->netdev->flags & IFF_UP) { + if (netif_running(netdev) && netdev->flags & IFF_UP) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + struct napi_struct *napi = &tp->napi; + tp->rtl_ops.autosuspend_en(tp, false); - napi_disable(&tp->napi); + napi_disable(napi); set_bit(WORK_ENABLE, &tp->flags); - if (netif_carrier_ok(tp->netdev)) - rtl_start_rx(tp); - napi_enable(&tp->napi); + if (netif_carrier_ok(netdev)) { + if (rtl8152_get_speed(tp) & LINK_STATUS) { + rtl_start_rx(tp); + } else { + netif_carrier_off(netdev); + tp->rtl_ops.disable(tp); + netif_info(tp, link, netdev, + "linking down\n"); + } + } + napi_enable(napi); clear_bit(SELECTIVE_SUSPEND, &tp->flags); smp_mb__after_atomic(); if (!list_empty(&tp->rx_done)) napi_schedule(&tp->napi); } else { tp->rtl_ops.up(tp); - netif_carrier_off(tp->netdev); + netif_carrier_off(netdev); set_bit(WORK_ENABLE, &tp->flags); } usb_submit_urb(tp->intr_urb, GFP_KERNEL); } else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - if (tp->netdev->flags & IFF_UP) + if (netdev->flags & IFF_UP) tp->rtl_ops.autosuspend_en(tp, false); clear_bit(SELECTIVE_SUSPEND, &tp->flags); } @@ -3800,7 +3826,8 @@ static void rtl8152_get_drvinfo(struct net_device *netdev, } static -int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +int rtl8152_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) { struct r8152 *tp = netdev_priv(netdev); int ret; @@ -3814,7 +3841,7 @@ int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) mutex_lock(&tp->control); - ret = mii_ethtool_gset(&tp->mii, cmd); + ret = mii_ethtool_get_link_ksettings(&tp->mii, cmd); mutex_unlock(&tp->control); @@ -3824,7 +3851,8 @@ out: return ret; } -static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int rtl8152_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct r8152 *tp = netdev_priv(dev); int ret; @@ -3835,11 +3863,12 @@ 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); + ret = rtl8152_set_speed(tp, cmd->base.autoneg, cmd->base.speed, + cmd->base.duplex); if (!ret) { - tp->autoneg = cmd->autoneg; - tp->speed = cmd->speed; - tp->duplex = cmd->duplex; + tp->autoneg = cmd->base.autoneg; + tp->speed = cmd->base.speed; + tp->duplex = cmd->base.duplex; } mutex_unlock(&tp->control); @@ -4117,8 +4146,6 @@ static int rtl8152_set_coalesce(struct net_device *netdev, static const 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, @@ -4132,6 +4159,8 @@ static const struct ethtool_ops ops = { .set_coalesce = rtl8152_set_coalesce, .get_eee = rtl_ethtool_get_eee, .set_eee = rtl_ethtool_set_eee, + .get_link_ksettings = rtl8152_get_link_ksettings, + .set_link_ksettings = rtl8152_set_link_ksettings, }; static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -4200,8 +4229,14 @@ static int rtl8152_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; - if (netif_running(dev) && netif_carrier_ok(dev)) - r8153_set_rx_early_size(tp); + if (netif_running(dev)) { + u32 rms = new_mtu + VLAN_ETH_HLEN + CRC_SIZE; + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, rms); + + if (netif_carrier_ok(dev)) + r8153_set_rx_early_size(tp); + } mutex_unlock(&tp->control); @@ -4224,44 +4259,6 @@ static const struct net_device_ops rtl8152_netdev_ops = { .ndo_features_check = rtl8152_features_check, }; -static void r8152b_get_version(struct r8152 *tp) -{ - u32 ocp_data; - u16 version; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR1); - version = (u16)(ocp_data & VERSION_MASK); - - switch (version) { - case 0x4c00: - tp->version = RTL_VER_01; - break; - case 0x4c10: - tp->version = RTL_VER_02; - break; - case 0x5c00: - tp->version = RTL_VER_03; - tp->mii.supports_gmii = 1; - break; - case 0x5c10: - tp->version = RTL_VER_04; - tp->mii.supports_gmii = 1; - break; - case 0x5c20: - tp->version = RTL_VER_05; - tp->mii.supports_gmii = 1; - break; - case 0x5c30: - tp->version = RTL_VER_06; - tp->mii.supports_gmii = 1; - break; - default: - netif_info(tp, probe, tp->netdev, - "Unknown version 0x%04x\n", version); - break; - } -} - static void rtl8152_unload(struct r8152 *tp) { if (test_bit(RTL8152_UNPLUG, &tp->flags)) @@ -4326,14 +4323,66 @@ static int rtl_ops_init(struct r8152 *tp) return ret; } +static u8 rtl_get_version(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + u32 ocp_data = 0; + __le32 *tmp; + u8 version; + int ret; + + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return 0; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, + PLA_TCR0, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500); + if (ret > 0) + ocp_data = (__le32_to_cpu(*tmp) >> 16) & VERSION_MASK; + + kfree(tmp); + + switch (ocp_data) { + case 0x4c00: + version = RTL_VER_01; + break; + case 0x4c10: + version = RTL_VER_02; + break; + case 0x5c00: + version = RTL_VER_03; + break; + case 0x5c10: + version = RTL_VER_04; + break; + case 0x5c20: + version = RTL_VER_05; + break; + case 0x5c30: + version = RTL_VER_06; + break; + default: + version = RTL_VER_UNKNOWN; + dev_info(&intf->dev, "Unknown version 0x%04x\n", ocp_data); + break; + } + + return version; +} + static int rtl8152_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); + u8 version = rtl_get_version(intf); struct r8152 *tp; struct net_device *netdev; int ret; + if (version == RTL_VER_UNKNOWN) + return -ENODEV; + if (udev->actconfig->desc.bConfigurationValue != 1) { usb_driver_set_configuration(udev, 1); return -ENODEV; @@ -4353,8 +4402,18 @@ static int rtl8152_probe(struct usb_interface *intf, tp->udev = udev; tp->netdev = netdev; tp->intf = intf; + tp->version = version; + + switch (version) { + case RTL_VER_01: + case RTL_VER_02: + tp->mii.supports_gmii = 0; + break; + default: + tp->mii.supports_gmii = 1; + break; + } - r8152b_get_version(tp); ret = rtl_ops_init(tp); if (ret) goto out; @@ -4497,6 +4556,8 @@ static void rtl8152_disconnect(struct usb_interface *intf) static struct usb_device_id rtl8152_table[] = { {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152)}, {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, + {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab)}, + {REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6)}, {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062)}, |