diff options
Diffstat (limited to 'drivers/net/usb')
| -rw-r--r-- | drivers/net/usb/cdc_ether.c | 16 | ||||
| -rw-r--r-- | drivers/net/usb/cdc_ncm.c | 271 | ||||
| -rw-r--r-- | drivers/net/usb/hso.c | 50 | ||||
| -rw-r--r-- | drivers/net/usb/huawei_cdc_ncm.c | 10 | ||||
| -rw-r--r-- | drivers/net/usb/ipheth.c | 10 | ||||
| -rw-r--r-- | drivers/net/usb/qmi_wwan.c | 16 | ||||
| -rw-r--r-- | drivers/net/usb/r8152.c | 18 | ||||
| -rw-r--r-- | drivers/net/usb/smsc95xx.c | 14 |
8 files changed, 281 insertions, 124 deletions
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_ncm.c b/drivers/net/usb/cdc_ncm.c index 2d0caf1eea2..80a844e0ae0 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -127,54 +127,8 @@ static void cdc_ncm_get_strings(struct net_device __always_unused *netdev, u32 s } } -static int cdc_ncm_get_coalesce(struct net_device *netdev, - struct ethtool_coalesce *ec) -{ - struct usbnet *dev = netdev_priv(netdev); - struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; - - /* assuming maximum sized dgrams and ignoring NDPs */ - ec->rx_max_coalesced_frames = ctx->rx_max / ctx->max_datagram_size; - ec->tx_max_coalesced_frames = ctx->tx_max / ctx->max_datagram_size; - - /* the timer will fire CDC_NCM_TIMER_PENDING_CNT times in a row */ - ec->tx_coalesce_usecs = (ctx->timer_interval * CDC_NCM_TIMER_PENDING_CNT) / NSEC_PER_USEC; - return 0; -} - static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx); -static int cdc_ncm_set_coalesce(struct net_device *netdev, - struct ethtool_coalesce *ec) -{ - struct usbnet *dev = netdev_priv(netdev); - struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; - u32 new_rx_max = ctx->rx_max; - u32 new_tx_max = ctx->tx_max; - - /* assuming maximum sized dgrams and a single NDP */ - if (ec->rx_max_coalesced_frames) - new_rx_max = ec->rx_max_coalesced_frames * ctx->max_datagram_size; - if (ec->tx_max_coalesced_frames) - new_tx_max = ec->tx_max_coalesced_frames * ctx->max_datagram_size; - - if (ec->tx_coalesce_usecs && - (ec->tx_coalesce_usecs < CDC_NCM_TIMER_INTERVAL_MIN * CDC_NCM_TIMER_PENDING_CNT || - ec->tx_coalesce_usecs > CDC_NCM_TIMER_INTERVAL_MAX * CDC_NCM_TIMER_PENDING_CNT)) - return -EINVAL; - - spin_lock_bh(&ctx->mtx); - ctx->timer_interval = ec->tx_coalesce_usecs * NSEC_PER_USEC / CDC_NCM_TIMER_PENDING_CNT; - if (!ctx->timer_interval) - ctx->tx_timer_pending = 0; - spin_unlock_bh(&ctx->mtx); - - /* inform device of new values */ - if (new_rx_max != ctx->rx_max || new_tx_max != ctx->tx_max) - cdc_ncm_update_rxtx_max(dev, new_rx_max, new_tx_max); - return 0; -} - static const struct ethtool_ops cdc_ncm_ethtool_ops = { .get_settings = usbnet_get_settings, .set_settings = usbnet_set_settings, @@ -187,15 +141,11 @@ static const struct ethtool_ops cdc_ncm_ethtool_ops = { .get_sset_count = cdc_ncm_get_sset_count, .get_strings = cdc_ncm_get_strings, .get_ethtool_stats = cdc_ncm_get_ethtool_stats, - .get_coalesce = cdc_ncm_get_coalesce, - .set_coalesce = cdc_ncm_set_coalesce, }; -/* handle rx_max and tx_max changes */ -static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx) +static u32 cdc_ncm_check_rx_max(struct usbnet *dev, u32 new_rx) { struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; - u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; u32 val, max, min; /* clamp new_rx to sane values */ @@ -210,13 +160,180 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx) } val = clamp_t(u32, new_rx, min, max); - if (val != new_rx) { - dev_dbg(&dev->intf->dev, "rx_max must be in the [%u, %u] range. Using %u\n", - min, max, val); - } + if (val != new_rx) + dev_dbg(&dev->intf->dev, "rx_max must be in the [%u, %u] range\n", min, max); - /* usbnet use these values for sizing rx queues */ - dev->rx_urb_size = val; + return val; +} + +static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx) +{ + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + u32 val, max, min; + + /* clamp new_tx to sane values */ + min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth16); + max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)); + + /* some devices set dwNtbOutMaxSize too low for the above default */ + min = min(min, max); + + val = clamp_t(u32, new_tx, min, max); + if (val != new_tx) + dev_dbg(&dev->intf->dev, "tx_max must be in the [%u, %u] range\n", min, max); + + return val; +} + +static ssize_t cdc_ncm_show_min_tx_pkt(struct device *d, struct device_attribute *attr, char *buf) +{ + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + + return sprintf(buf, "%u\n", ctx->min_tx_pkt); +} + +static ssize_t cdc_ncm_show_rx_max(struct device *d, struct device_attribute *attr, char *buf) +{ + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + + return sprintf(buf, "%u\n", ctx->rx_max); +} + +static ssize_t cdc_ncm_show_tx_max(struct device *d, struct device_attribute *attr, char *buf) +{ + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + + return sprintf(buf, "%u\n", ctx->tx_max); +} + +static ssize_t cdc_ncm_show_tx_timer_usecs(struct device *d, struct device_attribute *attr, char *buf) +{ + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + + return sprintf(buf, "%u\n", ctx->timer_interval / (u32)NSEC_PER_USEC); +} + +static ssize_t cdc_ncm_store_min_tx_pkt(struct device *d, struct device_attribute *attr, const char *buf, size_t len) +{ + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + unsigned long val; + + /* no need to restrict values - anything from 0 to infinity is OK */ + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + ctx->min_tx_pkt = val; + return len; +} + +static ssize_t cdc_ncm_store_rx_max(struct device *d, struct device_attribute *attr, const char *buf, size_t len) +{ + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + unsigned long val; + + if (kstrtoul(buf, 0, &val) || cdc_ncm_check_rx_max(dev, val) != val) + return -EINVAL; + + cdc_ncm_update_rxtx_max(dev, val, ctx->tx_max); + return len; +} + +static ssize_t cdc_ncm_store_tx_max(struct device *d, struct device_attribute *attr, const char *buf, size_t len) +{ + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + unsigned long val; + + if (kstrtoul(buf, 0, &val) || cdc_ncm_check_tx_max(dev, val) != val) + return -EINVAL; + + cdc_ncm_update_rxtx_max(dev, ctx->rx_max, val); + return len; +} + +static ssize_t cdc_ncm_store_tx_timer_usecs(struct device *d, struct device_attribute *attr, const char *buf, size_t len) +{ + struct usbnet *dev = netdev_priv(to_net_dev(d)); + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + ssize_t ret; + unsigned long val; + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + if (val && (val < CDC_NCM_TIMER_INTERVAL_MIN || val > CDC_NCM_TIMER_INTERVAL_MAX)) + return -EINVAL; + + spin_lock_bh(&ctx->mtx); + ctx->timer_interval = val * NSEC_PER_USEC; + if (!ctx->timer_interval) + ctx->tx_timer_pending = 0; + spin_unlock_bh(&ctx->mtx); + return len; +} + +static DEVICE_ATTR(min_tx_pkt, S_IRUGO | S_IWUSR, cdc_ncm_show_min_tx_pkt, cdc_ncm_store_min_tx_pkt); +static DEVICE_ATTR(rx_max, S_IRUGO | S_IWUSR, cdc_ncm_show_rx_max, cdc_ncm_store_rx_max); +static DEVICE_ATTR(tx_max, S_IRUGO | S_IWUSR, cdc_ncm_show_tx_max, cdc_ncm_store_tx_max); +static DEVICE_ATTR(tx_timer_usecs, S_IRUGO | S_IWUSR, cdc_ncm_show_tx_timer_usecs, cdc_ncm_store_tx_timer_usecs); + +#define NCM_PARM_ATTR(name, format, tocpu) \ +static ssize_t cdc_ncm_show_##name(struct device *d, struct device_attribute *attr, char *buf) \ +{ \ + struct usbnet *dev = netdev_priv(to_net_dev(d)); \ + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; \ + return sprintf(buf, format "\n", tocpu(ctx->ncm_parm.name)); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, cdc_ncm_show_##name, NULL) + +NCM_PARM_ATTR(bmNtbFormatsSupported, "0x%04x", le16_to_cpu); +NCM_PARM_ATTR(dwNtbInMaxSize, "%u", le32_to_cpu); +NCM_PARM_ATTR(wNdpInDivisor, "%u", le16_to_cpu); +NCM_PARM_ATTR(wNdpInPayloadRemainder, "%u", le16_to_cpu); +NCM_PARM_ATTR(wNdpInAlignment, "%u", le16_to_cpu); +NCM_PARM_ATTR(dwNtbOutMaxSize, "%u", le32_to_cpu); +NCM_PARM_ATTR(wNdpOutDivisor, "%u", le16_to_cpu); +NCM_PARM_ATTR(wNdpOutPayloadRemainder, "%u", le16_to_cpu); +NCM_PARM_ATTR(wNdpOutAlignment, "%u", le16_to_cpu); +NCM_PARM_ATTR(wNtbOutMaxDatagrams, "%u", le16_to_cpu); + +static struct attribute *cdc_ncm_sysfs_attrs[] = { + &dev_attr_min_tx_pkt.attr, + &dev_attr_rx_max.attr, + &dev_attr_tx_max.attr, + &dev_attr_tx_timer_usecs.attr, + &dev_attr_bmNtbFormatsSupported.attr, + &dev_attr_dwNtbInMaxSize.attr, + &dev_attr_wNdpInDivisor.attr, + &dev_attr_wNdpInPayloadRemainder.attr, + &dev_attr_wNdpInAlignment.attr, + &dev_attr_dwNtbOutMaxSize.attr, + &dev_attr_wNdpOutDivisor.attr, + &dev_attr_wNdpOutPayloadRemainder.attr, + &dev_attr_wNdpOutAlignment.attr, + &dev_attr_wNtbOutMaxDatagrams.attr, + NULL, +}; + +static struct attribute_group cdc_ncm_sysfs_attr_group = { + .name = "cdc_ncm", + .attrs = cdc_ncm_sysfs_attrs, +}; + +/* handle rx_max and tx_max changes */ +static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx) +{ + struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; + u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; + u32 val; + + val = cdc_ncm_check_rx_max(dev, new_rx); /* inform device about NTB input size changes */ if (val != ctx->rx_max) { @@ -224,10 +341,6 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx) dev_info(&dev->intf->dev, "setting rx_max = %u\n", val); - /* need to unlink rx urbs before increasing buffer size */ - if (netif_running(dev->net) && dev->rx_urb_size > ctx->rx_max) - usbnet_unlink_rx_urbs(dev); - /* tell device to use new size */ if (usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE, USB_TYPE_CLASS | USB_DIR_OUT @@ -238,18 +351,14 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx) ctx->rx_max = val; } - /* clamp new_tx to sane values */ - min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth16); - max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)); - - /* some devices set dwNtbOutMaxSize too low for the above default */ - min = min(min, max); - - val = clamp_t(u32, new_tx, min, max); - if (val != new_tx) { - dev_dbg(&dev->intf->dev, "tx_max must be in the [%u, %u] range. Using %u\n", - min, max, val); + /* usbnet use these values for sizing rx queues */ + if (dev->rx_urb_size != ctx->rx_max) { + dev->rx_urb_size = ctx->rx_max; + if (netif_running(dev->net)) + usbnet_unlink_rx_urbs(dev); } + + val = cdc_ncm_check_tx_max(dev, new_tx); if (val != ctx->tx_max) dev_info(&dev->intf->dev, "setting tx_max = %u\n", val); @@ -268,6 +377,11 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx) if (netif_running(dev->net) && val > ctx->tx_max) { netif_tx_lock_bh(dev->net); usbnet_start_xmit(NULL, dev->net); + /* make sure tx_curr_skb is reallocated if it was empty */ + if (ctx->tx_curr_skb) { + dev_kfree_skb_any(ctx->tx_curr_skb); + ctx->tx_curr_skb = NULL; + } ctx->tx_max = val; netif_tx_unlock_bh(dev->net); } else { @@ -357,7 +471,8 @@ static int cdc_ncm_init(struct usbnet *dev) * "The host shall only send this command while the NCM Data * Interface is in alternate setting 0." */ - if (le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported) & USB_CDC_NCM_NTH32_SIGN) { + if (le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported) & + USB_CDC_NCM_NTB32_SUPPORTED) { dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit\n"); err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS | USB_DIR_OUT @@ -743,6 +858,9 @@ advance: /* override ethtool_ops */ dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; + /* add our sysfs attrs */ + dev->net->sysfs_groups[0] = &cdc_ncm_sysfs_attr_group; + return 0; error2: @@ -1288,12 +1406,11 @@ next_ndp: break; } else { - skb = skb_clone(skb_in, GFP_ATOMIC); + /* create a fresh copy to reduce truesize */ + skb = netdev_alloc_skb_ip_align(dev->net, len); if (!skb) goto error; - skb->len = len; - skb->data = ((u8 *)skb_in->data) + offset; - skb_set_tail_pointer(skb, len); + memcpy(skb_put(skb, len), skb_in->data + offset, len); usbnet_skb_return(dev, skb); payload += len; /* count payload bytes in this NTB */ } diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index a3a05869309..a4272ed62da 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 { @@ -1252,14 +1250,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 +1285,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 +1333,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 +2000,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 +2010,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 +2202,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); diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c index f9822bc7542..735f7dadb9a 100644 --- a/drivers/net/usb/huawei_cdc_ncm.c +++ b/drivers/net/usb/huawei_cdc_ncm.c @@ -84,12 +84,13 @@ static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, ctx = drvstate->ctx; if (usbnet_dev->status) - /* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 - * decimal (0x100)" + /* The wMaxCommand buffer must be big enough to hold + * any message from the modem. Experience has shown + * that some replies are more than 256 bytes long */ subdriver = usb_cdc_wdm_register(ctx->control, &usbnet_dev->status->desc, - 256, /* wMaxCommand */ + 1024, /* wMaxCommand */ huawei_cdc_ncm_wdm_manage_power); if (IS_ERR(subdriver)) { ret = PTR_ERR(subdriver); @@ -193,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/ipheth.c b/drivers/net/usb/ipheth.c index f72570708ed..76465b117b7 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -59,6 +59,8 @@ #define USB_PRODUCT_IPHONE_3GS 0x1294 #define USB_PRODUCT_IPHONE_4 0x1297 #define USB_PRODUCT_IPAD 0x129a +#define USB_PRODUCT_IPAD_2 0x12a2 +#define USB_PRODUCT_IPAD_3 0x12a6 #define USB_PRODUCT_IPAD_MINI 0x12ab #define USB_PRODUCT_IPHONE_4_VZW 0x129c #define USB_PRODUCT_IPHONE_4S 0x12a0 @@ -107,6 +109,14 @@ static struct usb_device_id ipheth_table[] = { IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPAD_2, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPAD_3, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( USB_VENDOR_APPLE, USB_PRODUCT_IPAD_MINI, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 83208d4fdc5..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 */ @@ -748,18 +750,28 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */ {QMI_FIXED_INTF(0x1199, 0x68c0, 8)}, /* Sierra Wireless MC73xx */ {QMI_FIXED_INTF(0x1199, 0x68c0, 10)}, /* Sierra Wireless MC73xx */ - {QMI_FIXED_INTF(0x1199, 0x68c0, 11)}, /* Sierra Wireless MC73xx */ {QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */ {QMI_FIXED_INTF(0x1199, 0x901f, 8)}, /* Sierra Wireless EM7355 */ {QMI_FIXED_INTF(0x1199, 0x9041, 8)}, /* Sierra Wireless MC7305/MC7355 */ {QMI_FIXED_INTF(0x1199, 0x9051, 8)}, /* Netgear AirCard 340U */ + {QMI_FIXED_INTF(0x1199, 0x9053, 8)}, /* Sierra Wireless Modem */ + {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 */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */ - {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)}, /* Olivetti Olicard 200 */ + {QMI_FIXED_INTF(0x0b3c, 0xc000, 4)}, /* Olivetti Olicard 100 */ + {QMI_FIXED_INTF(0x0b3c, 0xc001, 4)}, /* Olivetti Olicard 120 */ + {QMI_FIXED_INTF(0x0b3c, 0xc002, 4)}, /* Olivetti Olicard 140 */ + {QMI_FIXED_INTF(0x0b3c, 0xc004, 6)}, /* Olivetti Olicard 155 */ + {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)}, /* Olivetti Olicard 200 */ + {QMI_FIXED_INTF(0x0b3c, 0xc00a, 6)}, /* Olivetti Olicard 160 */ {QMI_FIXED_INTF(0x0b3c, 0xc00b, 4)}, /* Olivetti Olicard 500 */ {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */ {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)}, /* Cinterion PHxx,PXxx */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 9f91c7aba4b..3eab74c7c55 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -282,7 +282,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 @@ -630,12 +630,10 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) int ret; void *tmp; - tmp = kmalloc(size, GFP_KERNEL); + tmp = kmemdup(data, size, GFP_KERNEL); if (!tmp) return -ENOMEM; - memcpy(tmp, data, size); - ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0), RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, value, index, tmp, size, 500); @@ -1361,7 +1359,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; @@ -2294,9 +2292,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); @@ -3206,8 +3203,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); 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, |
