aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2014-05-16 15:48:22 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-16 22:39:01 -0400
commit6c4e548ff36672eeb78f8288a2920d66fa4a6a66 (patch)
treefe2e6d17ffd63d02ee28d3a51e8a0b166ba1d311 /drivers/net/usb
parent68864abf08f06d7cbbabd03740beb383ccf5e5d5 (diff)
net: cdc_ncm: use ethtool to tune coalescing settings
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> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/cdc_ncm.c71
1 files changed, 69 insertions, 2 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);
65static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer); 65static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
66static struct usb_driver cdc_ncm_driver; 66static struct usb_driver cdc_ncm_driver;
67 67
68static int cdc_ncm_get_coalesce(struct net_device *netdev,
69 struct ethtool_coalesce *ec)
70{
71 struct usbnet *dev = netdev_priv(netdev);
72 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
73
74 /* assuming maximum sized dgrams and ignoring NDPs */
75 ec->rx_max_coalesced_frames = ctx->rx_max / ctx->max_datagram_size;
76 ec->tx_max_coalesced_frames = ctx->tx_max / ctx->max_datagram_size;
77
78 /* the timer will fire CDC_NCM_TIMER_PENDING_CNT times in a row */
79 ec->tx_coalesce_usecs = (ctx->timer_interval * CDC_NCM_TIMER_PENDING_CNT) / NSEC_PER_USEC;
80 return 0;
81}
82
83static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx);
84
85static int cdc_ncm_set_coalesce(struct net_device *netdev,
86 struct ethtool_coalesce *ec)
87{
88 struct usbnet *dev = netdev_priv(netdev);
89 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
90 u32 new_rx_max = ctx->rx_max;
91 u32 new_tx_max = ctx->tx_max;
92
93 /* assuming maximum sized dgrams and a single NDP */
94 if (ec->rx_max_coalesced_frames)
95 new_rx_max = ec->rx_max_coalesced_frames * ctx->max_datagram_size;
96 if (ec->tx_max_coalesced_frames)
97 new_tx_max = ec->tx_max_coalesced_frames * ctx->max_datagram_size;
98
99 if (ec->tx_coalesce_usecs &&
100 (ec->tx_coalesce_usecs < CDC_NCM_TIMER_INTERVAL_MIN * CDC_NCM_TIMER_PENDING_CNT ||
101 ec->tx_coalesce_usecs > CDC_NCM_TIMER_INTERVAL_MAX * CDC_NCM_TIMER_PENDING_CNT))
102 return -EINVAL;
103
104 spin_lock_bh(&ctx->mtx);
105 ctx->timer_interval = ec->tx_coalesce_usecs * NSEC_PER_USEC / CDC_NCM_TIMER_PENDING_CNT;
106 if (!ctx->timer_interval)
107 ctx->tx_timer_pending = 0;
108 spin_unlock_bh(&ctx->mtx);
109
110 /* inform device of new values */
111 if (new_rx_max != ctx->rx_max || new_tx_max != ctx->tx_max)
112 cdc_ncm_update_rxtx_max(dev, new_rx_max, new_tx_max);
113 return 0;
114}
115
116static const struct ethtool_ops cdc_ncm_ethtool_ops = {
117 .get_settings = usbnet_get_settings,
118 .set_settings = usbnet_set_settings,
119 .get_link = usbnet_get_link,
120 .nway_reset = usbnet_nway_reset,
121 .get_drvinfo = usbnet_get_drvinfo,
122 .get_msglevel = usbnet_get_msglevel,
123 .set_msglevel = usbnet_set_msglevel,
124 .get_ts_info = ethtool_op_get_ts_info,
125 .get_coalesce = cdc_ncm_get_coalesce,
126 .set_coalesce = cdc_ncm_set_coalesce,
127};
128
68/* handle rx_max and tx_max changes */ 129/* handle rx_max and tx_max changes */
69static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx) 130static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
70{ 131{
@@ -257,6 +318,9 @@ static int cdc_ncm_init(struct usbnet *dev)
257 (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX)) 318 (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
258 ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX; 319 ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
259 320
321 /* initial coalescing timer interval */
322 ctx->timer_interval = CDC_NCM_TIMER_INTERVAL_USEC * NSEC_PER_USEC;
323
260 return 0; 324 return 0;
261} 325}
262 326
@@ -596,6 +660,9 @@ advance:
596 /* finish setting up the device specific data */ 660 /* finish setting up the device specific data */
597 cdc_ncm_setup(dev); 661 cdc_ncm_setup(dev);
598 662
663 /* override ethtool_ops */
664 dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
665
599 return 0; 666 return 0;
600 667
601error2: 668error2:
@@ -863,7 +930,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
863 ctx->tx_curr_skb = skb_out; 930 ctx->tx_curr_skb = skb_out;
864 goto exit_no_skb; 931 goto exit_no_skb;
865 932
866 } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0)) { 933 } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0) && (ctx->timer_interval > 0)) {
867 /* wait for more frames */ 934 /* wait for more frames */
868 /* push variables */ 935 /* push variables */
869 ctx->tx_curr_skb = skb_out; 936 ctx->tx_curr_skb = skb_out;
@@ -915,7 +982,7 @@ static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
915 /* start timer, if not already started */ 982 /* start timer, if not already started */
916 if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop))) 983 if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop)))
917 hrtimer_start(&ctx->tx_timer, 984 hrtimer_start(&ctx->tx_timer,
918 ktime_set(0, CDC_NCM_TIMER_INTERVAL), 985 ktime_set(0, ctx->timer_interval),
919 HRTIMER_MODE_REL); 986 HRTIMER_MODE_REL);
920} 987}
921 988