Re: [PATCH v2 6/9] usbip: vhci-hcd: Add USB3 SuperSpeed support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux