diff options
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/Kconfig | 13 | ||||
-rw-r--r-- | drivers/net/usb/ax88179_178a.c | 264 | ||||
-rw-r--r-- | drivers/net/usb/cdc-phonet.c | 2 | ||||
-rw-r--r-- | drivers/net/usb/cdc_ether.c | 16 | ||||
-rw-r--r-- | drivers/net/usb/cdc_subset.c | 27 | ||||
-rw-r--r-- | drivers/net/usb/hso.c | 54 | ||||
-rw-r--r-- | drivers/net/usb/huawei_cdc_ncm.c | 3 | ||||
-rw-r--r-- | drivers/net/usb/qmi_wwan.c | 3 | ||||
-rw-r--r-- | drivers/net/usb/r8152.c | 52 | ||||
-rw-r--r-- | drivers/net/usb/smsc95xx.c | 14 | ||||
-rw-r--r-- | drivers/net/usb/usbnet.c | 8 |
11 files changed, 402 insertions, 54 deletions
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 7e7269fd370..9f194a0bef7 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -1,12 +1,16 @@ # # USB Network devices configuration # -comment "Networking support is needed for USB Network Adapter support" - depends on USB && !NET +comment "Host-side USB support is needed for USB Network Adapter support" + depends on !USB && NET -menu "USB Network Adapters" +menuconfig USB_NET_DRIVERS + bool "USB Network Adapters" + default y depends on USB && NET +if USB_NET_DRIVERS + config USB_CATC tristate "USB CATC NetMate-based Ethernet device support" select CRC32 @@ -568,5 +572,4 @@ config USB_VL600 http://ubuntuforums.org/showpost.php?p=10589647&postcount=17 - -endmenu +endif # USB_NET_DRIVERS diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 054e59ca694..be427572103 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -23,6 +23,8 @@ #include <linux/usb.h> #include <linux/crc32.h> #include <linux/usb/usbnet.h> +#include <uapi/linux/mdio.h> +#include <linux/mdio.h> #define AX88179_PHY_ID 0x03 #define AX_EEPROM_LEN 0x100 @@ -170,8 +172,12 @@ #define GMII_PHY_PAGE_SELECT 0x1f #define GMII_PHY_PGSEL_EXT 0x0007 #define GMII_PHY_PGSEL_PAGE0 0x0000 + #define GMII_PHY_PGSEL_PAGE3 0x0003 + #define GMII_PHY_PGSEL_PAGE5 0x0005 struct ax88179_data { + u8 eee_enabled; + u8 eee_active; u16 rxctl; u16 reserved; }; @@ -373,6 +379,60 @@ static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc, ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res); } +static inline int ax88179_phy_mmd_indirect(struct usbnet *dev, u16 prtad, + u16 devad) +{ + u16 tmp16; + int ret; + + tmp16 = devad; + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_CTRL, 2, &tmp16); + + tmp16 = prtad; + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_DATA, 2, &tmp16); + + tmp16 = devad | MII_MMD_CTRL_NOINCR; + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_CTRL, 2, &tmp16); + + return ret; +} + +static int +ax88179_phy_read_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad) +{ + int ret; + u16 tmp16; + + ax88179_phy_mmd_indirect(dev, prtad, devad); + + ret = ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_DATA, 2, &tmp16); + if (ret < 0) + return ret; + + return tmp16; +} + +static int +ax88179_phy_write_mmd_indirect(struct usbnet *dev, u16 prtad, u16 devad, + u16 data) +{ + int ret; + + ax88179_phy_mmd_indirect(dev, prtad, devad); + + ret = ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_MMD_DATA, 2, &data); + + if (ret < 0) + return ret; + + return 0; +} + static int ax88179_suspend(struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); @@ -572,6 +632,185 @@ static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd) return mii_ethtool_sset(&dev->mii, cmd); } +static int +ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data) +{ + int val; + + /* Get Supported EEE */ + val = ax88179_phy_read_mmd_indirect(dev, MDIO_PCS_EEE_ABLE, + MDIO_MMD_PCS); + if (val < 0) + return val; + data->supported = mmd_eee_cap_to_ethtool_sup_t(val); + + /* Get advertisement EEE */ + val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV, + MDIO_MMD_AN); + if (val < 0) + return val; + data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); + + /* Get LP advertisement EEE */ + val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE, + MDIO_MMD_AN); + if (val < 0) + return val; + data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); + + return 0; +} + +static int +ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_eee *data) +{ + u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised); + + return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV, + MDIO_MMD_AN, tmp16); +} + +static int ax88179_chk_eee(struct usbnet *dev) +{ + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + struct ax88179_data *priv = (struct ax88179_data *)dev->data; + + mii_ethtool_gset(&dev->mii, &ecmd); + + if (ecmd.duplex & DUPLEX_FULL) { + int eee_lp, eee_cap, eee_adv; + u32 lp, cap, adv, supported = 0; + + eee_cap = ax88179_phy_read_mmd_indirect(dev, + MDIO_PCS_EEE_ABLE, + MDIO_MMD_PCS); + if (eee_cap < 0) { + priv->eee_active = 0; + return false; + } + + cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap); + if (!cap) { + priv->eee_active = 0; + return false; + } + + eee_lp = ax88179_phy_read_mmd_indirect(dev, + MDIO_AN_EEE_LPABLE, + MDIO_MMD_AN); + if (eee_lp < 0) { + priv->eee_active = 0; + return false; + } + + eee_adv = ax88179_phy_read_mmd_indirect(dev, + MDIO_AN_EEE_ADV, + MDIO_MMD_AN); + + if (eee_adv < 0) { + priv->eee_active = 0; + return false; + } + + adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv); + lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp); + supported = (ecmd.speed == SPEED_1000) ? + SUPPORTED_1000baseT_Full : + SUPPORTED_100baseT_Full; + + if (!(lp & adv & supported)) { + priv->eee_active = 0; + return false; + } + + priv->eee_active = 1; + return true; + } + + priv->eee_active = 0; + return false; +} + +static void ax88179_disable_eee(struct usbnet *dev) +{ + u16 tmp16; + + tmp16 = GMII_PHY_PGSEL_PAGE3; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); + + tmp16 = 0x3246; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_PHYADDR, 2, &tmp16); + + tmp16 = GMII_PHY_PGSEL_PAGE0; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); +} + +static void ax88179_enable_eee(struct usbnet *dev) +{ + u16 tmp16; + + tmp16 = GMII_PHY_PGSEL_PAGE3; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); + + tmp16 = 0x3247; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_PHYADDR, 2, &tmp16); + + tmp16 = GMII_PHY_PGSEL_PAGE5; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); + + tmp16 = 0x0680; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + MII_BMSR, 2, &tmp16); + + tmp16 = GMII_PHY_PGSEL_PAGE0; + ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID, + GMII_PHY_PAGE_SELECT, 2, &tmp16); +} + +static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata) +{ + struct usbnet *dev = netdev_priv(net); + struct ax88179_data *priv = (struct ax88179_data *)dev->data; + + edata->eee_enabled = priv->eee_enabled; + edata->eee_active = priv->eee_active; + + return ax88179_ethtool_get_eee(dev, edata); +} + +static int ax88179_set_eee(struct net_device *net, struct ethtool_eee *edata) +{ + struct usbnet *dev = netdev_priv(net); + struct ax88179_data *priv = (struct ax88179_data *)dev->data; + int ret = -EOPNOTSUPP; + + priv->eee_enabled = edata->eee_enabled; + if (!priv->eee_enabled) { + ax88179_disable_eee(dev); + } else { + priv->eee_enabled = ax88179_chk_eee(dev); + if (!priv->eee_enabled) + return -EOPNOTSUPP; + + ax88179_enable_eee(dev); + } + + ret = ax88179_ethtool_set_eee(dev, edata); + if (ret) + return ret; + + mii_nway_restart(&dev->mii); + + usbnet_link_change(dev, 0, 0); + + return ret; +} static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd) { @@ -589,6 +828,8 @@ static const struct ethtool_ops ax88179_ethtool_ops = { .get_eeprom = ax88179_get_eeprom, .get_settings = ax88179_get_settings, .set_settings = ax88179_set_settings, + .get_eee = ax88179_get_eee, + .set_eee = ax88179_set_eee, .nway_reset = usbnet_nway_reset, }; @@ -980,6 +1221,7 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) u16 *tmp16; u8 *tmp; struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; + struct ethtool_eee eee_data; usbnet_get_endpoints(dev, intf); @@ -1062,6 +1304,15 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) ax88179_led_setting(dev); + ax179_data->eee_enabled = 0; + ax179_data->eee_active = 0; + + ax88179_disable_eee(dev); + + ax88179_ethtool_get_eee(dev, &eee_data); + eee_data.advertised = 0; + ax88179_ethtool_set_eee(dev, &eee_data); + /* Restart autoneg */ mii_nway_restart(&dev->mii); @@ -1261,6 +1512,8 @@ static int ax88179_link_reset(struct usbnet *dev) ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE, 2, 2, &mode); + ax179_data->eee_enabled = ax88179_chk_eee(dev); + netif_carrier_on(dev->net); return 0; @@ -1271,6 +1524,8 @@ static int ax88179_reset(struct usbnet *dev) u8 buf[5]; u16 *tmp16; u8 *tmp; + struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data; + struct ethtool_eee eee_data; tmp16 = (u16 *)buf; tmp = (u8 *)buf; @@ -1340,6 +1595,15 @@ static int ax88179_reset(struct usbnet *dev) ax88179_led_setting(dev); + ax179_data->eee_enabled = 0; + ax179_data->eee_active = 0; + + ax88179_disable_eee(dev); + + ax88179_ethtool_get_eee(dev, &eee_data); + eee_data.advertised = 0; + ax88179_ethtool_set_eee(dev, &eee_data); + /* Restart autoneg */ mii_nway_restart(&dev->mii); diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 6358d420e18..2ec1500d007 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -387,7 +387,7 @@ static int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *i return -EINVAL; dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size, - ifname, usbpn_setup); + ifname, NET_NAME_UNKNOWN, usbpn_setup); if (!dev) return -ENOMEM; diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 9ea4bfe5d31..2a32d9167d3 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -341,6 +341,22 @@ next_desc: usb_driver_release_interface(driver, info->data); return -ENODEV; } + + /* Some devices don't initialise properly. In particular + * the packet filter is not reset. There are devices that + * don't do reset all the way. So the packet filter should + * be set to a sane initial value. + */ + usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + USB_CDC_SET_ETHERNET_PACKET_FILTER, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + USB_CDC_PACKET_TYPE_ALL_MULTICAST | USB_CDC_PACKET_TYPE_DIRECTED | USB_CDC_PACKET_TYPE_BROADCAST, + intf->cur_altsetting->desc.bInterfaceNumber, + NULL, + 0, + USB_CTRL_SET_TIMEOUT + ); return 0; bad_desc: diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index 91f0919fe27..6ea98cff2d3 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -85,14 +85,28 @@ static int always_connected (struct usbnet *dev) * *-------------------------------------------------------------------------*/ +static void m5632_recover(struct usbnet *dev) +{ + struct usb_device *udev = dev->udev; + struct usb_interface *intf = dev->intf; + int r; + + r = usb_lock_device_for_reset(udev, intf); + if (r < 0) + return; + + usb_reset_device(udev); + usb_unlock_device(udev); +} + static const struct driver_info ali_m5632_info = { .description = "ALi M5632", .flags = FLAG_POINTTOPOINT, + .recover = m5632_recover, }; #endif - #ifdef CONFIG_USB_AN2720 #define HAVE_HARDWARE @@ -326,12 +340,23 @@ static const struct usb_device_id products [] = { MODULE_DEVICE_TABLE(usb, products); /*-------------------------------------------------------------------------*/ +static int dummy_prereset(struct usb_interface *intf) +{ + return 0; +} + +static int dummy_postreset(struct usb_interface *intf) +{ + return 0; +} static struct usb_driver cdc_subset_driver = { .name = "cdc_subset", .probe = usbnet_probe, .suspend = usbnet_suspend, .resume = usbnet_resume, + .pre_reset = dummy_prereset, + .post_reset = dummy_postreset, .disconnect = usbnet_disconnect, .id_table = products, .disable_hub_initiated_lpm = 1, diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index a3a05869309..babda7d8693 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -258,10 +258,8 @@ struct hso_serial { * so as not to drop characters on the floor. */ int curr_rx_urb_idx; - u16 curr_rx_urb_offset; u8 rx_urb_filled[MAX_RX_URBS]; struct tasklet_struct unthrottle_tasklet; - struct work_struct retry_unthrottle_workqueue; }; struct hso_device { @@ -469,6 +467,7 @@ static const struct usb_device_id hso_ids[] = { {USB_DEVICE(0x0af0, 0x8800)}, {USB_DEVICE(0x0af0, 0x8900)}, {USB_DEVICE(0x0af0, 0x9000)}, + {USB_DEVICE(0x0af0, 0x9200)}, /* Option GTM671WFS */ {USB_DEVICE(0x0af0, 0xd035)}, {USB_DEVICE(0x0af0, 0xd055)}, {USB_DEVICE(0x0af0, 0xd155)}, @@ -1252,14 +1251,6 @@ static void hso_unthrottle(struct tty_struct *tty) tasklet_hi_schedule(&serial->unthrottle_tasklet); } -static void hso_unthrottle_workfunc(struct work_struct *work) -{ - struct hso_serial *serial = - container_of(work, struct hso_serial, - retry_unthrottle_workqueue); - hso_unthrottle_tasklet(serial); -} - /* open the requested serial port */ static int hso_serial_open(struct tty_struct *tty, struct file *filp) { @@ -1295,8 +1286,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp) tasklet_init(&serial->unthrottle_tasklet, (void (*)(unsigned long))hso_unthrottle_tasklet, (unsigned long)serial); - INIT_WORK(&serial->retry_unthrottle_workqueue, - hso_unthrottle_workfunc); result = hso_start_serial_device(serial->parent, GFP_KERNEL); if (result) { hso_stop_serial_device(serial->parent); @@ -1345,7 +1334,6 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) if (!usb_gone) hso_stop_serial_device(serial->parent); tasklet_kill(&serial->unthrottle_tasklet); - cancel_work_sync(&serial->retry_unthrottle_workqueue); } if (!usb_gone) @@ -2013,8 +2001,7 @@ static void ctrl_callback(struct urb *urb) static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) { struct tty_struct *tty; - int write_length_remaining = 0; - int curr_write_len; + int count; /* Sanity check */ if (urb == NULL || serial == NULL) { @@ -2024,29 +2011,28 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) tty = tty_port_tty_get(&serial->port); + if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { + tty_kref_put(tty); + return -1; + } + /* Push data to tty */ - write_length_remaining = urb->actual_length - - serial->curr_rx_urb_offset; D1("data to push to tty"); - while (write_length_remaining) { - if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { - tty_kref_put(tty); - return -1; - } - curr_write_len = tty_insert_flip_string(&serial->port, - urb->transfer_buffer + serial->curr_rx_urb_offset, - write_length_remaining); - serial->curr_rx_urb_offset += curr_write_len; - write_length_remaining -= curr_write_len; + count = tty_buffer_request_room(&serial->port, urb->actual_length); + if (count >= urb->actual_length) { + tty_insert_flip_string(&serial->port, urb->transfer_buffer, + urb->actual_length); tty_flip_buffer_push(&serial->port); + } else { + dev_warn(&serial->parent->usb->dev, + "dropping data, %d bytes lost\n", urb->actual_length); } + tty_kref_put(tty); - if (write_length_remaining == 0) { - serial->curr_rx_urb_offset = 0; - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; - } - return write_length_remaining; + serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; + + return 0; } @@ -2217,7 +2203,6 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) } } serial->curr_rx_urb_idx = 0; - serial->curr_rx_urb_offset = 0; if (serial->tx_urb) usb_kill_urb(serial->tx_urb); @@ -2520,7 +2505,8 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface, /* allocate our network device, then we can put in our private data */ /* call hso_net_init to do the basic initialization */ - net = alloc_netdev(sizeof(struct hso_net), "hso%d", hso_net_init); + net = alloc_netdev(sizeof(struct hso_net), "hso%d", NET_NAME_UNKNOWN, + hso_net_init); if (!net) { dev_err(&interface->dev, "Unable to create ethernet device\n"); goto exit; diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c index 5d95a13dbe2..735f7dadb9a 100644 --- a/drivers/net/usb/huawei_cdc_ncm.c +++ b/drivers/net/usb/huawei_cdc_ncm.c @@ -194,6 +194,9 @@ static const struct usb_device_id huawei_cdc_ncm_devs[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x76), .driver_info = (unsigned long)&huawei_cdc_ncm_info, }, + { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x03, 0x16), + .driver_info = (unsigned long)&huawei_cdc_ncm_info, + }, /* Terminating entry */ { diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index cf62d7e8329..22756db53dc 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -667,6 +667,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x05c6, 0x9084, 4)}, {QMI_FIXED_INTF(0x05c6, 0x920d, 0)}, {QMI_FIXED_INTF(0x05c6, 0x920d, 5)}, + {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ {QMI_FIXED_INTF(0x16d8, 0x6003, 0)}, /* CMOTech 6003 */ @@ -741,6 +742,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x19d2, 0x1424, 2)}, {QMI_FIXED_INTF(0x19d2, 0x1425, 2)}, {QMI_FIXED_INTF(0x19d2, 0x1426, 2)}, /* ZTE MF91 */ + {QMI_FIXED_INTF(0x19d2, 0x1428, 2)}, /* Telewell TW-LTE 4G v2 */ {QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */ {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */ {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ @@ -756,6 +758,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x9054, 8)}, /* Sierra Wireless Modem */ {QMI_FIXED_INTF(0x1199, 0x9055, 8)}, /* Netgear AirCard 341U */ {QMI_FIXED_INTF(0x1199, 0x9056, 8)}, /* Sierra Wireless Modem */ + {QMI_FIXED_INTF(0x1199, 0x9057, 8)}, {QMI_FIXED_INTF(0x1199, 0x9061, 8)}, /* Sierra Wireless Modem */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 25431965a62..87f71047621 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -59,6 +59,7 @@ #define PLA_WDT6_CTRL 0xe428 #define PLA_TCR0 0xe610 #define PLA_TCR1 0xe612 +#define PLA_MTPS 0xe615 #define PLA_TXFIFO_CTRL 0xe618 #define PLA_RSTTALLY 0xe800 #define PLA_CR 0xe813 @@ -180,6 +181,10 @@ /* PLA_TCR1 */ #define VERSION_MASK 0x7cf0 +/* PLA_MTPS */ +#define MTPS_JUMBO (12 * 1024 / 64) +#define MTPS_DEFAULT (6 * 1024 / 64) + /* PLA_RSTTALLY */ #define TALLY_RESET 0x0001 @@ -282,7 +287,7 @@ /* USB_DEV_STAT */ #define STAT_SPEED_MASK 0x0006 #define STAT_SPEED_HIGH 0x0000 -#define STAT_SPEED_FULL 0x0001 +#define STAT_SPEED_FULL 0x0002 /* USB_TX_AGG */ #define TX_AGG_MAX_THRESHOLD 0x03 @@ -440,8 +445,11 @@ enum rtl_register_content { #define BYTE_EN_START_MASK 0x0f #define BYTE_EN_END_MASK 0xf0 +#define RTL8153_MAX_PACKET 9216 /* 9K */ +#define RTL8153_MAX_MTU (RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN) #define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN) -#define RTL8152_TX_TIMEOUT (HZ) +#define RTL8153_RMS RTL8153_MAX_PACKET +#define RTL8152_TX_TIMEOUT (5 * HZ) /* rtl8152 flags */ enum rtl8152_flags { @@ -1359,7 +1367,7 @@ static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb, struct sk_buff_head seg_list; struct sk_buff *segs, *nskb; - features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO); + features &= ~(NETIF_F_SG | NETIF_F_IPV6_CSUM | NETIF_F_TSO6); segs = skb_gso_segment(skb, features); if (IS_ERR(segs) || !segs) goto drop; @@ -2292,9 +2300,8 @@ static void r8152b_exit_oob(struct r8152 *tp) /* rx share fifo credit full threshold */ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL); - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_DEV_STAT); - ocp_data &= STAT_SPEED_MASK; - if (ocp_data == STAT_SPEED_FULL) { + if (tp->udev->speed == USB_SPEED_FULL || + tp->udev->speed == USB_SPEED_LOW) { /* rx share fifo credit near full threshold */ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_FULL); @@ -2522,7 +2529,8 @@ static void r8153_first_init(struct r8152 *tp) ocp_data &= ~CPCR_RX_VLAN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_MTPS, MTPS_JUMBO); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); ocp_data |= TCR0_AUTO_FIFO; @@ -2572,7 +2580,7 @@ static void r8153_enter_oob(struct r8152 *tp) mdelay(1); } - ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); ocp_data &= ~TEREDO_WAKE_MASK; @@ -3204,8 +3212,13 @@ static void rtl8152_get_ethtool_stats(struct net_device *dev, struct r8152 *tp = netdev_priv(dev); struct tally_counter tally; + if (usb_autopm_get_interface(tp->intf) < 0) + return; + generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA); + usb_autopm_put_interface(tp->intf); + data[0] = le64_to_cpu(tally.tx_packets); data[1] = le64_to_cpu(tally.rx_packets); data[2] = le64_to_cpu(tally.tx_errors); @@ -3284,6 +3297,26 @@ out: return res; } +static int rtl8152_change_mtu(struct net_device *dev, int new_mtu) +{ + struct r8152 *tp = netdev_priv(dev); + + switch (tp->version) { + case RTL_VER_01: + case RTL_VER_02: + return eth_change_mtu(dev, new_mtu); + default: + break; + } + + if (new_mtu < 68 || new_mtu > RTL8153_MAX_MTU) + return -EINVAL; + + dev->mtu = new_mtu; + + return 0; +} + static const struct net_device_ops rtl8152_netdev_ops = { .ndo_open = rtl8152_open, .ndo_stop = rtl8152_close, @@ -3292,8 +3325,7 @@ static const struct net_device_ops rtl8152_netdev_ops = { .ndo_tx_timeout = rtl8152_tx_timeout, .ndo_set_rx_mode = rtl8152_set_rx_mode, .ndo_set_mac_address = rtl8152_set_mac_address, - - .ndo_change_mtu = eth_change_mtu, + .ndo_change_mtu = rtl8152_change_mtu, .ndo_validate_addr = eth_validate_addr, }; diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 424db65e439..d07bf4cb893 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1714,6 +1714,18 @@ static int smsc95xx_resume(struct usb_interface *intf) return ret; } +static int smsc95xx_reset_resume(struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + int ret; + + ret = smsc95xx_reset(dev); + if (ret < 0) + return ret; + + return smsc95xx_resume(intf); +} + static void smsc95xx_rx_csum_offload(struct sk_buff *skb) { skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2); @@ -2004,7 +2016,7 @@ static struct usb_driver smsc95xx_driver = { .probe = usbnet_probe, .suspend = smsc95xx_suspend, .resume = smsc95xx_resume, - .reset_resume = smsc95xx_resume, + .reset_resume = smsc95xx_reset_resume, .disconnect = usbnet_disconnect, .disable_hub_initiated_lpm = 1, .supports_autosuspend = 1, diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index f9e96c42755..5173821a957 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1218,8 +1218,12 @@ void usbnet_tx_timeout (struct net_device *net) unlink_urbs (dev, &dev->txq); tasklet_schedule (&dev->bh); - - // FIXME: device recovery -- reset? + /* this needs to be handled individually because the generic layer + * doesn't know what is sufficient and could not restore private + * information if a remedy of an unconditional reset were used. + */ + if (dev->driver_info->recover) + (dev->driver_info->recover)(dev); } EXPORT_SYMBOL_GPL(usbnet_tx_timeout); |