On 05/18/2017 04:08 AM, Yuyang Du wrote:
> From: Yuyang Du <yuyang...@intel.com>
> 
> This patch adds a USB3 HCD to an existing USB2 HCD and provides
> the support of SuperSpeed, in case the device can only be enumerated
> with SuperSpeed.
> 
> The bulk of the added code in usb3_bos_desc and hub_control to support
> SuperSpeed is borrowed from the commit 1cd8fd2887e162ad ("usb: gadget:
> dummy_hcd: add SuperSpeed support").
> 
> With this patch, each vhci will have VHCI_HC_PORTS HighSpeed ports
> and VHCI_HC_PORTS SuperSpeed ports.
> 
> Suggested-by: Krzysztof Opasiak <k.opas...@samsung.com>
> Signed-off-by: Yuyang Du <yuyang...@intel.com>

> Signed-off-by: Yuyang Du <yuyang...@linux.intel.com>
Do you need this second signed-off??

Otherwise looks good.

Acked-by: Shuah Khan <shua...@osg.samsung.com>

thanks,
-- Shuah


> ---
>  drivers/usb/usbip/vhci.h             |   7 +-
>  drivers/usb/usbip/vhci_hcd.c         | 323 
> ++++++++++++++++++++++++++++-------
>  drivers/usb/usbip/vhci_sysfs.c       | 109 ++++++++----
>  tools/usb/usbip/libsrc/vhci_driver.c |  23 ++-
>  tools/usb/usbip/libsrc/vhci_driver.h |   8 +-
>  tools/usb/usbip/src/usbip_attach.c   |   3 +-
>  6 files changed, 370 insertions(+), 103 deletions(-)
> 
> diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h
> index 8a979fc..db28eb5 100644
> --- a/drivers/usb/usbip/vhci.h
> +++ b/drivers/usb/usbip/vhci.h
> @@ -72,6 +72,11 @@ struct vhci_unlink {
>       unsigned long unlink_seqnum;
>  };
>  
> +enum hub_speed {
> +     HUB_SPEED_HIGH = 0,
> +     HUB_SPEED_SUPER,
> +};
> +
>  /* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */
>  #ifdef CONFIG_USBIP_VHCI_HC_PORTS
>  #define VHCI_HC_PORTS CONFIG_USBIP_VHCI_HC_PORTS
> @@ -140,7 +145,7 @@ static inline __u32 port_to_rhport(__u32 port)
>  
>  static inline int port_to_pdev_nr(__u32 port)
>  {
> -     return port / VHCI_HC_PORTS;
> +     return port / (VHCI_HC_PORTS * 2);
>  }
>  
>  static inline struct vhci_hcd *hcd_to_vhci_hcd(struct usb_hcd *hcd)
> diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
> index 8cfba1d..43cacbc 100644
> --- a/drivers/usb/usbip/vhci_hcd.c
> +++ b/drivers/usb/usbip/vhci_hcd.c
> @@ -232,6 +232,40 @@ static int vhci_hub_status(struct usb_hcd *hcd, char 
> *buf)
>       return changed ? retval : 0;
>  }
>  
> +/* usb 3.0 root hub device descriptor */
> +static struct {
> +     struct usb_bos_descriptor bos;
> +     struct usb_ss_cap_descriptor ss_cap;
> +} __packed usb3_bos_desc = {
> +
> +     .bos = {
> +             .bLength                = USB_DT_BOS_SIZE,
> +             .bDescriptorType        = USB_DT_BOS,
> +             .wTotalLength           = cpu_to_le16(sizeof(usb3_bos_desc)),
> +             .bNumDeviceCaps         = 1,
> +     },
> +     .ss_cap = {
> +             .bLength                = USB_DT_USB_SS_CAP_SIZE,
> +             .bDescriptorType        = USB_DT_DEVICE_CAPABILITY,
> +             .bDevCapabilityType     = USB_SS_CAP_TYPE,
> +             .wSpeedSupported        = cpu_to_le16(USB_5GBPS_OPERATION),
> +             .bFunctionalitySupport  = ilog2(USB_5GBPS_OPERATION),
> +     },
> +};
> +
> +static inline void
> +ss_hub_descriptor(struct usb_hub_descriptor *desc)
> +{
> +     memset(desc, 0, sizeof *desc);
> +     desc->bDescriptorType = USB_DT_SS_HUB;
> +     desc->bDescLength = 12;
> +     desc->wHubCharacteristics = cpu_to_le16(
> +             HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM);
> +     desc->bNbrPorts = VHCI_HC_PORTS;
> +     desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
> +     desc->u.ss.DeviceRemovable = 0xffff;
> +}
> +
>  static inline void hub_descriptor(struct usb_hub_descriptor *desc)
>  {
>       memset(desc, 0, sizeof(*desc));
> @@ -260,13 +294,15 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 
> typeReq, u16 wValue,
>  
>       /*
>        * NOTE:
> -      * wIndex shows the port number and begins from 1.
> +      * wIndex (bits 0-7) shows the port number and begins from 1?
>        */
> +     wIndex = ((__u8)(wIndex & 0x00ff));
>       usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue,
>                         wIndex);
> +
>       if (wIndex > VHCI_HC_PORTS)
>               pr_err("invalid port number %d\n", wIndex);
> -     rhport = ((__u8)(wIndex & 0x00ff)) - 1;
> +     rhport = wIndex - 1;
>  
>       vhci_hcd = hcd_to_vhci_hcd(hcd);
>       vhci = vhci_hcd->vhci;
> @@ -286,34 +322,26 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 
> typeReq, u16 wValue,
>       case ClearPortFeature:
>               switch (wValue) {
>               case USB_PORT_FEAT_SUSPEND:
> +                     if (hcd->speed == HCD_USB3) {
> +                             pr_err(" ClearPortFeature: 
> USB_PORT_FEAT_SUSPEND req not "
> +                                    "supported for USB 3.0 roothub\n");
> +                             goto error;
> +                     }
> +                     usbip_dbg_vhci_rh(
> +                             " ClearPortFeature: USB_PORT_FEAT_SUSPEND\n");
>                       if (vhci_hcd->port_status[rhport] & 
> USB_PORT_STAT_SUSPEND) {
>                               /* 20msec signaling */
>                               vhci_hcd->resuming = 1;
> -                             vhci_hcd->re_timeout =
> -                                     jiffies + msecs_to_jiffies(20);
> +                             vhci_hcd->re_timeout = jiffies + 
> msecs_to_jiffies(20);
>                       }
>                       break;
>               case USB_PORT_FEAT_POWER:
>                       usbip_dbg_vhci_rh(
>                               " ClearPortFeature: USB_PORT_FEAT_POWER\n");
> -                     vhci_hcd->port_status[rhport] = 0;
> -                     vhci_hcd->resuming = 0;
> -                     break;
> -             case USB_PORT_FEAT_C_RESET:
> -                     usbip_dbg_vhci_rh(
> -                             " ClearPortFeature: USB_PORT_FEAT_C_RESET\n");
> -                     switch (vhci_hcd->vdev[rhport].speed) {
> -                     case USB_SPEED_HIGH:
> -                             vhci_hcd->port_status[rhport] |=
> -                                     USB_PORT_STAT_HIGH_SPEED;
> -                             break;
> -                     case USB_SPEED_LOW:
> -                             vhci_hcd->port_status[rhport] |=
> -                                     USB_PORT_STAT_LOW_SPEED;
> -                             break;
> -                     default:
> -                             break;
> -                     }
> +                     if (hcd->speed == HCD_USB3)
> +                             vhci_hcd->port_status[rhport] &= 
> ~USB_SS_PORT_STAT_POWER;
> +                     else
> +                             vhci_hcd->port_status[rhport] &= 
> ~USB_PORT_STAT_POWER;
>                       break;
>               default:
>                       usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n",
> @@ -324,7 +352,26 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 
> typeReq, u16 wValue,
>               break;
>       case GetHubDescriptor:
>               usbip_dbg_vhci_rh(" GetHubDescriptor\n");
> -             hub_descriptor((struct usb_hub_descriptor *) buf);
> +             if (hcd->speed == HCD_USB3 &&
> +                             (wLength < USB_DT_SS_HUB_SIZE ||
> +                              wValue != (USB_DT_SS_HUB << 8))) {
> +                     pr_err("Wrong hub descriptor type for USB 3.0 
> roothub.\n");
> +                     goto error;
> +             }
> +             if (hcd->speed == HCD_USB3)
> +                     ss_hub_descriptor((struct usb_hub_descriptor *) buf);
> +             else
> +                     hub_descriptor((struct usb_hub_descriptor *) buf);
> +             break;
> +     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
> +             if (hcd->speed != HCD_USB3)
> +                     goto error;
> +
> +             if ((wValue >> 8) != USB_DT_BOS)
> +                     goto error;
> +
> +             memcpy(buf, &usb3_bos_desc, sizeof(usb3_bos_desc));
> +             retval = sizeof(usb3_bos_desc);
>               break;
>       case GetHubStatus:
>               usbip_dbg_vhci_rh(" GetHubStatus\n");
> @@ -332,7 +379,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 
> typeReq, u16 wValue,
>               break;
>       case GetPortStatus:
>               usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex);
> -             if (wIndex > VHCI_HC_PORTS || wIndex < 1) {
> +             if (wIndex < 1) {
>                       pr_err("invalid port number %d\n", wIndex);
>                       retval = -EPIPE;
>               }
> @@ -343,20 +390,16 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 
> typeReq, u16 wValue,
>                * complete it!!
>                */
>               if (vhci_hcd->resuming && time_after(jiffies, 
> vhci_hcd->re_timeout)) {
> -                     vhci_hcd->port_status[rhport] |=
> -                             (1 << USB_PORT_FEAT_C_SUSPEND);
> -                     vhci_hcd->port_status[rhport] &=
> -                             ~(1 << USB_PORT_FEAT_SUSPEND);
> +                     vhci_hcd->port_status[rhport] |= (1 << 
> USB_PORT_FEAT_C_SUSPEND);
> +                     vhci_hcd->port_status[rhport] &= ~(1 << 
> USB_PORT_FEAT_SUSPEND);
>                       vhci_hcd->resuming = 0;
>                       vhci_hcd->re_timeout = 0;
>               }
>  
>               if ((vhci_hcd->port_status[rhport] & (1 << 
> USB_PORT_FEAT_RESET)) !=
>                   0 && time_after(jiffies, vhci_hcd->re_timeout)) {
> -                     vhci_hcd->port_status[rhport] |=
> -                             (1 << USB_PORT_FEAT_C_RESET);
> -                     vhci_hcd->port_status[rhport] &=
> -                             ~(1 << USB_PORT_FEAT_RESET);
> +                     vhci_hcd->port_status[rhport] |= (1 << 
> USB_PORT_FEAT_C_RESET);
> +                     vhci_hcd->port_status[rhport] &= ~(1 << 
> USB_PORT_FEAT_RESET);
>                       vhci_hcd->re_timeout = 0;
>  
>                       if (vhci_hcd->vdev[rhport].ud.status ==
> @@ -368,6 +411,22 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 
> typeReq, u16 wValue,
>                               vhci_hcd->port_status[rhport] |=
>                                       USB_PORT_STAT_ENABLE;
>                       }
> +
> +                     if (hcd->speed < HCD_USB3) {
> +                             switch (vhci_hcd->vdev[rhport].speed) {
> +                             case USB_SPEED_HIGH:
> +                                     vhci_hcd->port_status[rhport] |=
> +                                           USB_PORT_STAT_HIGH_SPEED;
> +                                     break;
> +                             case USB_SPEED_LOW:
> +                                     vhci_hcd->port_status[rhport] |=
> +                                             USB_PORT_STAT_LOW_SPEED;
> +                                     break;
> +                             default:
> +                                     pr_err("vhci_device speed not set\n");
> +                                     break;
> +                             }
> +                     }
>               }
>               ((__le16 *) buf)[0] = 
> cpu_to_le16(vhci_hcd->port_status[rhport]);
>               ((__le16 *) buf)[1] =
> @@ -382,36 +441,119 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 
> typeReq, u16 wValue,
>               break;
>       case SetPortFeature:
>               switch (wValue) {
> +             case USB_PORT_FEAT_LINK_STATE:
> +                     usbip_dbg_vhci_rh(
> +                             " SetPortFeature: USB_PORT_FEAT_LINK_STATE\n");
> +                     if (hcd->speed != HCD_USB3) {
> +                             pr_err("USB_PORT_FEAT_LINK_STATE req not "
> +                                    "supported for USB 2.0 roothub\n");
> +                             goto error;
> +                     }
> +                     /*
> +                      * Since this is dummy we don't have an actual link so
> +                      * there is nothing to do for the SET_LINK_STATE cmd
> +                      */
> +                     break;
> +             case USB_PORT_FEAT_U1_TIMEOUT:
> +                     usbip_dbg_vhci_rh(
> +                             " SetPortFeature: USB_PORT_FEAT_U1_TIMEOUT\n");
> +             case USB_PORT_FEAT_U2_TIMEOUT:
> +                     usbip_dbg_vhci_rh(
> +                             " SetPortFeature: USB_PORT_FEAT_U2_TIMEOUT\n");
> +                     /* TODO: add suspend/resume support! */
> +                     if (hcd->speed != HCD_USB3) {
> +                             pr_err("USB_PORT_FEAT_U1/2_TIMEOUT req not "
> +                                    "supported for USB 2.0 roothub\n");
> +                             goto error;
> +                     }
> +                     break;
>               case USB_PORT_FEAT_SUSPEND:
>                       usbip_dbg_vhci_rh(
>                               " SetPortFeature: USB_PORT_FEAT_SUSPEND\n");
> +                     /* Applicable only for USB2.0 hub */
> +                     if (hcd->speed == HCD_USB3) {
> +                             pr_err("USB_PORT_FEAT_SUSPEND req not "
> +                                    "supported for USB 3.0 roothub\n");
> +                             goto error;
> +                     }
> +
> +                     vhci_hcd->port_status[rhport] |= USB_PORT_STAT_SUSPEND;
> +                     break;
> +             case USB_PORT_FEAT_POWER:
> +                     usbip_dbg_vhci_rh(
> +                             " SetPortFeature: USB_PORT_FEAT_POWER\n");
> +                     if (hcd->speed == HCD_USB3)
> +                             vhci_hcd->port_status[rhport] |= 
> USB_SS_PORT_STAT_POWER;
> +                     else
> +                             vhci_hcd->port_status[rhport] |= 
> USB_PORT_STAT_POWER;
>                       break;
> +             case USB_PORT_FEAT_BH_PORT_RESET:
> +                     usbip_dbg_vhci_rh(
> +                             " SetPortFeature: 
> USB_PORT_FEAT_BH_PORT_RESET\n");
> +                     /* Applicable only for USB3.0 hub */
> +                     if (hcd->speed != HCD_USB3) {
> +                             pr_err("USB_PORT_FEAT_BH_PORT_RESET req not "
> +                                    "supported for USB 2.0 roothub\n");
> +                             goto error;
> +                     }
> +                     /* FALLS THROUGH */
>               case USB_PORT_FEAT_RESET:
>                       usbip_dbg_vhci_rh(
>                               " SetPortFeature: USB_PORT_FEAT_RESET\n");
> -                     /* if it's already running, disconnect first */
> -                     if (vhci_hcd->port_status[rhport] & 
> USB_PORT_STAT_ENABLE) {
> -                             vhci_hcd->port_status[rhport] &=
> -                                     ~(USB_PORT_STAT_ENABLE |
> -                                       USB_PORT_STAT_LOW_SPEED |
> -                                       USB_PORT_STAT_HIGH_SPEED);
> -                             /* FIXME test that code path! */
> +                     /* if it's already enabled, disable */
> +                     if (hcd->speed == HCD_USB3) {
> +                             vhci_hcd->port_status[rhport] = 0;
> +                             vhci_hcd->port_status[rhport] =
> +                                     (USB_SS_PORT_STAT_POWER |
> +                                      USB_PORT_STAT_CONNECTION |
> +                                      USB_PORT_STAT_RESET);
> +                     } else if (vhci_hcd->port_status[rhport] & 
> USB_PORT_STAT_ENABLE) {
> +                             vhci_hcd->port_status[rhport] &= 
> ~(USB_PORT_STAT_ENABLE
> +                                     | USB_PORT_STAT_LOW_SPEED
> +                                     | USB_PORT_STAT_HIGH_SPEED);
>                       }
> +
>                       /* 50msec reset signaling */
>                       vhci_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
>  
> -                     /* FALLTHROUGH */
> +                     /* FALLS THROUGH */
>               default:
>                       usbip_dbg_vhci_rh(" SetPortFeature: default %d\n",
>                                         wValue);
> -                     vhci_hcd->port_status[rhport] |= (1 << wValue);
> -                     break;
> +                     if (hcd->speed == HCD_USB3) {
> +                             if ((vhci_hcd->port_status[rhport] &
> +                                  USB_SS_PORT_STAT_POWER) != 0) {
> +                                     vhci_hcd->port_status[rhport] |= (1 << 
> wValue);
> +                             }
> +                     } else
> +                             if ((vhci_hcd->port_status[rhport] &
> +                                  USB_PORT_STAT_POWER) != 0) {
> +                                     vhci_hcd->port_status[rhport] |= (1 << 
> wValue);
> +                             }
> +             }
> +             break;
> +     case GetPortErrorCount:
> +             usbip_dbg_vhci_rh(" GetPortErrorCount\n");
> +             if (hcd->speed != HCD_USB3) {
> +                     pr_err("GetPortErrorCount req not "
> +                            "supported for USB 2.0 roothub\n");
> +                     goto error;
> +             }
> +             /* We'll always return 0 since this is a dummy hub */
> +             *(__le32 *) buf = cpu_to_le32(0);
> +             break;
> +     case SetHubDepth:
> +             usbip_dbg_vhci_rh(" SetHubDepth\n");
> +             if (hcd->speed != HCD_USB3) {
> +                     pr_err("SetHubDepth req not supported for "
> +                            "USB 2.0 roothub\n");
> +                     goto error;
>               }
>               break;
> -
>       default:
> -             pr_err("default: no such request\n");
> -
> +             pr_err("default hub control req: %04x v%04x i%04x l%d\n",
> +                     typeReq, wValue, wIndex, wLength);
> +error:
>               /* "protocol stall" on error */
>               retval = -EPIPE;
>       }
> @@ -428,6 +570,9 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 
> typeReq, u16 wValue,
>  
>       spin_unlock_irqrestore(&vhci->lock, flags);
>  
> +     if ((vhci_hcd->port_status[rhport] & PORT_C_MASK) != 0)
> +             usb_hcd_poll_rh_status(hcd);
> +
>       return retval;
>  }
>  
> @@ -466,8 +611,7 @@ static void vhci_tx_urb(struct urb *urb, struct 
> vhci_device *vdev)
>       spin_unlock_irqrestore(&vdev->priv_lock, flags);
>  }
>  
> -static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
> -                         gfp_t mem_flags)
> +static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t 
> mem_flags)
>  {
>       struct vhci_hcd *vhci_hcd = hcd_to_vhci_hcd(hcd);
>       struct vhci *vhci = vhci_hcd->vhci;
> @@ -845,7 +989,6 @@ static void vhci_shutdown_connection(struct usbip_device 
> *ud)
>       pr_info("disconnect device\n");
>  }
>  
> -
>  static void vhci_device_reset(struct usbip_device *ud)
>  {
>       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
> @@ -921,12 +1064,22 @@ static int vhci_setup(struct usb_hcd *hcd)
>  {
>       struct vhci *vhci = *((void **)dev_get_platdata(hcd->self.controller));
>       hcd->self.sg_tablesize = ~0;
> -
> -     vhci->vhci_hcd_hs = hcd_to_vhci_hcd(hcd);
> -     vhci->vhci_hcd_hs->vhci = vhci;
> -     hcd->speed = HCD_USB2;
> -     hcd->self.root_hub->speed = USB_SPEED_HIGH;
> -
> +     if (usb_hcd_is_primary_hcd(hcd)) {
> +             vhci->vhci_hcd_hs = hcd_to_vhci_hcd(hcd);
> +             vhci->vhci_hcd_hs->vhci = vhci;
> +             /*
> +              * Mark the first roothub as being USB 2.0.
> +              * The USB 3.0 roothub will be registered later by
> +              * vhci_hcd_probe()
> +              */
> +             hcd->speed = HCD_USB2;
> +             hcd->self.root_hub->speed = USB_SPEED_HIGH;
> +     } else {
> +             vhci->vhci_hcd_ss = hcd_to_vhci_hcd(hcd);
> +             vhci->vhci_hcd_ss->vhci = vhci;
> +             hcd->speed = HCD_USB3;
> +             hcd->self.root_hub->speed = USB_SPEED_SUPER;
> +     }
>       return 0;
>  }
>  
> @@ -938,7 +1091,8 @@ static int vhci_start(struct usb_hcd *hcd)
>  
>       usbip_dbg_vhci_hc("enter vhci_start\n");
>  
> -     spin_lock_init(&vhci_hcd->vhci->lock);
> +     if (usb_hcd_is_primary_hcd(hcd))
> +             spin_lock_init(&vhci_hcd->vhci->lock);
>  
>       /* initialize private data of usb_hcd */
>  
> @@ -965,7 +1119,7 @@ static int vhci_start(struct usb_hcd *hcd)
>       }
>  
>       /* vhci_hcd is now ready to be controlled through sysfs */
> -     if (id == 0) {
> +     if (id == 0 && usb_hcd_is_primary_hcd(hcd)) {
>               err = vhci_init_attr_group();
>               if (err) {
>                       pr_err("init attr group\n");
> @@ -992,7 +1146,7 @@ static void vhci_stop(struct usb_hcd *hcd)
>  
>       /* 1. remove the userland interface of vhci_hcd */
>       id = hcd_name_to_id(hcd_name(hcd));
> -     if (id == 0) {
> +     if (id == 0 && usb_hcd_is_primary_hcd(hcd)) {
>               sysfs_remove_group(&hcd_dev(hcd)->kobj, &vhci_attr_group);
>               vhci_finish_attr_group();
>       }
> @@ -1053,12 +1207,30 @@ static int vhci_bus_resume(struct usb_hcd *hcd)
>  #define vhci_bus_resume       NULL
>  #endif
>  
> +/* Change a group of bulk endpoints to support multiple stream IDs */
> +static int vhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
> +     struct usb_host_endpoint **eps, unsigned int num_eps,
> +     unsigned int num_streams, gfp_t mem_flags)
> +{
> +     dev_dbg(&hcd->self.root_hub->dev, "vhci_alloc_streams not 
> implemented\n");
> +     return 0;
> +}
> +
> +/* Reverts a group of bulk endpoints back to not using stream IDs. */
> +static int vhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
> +     struct usb_host_endpoint **eps, unsigned int num_eps,
> +     gfp_t mem_flags)
> +{
> +     dev_dbg(&hcd->self.root_hub->dev, "vhci_free_streams not 
> implemented\n");
> +     return 0;
> +}
> +
>  static struct hc_driver vhci_hc_driver = {
>       .description    = driver_name,
>       .product_desc   = driver_desc,
>       .hcd_priv_size  = sizeof(struct vhci_hcd),
>  
> -     .flags          = HCD_USB2,
> +     .flags          = HCD_USB3 | HCD_SHARED,
>  
>       .reset          = vhci_setup,
>       .start          = vhci_start,
> @@ -1073,12 +1245,16 @@ static struct hc_driver vhci_hc_driver = {
>       .hub_control    = vhci_hub_control,
>       .bus_suspend    = vhci_bus_suspend,
>       .bus_resume     = vhci_bus_resume,
> +
> +     .alloc_streams  = vhci_alloc_streams,
> +     .free_streams   = vhci_free_streams,
>  };
>  
>  static int vhci_hcd_probe(struct platform_device *pdev)
>  {
>       struct vhci             *vhci;
>       struct usb_hcd          *hcd_hs;
> +     struct usb_hcd          *hcd_ss;
>       int                     ret;
>  
>       usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id);
> @@ -1089,7 +1265,7 @@ static int vhci_hcd_probe(struct platform_device *pdev)
>        */
>       hcd_hs = usb_create_hcd(&vhci_hc_driver, &pdev->dev, 
> dev_name(&pdev->dev));
>       if (!hcd_hs) {
> -             pr_err("create hcd failed\n");
> +             pr_err("create primary hcd failed\n");
>               return -ENOMEM;
>       }
>       hcd_hs->has_tt = 1;
> @@ -1104,12 +1280,31 @@ static int vhci_hcd_probe(struct platform_device 
> *pdev)
>               goto put_usb2_hcd;
>       }
>  
> +     hcd_ss = usb_create_shared_hcd(&vhci_hc_driver, &pdev->dev,
> +                                    dev_name(&pdev->dev), hcd_hs);
> +     if (!hcd_ss) {
> +             ret = -ENOMEM;
> +             pr_err("create shared hcd failed\n");
> +             goto remove_usb2_hcd;
> +     }
> +
> +     ret = usb_add_hcd(hcd_ss, 0, 0);
> +     if (ret) {
> +             pr_err("usb_add_hcd ss failed %d\n", ret);
> +             goto put_usb3_hcd;
> +     }
> +
>       usbip_dbg_vhci_hc("bye\n");
>       return 0;
>  
> +put_usb3_hcd:
> +     usb_put_hcd(hcd_ss);
> +remove_usb2_hcd:
> +     usb_remove_hcd(hcd_hs);
>  put_usb2_hcd:
>       usb_put_hcd(hcd_hs);
>       vhci->vhci_hcd_hs = NULL;
> +     vhci->vhci_hcd_ss = NULL;
>       return ret;
>  }
>  
> @@ -1122,10 +1317,14 @@ static int vhci_hcd_remove(struct platform_device 
> *pdev)
>        * then reverses the effects of usb_add_hcd(),
>        * invoking the HCD's stop() methods.
>        */
> +     usb_remove_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_ss));
> +     usb_put_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_ss));
> +
>       usb_remove_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_hs));
>       usb_put_hcd(vhci_hcd_to_hcd(vhci->vhci_hcd_hs));
>  
>       vhci->vhci_hcd_hs = NULL;
> +     vhci->vhci_hcd_ss = NULL;
>  
>       return 0;
>  }
> @@ -1137,7 +1336,7 @@ static int vhci_hcd_suspend(struct platform_device 
> *pdev, pm_message_t state)
>  {
>       struct usb_hcd *hcd;
>       struct vhci *vhci;
> -     int rhport = 0;
> +     int rhport;
>       int connected = 0;
>       int ret = 0;
>       unsigned long flags;
> @@ -1156,6 +1355,10 @@ static int vhci_hcd_suspend(struct platform_device 
> *pdev, pm_message_t state)
>               if (vhci->vhci_hcd_hs->port_status[rhport] &
>                   USB_PORT_STAT_CONNECTION)
>                       connected += 1;
> +
> +             if (vhci->vhci_hcd_ss->port_status[rhport] &
> +                 USB_PORT_STAT_CONNECTION)
> +                     connected += 1;
>       }
>  
>       spin_unlock_irqrestore(&vhci->lock, flags);
> diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
> index 63e10a4..cac2319 100644
> --- a/drivers/usb/usbip/vhci_sysfs.c
> +++ b/drivers/usb/usbip/vhci_sysfs.c
> @@ -29,6 +29,42 @@
>  
>  /* TODO: refine locking ?*/
>  
> +/*
> + * output example:
> + * hub port sta spd dev      socket           local_busid
> + * hs  0000 004 000 00000000         c5a7bb80 1-2.3
> + * ................................................
> + * ss  0008 004 000 00000000         d8cee980 2-3.4
> + * ................................................
> + *
> + * IP address can be retrieved from a socket pointer address by looking
> + * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
> + * port number and its peer IP address.
> + */
> +static void port_show_vhci(char **out, int hub, int port, struct vhci_device 
> *vdev)
> +{
> +     if (hub == HUB_SPEED_HIGH)
> +             *out += sprintf(*out, "hs  %04u %03u ",
> +                                   port, vdev->ud.status);
> +     else /* hub == HUB_SPEED_SUPER */
> +             *out += sprintf(*out, "ss  %04u %03u ",
> +                                   port, vdev->ud.status);
> +
> +     if (vdev->ud.status == VDEV_ST_USED) {
> +             *out += sprintf(*out, "%03u %08x ",
> +                                   vdev->speed, vdev->devid);
> +             *out += sprintf(*out, "%16p %s",
> +                                   vdev->ud.tcp_socket,
> +                                   dev_name(&vdev->udev->dev));
> +
> +     } else {
> +             *out += sprintf(*out, "000 00000000 ");
> +             *out += sprintf(*out, "0000000000000000 0-0");
> +     }
> +
> +     *out += sprintf(*out, "\n");
> +}
> +
>  /* Sysfs entry to show port status */
>  static ssize_t status_show_vhci(int pdev_nr, char *out)
>  {
> @@ -51,37 +87,21 @@ static ssize_t status_show_vhci(int pdev_nr, char *out)
>  
>       spin_lock_irqsave(&vhci->lock, flags);
>  
> -     /*
> -      * output example:
> -      * port sta spd dev      socket           local_busid
> -      * 0000 004 000 00000000         c5a7bb80 1-2.3
> -      * 0001 004 000 00000000         d8cee980 2-3.4
> -      *
> -      * IP address can be retrieved from a socket pointer address by looking
> -      * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
> -      * port number and its peer IP address.
> -      */
>       for (i = 0; i < VHCI_HC_PORTS; i++) {
> -             struct vhci_device *vdev = &vhci_hcd->vdev[i];
> +             struct vhci_device *vdev = &vhci->vhci_hcd_hs->vdev[i];
>  
>               spin_lock(&vdev->ud.lock);
> -             out += sprintf(out, "%04u %03u ",
> -                                 (pdev_nr * VHCI_HC_PORTS) + i,
> -                                 vdev->ud.status);
> -
> -             if (vdev->ud.status == VDEV_ST_USED) {
> -                     out += sprintf(out, "%03u %08x ",
> -                                         vdev->speed, vdev->devid);
> -                     out += sprintf(out, "%16p %s",
> -                                         vdev->ud.tcp_socket,
> -                                         dev_name(&vdev->udev->dev));
> -
> -             } else {
> -                     out += sprintf(out, "000 00000000 ");
> -                     out += sprintf(out, "0000000000000000 0-0");
> -             }
> +             port_show_vhci(&out, HUB_SPEED_HIGH,
> +                            pdev_nr * VHCI_HC_PORTS * 2 + i, vdev);
> +             spin_unlock(&vdev->ud.lock);
> +     }
>  
> -             out += sprintf(out, "\n");
> +     for (i = 0; i < VHCI_HC_PORTS; i++) {
> +             struct vhci_device *vdev = &vhci->vhci_hcd_ss->vdev[i];
> +
> +             spin_lock(&vdev->ud.lock);
> +             port_show_vhci(&out, HUB_SPEED_SUPER,
> +                            pdev_nr * VHCI_HC_PORTS * 2 + VHCI_HC_PORTS + i, 
> vdev);
>               spin_unlock(&vdev->ud.lock);
>       }
>  
> @@ -96,8 +116,16 @@ static ssize_t status_show_not_ready(int pdev_nr, char 
> *out)
>       int i = 0;
>  
>       for (i = 0; i < VHCI_HC_PORTS; i++) {
> -             out += sprintf(out, "%04u %03u ",
> -                                 (pdev_nr * VHCI_HC_PORTS) + i,
> +             out += sprintf(out, "hs  %04u %03u ",
> +                                 (pdev_nr * VHCI_HC_PORTS * 2) + i,
> +                                 VDEV_ST_NOTASSIGNED);
> +             out += sprintf(out, "000 00000000 0000000000000000 0-0");
> +             out += sprintf(out, "\n");
> +     }
> +
> +     for (i = 0; i < VHCI_HC_PORTS; i++) {
> +             out += sprintf(out, "ss  %04u %03u ",
> +                                 (pdev_nr * VHCI_HC_PORTS * 2) + 
> VHCI_HC_PORTS + i,
>                                   VDEV_ST_NOTASSIGNED);
>               out += sprintf(out, "000 00000000 0000000000000000 0-0");
>               out += sprintf(out, "\n");
> @@ -129,7 +157,7 @@ static ssize_t status_show(struct device *dev,
>       int pdev_nr;
>  
>       out += sprintf(out,
> -                    "port sta spd dev      socket           local_busid\n");
> +                    "hub port sta spd dev      socket           
> local_busid\n");
>  
>       pdev_nr = status_name_to_id(attr->attr.name);
>       if (pdev_nr < 0)
> @@ -145,7 +173,10 @@ static ssize_t nports_show(struct device *dev, struct 
> device_attribute *attr,
>  {
>       char *s = out;
>  
> -     out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers);
> +     /*
> +      * Half the ports are for SPEED_HIGH and half for SPEED_SUPER, thus the 
> * 2.
> +      */
> +     out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers * 2);
>       return out - s;
>  }
>  static DEVICE_ATTR_RO(nports);
> @@ -200,6 +231,7 @@ static ssize_t store_detach(struct device *dev, struct 
> device_attribute *attr,
>  {
>       __u32 port = 0, pdev_nr = 0, rhport = 0;
>       struct usb_hcd *hcd;
> +     struct vhci_hcd *vhci_hcd;
>       int ret;
>  
>       if (kstrtoint(buf, 10, &port) < 0)
> @@ -217,7 +249,14 @@ static ssize_t store_detach(struct device *dev, struct 
> device_attribute *attr,
>               return -EAGAIN;
>       }
>  
> -     ret = vhci_port_disconnect(hcd_to_vhci_hcd(hcd), rhport);
> +     usbip_dbg_vhci_sysfs("rhport %d\n", rhport);
> +
> +     if ((port / VHCI_HC_PORTS) % 2)
> +             vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_ss;
> +     else
> +             vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_hs;
> +
> +     ret = vhci_port_disconnect(vhci_hcd, rhport);
>       if (ret < 0)
>               return -EINVAL;
>  
> @@ -301,7 +340,11 @@ static ssize_t store_attach(struct device *dev, struct 
> device_attribute *attr,
>  
>       vhci_hcd = hcd_to_vhci_hcd(hcd);
>       vhci = vhci_hcd->vhci;
> -     vdev = &vhci_hcd->vdev[rhport];
> +
> +     if (speed == USB_SPEED_SUPER)
> +             vdev = &vhci->vhci_hcd_ss->vdev[rhport];
> +     else
> +             vdev = &vhci->vhci_hcd_hs->vdev[rhport];
>  
>       /* Extract socket from fd. */
>       socket = sockfd_lookup(sockfd, &err);
> diff --git a/tools/usb/usbip/libsrc/vhci_driver.c 
> b/tools/usb/usbip/libsrc/vhci_driver.c
> index 5b19a32..b1aafe8 100644
> --- a/tools/usb/usbip/libsrc/vhci_driver.c
> +++ b/tools/usb/usbip/libsrc/vhci_driver.c
> @@ -52,9 +52,10 @@ static int parse_status(const char *value)
>               unsigned long socket;
>               char lbusid[SYSFS_BUS_ID_SIZE];
>               struct usbip_imported_device *idev;
> +             char hub[3];
>  
> -             ret = sscanf(c, "%d %d %d %x %lx %31s\n",
> -                             &port, &status, &speed,
> +             ret = sscanf(c, "%2s  %d %d %d %x %lx %31s\n",
> +                             hub, &port, &status, &speed,
>                               &devid, &socket, lbusid);
>  
>               if (ret < 5) {
> @@ -62,15 +63,19 @@ static int parse_status(const char *value)
>                       BUG();
>               }
>  
> -             dbg("port %d status %d speed %d devid %x",
> -                             port, status, speed, devid);
> +             dbg("hub %s port %d status %d speed %d devid %x",
> +                             hub, port, status, speed, devid);
>               dbg("socket %lx lbusid %s", socket, lbusid);
>  
>               /* if a device is connected, look at it */
>               idev = &vhci_driver->idev[port];
> -
>               memset(idev, 0, sizeof(*idev));
>  
> +             if (strncmp("hs", hub, 2) == 0)
> +                     idev->hub = HUB_SPEED_HIGH;
> +             else /* strncmp("ss", hub, 2) == 0 */
> +                     idev->hub = HUB_SPEED_SUPER;
> +
>               idev->port      = port;
>               idev->status    = status;
>  
> @@ -321,11 +326,15 @@ int usbip_vhci_refresh_device_list(void)
>  }
>  
>  
> -int usbip_vhci_get_free_port(void)
> +int usbip_vhci_get_free_port(uint32_t speed)
>  {
>       for (int i = 0; i < vhci_driver->nports; i++) {
> +             if (speed == USB_SPEED_SUPER &&
> +                 vhci_driver->idev[i].hub != HUB_SPEED_SUPER)
> +                     continue;
> +
>               if (vhci_driver->idev[i].status == VDEV_ST_NULL)
> -                     return i;
> +                     return vhci_driver->idev[i].port;
>       }
>  
>       return -1;
> diff --git a/tools/usb/usbip/libsrc/vhci_driver.h 
> b/tools/usb/usbip/libsrc/vhci_driver.h
> index dfe19c1..4898d3b 100644
> --- a/tools/usb/usbip/libsrc/vhci_driver.h
> +++ b/tools/usb/usbip/libsrc/vhci_driver.h
> @@ -14,7 +14,13 @@
>  #define USBIP_VHCI_DEVICE_NAME "vhci_hcd.0"
>  #define MAXNPORT 128
>  
> +enum hub_speed {
> +     HUB_SPEED_HIGH = 0,
> +     HUB_SPEED_SUPER,
> +};
> +
>  struct usbip_imported_device {
> +     enum hub_speed hub;
>       uint8_t port;
>       uint32_t status;
>  
> @@ -46,7 +52,7 @@ void usbip_vhci_driver_close(void);
>  int  usbip_vhci_refresh_device_list(void);
>  
>  
> -int usbip_vhci_get_free_port(void);
> +int usbip_vhci_get_free_port(uint32_t speed);
>  int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
>               uint32_t speed);
>  
> diff --git a/tools/usb/usbip/src/usbip_attach.c 
> b/tools/usb/usbip/src/usbip_attach.c
> index 62a297f..6e89768 100644
> --- a/tools/usb/usbip/src/usbip_attach.c
> +++ b/tools/usb/usbip/src/usbip_attach.c
> @@ -94,6 +94,7 @@ static int import_device(int sockfd, struct 
> usbip_usb_device *udev)
>  {
>       int rc;
>       int port;
> +     uint32_t speed = udev->speed;
>  
>       rc = usbip_vhci_driver_open();
>       if (rc < 0) {
> @@ -101,7 +102,7 @@ static int import_device(int sockfd, struct 
> usbip_usb_device *udev)
>               return -1;
>       }
>  
> -     port = usbip_vhci_get_free_port();
> +     port = usbip_vhci_get_free_port(speed);
>       if (port < 0) {
>               err("no free port");
>               usbip_vhci_driver_close();
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to