* [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
@ 2014-05-16 19:48 Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 01/12] net: cdc_ncm: split out rx_max/tx_max update of setup Bjørn Mork
` (9 more replies)
0 siblings, 10 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Quoting the previous description of this series (skip to the
changelog below if you only want a summary of the changes):
"I have got quite a few reports from frustrated users of OpenWRT
hosts trying to use some powerful LTE modem, but not achieving
full speed. This is typically caused by a combination of
big buffers and little memory, giving in allocation errors and
bad performance as a result.
This series is an attempt to let users adjust the size of these
buffers without having to rebuild the driver.
Patches 1 - 4 are mostly rearranging existing code, in preparing
for the dynamic buffer size changes.
Patch 5 adds userspace control (ab)using the ethtool coalescing
API. This isn't a perfect match, which is the main reason why I
post this series as a RFC.
Patch 6 is an unrelated framing optimization, reducing the
overhead quite a bit and allowing for better use of smaller
buffers.
Patch 7 changes the way we calculate frame padding cutoff. The
problem with big buffers is made much worse by the current padding
strategy where zero padding often can account for more than 90% of
the frames.
Patch 8 add some counters giving some insight into how well the
NCM/MBIM protocol works, supporting further tuning.
Patch 9 reduce the initial maximum buffer size from 32kB to 16kB
in an attempt to make the default better suit all. It is still
possible to tune this up again to the old fixed max, using the
new tuning knobs.
I must admit that I had higher hopes for this series before I
tested it on my own modems. One really unexpected result was
that one of the MBIM modems accepted the new rx buffer size we
set, but happily continued sending buffers of the same size as
before. Needless to say: This did not work very well...
So don't really expect to be able to use any values with any
given device. Firmware implementations are still... I don't
think I have words suitable for a public mailing list.
But I am hoping this will help the many users who have had success
rebuilding the driver with lower fixed limits.
Please test and/or comment!"
Changes:
** RFC -> v1 **
Patch 10 - a follow-up to a comment Joe Perches made in November
2013. I don't always forget :-)
Patch 11 - removes the redundant "connected" driver state, and the
associated .check_connect callbacks.
** v1 -> v2 **
Patch 1 - Better handling of minium rx buffer size, based on feedback
from Oliver Neukum and Enrico Mioso
Patch 5 - fixed locking around timer interval update
Patch 9 - fixed whitespace error
Patch 12 - new fix related to the tuneable tx timer
...and spelling fixes all over the commit messages. I have finally
added a spelling hook, which I'm sure may of you will appreciate :-)
Bjørn Mork (12):
net: cdc_ncm: split out rx_max/tx_max update of setup
net: cdc_ncm: factor out one-time device initialization
net: cdc_ncm: split .bind device initialization
net: cdc_ncm: support rx_max/tx_max updates when running
net: cdc_ncm: use ethtool to tune coalescing settings
net: cdc_ncm: use true max dgram count for header estimates
net: cdc_ncm: set reasonable padding limits
net: cdc_ncm/cdc_mbim: adding NCM protocol statistics
net: cdc_ncm: use sane defaults for rx/tx buffers
net: cdc_ncm: fix argument alignment
net: cdc_ncm: remove redundant "disconnected" flag
net: cdc_ncm: do not start timer on an empty skb
drivers/net/usb/cdc_mbim.c | 6 +
drivers/net/usb/cdc_ncm.c | 590 ++++++++++++++++++++++++++++-----------
drivers/net/usb/huawei_cdc_ncm.c | 13 -
include/linux/usb/cdc_ncm.h | 33 ++-
4 files changed, 455 insertions(+), 187 deletions(-)
--
2.0.0.rc2
^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH net-next v2 01/12] net: cdc_ncm: split out rx_max/tx_max update of setup
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 02/12] net: cdc_ncm: factor out one-time device initialization Bjørn Mork
` (8 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Split out the part of setup dealing with updating the rx_max
and tx_max buffer sizes so that this code can be reused for
dynamically updating the limits.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 88 ++++++++++++++++++++++++++++++-----------------
1 file changed, 57 insertions(+), 31 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index d23bca57a23f..e5f5153bf8c6 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -65,6 +65,61 @@ static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
static struct usb_driver cdc_ncm_driver;
+/* 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, max, min;
+
+ /* clamp new_rx to sane values */
+ min = USB_CDC_NCM_NTB_MIN_IN_SIZE;
+ max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_RX, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize));
+
+ /* dwNtbInMaxSize spec violation? Use MIN size for both limits */
+ if (max < min) {
+ dev_warn(&dev->intf->dev, "dwNtbInMaxSize=%u is too small. Using %u\n",
+ le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize), min);
+ max = min;
+ }
+
+ 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);
+ }
+
+ /* inform device about NTB input size changes */
+ if (val != ctx->rx_max) {
+ __le32 dwNtbInMaxSize = cpu_to_le32(val);
+
+ dev_info(&dev->intf->dev, "setting rx_max = %u\n", val);
+ if (usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
+ USB_TYPE_CLASS | USB_DIR_OUT
+ | USB_RECIP_INTERFACE,
+ 0, iface_no, &dwNtbInMaxSize, 4) < 0)
+ dev_dbg(&dev->intf->dev, "Setting NTB Input Size failed\n");
+ else
+ ctx->rx_max = val;
+ }
+
+ /* clamp new_tx to sane values */
+ min = CDC_NCM_MIN_HDR_SIZE + ctx->max_datagram_size;
+ 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);
+ }
+ if (val != ctx->tx_max)
+ dev_info(&dev->intf->dev, "setting tx_max = %u\n", val);
+ ctx->tx_max = val;
+}
+
static int cdc_ncm_setup(struct usbnet *dev)
{
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -132,37 +187,8 @@ static int cdc_ncm_setup(struct usbnet *dev)
(ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
- /* verify maximum size of received NTB in bytes */
- if (ctx->rx_max < USB_CDC_NCM_NTB_MIN_IN_SIZE) {
- dev_dbg(&dev->intf->dev, "Using min receive length=%d\n",
- USB_CDC_NCM_NTB_MIN_IN_SIZE);
- ctx->rx_max = USB_CDC_NCM_NTB_MIN_IN_SIZE;
- }
-
- if (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX) {
- dev_dbg(&dev->intf->dev, "Using default maximum receive length=%d\n",
- CDC_NCM_NTB_MAX_SIZE_RX);
- ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX;
- }
-
- /* inform device about NTB input size changes */
- if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
- __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
-
- err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
- USB_TYPE_CLASS | USB_DIR_OUT
- | USB_RECIP_INTERFACE,
- 0, iface_no, &dwNtbInMaxSize, 4);
- if (err < 0)
- dev_dbg(&dev->intf->dev, "Setting NTB Input Size failed\n");
- }
-
- /* verify maximum size of transmitted NTB in bytes */
- if (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX) {
- dev_dbg(&dev->intf->dev, "Using default maximum transmit length=%d\n",
- CDC_NCM_NTB_MAX_SIZE_TX);
- ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
- }
+ /* clamp rx_max and tx_max and inform device */
+ cdc_ncm_update_rxtx_max(dev, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize), le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
/*
* verify that the structure alignment is:
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 02/12] net: cdc_ncm: factor out one-time device initialization
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 01/12] net: cdc_ncm: split out rx_max/tx_max update of setup Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 03/12] net: cdc_ncm: split .bind " Bjørn Mork
` (7 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Split the parts of setup dealing with device initialization from
parts just setting defaults for attributes which might be
changed after initialization.
Some commands of the device initialization are only allowed when
the data interface is in its disabled altsetting, so we must
separate them out of we are to allow rerunning parts of setup.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 251 ++++++++++++++++++++++++++++------------------
1 file changed, 155 insertions(+), 96 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index e5f5153bf8c6..b70e061e3473 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -120,19 +120,51 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
ctx->tx_max = val;
}
-static int cdc_ncm_setup(struct usbnet *dev)
+/* helpers for NCM and MBIM differences */
+static u8 cdc_ncm_flags(struct usbnet *dev)
{
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
- u32 val;
- u8 flags;
- u8 iface_no;
- int err;
- int eth_hlen;
- u16 mbim_mtu;
- u16 ntb_fmt_supported;
- __le16 max_datagram_size;
- iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
+ if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting) && ctx->mbim_desc)
+ return ctx->mbim_desc->bmNetworkCapabilities;
+ if (ctx->func_desc)
+ return ctx->func_desc->bmNetworkCapabilities;
+ return 0;
+}
+
+static int cdc_ncm_eth_hlen(struct usbnet *dev)
+{
+ if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting))
+ return 0;
+ return ETH_HLEN;
+}
+
+static u32 cdc_ncm_min_dgram_size(struct usbnet *dev)
+{
+ if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting))
+ return CDC_MBIM_MIN_DATAGRAM_SIZE;
+ return CDC_NCM_MIN_DATAGRAM_SIZE;
+}
+
+static u32 cdc_ncm_max_dgram_size(struct usbnet *dev)
+{
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+
+ if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting) && ctx->mbim_desc)
+ return le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize);
+ if (ctx->ether_desc)
+ return le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+ return CDC_NCM_MAX_DATAGRAM_SIZE;
+}
+
+/* initial one-time device setup. MUST be called with the data interface
+ * in altsetting 0
+ */
+static int cdc_ncm_init(struct usbnet *dev)
+{
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
+ int err;
err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
USB_TYPE_CLASS | USB_DIR_IN
@@ -144,7 +176,35 @@ static int cdc_ncm_setup(struct usbnet *dev)
return err; /* GET_NTB_PARAMETERS is required */
}
- /* read correct set of parameters according to device mode */
+ /* set CRC Mode */
+ if (cdc_ncm_flags(dev) & USB_CDC_NCM_NCAP_CRC_MODE) {
+ dev_dbg(&dev->intf->dev, "Setting CRC mode off\n");
+ err = usbnet_write_cmd(dev, USB_CDC_SET_CRC_MODE,
+ USB_TYPE_CLASS | USB_DIR_OUT
+ | USB_RECIP_INTERFACE,
+ USB_CDC_NCM_CRC_NOT_APPENDED,
+ iface_no, NULL, 0);
+ if (err < 0)
+ dev_err(&dev->intf->dev, "SET_CRC_MODE failed\n");
+ }
+
+ /* set NTB format, if both formats are supported.
+ *
+ * "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) {
+ 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
+ | USB_RECIP_INTERFACE,
+ USB_CDC_NCM_NTB16_FORMAT,
+ iface_no, NULL, 0);
+ if (err < 0)
+ dev_err(&dev->intf->dev, "SET_NTB_FORMAT failed\n");
+ }
+
+ /* set initial device values */
ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
@@ -152,43 +212,73 @@ static int cdc_ncm_setup(struct usbnet *dev)
ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
/* devices prior to NCM Errata shall set this field to zero */
ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
- ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
-
- /* there are some minor differences in NCM and MBIM defaults */
- if (cdc_ncm_comm_intf_is_mbim(ctx->control->cur_altsetting)) {
- if (!ctx->mbim_desc)
- return -EINVAL;
- eth_hlen = 0;
- flags = ctx->mbim_desc->bmNetworkCapabilities;
- ctx->max_datagram_size = le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize);
- if (ctx->max_datagram_size < CDC_MBIM_MIN_DATAGRAM_SIZE)
- ctx->max_datagram_size = CDC_MBIM_MIN_DATAGRAM_SIZE;
- } else {
- if (!ctx->func_desc)
- return -EINVAL;
- eth_hlen = ETH_HLEN;
- flags = ctx->func_desc->bmNetworkCapabilities;
- ctx->max_datagram_size = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
- if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
- ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
- }
-
- /* common absolute max for NCM and MBIM */
- if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE)
- ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE;
dev_dbg(&dev->intf->dev,
"dwNtbInMaxSize=%u dwNtbOutMaxSize=%u wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n",
ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
- ctx->tx_ndp_modulus, ctx->tx_max_datagrams, flags);
+ ctx->tx_ndp_modulus, ctx->tx_max_datagrams, cdc_ncm_flags(dev));
/* max count of tx datagrams */
if ((ctx->tx_max_datagrams == 0) ||
(ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
- /* clamp rx_max and tx_max and inform device */
- cdc_ncm_update_rxtx_max(dev, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize), le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
+ return 0;
+}
+
+/* set a new max datagram size */
+static void cdc_ncm_set_dgram_size(struct usbnet *dev, int new_size)
+{
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
+ __le16 max_datagram_size;
+ u16 mbim_mtu;
+ int err;
+
+ /* set default based on descriptors */
+ ctx->max_datagram_size = clamp_t(u32, new_size,
+ cdc_ncm_min_dgram_size(dev),
+ CDC_NCM_MAX_DATAGRAM_SIZE);
+
+ /* inform the device about the selected Max Datagram Size? */
+ if (!(cdc_ncm_flags(dev) & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE))
+ goto out;
+
+ /* read current mtu value from device */
+ err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE,
+ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+ 0, iface_no, &max_datagram_size, 2);
+ if (err < 0) {
+ dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n");
+ goto out;
+ }
+
+ if (le16_to_cpu(max_datagram_size) == ctx->max_datagram_size)
+ goto out;
+
+ max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
+ err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE,
+ USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
+ 0, iface_no, &max_datagram_size, 2);
+ if (err < 0)
+ dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n");
+
+out:
+ /* set MTU to max supported by the device if necessary */
+ dev->net->mtu = min_t(int, dev->net->mtu, ctx->max_datagram_size - cdc_ncm_eth_hlen(dev));
+
+ /* do not exceed operater preferred MTU */
+ if (ctx->mbim_extended_desc) {
+ mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
+ if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
+ dev->net->mtu = mbim_mtu;
+ }
+}
+
+static void cdc_ncm_fix_modulus(struct usbnet *dev)
+{
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ u32 val;
/*
* verify that the structure alignment is:
@@ -225,68 +315,26 @@ static int cdc_ncm_setup(struct usbnet *dev)
}
/* adjust TX-remainder according to NCM specification. */
- ctx->tx_remainder = ((ctx->tx_remainder - eth_hlen) &
+ ctx->tx_remainder = ((ctx->tx_remainder - cdc_ncm_eth_hlen(dev)) &
(ctx->tx_modulus - 1));
+}
- /* additional configuration */
-
- /* set CRC Mode */
- if (flags & USB_CDC_NCM_NCAP_CRC_MODE) {
- err = usbnet_write_cmd(dev, USB_CDC_SET_CRC_MODE,
- USB_TYPE_CLASS | USB_DIR_OUT
- | USB_RECIP_INTERFACE,
- USB_CDC_NCM_CRC_NOT_APPENDED,
- iface_no, NULL, 0);
- if (err < 0)
- dev_dbg(&dev->intf->dev, "Setting CRC mode off failed\n");
- }
-
- /* set NTB format, if both formats are supported */
- if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) {
- err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
- USB_TYPE_CLASS | USB_DIR_OUT
- | USB_RECIP_INTERFACE,
- USB_CDC_NCM_NTB16_FORMAT,
- iface_no, NULL, 0);
- if (err < 0)
- dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit failed\n");
- }
-
- /* inform the device about the selected Max Datagram Size */
- if (!(flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE))
- goto out;
-
- /* read current mtu value from device */
- err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE,
- USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
- 0, iface_no, &max_datagram_size, 2);
- if (err < 0) {
- dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n");
- goto out;
- }
+static int cdc_ncm_setup(struct usbnet *dev)
+{
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
- if (le16_to_cpu(max_datagram_size) == ctx->max_datagram_size)
- goto out;
+ /* initialize basic device settings */
+ cdc_ncm_init(dev);
- max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
- err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE,
- USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
- 0, iface_no, &max_datagram_size, 2);
- if (err < 0)
- dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n");
-
-out:
- /* set MTU to max supported by the device if necessary */
- if (dev->net->mtu > ctx->max_datagram_size - eth_hlen)
- dev->net->mtu = ctx->max_datagram_size - eth_hlen;
+ /* clamp rx_max and tx_max and inform device */
+ cdc_ncm_update_rxtx_max(dev, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize),
+ le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
- /* do not exceed operater preferred MTU */
- if (ctx->mbim_extended_desc) {
- mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
- if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
- dev->net->mtu = mbim_mtu;
- }
+ /* sanitize the modulus and remainder values */
+ cdc_ncm_fix_modulus(dev);
+ /* set max datagram size */
+ cdc_ncm_set_dgram_size(dev, cdc_ncm_max_dgram_size(dev));
return 0;
}
@@ -450,10 +498,21 @@ advance:
}
/* check if we got everything */
- if (!ctx->data || (!ctx->mbim_desc && !ctx->ether_desc)) {
- dev_dbg(&intf->dev, "CDC descriptors missing\n");
+ if (!ctx->data) {
+ dev_dbg(&intf->dev, "CDC Union missing and no IAD found\n");
goto error;
}
+ if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) {
+ if (!ctx->mbim_desc) {
+ dev_dbg(&intf->dev, "MBIM functional descriptor missing\n");
+ goto error;
+ }
+ } else {
+ if (!ctx->ether_desc || !ctx->func_desc) {
+ dev_dbg(&intf->dev, "NCM or ECM functional descriptors missing\n");
+ goto error;
+ }
+ }
/* claim data interface, if different from control */
if (ctx->data != ctx->control) {
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 03/12] net: cdc_ncm: split .bind device initialization
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 01/12] net: cdc_ncm: split out rx_max/tx_max update of setup Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 02/12] net: cdc_ncm: factor out one-time device initialization Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 04/12] net: cdc_ncm: support rx_max/tx_max updates when running Bjørn Mork
` (6 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Now that we have split out the part of the device setup
which MUST be done with the data interface in altsetting 0,
we can delay the rest of the initialization. This allows us
to move some of post-init buffer size config from bind to
the appropriate setup function.
The purpose of this refactoring is to collect all code
adjusting the rx_max and tx_max buffers in one place, so
that it is easier to call it from multiple call sites.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index b70e061e3473..7a3de73c8ded 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -118,6 +118,21 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
if (val != ctx->tx_max)
dev_info(&dev->intf->dev, "setting tx_max = %u\n", val);
ctx->tx_max = val;
+
+ /* Adding a pad byte here if necessary simplifies the handling
+ * in cdc_ncm_fill_tx_frame, making tx_max always represent
+ * the real skb max size.
+ *
+ * We cannot use dev->maxpacket here because this is called from
+ * .bind which is called before usbnet sets up dev->maxpacket
+ */
+ if (ctx->tx_max != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
+ ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
+ ctx->tx_max++;
+
+ /* usbnet use these values for sizing tx/rx queues */
+ dev->hard_mtu = ctx->tx_max;
+ dev->rx_urb_size = ctx->rx_max;
}
/* helpers for NCM and MBIM differences */
@@ -323,9 +338,6 @@ static int cdc_ncm_setup(struct usbnet *dev)
{
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
- /* initialize basic device settings */
- cdc_ncm_init(dev);
-
/* clamp rx_max and tx_max and inform device */
cdc_ncm_update_rxtx_max(dev, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize),
le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
@@ -532,8 +544,8 @@ advance:
goto error2;
}
- /* initialize data interface */
- if (cdc_ncm_setup(dev))
+ /* initialize basic device settings */
+ if (cdc_ncm_init(dev))
goto error2;
/* configure data interface */
@@ -562,18 +574,8 @@ advance:
dev_info(&intf->dev, "MAC-Address: %pM\n", dev->net->dev_addr);
}
- /* usbnet use these values for sizing tx/rx queues */
- dev->hard_mtu = ctx->tx_max;
- dev->rx_urb_size = ctx->rx_max;
-
- /* cdc_ncm_setup will override dwNtbOutMaxSize if it is
- * outside the sane range. Adding a pad byte here if necessary
- * simplifies the handling in cdc_ncm_fill_tx_frame, making
- * tx_max always represent the real skb max size.
- */
- if (ctx->tx_max != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
- ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
- ctx->tx_max++;
+ /* finish setting up the device specific data */
+ cdc_ncm_setup(dev);
return 0;
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 04/12] net: cdc_ncm: support rx_max/tx_max updates when running
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
` (2 preceding siblings ...)
2014-05-16 19:48 ` [PATCH net-next v2 03/12] net: cdc_ncm: split .bind " Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 05/12] net: cdc_ncm: use ethtool to tune coalescing settings Bjørn Mork
` (5 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Finish the rx_max/tx_max setup by flushing buffers and
informing usbnet about the changes. This way, the settings
can be modified while the netdev is up and running.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 7a3de73c8ded..2ec3790a4db8 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -89,11 +89,20 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
min, max, val);
}
+ /* usbnet use these values for sizing rx queues */
+ dev->rx_urb_size = val;
+
/* inform device about NTB input size changes */
if (val != ctx->rx_max) {
__le32 dwNtbInMaxSize = cpu_to_le32(val);
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
| USB_RECIP_INTERFACE,
@@ -117,7 +126,6 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
}
if (val != ctx->tx_max)
dev_info(&dev->intf->dev, "setting tx_max = %u\n", val);
- ctx->tx_max = val;
/* Adding a pad byte here if necessary simplifies the handling
* in cdc_ncm_fill_tx_frame, making tx_max always represent
@@ -126,13 +134,24 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
* We cannot use dev->maxpacket here because this is called from
* .bind which is called before usbnet sets up dev->maxpacket
*/
- if (ctx->tx_max != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
- ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
- ctx->tx_max++;
+ if (val != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
+ val % usb_maxpacket(dev->udev, dev->out, 1) == 0)
+ val++;
+
+ /* we might need to flush any pending tx buffers if running */
+ if (netif_running(dev->net) && val > ctx->tx_max) {
+ netif_tx_lock_bh(dev->net);
+ usbnet_start_xmit(NULL, dev->net);
+ ctx->tx_max = val;
+ netif_tx_unlock_bh(dev->net);
+ } else {
+ ctx->tx_max = val;
+ }
- /* usbnet use these values for sizing tx/rx queues */
dev->hard_mtu = ctx->tx_max;
- dev->rx_urb_size = ctx->rx_max;
+
+ /* max qlen depend on hard_mtu and rx_urb_size */
+ usbnet_update_max_qlen(dev);
}
/* helpers for NCM and MBIM differences */
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 05/12] net: cdc_ncm: use ethtool to tune coalescing settings
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
` (3 preceding siblings ...)
2014-05-16 19:48 ` [PATCH net-next v2 04/12] net: cdc_ncm: support rx_max/tx_max updates when running Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 06/12] net: cdc_ncm: use true max dgram count for header estimates Bjørn Mork
` (4 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Datagram coalescing is an integral part of the NCM and MBIM
protocols, intended to reduce the interrupt load primarily
on the device end of the USB link. As with all coalescing
solutions, there is a trade-off between buffering and
interrupts.
The current defaults are based on the assumption that device
side buffers should be the limiting factor. However, many
modern high speed LTE modems suffers from buffer-bloat,
making this assumption fail. This results in sub-optimal
performance due to excessive coalescing. And in cases where
such modems are connected to cheap embedded hosts there is
often severe buffer allocation issues, giving very noticeable
performance degradation .
A start on improving this is going from build time hard
coded limits to per device user configurable limits. The
ethtool coalescing API was selected as user interface
because, although the tuned values are buffer sizes, these
settings directly control datagram coalescing.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 71 +++++++++++++++++++++++++++++++++++++++++++--
include/linux/usb/cdc_ncm.h | 6 +++-
2 files changed, 74 insertions(+), 3 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 2ec3790a4db8..141dbec912be 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -65,6 +65,67 @@ static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
static struct usb_driver cdc_ncm_driver;
+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,
+ .get_link = usbnet_get_link,
+ .nway_reset = usbnet_nway_reset,
+ .get_drvinfo = usbnet_get_drvinfo,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_ts_info = ethtool_op_get_ts_info,
+ .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)
{
@@ -257,6 +318,9 @@ static int cdc_ncm_init(struct usbnet *dev)
(ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
+ /* initial coalescing timer interval */
+ ctx->timer_interval = CDC_NCM_TIMER_INTERVAL_USEC * NSEC_PER_USEC;
+
return 0;
}
@@ -596,6 +660,9 @@ advance:
/* finish setting up the device specific data */
cdc_ncm_setup(dev);
+ /* override ethtool_ops */
+ dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
+
return 0;
error2:
@@ -863,7 +930,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
ctx->tx_curr_skb = skb_out;
goto exit_no_skb;
- } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) {
+ } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0) && (ctx->timer_interval > 0)) {
/* wait for more frames */
/* push variables */
ctx->tx_curr_skb = skb_out;
@@ -915,7 +982,7 @@ static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
/* start timer, if not already started */
if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop)))
hrtimer_start(&ctx->tx_timer,
- ktime_set(0, CDC_NCM_TIMER_INTERVAL),
+ ktime_set(0, ctx->timer_interval),
HRTIMER_MODE_REL);
}
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index 55b6feead93b..5c1066b4dc41 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -72,7 +72,9 @@
/* Restart the timer, if amount of datagrams is less than given value */
#define CDC_NCM_RESTART_TIMER_DATAGRAM_CNT 3
#define CDC_NCM_TIMER_PENDING_CNT 2
-#define CDC_NCM_TIMER_INTERVAL (400UL * NSEC_PER_USEC)
+#define CDC_NCM_TIMER_INTERVAL_USEC 400UL
+#define CDC_NCM_TIMER_INTERVAL_MIN 5UL
+#define CDC_NCM_TIMER_INTERVAL_MAX (15UL * USEC_PER_SEC)
/* The following macro defines the minimum header space */
#define CDC_NCM_MIN_HDR_SIZE \
@@ -107,6 +109,8 @@ struct cdc_ncm_ctx {
spinlock_t mtx;
atomic_t stop;
+ u64 timer_interval;
+
u32 tx_timer_pending;
u32 tx_curr_frame_num;
u32 rx_max;
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 06/12] net: cdc_ncm: use true max dgram count for header estimates
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
` (4 preceding siblings ...)
2014-05-16 19:48 ` [PATCH net-next v2 05/12] net: cdc_ncm: use ethtool to tune coalescing settings Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 10/12] net: cdc_ncm: fix argument alignment Bjørn Mork
` (3 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Many newer NCM and MBIM devices will request a maximum tx
datagram count which is much smaller than our hard-coded
absolute max. We can reduce the overhead without sacrificing
any of the simplicity for these devices, by simply using the
true negotiated count in when calculated the maximum NTH and
NDP header sizes.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 9 ++++++---
include/linux/usb/cdc_ncm.h | 10 +---------
2 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 141dbec912be..b9b562b9128a 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -174,7 +174,7 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
}
/* clamp new_tx to sane values */
- min = CDC_NCM_MIN_HDR_SIZE + ctx->max_datagram_size;
+ 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 */
@@ -318,6 +318,9 @@ static int cdc_ncm_init(struct usbnet *dev)
(ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
+ /* set up maximum NDP size */
+ ctx->max_ndp_size = sizeof(struct usb_cdc_ncm_ndp16) + (ctx->tx_max_datagrams + 1) * sizeof(struct usb_cdc_ncm_dpe16);
+
/* initial coalescing timer interval */
ctx->timer_interval = CDC_NCM_TIMER_INTERVAL_USEC * NSEC_PER_USEC;
@@ -800,7 +803,7 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_
cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
/* verify that there is room for the NDP and the datagram (reserve) */
- if ((ctx->tx_max - skb->len - reserve) < CDC_NCM_NDP_SIZE)
+ if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size)
return NULL;
/* link to it */
@@ -810,7 +813,7 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_
nth16->wNdpIndex = cpu_to_le16(skb->len);
/* push a new empty NDP */
- ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, CDC_NCM_NDP_SIZE), 0, CDC_NCM_NDP_SIZE);
+ ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
ndp16->dwSignature = sign;
ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16));
return ndp16;
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index 5c1066b4dc41..60a44b8a464e 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -76,15 +76,6 @@
#define CDC_NCM_TIMER_INTERVAL_MIN 5UL
#define CDC_NCM_TIMER_INTERVAL_MAX (15UL * USEC_PER_SEC)
-/* The following macro defines the minimum header space */
-#define CDC_NCM_MIN_HDR_SIZE \
- (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
- (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
-
-#define CDC_NCM_NDP_SIZE \
- (sizeof(struct usb_cdc_ncm_ndp16) + \
- (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
-
#define cdc_ncm_comm_intf_is_mbim(x) ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
(x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)
#define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
@@ -110,6 +101,7 @@ struct cdc_ncm_ctx {
atomic_t stop;
u64 timer_interval;
+ u32 max_ndp_size;
u32 tx_timer_pending;
u32 tx_curr_frame_num;
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 07/12] net: cdc_ncm: set reasonable padding limits
[not found] ` <1400269709-18854-1-git-send-email-bjorn-yOkvZcmFvRU@public.gmane.org>
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 08/12] net: cdc_ncm/cdc_mbim: adding NCM protocol statistics Bjørn Mork
` (2 subsequent siblings)
3 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA, Alexey Orishko, Oliver Neukum,
Enrico Mioso, David Laight, Bjørn Mork
We pad frames larger than X to maximum size for devices which
don't need a ZLP after maximum sized frames. This allows the
device to optimize its transfers for one fixed buffer size.
X was arbitrarily set at 512 bytes regardless of real buffer
maximum, causing extreme overheads due to excessive padding of
larger tx buffers. Limit the padding to at most 3 full USB
packets, still allowing the overhead to payload ratio of 3/1.
Signed-off-by: Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
---
drivers/net/usb/cdc_ncm.c | 8 ++++++--
include/linux/usb/cdc_ncm.h | 1 +
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index b9b562b9128a..9592d4669435 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -213,6 +213,10 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
/* max qlen depend on hard_mtu and rx_urb_size */
usbnet_update_max_qlen(dev);
+
+ /* never pad more than 3 full USB packets per transfer */
+ ctx->min_tx_pkt = clamp_t(u16, ctx->tx_max - 3 * usb_maxpacket(dev->udev, dev->out, 1),
+ CDC_NCM_MIN_TX_PKT, ctx->tx_max);
}
/* helpers for NCM and MBIM differences */
@@ -947,7 +951,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
/* variables will be reset at next call */
}
- /* If collected data size is less or equal CDC_NCM_MIN_TX_PKT
+ /* If collected data size is less or equal ctx->min_tx_pkt
* bytes, we send buffers as it is. If we get more data, it
* would be more efficient for USB HS mobile device with DMA
* engine to receive a full size NTB, than canceling DMA
@@ -957,7 +961,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
* a ZLP after full sized NTBs.
*/
if (!(dev->driver_info->flags & FLAG_SEND_ZLP) &&
- skb_out->len > CDC_NCM_MIN_TX_PKT)
+ skb_out->len > ctx->min_tx_pkt)
memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0,
ctx->tx_max - skb_out->len);
else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0)
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index 60a44b8a464e..79de6724d398 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -115,6 +115,7 @@ struct cdc_ncm_ctx {
u16 tx_seq;
u16 rx_seq;
u16 connected;
+ u16 min_tx_pkt;
};
u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
--
2.0.0.rc2
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 08/12] net: cdc_ncm/cdc_mbim: adding NCM protocol statistics
[not found] ` <1400269709-18854-1-git-send-email-bjorn-yOkvZcmFvRU@public.gmane.org>
2014-05-16 19:48 ` [PATCH net-next v2 07/12] net: cdc_ncm: set reasonable padding limits Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 09/12] net: cdc_ncm: use sane defaults for rx/tx buffers Bjørn Mork
2014-05-17 2:40 ` [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool David Miller
3 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA, Alexey Orishko, Oliver Neukum,
Enrico Mioso, David Laight, Bjørn Mork
To have an idea of the effects of the protocol coalescing
it's useful to have some counters showing the different
aspects.
Due to the asymmetrical usbnet interface the netdev
rx_bytes counter has been counting real received payload,
while the tx_bytes counter has included the NCM/MBIM
framing overhead. This overhead can be many times the
payload because of the aggressive padding strategy of
this driver, and will vary a lot depending on device
and traffic.
With very few exceptions, users are only interested in
the payload size. Having an somewhat accurate payload
byte counter is particularly important for mobile
broadband devices, which many NCM devices and of course
all MBIM devices are. Users and userspace applications
will use this counter to monitor account quotas.
Having protocol specific counters for the overhead, we are
now able to correct the tx_bytes netdev counter so that
it shows the real payload
Signed-off-by: Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
---
drivers/net/usb/cdc_mbim.c | 6 +++
drivers/net/usb/cdc_ncm.c | 91 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/usb/cdc_ncm.h | 11 ++++++
3 files changed, 108 insertions(+)
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index bc23273d0455..5ee7a1dbc023 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -420,6 +420,7 @@ static int cdc_mbim_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
struct usb_cdc_ncm_dpe16 *dpe16;
int ndpoffset;
int loopcount = 50; /* arbitrary max preventing infinite loop */
+ u32 payload = 0;
u8 *c;
u16 tci;
@@ -482,6 +483,7 @@ next_ndp:
if (!skb)
goto error;
usbnet_skb_return(dev, skb);
+ payload += len; /* count payload bytes in this NTB */
}
}
err_ndp:
@@ -490,6 +492,10 @@ err_ndp:
if (ndpoffset && loopcount--)
goto next_ndp;
+ /* update stats */
+ ctx->rx_overhead += skb_in->len - payload;
+ ctx->rx_ntbs++;
+
return 1;
error:
return 0;
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 9592d4669435..f4b439847d04 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -65,6 +65,68 @@ static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
static struct usb_driver cdc_ncm_driver;
+struct cdc_ncm_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define CDC_NCM_STAT(str, m) { \
+ .stat_string = str, \
+ .sizeof_stat = sizeof(((struct cdc_ncm_ctx *)0)->m), \
+ .stat_offset = offsetof(struct cdc_ncm_ctx, m) }
+#define CDC_NCM_SIMPLE_STAT(m) CDC_NCM_STAT(__stringify(m), m)
+
+static const struct cdc_ncm_stats cdc_ncm_gstrings_stats[] = {
+ CDC_NCM_SIMPLE_STAT(tx_reason_ntb_full),
+ CDC_NCM_SIMPLE_STAT(tx_reason_ndp_full),
+ CDC_NCM_SIMPLE_STAT(tx_reason_timeout),
+ CDC_NCM_SIMPLE_STAT(tx_reason_max_datagram),
+ CDC_NCM_SIMPLE_STAT(tx_overhead),
+ CDC_NCM_SIMPLE_STAT(tx_ntbs),
+ CDC_NCM_SIMPLE_STAT(rx_overhead),
+ CDC_NCM_SIMPLE_STAT(rx_ntbs),
+};
+
+static int cdc_ncm_get_sset_count(struct net_device __always_unused *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(cdc_ncm_gstrings_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void cdc_ncm_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats __always_unused *stats,
+ u64 *data)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ int i;
+ char *p = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(cdc_ncm_gstrings_stats); i++) {
+ p = (char *)ctx + cdc_ncm_gstrings_stats[i].stat_offset;
+ data[i] = (cdc_ncm_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+}
+
+static void cdc_ncm_get_strings(struct net_device __always_unused *netdev, u32 stringset, u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ARRAY_SIZE(cdc_ncm_gstrings_stats); i++) {
+ memcpy(p, cdc_ncm_gstrings_stats[i].stat_string, ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ }
+}
+
static int cdc_ncm_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec)
{
@@ -122,6 +184,9 @@ static const struct ethtool_ops cdc_ncm_ethtool_ops = {
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_ts_info = ethtool_op_get_ts_info,
+ .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,
};
@@ -862,6 +927,9 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
/* count total number of frames in this NTB */
ctx->tx_curr_frame_num = 0;
+
+ /* recent payload counter for this skb_out */
+ ctx->tx_curr_frame_payload = 0;
}
for (n = ctx->tx_curr_frame_num; n < ctx->tx_max_datagrams; n++) {
@@ -899,6 +967,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
ctx->tx_rem_sign = sign;
skb = NULL;
ready2send = 1;
+ ctx->tx_reason_ntb_full++; /* count reason for transmitting */
}
break;
}
@@ -912,12 +981,14 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len);
ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16));
memcpy(skb_put(skb_out, skb->len), skb->data, skb->len);
+ ctx->tx_curr_frame_payload += skb->len; /* count real tx payload data */
dev_kfree_skb_any(skb);
skb = NULL;
/* send now if this NDP is full */
if (index >= CDC_NCM_DPT_DATAGRAMS_MAX) {
ready2send = 1;
+ ctx->tx_reason_ndp_full++; /* count reason for transmitting */
break;
}
}
@@ -947,6 +1018,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
goto exit_no_skb;
} else {
+ if (n == ctx->tx_max_datagrams)
+ ctx->tx_reason_max_datagram++; /* count reason for transmitting */
/* frame goes out */
/* variables will be reset at next call */
}
@@ -974,6 +1047,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
/* return skb */
ctx->tx_curr_skb = NULL;
dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
+
+ /* keep private stats: framing overhead and number of NTBs */
+ ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload;
+ ctx->tx_ntbs++;
+
+ /* usbnet has already counted all the framing overhead.
+ * Adjust the stats so that the tx_bytes counter show real
+ * payload data instead.
+ */
+ dev->net->stats.tx_bytes -= skb_out->len - ctx->tx_curr_frame_payload;
+
return skb_out;
exit_no_skb:
@@ -1014,6 +1098,7 @@ static void cdc_ncm_txpath_bh(unsigned long param)
cdc_ncm_tx_timeout_start(ctx);
spin_unlock_bh(&ctx->mtx);
} else if (dev->net != NULL) {
+ ctx->tx_reason_timeout++; /* count reason for transmitting */
spin_unlock_bh(&ctx->mtx);
netif_tx_lock_bh(dev->net);
usbnet_start_xmit(NULL, dev->net);
@@ -1149,6 +1234,7 @@ int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
struct usb_cdc_ncm_dpe16 *dpe16;
int ndpoffset;
int loopcount = 50; /* arbitrary max preventing infinite loop */
+ u32 payload = 0;
ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
if (ndpoffset < 0)
@@ -1201,6 +1287,7 @@ next_ndp:
skb->data = ((u8 *)skb_in->data) + offset;
skb_set_tail_pointer(skb, len);
usbnet_skb_return(dev, skb);
+ payload += len; /* count payload bytes in this NTB */
}
}
err_ndp:
@@ -1209,6 +1296,10 @@ err_ndp:
if (ndpoffset && loopcount--)
goto next_ndp;
+ /* update stats */
+ ctx->rx_overhead += skb_in->len - payload;
+ ctx->rx_ntbs++;
+
return 1;
error:
return 0;
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index 79de6724d398..88d2d7f1820f 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -116,6 +116,17 @@ struct cdc_ncm_ctx {
u16 rx_seq;
u16 connected;
u16 min_tx_pkt;
+
+ /* statistics */
+ u32 tx_curr_frame_payload;
+ u32 tx_reason_ntb_full;
+ u32 tx_reason_ndp_full;
+ u32 tx_reason_timeout;
+ u32 tx_reason_max_datagram;
+ u64 tx_overhead;
+ u64 tx_ntbs;
+ u64 rx_overhead;
+ u64 rx_ntbs;
};
u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
--
2.0.0.rc2
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 09/12] net: cdc_ncm: use sane defaults for rx/tx buffers
[not found] ` <1400269709-18854-1-git-send-email-bjorn-yOkvZcmFvRU@public.gmane.org>
2014-05-16 19:48 ` [PATCH net-next v2 07/12] net: cdc_ncm: set reasonable padding limits Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 08/12] net: cdc_ncm/cdc_mbim: adding NCM protocol statistics Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-17 2:40 ` [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool David Miller
3 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA, Alexey Orishko, Oliver Neukum,
Enrico Mioso, David Laight, Bjørn Mork
Lots of devices request much larger buffers than reasonable. This
cause real problems for users of hosts with limited resources.
Reducing the default buffer size to 16kB for such devices is
a reasonable trade-off between allowing them to aggregate traffic
and avoiding memory exhaustion on resource restrained hosts.
Signed-off-by: Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
---
drivers/net/usb/cdc_ncm.c | 12 ++++++++++--
include/linux/usb/cdc_ncm.h | 4 ++++
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index f4b439847d04..bb53abe1f3a1 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -492,10 +492,18 @@ static void cdc_ncm_fix_modulus(struct usbnet *dev)
static int cdc_ncm_setup(struct usbnet *dev)
{
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ u32 def_rx, def_tx;
+
+ /* be conservative when selecting intial buffer size to
+ * increase the number of hosts this will work for
+ */
+ def_rx = min_t(u32, CDC_NCM_NTB_DEF_SIZE_RX,
+ le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize));
+ def_tx = min_t(u32, CDC_NCM_NTB_DEF_SIZE_TX,
+ le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
/* clamp rx_max and tx_max and inform device */
- cdc_ncm_update_rxtx_max(dev, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize),
- le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
+ cdc_ncm_update_rxtx_max(dev, def_rx, def_tx);
/* sanitize the modulus and remainder values */
cdc_ncm_fix_modulus(dev);
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index 88d2d7f1820f..cde506731c48 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -52,6 +52,10 @@
#define CDC_NCM_NTB_MAX_SIZE_TX 32768 /* bytes */
#define CDC_NCM_NTB_MAX_SIZE_RX 32768 /* bytes */
+/* Initial NTB length */
+#define CDC_NCM_NTB_DEF_SIZE_TX 16384 /* bytes */
+#define CDC_NCM_NTB_DEF_SIZE_RX 16384 /* bytes */
+
/* Minimum value for MaxDatagramSize, ch. 6.2.9 */
#define CDC_NCM_MIN_DATAGRAM_SIZE 1514 /* bytes */
--
2.0.0.rc2
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 10/12] net: cdc_ncm: fix argument alignment
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
` (5 preceding siblings ...)
2014-05-16 19:48 ` [PATCH net-next v2 06/12] net: cdc_ncm: use true max dgram count for header estimates Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 11/12] net: cdc_ncm: remove redundant "disconnected" flag Bjørn Mork
` (2 subsequent siblings)
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Reported-by: Joe Perches <joe@perches.com>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index bb53abe1f3a1..1d1ff2fa8ae1 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1327,14 +1327,14 @@ cdc_ncm_speed_change(struct usbnet *dev,
*/
if ((tx_speed > 1000000) && (rx_speed > 1000000)) {
netif_info(dev, link, dev->net,
- "%u mbit/s downlink %u mbit/s uplink\n",
- (unsigned int)(rx_speed / 1000000U),
- (unsigned int)(tx_speed / 1000000U));
+ "%u mbit/s downlink %u mbit/s uplink\n",
+ (unsigned int)(rx_speed / 1000000U),
+ (unsigned int)(tx_speed / 1000000U));
} else {
netif_info(dev, link, dev->net,
- "%u kbit/s downlink %u kbit/s uplink\n",
- (unsigned int)(rx_speed / 1000U),
- (unsigned int)(tx_speed / 1000U));
+ "%u kbit/s downlink %u kbit/s uplink\n",
+ (unsigned int)(rx_speed / 1000U),
+ (unsigned int)(tx_speed / 1000U));
}
}
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 11/12] net: cdc_ncm: remove redundant "disconnected" flag
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
` (6 preceding siblings ...)
2014-05-16 19:48 ` [PATCH net-next v2 10/12] net: cdc_ncm: fix argument alignment Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 12/12] net: cdc_ncm: do not start timer on an empty skb Bjørn Mork
[not found] ` <1400269709-18854-1-git-send-email-bjorn-yOkvZcmFvRU@public.gmane.org>
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
Calling netif_carrier_{on,off} is sufficient. There is no need
to duplicate the carrier state in a driver specific flag.
Acked-by: Enrico Mioso <mrkiko.rs@gmail.com>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 19 ++-----------------
drivers/net/usb/huawei_cdc_ncm.c | 13 -------------
include/linux/usb/cdc_ncm.h | 1 -
3 files changed, 2 insertions(+), 31 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 1d1ff2fa8ae1..783c4ed96395 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1364,11 +1364,10 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
* USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
* sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
*/
- ctx->connected = le16_to_cpu(event->wValue);
netif_info(dev, link, dev->net,
"network connection: %sconnected\n",
- ctx->connected ? "" : "dis");
- usbnet_link_change(dev, ctx->connected, 0);
+ !!event->wValue ? "" : "dis");
+ usbnet_link_change(dev, !!event->wValue, 0);
break;
case USB_CDC_NOTIFY_SPEED_CHANGE:
@@ -1388,23 +1387,11 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
}
}
-static int cdc_ncm_check_connect(struct usbnet *dev)
-{
- struct cdc_ncm_ctx *ctx;
-
- ctx = (struct cdc_ncm_ctx *)dev->data[0];
- if (ctx == NULL)
- return 1; /* disconnected */
-
- return !ctx->connected;
-}
-
static const struct driver_info cdc_ncm_info = {
.description = "CDC NCM",
.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET,
.bind = cdc_ncm_bind,
.unbind = cdc_ncm_unbind,
- .check_connect = cdc_ncm_check_connect,
.manage_power = usbnet_manage_power,
.status = cdc_ncm_status,
.rx_fixup = cdc_ncm_rx_fixup,
@@ -1418,7 +1405,6 @@ static const struct driver_info wwan_info = {
| FLAG_WWAN,
.bind = cdc_ncm_bind,
.unbind = cdc_ncm_unbind,
- .check_connect = cdc_ncm_check_connect,
.manage_power = usbnet_manage_power,
.status = cdc_ncm_status,
.rx_fixup = cdc_ncm_rx_fixup,
@@ -1432,7 +1418,6 @@ static const struct driver_info wwan_noarp_info = {
| FLAG_WWAN | FLAG_NOARP,
.bind = cdc_ncm_bind,
.unbind = cdc_ncm_unbind,
- .check_connect = cdc_ncm_check_connect,
.manage_power = usbnet_manage_power,
.status = cdc_ncm_status,
.rx_fixup = cdc_ncm_rx_fixup,
diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c
index 312178d7b698..f9822bc75425 100644
--- a/drivers/net/usb/huawei_cdc_ncm.c
+++ b/drivers/net/usb/huawei_cdc_ncm.c
@@ -172,24 +172,11 @@ err:
return ret;
}
-static int huawei_cdc_ncm_check_connect(struct usbnet *usbnet_dev)
-{
- struct cdc_ncm_ctx *ctx;
-
- ctx = (struct cdc_ncm_ctx *)usbnet_dev->data[0];
-
- if (ctx == NULL)
- return 1; /* disconnected */
-
- return !ctx->connected;
-}
-
static const struct driver_info huawei_cdc_ncm_info = {
.description = "Huawei CDC NCM device",
.flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
.bind = huawei_cdc_ncm_bind,
.unbind = huawei_cdc_ncm_unbind,
- .check_connect = huawei_cdc_ncm_check_connect,
.manage_power = huawei_cdc_ncm_manage_power,
.rx_fixup = cdc_ncm_rx_fixup,
.tx_fixup = cdc_ncm_tx_fixup,
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index cde506731c48..8c5e38819828 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -118,7 +118,6 @@ struct cdc_ncm_ctx {
u16 tx_ndp_modulus;
u16 tx_seq;
u16 rx_seq;
- u16 connected;
u16 min_tx_pkt;
/* statistics */
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* [PATCH net-next v2 12/12] net: cdc_ncm: do not start timer on an empty skb
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
` (7 preceding siblings ...)
2014-05-16 19:48 ` [PATCH net-next v2 11/12] net: cdc_ncm: remove redundant "disconnected" flag Bjørn Mork
@ 2014-05-16 19:48 ` Bjørn Mork
[not found] ` <1400269709-18854-1-git-send-email-bjorn-yOkvZcmFvRU@public.gmane.org>
9 siblings, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-16 19:48 UTC (permalink / raw)
To: netdev
Cc: linux-usb, Alexey Orishko, Oliver Neukum, Enrico Mioso,
David Laight, Bjørn Mork
We can end up with a freshly allocated tx_curr_skb with no frames
in it. In this case it does not make any sense to start the timer.
This avoids the timer periodically trying to start tx when there
is nothing in the queue.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 783c4ed96395..2d0caf1eea25 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1069,8 +1069,8 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
return skb_out;
exit_no_skb:
- /* Start timer, if there is a remaining skb */
- if (ctx->tx_curr_skb != NULL)
+ /* Start timer, if there is a remaining non-empty skb */
+ if (ctx->tx_curr_skb != NULL && n > 0)
cdc_ncm_tx_timeout_start(ctx);
return NULL;
}
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
[not found] ` <1400269709-18854-1-git-send-email-bjorn-yOkvZcmFvRU@public.gmane.org>
` (2 preceding siblings ...)
2014-05-16 19:48 ` [PATCH net-next v2 09/12] net: cdc_ncm: use sane defaults for rx/tx buffers Bjørn Mork
@ 2014-05-17 2:40 ` David Miller
[not found] ` <20140516.224032.2301577488192248796.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
3 siblings, 1 reply; 23+ messages in thread
From: David Miller @ 2014-05-17 2:40 UTC (permalink / raw)
To: bjorn-yOkvZcmFvRU
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA,
alexey.orishko-Re5JQEeQqe8AvxtiuMwx3w,
oliver-GvhC2dPhHPQdnm+yROfE0A, mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w,
David.Laight-ZS65k/vG3HxXrIkS9f7CXA
From: Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
Date: Fri, 16 May 2014 21:48:17 +0200
> Quoting the previous description of this series (skip to the
> changelog below if you only want a summary of the changes):
Ok I'm fine with this, applied to net-next.
Just make doubly sure that you will be ok, for a long time, with using
the ethtool coalescing interface for configuring this because you'll
really be stuck with this forever.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
[not found] ` <20140516.224032.2301577488192248796.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
@ 2014-05-17 6:46 ` Bjørn Mork
[not found] ` <87d2fcoqay.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
0 siblings, 1 reply; 23+ messages in thread
From: Bjørn Mork @ 2014-05-17 6:46 UTC (permalink / raw)
To: David Miller
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA,
alexey.orishko-Re5JQEeQqe8AvxtiuMwx3w,
oliver-GvhC2dPhHPQdnm+yROfE0A, mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w,
David.Laight-ZS65k/vG3HxXrIkS9f7CXA
David Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> writes:
> From: Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
> Date: Fri, 16 May 2014 21:48:17 +0200
>
>> Quoting the previous description of this series (skip to the
>> changelog below if you only want a summary of the changes):
>
> Ok I'm fine with this, applied to net-next.
Thanks.
> Just make doubly sure that you will be ok, for a long time, with using
> the ethtool coalescing interface for configuring this because you'll
> really be stuck with this forever.
Yes, I am painfull aware of that. So I was hoping someone would jump at
this and say something like "That's not the way to do it. Use the foo
interface instead. It's made for stuff like this".
Let's see if having it in net-next makes anyone react.
Bjørn
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
[not found] ` <87d2fcoqay.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
@ 2014-05-18 1:19 ` Peter Stuge
2014-05-18 9:57 ` Enrico Mioso
0 siblings, 1 reply; 23+ messages in thread
From: Peter Stuge @ 2014-05-18 1:19 UTC (permalink / raw)
To: Bjørn Mork
Cc: David Miller, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
alexey.orishko-Re5JQEeQqe8AvxtiuMwx3w,
oliver-GvhC2dPhHPQdnm+yROfE0A, mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w,
David.Laight-ZS65k/vG3HxXrIkS9f7CXA
Bjørn Mork wrote:
> > Just make doubly sure that you will be ok, for a long time, with using
> > the ethtool coalescing interface for configuring this because you'll
> > really be stuck with this forever.
>
> Yes, I am painfull aware of that. So I was hoping someone would jump at
> this and say something like "That's not the way to do it. Use the foo
> interface instead. It's made for stuff like this".
sysfs?
//Peter
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
2014-05-18 1:19 ` Peter Stuge
@ 2014-05-18 9:57 ` Enrico Mioso
[not found] ` <alpine.LNX.2.03.1405181155310.7743-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
0 siblings, 1 reply; 23+ messages in thread
From: Enrico Mioso @ 2014-05-18 9:57 UTC (permalink / raw)
To: Bjørn Mork, David Miller, netdev, linux-usb, alexey.orishko,
oliver, David.Laight
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1303 bytes --]
Or a set of module parameters, allowing them to be tuned at run-time via (e.g.)
the param directory of the module in sysfs?
Yes, I imagine it's not the best solution.
On Sun, 18 May 2014, Peter Stuge wrote:
==Date: Sun, 18 May 2014 03:19:17
==From: Peter Stuge <peter@stuge.se>
==Reply-To: Bjørn Mork <bjorn@mork.no>, David Miller <davem@davemloft.net>,
== netdev@vger.kernel.org, linux-usb@vger.kernel.org,
== alexey.orishko@gmail.com, oliver@neukum.org, mrkiko.rs@gmail.com,
== David.Laight@aculab.com
==To: Bjørn Mork <bjorn@mork.no>
==Cc: David Miller <davem@davemloft.net>, netdev@vger.kernel.org,
== linux-usb@vger.kernel.org, alexey.orishko@gmail.com, oliver@neukum.org,
== mrkiko.rs@gmail.com, David.Laight@aculab.com
==Subject: Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats
== using ethtool
==
==Bjørn Mork wrote:
==> > Just make doubly sure that you will be ok, for a long time, with using
==> > the ethtool coalescing interface for configuring this because you'll
==> > really be stuck with this forever.
==>
==> Yes, I am painfull aware of that. So I was hoping someone would jump at
==> this and say something like "That's not the way to do it. Use the foo
==> interface instead. It's made for stuff like this".
==
==sysfs?
==
==
==//Peter
==
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
[not found] ` <alpine.LNX.2.03.1405181155310.7743-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2014-05-18 14:50 ` Bjørn Mork
2014-05-18 17:10 ` Lars Melin
2014-05-18 22:08 ` David Miller
0 siblings, 2 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-18 14:50 UTC (permalink / raw)
To: Peter Stuge, Enrico Mioso
Cc: David Miller, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
alexey.orishko-Re5JQEeQqe8AvxtiuMwx3w,
oliver-GvhC2dPhHPQdnm+yROfE0A,
David.Laight-JxhZ9S5GRejQT0dZR+AlfA
I could be wrong, but my impression is that the userspace API
preferences for network devices are
1. ethtool
2. sysfs
3. module param
..
99. ioctl
This is the primary reason why I was looking for someplace to put this
within the existing ethtool API. Using sysfs would have worked fine
too, I guess. But is there any real advantage, making it worth a
switch? I am all open to change to sysfs instead before v3.16 is
released, *if* there are good reasons to do it. And no objections. But
I do want more of a reason than the fact that it can be done. Maybe I
got the preferred order wrong?
I ruled out module parameters early because I believe there are real use
cases requiring different settings per device. The limited host system
resources will of course affect all devices on a single host the same
way. But not all devices can cope with the reduced buffers. So there
should be some way to tune two devices connected to the same host
differently.
I am not going to say anything about ioctls :-)
Bjørn
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
2014-05-18 14:50 ` Bjørn Mork
@ 2014-05-18 17:10 ` Lars Melin
2014-05-19 7:36 ` Bjørn Mork
2014-05-18 22:08 ` David Miller
1 sibling, 1 reply; 23+ messages in thread
From: Lars Melin @ 2014-05-18 17:10 UTC (permalink / raw)
To: Bjørn Mork, Peter Stuge, Enrico Mioso
Cc: David Miller, netdev, linux-usb, alexey.orishko, oliver,
David.Laight
On 2014-05-18 21:50, Bjørn Mork wrote:
> I could be wrong, but my impression is that the userspace API
> preferences for network devices are
>
> 1. ethtool
> 2. sysfs
> 3. module param
> ..
> 99. ioctl
>
> This is the primary reason why I was looking for someplace to put this
> within the existing ethtool API. Using sysfs would have worked fine
> too, I guess. But is there any real advantage, making it worth a
> switch? I am all open to change to sysfs instead before v3.16 is
> released, *if* there are good reasons to do it. And no objections. But
> I do want more of a reason than the fact that it can be done. Maybe I
> got the preferred order wrong?
>
> I ruled out module parameters early because I believe there are real use
> cases requiring different settings per device. The limited host system
> resources will of course affect all devices on a single host the same
> way. But not all devices can cope with the reduced buffers. So there
> should be some way to tune two devices connected to the same host
> differently.
>
> I am not going to say anything about ioctls :-)
>
>
> Bjørn
> --
Your target audience is embedded systems with limited cpu power and
buffer memory, right?
If so, then you can't expect them to have ethtool included and their
developers are not likely to be happy over having to "waste" another
100KB in order to tune a 20KB driver.
My vote goes for sysfs.
/Lars
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
2014-05-18 14:50 ` Bjørn Mork
2014-05-18 17:10 ` Lars Melin
@ 2014-05-18 22:08 ` David Miller
1 sibling, 0 replies; 23+ messages in thread
From: David Miller @ 2014-05-18 22:08 UTC (permalink / raw)
To: bjorn
Cc: peter, mrkiko.rs, netdev, linux-usb, alexey.orishko, oliver,
David.Laight
From: Bjørn Mork <bjorn@mork.no>
Date: Sun, 18 May 2014 16:50:30 +0200
> I could be wrong, but my impression is that the userspace API
> preferences for network devices are
>
> 1. ethtool
> 2. sysfs
> 3. module param
> ..
> 99. ioctl
I would swap module param and ioctl, module params are the least
desirable interface and strongly discouraged.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
2014-05-18 17:10 ` Lars Melin
@ 2014-05-19 7:36 ` Bjørn Mork
2014-05-20 7:36 ` Bjørn Mork
[not found] ` <87egzqmd8h.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
0 siblings, 2 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-19 7:36 UTC (permalink / raw)
To: Lars Melin
Cc: Peter Stuge, Enrico Mioso, David Miller, netdev, linux-usb,
alexey.orishko, oliver, David.Laight
Lars Melin <larsm17@gmail.com> writes:
> Your target audience is embedded systems with limited cpu power and
> buffer memory, right?
> If so, then you can't expect them to have ethtool included and their
> developers are not likely to be happy over having to "waste" another
> 100KB in order to tune a 20KB driver.
> My vote goes for sysfs.
That's of course a very good point.
I will argue that you often need ethtool anyway for basic stuff like
forcing duplex/speed, enabling debug messages, turning on/off pause
frames etc. But I don't doubt you know what you are talking about here
:-) So I guess many small embedded devices don't include an ethtool
binary by default. I do wonder how much we should adapt to that though?
I understand that you don't see it this way, but others might actually
see it as an advantage if we're forcing ethtool onto these devices...
Anyway, I'll start looking at an alternative sysfs implementation so we
can discuss this in terms of actual code.
But I will definitely leave the statistics in any case, so if you want
that then you will need ethtool.
Bjørn
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
2014-05-19 7:36 ` Bjørn Mork
@ 2014-05-20 7:36 ` Bjørn Mork
[not found] ` <87egzqmd8h.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
1 sibling, 0 replies; 23+ messages in thread
From: Bjørn Mork @ 2014-05-20 7:36 UTC (permalink / raw)
To: Lars Melin
Cc: Peter Stuge, Enrico Mioso, David Miller, netdev, linux-usb,
alexey.orishko, oliver, David.Laight, Greg Suarez
[-- Attachment #1: Type: text/plain, Size: 2659 bytes --]
[adding Greg Suarez to the Cc list after noticing that he was missing
from this thread. Sorry Greg, that was not my intention. This
discussion is just as relevant to cdc_mbim as to cdc_ncm, defining a
new common userspace API for all the cdc_ncm based drivers]
Bjørn Mork <bjorn@mork.no> writes:
> Lars Melin <larsm17@gmail.com> writes:
>
>> Your target audience is embedded systems with limited cpu power and
>> buffer memory, right?
>> If so, then you can't expect them to have ethtool included and their
>> developers are not likely to be happy over having to "waste" another
>> 100KB in order to tune a 20KB driver.
>> My vote goes for sysfs.
>
> That's of course a very good point.
>
> I will argue that you often need ethtool anyway for basic stuff like
> forcing duplex/speed, enabling debug messages, turning on/off pause
> frames etc. But I don't doubt you know what you are talking about here
> :-) So I guess many small embedded devices don't include an ethtool
> binary by default. I do wonder how much we should adapt to that though?
> I understand that you don't see it this way, but others might actually
> see it as an advantage if we're forcing ethtool onto these devices...
>
> Anyway, I'll start looking at an alternative sysfs implementation so we
> can discuss this in terms of actual code.
As this is just a very informal RFC, I'm just attaching the patch to
this mail. Please test and/or comment.
The patch works for me. It doesn't remove the ethtool coalescing
support, but I will do that in the final submission if we decide to go
for this sysfs interface instead.
Example output:
bjorn@nemi:~$ grep . /sys/class/net/wwan0/cdc_ncm/*
/sys/class/net/wwan0/cdc_ncm/rx_max:16384
/sys/class/net/wwan0/cdc_ncm/tx_max:4096
/sys/class/net/wwan0/cdc_ncm/tx_timer_usecs:400
I should probably also add a bit more sanity checking of the input for
the final submission. Maybe even make sure the buffers match the
alignment? Or should that be up to the user?
But we could add information about the device alignment requirements so
that the end user (or userspace application) can make informed decisions.
The whole NTB parameter struct is vital information which is currently only
available for userspace in a debug log message. Exporting it as a set
of sysfs read only attributes would be nice. Maybe? Or am I just
overdoing things now?
It's also tempting to add the 'timer restart count' to this API. I left
it out of the ethtool based version because I couldn't make it fit
anywhere. But it is part of the driver's frame aggregation algorithm.
Bjørn
[-- Attachment #2: 0001-net-cdc_ncm-add-sysfs-support-for-buffer-tuning.patch --]
[-- Type: text/x-diff, Size: 6729 bytes --]
>From 017c9fc8702132ed76b9c28a196203b1788ef4c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= <bjorn@mork.no>
Date: Mon, 19 May 2014 16:08:49 +0200
Subject: [RFC] net: cdc_ncm: add sysfs support for buffer tuning
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Adding a sysfs group to the network device, allowing tuning of
buffers and tx timer.
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/cdc_ncm.c | 143 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 124 insertions(+), 19 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index ad2a386a6e92..30b943200ca3 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -191,11 +191,9 @@ static const struct ethtool_ops cdc_ncm_ethtool_ops = {
.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,10 +208,125 @@ 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);
+
+ 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;
+}
+
+/* sysfs attributes */
+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_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(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);
+
+static struct attribute *cdc_ncm_sysfs_attrs[] = {
+ &dev_attr_rx_max.attr,
+ &dev_attr_tx_max.attr,
+ &dev_attr_tx_timer_usecs.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);
/* usbnet use these values for sizing rx queues */
dev->rx_urb_size = val;
@@ -238,18 +351,7 @@ 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);
- }
+ 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);
@@ -743,6 +845,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:
--
2.0.0.rc2
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool
[not found] ` <87egzqmd8h.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
@ 2014-06-08 22:02 ` Ben Hutchings
0 siblings, 0 replies; 23+ messages in thread
From: Ben Hutchings @ 2014-06-08 22:02 UTC (permalink / raw)
To: Bjørn Mork
Cc: Lars Melin, Peter Stuge, Enrico Mioso, David Miller,
netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA,
alexey.orishko-Re5JQEeQqe8AvxtiuMwx3w,
oliver-GvhC2dPhHPQdnm+yROfE0A,
David.Laight-JxhZ9S5GRejQT0dZR+AlfA
[-- Attachment #1: Type: text/plain, Size: 1401 bytes --]
On Mon, 2014-05-19 at 09:36 +0200, Bjørn Mork wrote:
> Lars Melin <larsm17-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> writes:
>
> > Your target audience is embedded systems with limited cpu power and
> > buffer memory, right?
> > If so, then you can't expect them to have ethtool included and their
> > developers are not likely to be happy over having to "waste" another
> > 100KB in order to tune a 20KB driver.
> > My vote goes for sysfs.
>
> That's of course a very good point.
>
> I will argue that you often need ethtool anyway for basic stuff like
> forcing duplex/speed, enabling debug messages, turning on/off pause
> frames etc. But I don't doubt you know what you are talking about here
> :-) So I guess many small embedded devices don't include an ethtool
> binary by default. I do wonder how much we should adapt to that though?
> I understand that you don't see it this way, but others might actually
> see it as an advantage if we're forcing ethtool onto these devices...
[...]
By the way, ethtool can now be configured without pretty-printing of
register/EEPROM dumps. This reduces it in size from ~240K to ~60K.
If that's still not small enough, the answer might be to put a limited
reimplementation of ethtool in busybox, toybox or similar.
Ben.
--
Ben Hutchings
Never attribute to conspiracy what can adequately be explained by stupidity.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2014-06-08 22:02 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-16 19:48 [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 01/12] net: cdc_ncm: split out rx_max/tx_max update of setup Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 02/12] net: cdc_ncm: factor out one-time device initialization Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 03/12] net: cdc_ncm: split .bind " Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 04/12] net: cdc_ncm: support rx_max/tx_max updates when running Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 05/12] net: cdc_ncm: use ethtool to tune coalescing settings Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 06/12] net: cdc_ncm: use true max dgram count for header estimates Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 10/12] net: cdc_ncm: fix argument alignment Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 11/12] net: cdc_ncm: remove redundant "disconnected" flag Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 12/12] net: cdc_ncm: do not start timer on an empty skb Bjørn Mork
[not found] ` <1400269709-18854-1-git-send-email-bjorn-yOkvZcmFvRU@public.gmane.org>
2014-05-16 19:48 ` [PATCH net-next v2 07/12] net: cdc_ncm: set reasonable padding limits Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 08/12] net: cdc_ncm/cdc_mbim: adding NCM protocol statistics Bjørn Mork
2014-05-16 19:48 ` [PATCH net-next v2 09/12] net: cdc_ncm: use sane defaults for rx/tx buffers Bjørn Mork
2014-05-17 2:40 ` [PATCH net-next v2 00/12] cdc_ncm: add buffer tuning and stats using ethtool David Miller
[not found] ` <20140516.224032.2301577488192248796.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2014-05-17 6:46 ` Bjørn Mork
[not found] ` <87d2fcoqay.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
2014-05-18 1:19 ` Peter Stuge
2014-05-18 9:57 ` Enrico Mioso
[not found] ` <alpine.LNX.2.03.1405181155310.7743-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2014-05-18 14:50 ` Bjørn Mork
2014-05-18 17:10 ` Lars Melin
2014-05-19 7:36 ` Bjørn Mork
2014-05-20 7:36 ` Bjørn Mork
[not found] ` <87egzqmd8h.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
2014-06-08 22:02 ` Ben Hutchings
2014-05-18 22:08 ` David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).