diff options
author | Yuyang Du <yuyang.du@intel.com> | 2017-06-08 07:04:10 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-06-13 10:51:10 +0200 |
commit | 1c9de5bf428612458427943b724bea51abde520a (patch) | |
tree | deb6f9bed592da3a5952239dc5212e721ff4ab5f /drivers/usb/usbip/vhci_sysfs.c | |
parent | usbip: vhci-hcd: Set the vhci structure up to work (diff) | |
download | linux-1c9de5bf428612458427943b724bea51abde520a.tar.xz linux-1c9de5bf428612458427943b724bea51abde520a.zip |
usbip: vhci-hcd: Add USB3 SuperSpeed support
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@samsung.com>
Signed-off-by: Yuyang Du <yuyang.du@intel.com>
Acked-by: Shuah Khan <shuahkh@osg.samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/usbip/vhci_sysfs.c')
-rw-r--r-- | drivers/usb/usbip/vhci_sysfs.c | 109 |
1 files changed, 76 insertions, 33 deletions
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 63e10a4ffeec..cac2319df742 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); |