]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/usb/cdc_ncm.c
Merge branch 'r8152-adjustments'
[karo-tx-linux.git] / drivers / net / usb / cdc_ncm.c
index 1e9843a411685ea887e1dd6d732cd8d5d7bb4a82..dc0212c3cc28cc36267d62cfebe726f51fe0c910 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/ctype.h>
+#include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/workqueue.h>
 #include <linux/mii.h>
@@ -283,6 +284,48 @@ static DEVICE_ATTR(rx_max, S_IRUGO | S_IWUSR, cdc_ncm_show_rx_max, cdc_ncm_store
 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);
 
+static ssize_t ndp_to_end_show(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, "%c\n", ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END ? 'Y' : 'N');
+}
+
+static ssize_t ndp_to_end_store(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];
+       bool enable;
+
+       if (strtobool(buf, &enable))
+               return -EINVAL;
+
+       /* no change? */
+       if (enable == (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
+               return len;
+
+       if (enable && !ctx->delayed_ndp16) {
+               ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
+               if (!ctx->delayed_ndp16)
+                       return -ENOMEM;
+       }
+
+       /* flush pending data before changing flag */
+       netif_tx_lock_bh(dev->net);
+       usbnet_start_xmit(NULL, dev->net);
+       spin_lock_bh(&ctx->mtx);
+       if (enable)
+               ctx->drvflags |= CDC_NCM_FLAG_NDP_TO_END;
+       else
+               ctx->drvflags &= ~CDC_NCM_FLAG_NDP_TO_END;
+       spin_unlock_bh(&ctx->mtx);
+       netif_tx_unlock_bh(dev->net);
+
+       return len;
+}
+static DEVICE_ATTR_RW(ndp_to_end);
+
 #define NCM_PARM_ATTR(name, format, tocpu)                             \
 static ssize_t cdc_ncm_show_##name(struct device *d, struct device_attribute *attr, char *buf) \
 { \
@@ -305,6 +348,7 @@ NCM_PARM_ATTR(wNtbOutMaxDatagrams, "%u", le16_to_cpu);
 
 static struct attribute *cdc_ncm_sysfs_attrs[] = {
        &dev_attr_min_tx_pkt.attr,
+       &dev_attr_ndp_to_end.attr,
        &dev_attr_rx_max.attr,
        &dev_attr_tx_max.attr,
        &dev_attr_tx_timer_usecs.attr,
@@ -689,6 +733,33 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
        kfree(ctx);
 }
 
+/* we need to override the usbnet change_mtu ndo for two reasons:
+ *  - respect the negotiated maximum datagram size
+ *  - avoid unwanted changes to rx and tx buffers
+ */
+int cdc_ncm_change_mtu(struct net_device *net, int new_mtu)
+{
+       struct usbnet *dev = netdev_priv(net);
+       struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+       int maxmtu = ctx->max_datagram_size - cdc_ncm_eth_hlen(dev);
+
+       if (new_mtu <= 0 || new_mtu > maxmtu)
+               return -EINVAL;
+       net->mtu = new_mtu;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(cdc_ncm_change_mtu);
+
+static const struct net_device_ops cdc_ncm_netdev_ops = {
+       .ndo_open            = usbnet_open,
+       .ndo_stop            = usbnet_stop,
+       .ndo_start_xmit      = usbnet_start_xmit,
+       .ndo_tx_timeout      = usbnet_tx_timeout,
+       .ndo_change_mtu      = cdc_ncm_change_mtu,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr   = eth_validate_addr,
+};
+
 int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
 {
        struct cdc_ncm_ctx *ctx;
@@ -823,6 +894,9 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        /* add our sysfs attrs */
        dev->net->sysfs_groups[0] = &cdc_ncm_sysfs_attr_group;
 
+       /* must handle MTU changes */
+       dev->net->netdev_ops = &cdc_ncm_netdev_ops;
+
        return 0;
 
 error2:
@@ -1558,6 +1632,24 @@ static const struct usb_device_id cdc_devs[] = {
          .driver_info = (unsigned long) &wwan_info,
        },
 
+       /* DW5812 LTE Verizon Mobile Broadband Card
+        * Unlike DW5550 this device requires FLAG_NOARP
+        */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bb,
+               USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&wwan_noarp_info,
+       },
+
+       /* DW5813 LTE AT&T Mobile Broadband Card
+        * Unlike DW5550 this device requires FLAG_NOARP
+        */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bc,
+               USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&wwan_noarp_info,
+       },
+
        /* Dell branded MBM devices like DW5550 */
        { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
                | USB_DEVICE_ID_MATCH_VENDOR,