Skip to content

Commit

Permalink
usb: Using correct way to clear usb3.0 device's remote wakeup feature.
Browse files Browse the repository at this point in the history
Usb3.0 device defines function remote wakeup which is only for interface
recipient rather than device recipient. This is different with usb2.0 device's
remote wakeup feature which is defined for device recipient. According usb3.0
spec 9.4.5, the function remote wakeup can be modified by the SetFeature()
requests using the FUNCTION_SUSPEND feature selector. This patch is to use
correct way to disable usb3.0 device's function remote wakeup after suspend
error and resuming.

This should be backported to kernels as old as 3.4, that contain the
commit 623bef9 "USB/xhci: Enable remote
wakeup for USB3 devices."

Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable@vger.kernel.org
  • Loading branch information
Lan Tianyu authored and Sarah Sharp committed Jan 24, 2013
1 parent 58b2939 commit 54a3ac0
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 18 deletions.
70 changes: 52 additions & 18 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -2838,6 +2838,23 @@ void usb_enable_ltm(struct usb_device *udev)
EXPORT_SYMBOL_GPL(usb_enable_ltm);

#ifdef CONFIG_USB_SUSPEND
/*
* usb_disable_function_remotewakeup - disable usb3.0
* device's function remote wakeup
* @udev: target device
*
* Assume there's only one function on the USB 3.0
* device and disable remote wake for the first
* interface. FIXME if the interface association
* descriptor shows there's more than one function.
*/
static int usb_disable_function_remotewakeup(struct usb_device *udev)
{
return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE,
USB_INTRF_FUNC_SUSPEND, 0, NULL, 0,
USB_CTRL_SET_TIMEOUT);
}

/*
* usb_port_suspend - suspend a usb device's upstream port
Expand Down Expand Up @@ -2955,12 +2972,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
port1, status);
/* paranoia: "should not happen" */
if (udev->do_remote_wakeup)
(void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (udev->do_remote_wakeup) {
if (!hub_is_superspeed(hub->hdev)) {
(void) usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE,
USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
} else
(void) usb_disable_function_remotewakeup(udev);

}

/* Try to enable USB2 hardware LPM again */
if (udev->usb2_hw_lpm_capable == 1)
Expand Down Expand Up @@ -3052,20 +3076,30 @@ static int finish_port_resume(struct usb_device *udev)
* udev->reset_resume
*/
} else if (udev->actconfig && !udev->reset_resume) {
le16_to_cpus(&devstatus);
if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
status = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE,
if (!hub_is_superspeed(udev->parent)) {
le16_to_cpus(&devstatus);
if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
status = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE,
USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (status)
dev_dbg(&udev->dev,
"disable remote wakeup, status %d\n",
status);
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
} else {
status = usb_get_status(udev, USB_RECIP_INTERFACE, 0,
&devstatus);
le16_to_cpus(&devstatus);
if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP
| USB_INTRF_STAT_FUNC_RW))
status =
usb_disable_function_remotewakeup(udev);
}

if (status)
dev_dbg(&udev->dev,
"disable remote wakeup, status %d\n",
status);
status = 0;
}
return status;
Expand Down
6 changes: 6 additions & 0 deletions include/uapi/linux/usb/ch9.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@
#define USB_INTRF_FUNC_SUSPEND_LP (1 << (8 + 0))
#define USB_INTRF_FUNC_SUSPEND_RW (1 << (8 + 1))

/*
* Interface status, Figure 9-5 USB 3.0 spec
*/
#define USB_INTRF_STAT_FUNC_RW_CAP 1
#define USB_INTRF_STAT_FUNC_RW 2

#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */

/* Bit array elements as returned by the USB_REQ_GET_STATUS request. */
Expand Down

0 comments on commit 54a3ac0

Please sign in to comment.