Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: ncm: Add support to update wMaxSegmentSize via configfs

The max segment size is currently limited to the ethernet frame length of
the kernel which happens to be 1514 at this point in time. However the NCM
specification limits it to 64K for sixtenn bit NTB's. For peer to peer
connections, increasing the segment size gives better throughput.

Add support to configure this value before configfs symlink is created.
Also since the NTB Out/In buffer sizes are fixed at 16384 bytes, limit the
segment size to an upper cap of 8000 to allow at least a minimum of 2 MTU
sized datagrams to be aggregated.

Set the default MTU size for the ncm interface during function bind before
network interface is registered allowing MTU to be set in parity with
wMaxSegmentSize.

Update gadget documentation describing the new configfs property.

Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
Link: https://lore.kernel.org/r/20231221153216.18657-1-quic_kriskura@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Krishna Kurapati and committed by
Greg Kroah-Hartman
1900daee 68c26fe5

+79 -12
+11 -9
Documentation/usb/gadget-testing.rst
··· 448 448 The function name to use when creating the function directory is "ncm". 449 449 The NCM function provides these attributes in its function directory: 450 450 451 - =============== ================================================== 452 - ifname network device interface name associated with this 453 - function instance 454 - qmult queue length multiplier for high and super speed 455 - host_addr MAC address of host's end of this 456 - Ethernet over USB link 457 - dev_addr MAC address of device's end of this 458 - Ethernet over USB link 459 - =============== ================================================== 451 + =============== ================================================== 452 + ifname network device interface name associated with this 453 + function instance 454 + qmult queue length multiplier for high and super speed 455 + host_addr MAC address of host's end of this 456 + Ethernet over USB link 457 + dev_addr MAC address of device's end of this 458 + Ethernet over USB link 459 + max_segment_size Segment size required for P2P connections. This 460 + will set MTU to (max_segment_size - 14 bytes) 461 + =============== ================================================== 460 462 461 463 and after creating the functions/ncm.<instance name> they contain default 462 464 values: qmult is 5, dev_addr and host_addr are randomly selected.
+66 -3
drivers/usb/gadget/function/f_ncm.c
··· 103 103 /* Delay for the transmit to wait before sending an unfilled NTB frame. */ 104 104 #define TX_TIMEOUT_NSECS 300000 105 105 106 + /* 107 + * Although max mtu as dictated by u_ether is 15412 bytes, setting 108 + * max_segment_sizeto 15426 would not be efficient. If user chooses segment 109 + * size to be (>= 8192), then we can't aggregate more than one buffer in each 110 + * NTB (assuming each packet coming from network layer is >= 8192 bytes) as ep 111 + * maxpacket limit is 16384. So let max_segment_size be limited to 8000 to allow 112 + * at least 2 packets to be aggregated reducing wastage of NTB buffer space 113 + */ 114 + #define MAX_DATAGRAM_SIZE 8000 115 + 106 116 #define FORMATS_SUPPORTED (USB_CDC_NCM_NTB16_SUPPORTED | \ 107 117 USB_CDC_NCM_NTB32_SUPPORTED) 108 118 ··· 189 179 /* this descriptor actually adds value, surprise! */ 190 180 /* .iMACAddress = DYNAMIC */ 191 181 .bmEthernetStatistics = cpu_to_le32(0), /* no statistics */ 192 - .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN), 193 182 .wNumberMCFilters = cpu_to_le16(0), 194 183 .bNumberPowerFilters = 0, 195 184 }; ··· 1175 1166 struct sk_buff *skb2; 1176 1167 int ret = -EINVAL; 1177 1168 unsigned ntb_max = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize); 1178 - unsigned frame_max = le16_to_cpu(ecm_desc.wMaxSegmentSize); 1169 + unsigned frame_max; 1179 1170 const struct ndp_parser_opts *opts = ncm->parser_opts; 1180 1171 unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; 1181 1172 int dgram_counter; 1182 1173 int to_process = skb->len; 1174 + struct f_ncm_opts *ncm_opts; 1175 + 1176 + ncm_opts = container_of(port->func.fi, struct f_ncm_opts, func_inst); 1177 + frame_max = ncm_opts->max_segment_size; 1183 1178 1184 1179 parse_ntb: 1185 1180 tmp = (__le16 *)ntb_ptr; ··· 1443 1430 1444 1431 mutex_lock(&ncm_opts->lock); 1445 1432 gether_set_gadget(ncm_opts->net, cdev->gadget); 1446 - if (!ncm_opts->bound) 1433 + if (!ncm_opts->bound) { 1434 + ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN); 1447 1435 status = gether_register_netdev(ncm_opts->net); 1436 + } 1448 1437 mutex_unlock(&ncm_opts->lock); 1449 1438 1450 1439 if (status) ··· 1488 1473 ncm_data_nop_intf.bInterfaceNumber = status; 1489 1474 ncm_data_intf.bInterfaceNumber = status; 1490 1475 ncm_union_desc.bSlaveInterface0 = status; 1476 + 1477 + ecm_desc.wMaxSegmentSize = ncm_opts->max_segment_size; 1491 1478 1492 1479 status = -ENODEV; 1493 1480 ··· 1593 1576 /* f_ncm_opts_ifname */ 1594 1577 USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm); 1595 1578 1579 + static ssize_t ncm_opts_max_segment_size_show(struct config_item *item, 1580 + char *page) 1581 + { 1582 + struct f_ncm_opts *opts = to_f_ncm_opts(item); 1583 + u16 segment_size; 1584 + 1585 + mutex_lock(&opts->lock); 1586 + segment_size = opts->max_segment_size; 1587 + mutex_unlock(&opts->lock); 1588 + 1589 + return sysfs_emit(page, "%u\n", segment_size); 1590 + } 1591 + 1592 + static ssize_t ncm_opts_max_segment_size_store(struct config_item *item, 1593 + const char *page, size_t len) 1594 + { 1595 + struct f_ncm_opts *opts = to_f_ncm_opts(item); 1596 + u16 segment_size; 1597 + int ret; 1598 + 1599 + mutex_lock(&opts->lock); 1600 + if (opts->refcnt) { 1601 + ret = -EBUSY; 1602 + goto out; 1603 + } 1604 + 1605 + ret = kstrtou16(page, 0, &segment_size); 1606 + if (ret) 1607 + goto out; 1608 + 1609 + if (segment_size > MAX_DATAGRAM_SIZE) { 1610 + ret = -EINVAL; 1611 + goto out; 1612 + } 1613 + 1614 + opts->max_segment_size = segment_size; 1615 + ret = len; 1616 + out: 1617 + mutex_unlock(&opts->lock); 1618 + return ret; 1619 + } 1620 + 1621 + CONFIGFS_ATTR(ncm_opts_, max_segment_size); 1622 + 1596 1623 static struct configfs_attribute *ncm_attrs[] = { 1597 1624 &ncm_opts_attr_dev_addr, 1598 1625 &ncm_opts_attr_host_addr, 1599 1626 &ncm_opts_attr_qmult, 1600 1627 &ncm_opts_attr_ifname, 1628 + &ncm_opts_attr_max_segment_size, 1601 1629 NULL, 1602 1630 }; 1603 1631 ··· 1685 1623 kfree(opts); 1686 1624 return ERR_CAST(net); 1687 1625 } 1626 + opts->max_segment_size = cpu_to_le16(ETH_FRAME_LEN); 1688 1627 INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop); 1689 1628 1690 1629 descs[0] = &opts->ncm_os_desc;
+2
drivers/usb/gadget/function/u_ncm.h
··· 31 31 */ 32 32 struct mutex lock; 33 33 int refcnt; 34 + 35 + u16 max_segment_size; 34 36 }; 35 37 36 38 #endif /* U_NCM_H */