net: cdc_ncm: add "ndp_to_end" sysfs attribute

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>
This commit is contained in:
Bjørn Mork 2015-12-06 22:47:15 +01:00 committed by David S. Miller
parent 0fe3e20416
commit 404814af69
2 changed files with 62 additions and 0 deletions

View 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

View 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,