aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2014-05-30 03:31:06 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-02 19:01:30 -0400
commit289507d3364f96f4b8814726917d572f71350d87 (patch)
tree5e42e9c43b768c0d8a4792cb898bcb8e40d4d511 /drivers/net/usb
parentf42763dbdf043c9996dfabf6d167eab28e016eb8 (diff)
net: cdc_ncm: use sysfs for rx/tx aggregation tuning
Attach a driver specific sysfs group to the netdev, and use it for the rx/tx aggregation variables. The datagram aggregation defined by the CDC NCM specification is specific to this device class (including CDC MBIM). Using the ethtool interrupt coalesce API as an interface to the aggregation parameters redefined that API in a driver specific and confusing way. A sysfs group - makes it clear that this is a driver specific userspace API, and - allows us to export the real values instead of some translated version, and - lets us include more aggregation variables which were impossible to force into the ethtool API. Additionally, using sysfs allows tuning the driver on space constrained hosts where userspace tools like ethtool are undesired. Suggested-by: Peter Stuge <peter@stuge.se> 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.c144
1 files changed, 125 insertions, 19 deletions
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 5bce86a0d063..631741c8ff22 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 = {
191 .set_coalesce = cdc_ncm_set_coalesce, 191 .set_coalesce = cdc_ncm_set_coalesce,
192}; 192};
193 193
194/* handle rx_max and tx_max changes */ 194static u32 cdc_ncm_check_rx_max(struct usbnet *dev, u32 new_rx)
195static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
196{ 195{
197 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; 196 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
198 u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
199 u32 val, max, min; 197 u32 val, max, min;
200 198
201 /* clamp new_rx to sane values */ 199 /* clamp new_rx to sane values */
@@ -210,10 +208,126 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
210 } 208 }
211 209
212 val = clamp_t(u32, new_rx, min, max); 210 val = clamp_t(u32, new_rx, min, max);
213 if (val != new_rx) { 211 if (val != new_rx)
214 dev_dbg(&dev->intf->dev, "rx_max must be in the [%u, %u] range. Using %u\n", 212 dev_dbg(&dev->intf->dev, "rx_max must be in the [%u, %u] range\n", min, max);
215 min, max, val); 213
216 } 214 return val;
215}
216
217static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx)
218{
219 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
220 u32 val, max, min;
221
222 /* clamp new_tx to sane values */
223 min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth16);
224 max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
225
226 /* some devices set dwNtbOutMaxSize too low for the above default */
227 min = min(min, max);
228
229 val = clamp_t(u32, new_tx, min, max);
230 if (val != new_tx)
231 dev_dbg(&dev->intf->dev, "tx_max must be in the [%u, %u] range\n", min, max);
232
233 return val;
234}
235
236static ssize_t cdc_ncm_show_rx_max(struct device *d, struct device_attribute *attr, char *buf)
237{
238 struct usbnet *dev = netdev_priv(to_net_dev(d));
239 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
240
241 return sprintf(buf, "%u\n", ctx->rx_max);
242}
243
244static ssize_t cdc_ncm_show_tx_max(struct device *d, struct device_attribute *attr, char *buf)
245{
246 struct usbnet *dev = netdev_priv(to_net_dev(d));
247 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
248
249 return sprintf(buf, "%u\n", ctx->tx_max);
250}
251
252static ssize_t cdc_ncm_show_tx_timer_usecs(struct device *d, struct device_attribute *attr, char *buf)
253{
254 struct usbnet *dev = netdev_priv(to_net_dev(d));
255 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
256
257 return sprintf(buf, "%u\n", ctx->timer_interval / (u32)NSEC_PER_USEC);
258}
259
260static ssize_t cdc_ncm_store_rx_max(struct device *d, struct device_attribute *attr, const char *buf, size_t len)
261{
262 struct usbnet *dev = netdev_priv(to_net_dev(d));
263 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
264 unsigned long val;
265
266 if (kstrtoul(buf, 0, &val) || cdc_ncm_check_rx_max(dev, val) != val)
267 return -EINVAL;
268
269 cdc_ncm_update_rxtx_max(dev, val, ctx->tx_max);
270 return len;
271}
272
273static ssize_t cdc_ncm_store_tx_max(struct device *d, struct device_attribute *attr, const char *buf, size_t len)
274{
275 struct usbnet *dev = netdev_priv(to_net_dev(d));
276 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
277 unsigned long val;
278
279 if (kstrtoul(buf, 0, &val) || cdc_ncm_check_tx_max(dev, val) != val)
280 return -EINVAL;
281
282 cdc_ncm_update_rxtx_max(dev, ctx->rx_max, val);
283 return len;
284}
285
286static ssize_t cdc_ncm_store_tx_timer_usecs(struct device *d, struct device_attribute *attr, const char *buf, size_t len)
287{
288 struct usbnet *dev = netdev_priv(to_net_dev(d));
289 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
290 ssize_t ret;
291 unsigned long val;
292
293 ret = kstrtoul(buf, 0, &val);
294 if (ret)
295 return ret;
296 if (val && (val < CDC_NCM_TIMER_INTERVAL_MIN || val > CDC_NCM_TIMER_INTERVAL_MAX))
297 return -EINVAL;
298
299 spin_lock_bh(&ctx->mtx);
300 ctx->timer_interval = val * NSEC_PER_USEC;
301 if (!ctx->timer_interval)
302 ctx->tx_timer_pending = 0;
303 spin_unlock_bh(&ctx->mtx);
304 return len;
305}
306
307static DEVICE_ATTR(rx_max, S_IRUGO | S_IWUSR, cdc_ncm_show_rx_max, cdc_ncm_store_rx_max);
308static DEVICE_ATTR(tx_max, S_IRUGO | S_IWUSR, cdc_ncm_show_tx_max, cdc_ncm_store_tx_max);
309static DEVICE_ATTR(tx_timer_usecs, S_IRUGO | S_IWUSR, cdc_ncm_show_tx_timer_usecs, cdc_ncm_store_tx_timer_usecs);
310
311static struct attribute *cdc_ncm_sysfs_attrs[] = {
312 &dev_attr_rx_max.attr,
313 &dev_attr_tx_max.attr,
314 &dev_attr_tx_timer_usecs.attr,
315 NULL,
316};
317
318static struct attribute_group cdc_ncm_sysfs_attr_group = {
319 .name = "cdc_ncm",
320 .attrs = cdc_ncm_sysfs_attrs,
321};
322
323/* handle rx_max and tx_max changes */
324static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
325{
326 struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
327 u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
328 u32 val;
329
330 val = cdc_ncm_check_rx_max(dev, new_rx);
217 331
218 /* inform device about NTB input size changes */ 332 /* inform device about NTB input size changes */
219 if (val != ctx->rx_max) { 333 if (val != ctx->rx_max) {
@@ -238,18 +352,7 @@ static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
238 usbnet_unlink_rx_urbs(dev); 352 usbnet_unlink_rx_urbs(dev);
239 } 353 }
240 354
241 /* clamp new_tx to sane values */ 355 val = cdc_ncm_check_tx_max(dev, new_tx);
242 min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth16);
243 max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
244
245 /* some devices set dwNtbOutMaxSize too low for the above default */
246 min = min(min, max);
247
248 val = clamp_t(u32, new_tx, min, max);
249 if (val != new_tx) {
250 dev_dbg(&dev->intf->dev, "tx_max must be in the [%u, %u] range. Using %u\n",
251 min, max, val);
252 }
253 if (val != ctx->tx_max) 356 if (val != ctx->tx_max)
254 dev_info(&dev->intf->dev, "setting tx_max = %u\n", val); 357 dev_info(&dev->intf->dev, "setting tx_max = %u\n", val);
255 358
@@ -749,6 +852,9 @@ advance:
749 /* override ethtool_ops */ 852 /* override ethtool_ops */
750 dev->net->ethtool_ops = &cdc_ncm_ethtool_ops; 853 dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
751 854
855 /* add our sysfs attrs */
856 dev->net->sysfs_groups[0] = &cdc_ncm_sysfs_attr_group;
857
752 return 0; 858 return 0;
753 859
754error2: 860error2: