aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2020-03-26 05:38:33 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2020-03-26 05:38:33 +0000
commit9c75837402cef1e0043977f2e11e44513556b2e1 (patch)
tree222f5489e1931b9b2a2584569e675bdb96215312
parent8faa6d591f4db44964ad0dc4247765e1ded41abf (diff)
downloadsrc-9c75837402cef1e0043977f2e11e44513556b2e1.tar.gz
src-9c75837402cef1e0043977f2e11e44513556b2e1.zip
MFC r359120:
Correctly implement support for remote wakeup for USB 3.0 device. Submitted by: Horse Ma <Shichun.Ma@dell.com> Sponsored by: Mellanox Technologies
Notes
Notes: svn path=/stable/10/; revision=359318
-rw-r--r--sys/dev/usb/usb.h5
-rw-r--r--sys/dev/usb/usb_hub.c53
2 files changed, 52 insertions, 6 deletions
diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h
index 92394f7d8bed..7a4f258ec563 100644
--- a/sys/dev/usb/usb.h
+++ b/sys/dev/usb/usb.h
@@ -273,6 +273,11 @@ typedef struct usb_device_request usb_device_request_t;
#define UHF_C_BH_PORT_RESET 29
#define UHF_FORCE_LINKPM_ACCEPT 30
+/* SuperSpeed suspend support */
+#define USB_INTERFACE_FUNC_SUSPEND 0
+#define USB_INTERFACE_FUNC_SUSPEND_LP (1 << 8)
+#define USB_INTERFACE_FUNC_SUSPEND_RW (1 << 9)
+
struct usb_descriptor {
uByte bLength;
uByte bDescriptorType;
diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c
index 411460ce73ed..28d9bc002ebb 100644
--- a/sys/dev/usb/usb_hub.c
+++ b/sys/dev/usb/usb_hub.c
@@ -2617,6 +2617,50 @@ usb_bus_powerd(struct usb_bus *bus)
}
#endif
+static usb_error_t
+usbd_device_30_remote_wakeup(struct usb_device *udev, uint8_t bRequest)
+{
+ struct usb_device_request req = {};
+
+ req.bmRequestType = UT_WRITE_INTERFACE;
+ req.bRequest = bRequest;
+ USETW(req.wValue, USB_INTERFACE_FUNC_SUSPEND);
+ USETW(req.wIndex, USB_INTERFACE_FUNC_SUSPEND_LP |
+ USB_INTERFACE_FUNC_SUSPEND_RW);
+
+ return (usbd_do_request(udev, NULL, &req, 0));
+}
+
+static usb_error_t
+usbd_clear_dev_wakeup(struct usb_device *udev)
+{
+ usb_error_t err;
+
+ if (usb_device_20_compatible(udev)) {
+ err = usbd_req_clear_device_feature(udev,
+ NULL, UF_DEVICE_REMOTE_WAKEUP);
+ } else {
+ err = usbd_device_30_remote_wakeup(udev,
+ UR_CLEAR_FEATURE);
+ }
+ return (err);
+}
+
+static usb_error_t
+usbd_set_dev_wakeup(struct usb_device *udev)
+{
+ usb_error_t err;
+
+ if (usb_device_20_compatible(udev)) {
+ err = usbd_req_set_device_feature(udev,
+ NULL, UF_DEVICE_REMOTE_WAKEUP);
+ } else {
+ err = usbd_device_30_remote_wakeup(udev,
+ UR_SET_FEATURE);
+ }
+ return (err);
+}
+
/*------------------------------------------------------------------------*
* usb_dev_resume_peer
*
@@ -2720,8 +2764,7 @@ usb_dev_resume_peer(struct usb_device *udev)
/* check if peer has wakeup capability */
if (usb_peer_can_wakeup(udev)) {
/* clear remote wakeup */
- err = usbd_req_clear_device_feature(udev,
- NULL, UF_DEVICE_REMOTE_WAKEUP);
+ err = usbd_clear_dev_wakeup(udev);
if (err) {
DPRINTFN(0, "Clearing device "
"remote wakeup failed: %s\n",
@@ -2786,8 +2829,7 @@ repeat:
*/
/* allow device to do remote wakeup */
- err = usbd_req_set_device_feature(udev,
- NULL, UF_DEVICE_REMOTE_WAKEUP);
+ err = usbd_set_dev_wakeup(udev);
if (err) {
DPRINTFN(0, "Setting device "
"remote wakeup failed\n");
@@ -2813,8 +2855,7 @@ repeat:
if (err != 0) {
if (usb_peer_can_wakeup(udev)) {
/* allow device to do remote wakeup */
- err = usbd_req_clear_device_feature(udev,
- NULL, UF_DEVICE_REMOTE_WAKEUP);
+ err = usbd_clear_dev_wakeup(udev);
if (err) {
DPRINTFN(0, "Setting device "
"remote wakeup failed\n");