net: cdc_ncm: add "ndp_to_end" sysfs attribute
authorBjørn Mork <bjorn@mork.no>
Sun, 6 Dec 2015 21:47:15 +0000 (22:47 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 7 Dec 2015 03:52:18 +0000 (22:52 -0500)
Adding a writable sysfs attribute for the "NDP to end"
quirk flag.

This makes it easier for end users to test new devices for
this firmware bug.  We've been lucky so far, but we should
not depend on reporters capable of rebuilding the driver.

Cc: Enrico Mioso <mrkiko.rs@gmail.com>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/ABI/testing/sysfs-class-net-cdc_ncm
drivers/net/usb/cdc_ncm.c

index 5cedf72..f7be0e8 100644 (file)
@@ -19,6 +19,25 @@ Description:
                Set to 0 to pad all frames. Set greater than tx_max to
                disable all padding.
 
+What:          /sys/class/net/<iface>/cdc_ncm/ndp_to_end
+Date:          Dec 2015
+KernelVersion: 4.5
+Contact:       Bjørn Mork <bjorn@mork.no>
+Description:
+               Boolean attribute showing the status of the "NDP to
+               end" quirk.  Defaults to 'N', except for devices
+               already known to need it enabled.
+
+               The "NDP to end" quirk makes the driver place the NDP
+               (the packet index table) after the payload.  The NCM
+               specification does not mandate this, but some devices
+               are known to be more restrictive. Write 'Y' to this
+               attribute for temporary testing of a suspect device
+               failing to work with the default driver settings.
+
+               A device entry should be added to the driver if this
+               quirk is found to be required.
+
 What:          /sys/class/net/<iface>/cdc_ncm/rx_max
 Date:          May 2014
 KernelVersion: 3.16
index 3b1ba82..b45e5ca 100644 (file)
@@ -283,6 +283,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 +347,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,