Currently, using f_ncm in a SuperSpeed Plus gadget results in an oops in config_ep_by_speed because ncm_set_alt passes in NULL ssp_descriptors. Fix this by defining new descriptors for SuperSpeed Plus. (We cannot re-use the existing definitions for the SuperSpeed descriptors, even though they are mostly the same, because they are not fixed initializers). Also fix reported bandwidth to match bandwidth reported for SuperSpeed. This calculation is already incorrect, because it returns 851 Mbps and NCM can already reach speeds in excess of 1.7 Gbps on a 5 Gbps port. But it's better to return 851 Mbps than 9 Mbps for SuperSpeed Plus. Tested: enabled f_ncm on a dwc3 gadget and 10Gbps link, ran iperf Signed-off-by: Lorenzo Colitti <lorenzo@xxxxxxxxxx> --- drivers/usb/gadget/function/f_ncm.c | 79 ++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 1d900081b1..91f87165e7 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -85,7 +85,8 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f) /* peak (theoretical) bulk transfer rate in bits-per-second */ static inline unsigned ncm_bitrate(struct usb_gadget *g) { - if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) + if ((gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) || + (gadget_is_superspeed_plus(g) && g->speed == USB_SPEED_SUPER_PLUS)) return 13 * 1024 * 8 * 1000 * 8; else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return 13 * 512 * 8 * 1000 * 8; @@ -400,6 +401,75 @@ static struct usb_descriptor_header *ncm_ss_function[] = { NULL, }; +/* super speed plus support: */ + +static struct usb_endpoint_descriptor ssp_ncm_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT), + .bInterval = USB_MS_TO_HS_INTERVAL(NCM_STATUS_INTERVAL_MS) +}; + +static struct usb_ss_ep_comp_descriptor ssp_ncm_notify_comp_desc = { + .bLength = sizeof(ssp_ncm_notify_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ + .wBytesPerInterval = cpu_to_le16(NCM_STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor ssp_ncm_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ssp_ncm_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ssp_ncm_bulk_comp_desc = { + .bLength = sizeof(ssp_ncm_bulk_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_descriptor_header *ncm_ssp_function[] = { + (struct usb_descriptor_header *) &ncm_iad_desc, + /* CDC NCM control descriptors */ + (struct usb_descriptor_header *) &ncm_control_intf, + (struct usb_descriptor_header *) &ncm_header_desc, + (struct usb_descriptor_header *) &ncm_union_desc, + (struct usb_descriptor_header *) &ecm_desc, + (struct usb_descriptor_header *) &ncm_desc, + (struct usb_descriptor_header *) &ssp_ncm_notify_desc, + (struct usb_descriptor_header *) &ssp_ncm_notify_comp_desc, + /* data interface, altsettings 0 and 1 */ + (struct usb_descriptor_header *) &ncm_data_nop_intf, + (struct usb_descriptor_header *) &ncm_data_intf, + (struct usb_descriptor_header *) &ssp_ncm_in_desc, + (struct usb_descriptor_header *) &ssp_ncm_bulk_comp_desc, + (struct usb_descriptor_header *) &ssp_ncm_out_desc, + (struct usb_descriptor_header *) &ssp_ncm_bulk_comp_desc, + NULL, +}; + /* string descriptors: */ #define STRING_CTRL_IDX 0 @@ -1502,8 +1572,13 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ss_ncm_notify_desc.bEndpointAddress = fs_ncm_notify_desc.bEndpointAddress; + ssp_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress; + ssp_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress; + ssp_ncm_notify_desc.bEndpointAddress = + fs_ncm_notify_desc.bEndpointAddress; + status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function, - ncm_ss_function, NULL); + ncm_ss_function, ncm_ssp_function); if (status) goto fail; -- 2.28.0.163.g6104cc2f0b6-goog