usb: gadget: f_ncm: add SuperSpeed descriptors for CDC NCM
authorJussi Kivilinna <jussi.kivilinna@haltian.com>
Fri, 12 Aug 2016 14:28:05 +0000 (17:28 +0300)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Thu, 25 Aug 2016 09:13:09 +0000 (12:13 +0300)
Patch enables SuperSpeed for NCM gadget.

Tested with USB3380 and measured TCP throughput with two Intel PCs:
  udc to host: 920 Mbit/s
  host to udc: 550 Mbit/s

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@haltian.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/gadget/function/f_ncm.c

index 97f0a9bc84df23bf39fe4b6b1b21a55965907ec1..08cff495195f13b4f623a4ab7af135433019f1e8 100644 (file)
@@ -90,7 +90,9 @@ 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_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+       if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+               return 13 * 1024 * 8 * 1000 * 8;
+       else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
                return 13 * 512 * 8 * 1000 * 8;
        else
                return 19 *  64 * 1 * 1000 * 8;
@@ -333,6 +335,76 @@ static struct usb_descriptor_header *ncm_hs_function[] = {
        NULL,
 };
 
+
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_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 ss_ncm_notify_comp_desc = {
+       .bLength =              sizeof(ss_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 ss_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 ss_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 ss_ncm_bulk_comp_desc = {
+       .bLength =              sizeof(ss_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_ss_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 *) &ss_ncm_notify_desc,
+       (struct usb_descriptor_header *) &ss_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 *) &ss_ncm_in_desc,
+       (struct usb_descriptor_header *) &ss_ncm_bulk_comp_desc,
+       (struct usb_descriptor_header *) &ss_ncm_out_desc,
+       (struct usb_descriptor_header *) &ss_ncm_bulk_comp_desc,
+       NULL,
+};
+
 /* string descriptors: */
 
 #define STRING_CTRL_IDX        0
@@ -1431,8 +1503,13 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
        hs_ncm_notify_desc.bEndpointAddress =
                fs_ncm_notify_desc.bEndpointAddress;
 
+       ss_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress;
+       ss_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress;
+       ss_ncm_notify_desc.bEndpointAddress =
+               fs_ncm_notify_desc.bEndpointAddress;
+
        status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
-                       NULL, NULL);
+                       ncm_ss_function, NULL);
        if (status)
                goto fail;
 
@@ -1450,6 +1527,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
        ncm->task_timer.function = ncm_tx_timeout;
 
        DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+                       gadget_is_superspeed(c->cdev->gadget) ? "super" :
                        gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
                        ncm->port.in_ep->name, ncm->port.out_ep->name,
                        ncm->notify->name);