Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 86cb50e7 authored by Danny Segal's avatar Danny Segal Committed by Mayank Rana
Browse files

usb: gadget: Fix missing function wakeup notification sending on BAM wakeup



In super-speed mode, when the USB core wishes to issue remote wakeup due to
new data arriving on the BAM to BAM path, it needs to send function wakeup
notification to the USB host after the USB bus is resumed. However, the
sending of this notification fails when the USB core needs to wake up from
low-power mode, because the low-power mode exit is done asynchronously and
the sending of the function wakeup notification can not be done until the
USB bus is resumed.
This patch fixes this issue by checking whether the USB bus is suspended,
and if so, the sending function wakeup notification is delayed until the
USB bus is resumed.

Change-Id: I293476aaaf920b67fdbdf72a63524edc7a35750b
Signed-off-by: default avatarDanny Segal <dsegal@codeaurora.org>
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 0d90962f
Loading
Loading
Loading
Loading
+17 −5
Original line number Diff line number Diff line
@@ -479,17 +479,21 @@ int usb_func_wakeup(struct usb_function *func)
	if (ret) {
		if (ret == -EAGAIN) {
			DBG(func->config->cdev,
				"Function wakeup for %s could not be complete. Retry is needed.\n",
				"Function wakeup for %s could not complete due to suspend state. Delayed until after bus resume.\n",
				func->name ? func->name : "");
			func->func_wakeup_pending = true;
			ret = 0;
		} else {
			ERROR(func->config->cdev,
				"Failed to wake function %s from suspend state. interface id: %d, ret=%d. Canceling USB request.\n",
				func->name ? func->name : "",
				interface_id, ret);
		}

		return ret;
	}

	func->func_wakeup_pending = false;
	return 0;
}
EXPORT_SYMBOL(usb_func_wakeup);
@@ -513,7 +517,6 @@ int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep,
	if ((gadget->speed == USB_SPEED_SUPER) && func->func_is_suspended) {
		ret = usb_func_wakeup(func);
		if (ret) {
			if (ret != -EAGAIN)
			pr_err("Failed to send function wake up notification. func name:%s, ep:%u\n",
				func->name ? func->name : "",
				ep->address);
@@ -2389,6 +2392,7 @@ void composite_resume(struct usb_gadget *gadget)
	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
	struct usb_function		*f;
	u16				maxpower;
	int ret;

	/* REVISIT:  should we have config level
	 * suspend/resume callbacks?
@@ -2398,6 +2402,14 @@ void composite_resume(struct usb_gadget *gadget)
		cdev->driver->resume(cdev);
	if (cdev->config) {
		list_for_each_entry(f, &cdev->config->functions, list) {
			if (f->func_wakeup_pending) {
				ret = usb_func_wakeup(f);
				if (ret)
					ERROR(cdev,
						"Failed to send function wakeup notification for the %s function. Error code: %d\n",
						f->name ? f->name : "", ret);
			}

			if (f->resume)
				f->resume(f);
		}
+4 −0
Original line number Diff line number Diff line
@@ -167,6 +167,9 @@ struct usb_os_desc_table {
 *	Function Suspend state (used in Super Speed mode only).
 * @func_wakeup_allowed: Tells whether Function Remote Wakeup has been allowed
 *	by the USB host (used in Super Speed mode only).
 * @func_wakeup_pending: Marks that the function has issued a Function Wakeup
 *	while the USB bus was suspended and therefore a Function Wakeup
 *	notification needs to be sent once the USB bus is resumed.
 *
 * A single USB function uses one or more interfaces, and should in most
 * cases support operation at both full and high speeds.  Each function is
@@ -239,6 +242,7 @@ struct usb_function {
						u8 suspend_opt);
	unsigned		func_is_suspended:1;
	unsigned		func_wakeup_allowed:1;
	unsigned		func_wakeup_pending:1;
	/* private: */
	/* internals */
	struct list_head		list;