On 05/18/2017 04:08 AM, Yuyang Du wrote: > From: Yuyang Du <yuyang.du@xxxxxxxxx> > > 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.opasiak@xxxxxxxxxxx> > Signed-off-by: Yuyang Du <yuyang.du@xxxxxxxxx> > Signed-off-by: Yuyang Du <yuyang.du@xxxxxxxxxxxxxxx> Do you need this second signed-off?? Otherwise looks good. Acked-by: Shuah Khan <shuahkh@xxxxxxxxxxxxxxx> 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html