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

Commit 94ffa3ab authored by Chandana Kishori Chiluveru's avatar Chandana Kishori Chiluveru Committed by Mayank Rana
Browse files

usb: gadget: Fix issue in queuing notification req upon function suspend



Selective suspend of device with remote-wakeup enabled by host
could race with device driver queuing a notification request on
interrupt endpoint. Driver calling usb_func_ep_queue() directly
and issues function wakeup command to controller and returns success to
the function driver. As a result notification request is not queued to
endpoint but returns with success and notify_req_queued remains true.
If function driver tries to queue any request further this results into
request drop as request is already queued.

Hence return -EAGAIN in usb_func_ep_queue to queue the notification request
upon function resume. Also initiate remote wakeup immediately after suspend
if notification request already queued to controller.

Change-Id: I7ac9231c44e8126a043886f5d6cedde491ff818d
Signed-off-by: default avatarChandana Kishori Chiluveru <cchiluve@codeaurora.org>
Signed-off-by: default avatarSriharsha Allenki <sallenki@codeaurora.org>
parent 018df480
Loading
Loading
Loading
Loading
+7 −1
Original line number Original line Diff line number Diff line
@@ -533,9 +533,15 @@ int usb_func_ep_queue(struct usb_function *func, struct usb_ep *ep,
		} else if (ret < 0 && ret != -ENOTSUPP) {
		} else if (ret < 0 && ret != -ENOTSUPP) {
			pr_err("Failed to wake function %s from suspend state. ret=%d.\n",
			pr_err("Failed to wake function %s from suspend state. ret=%d.\n",
				func->name ? func->name : "", ret);
				func->name ? func->name : "", ret);
		}
		} else {
			/*
			 * Return -EAGAIN to queue the request from
			 * function driver wakeup function.
			 */
			ret = -EAGAIN;
			goto done;
			goto done;
		}
		}
	}


	if (!func->func_is_suspended)
	if (!func->func_is_suspended)
		ret = 0;
		ret = 0;
+20 −10
Original line number Original line Diff line number Diff line
@@ -103,6 +103,21 @@ static inline bool usb_gsi_remote_wakeup_allowed(struct usb_function *f)
	return remote_wakeup_allowed;
	return remote_wakeup_allowed;
}
}


static void usb_gsi_check_pending_wakeup(struct usb_function *f)
{
	struct f_gsi *gsi = func_to_gsi(f);

	/*
	 * If host suspended bus without receiving notification request then
	 * initiate remote-wakeup. As driver won't be able to do it later since
	 * notification request is already queued.
	 */
	if (gsi->c_port.notify_req_queued && usb_gsi_remote_wakeup_allowed(f)) {
		mod_timer(&gsi->gsi_rw_timer, jiffies + msecs_to_jiffies(2000));
		log_event_dbg("%s: pending response, arm rw_timer\n", __func__);
	}
}

static void post_event(struct gsi_data_port *port, u8 event)
static void post_event(struct gsi_data_port *port, u8 event)
{
{
	unsigned long flags;
	unsigned long flags;
@@ -1903,6 +1918,9 @@ static void gsi_ctrl_notify_resp_complete(struct usb_ep *ep,
	gsi->c_port.notify_req_queued = false;
	gsi->c_port.notify_req_queued = false;
	spin_unlock_irqrestore(&gsi->c_port.lock, flags);
	spin_unlock_irqrestore(&gsi->c_port.lock, flags);


	log_event_dbg("%s: status:%d req_queued:%d",
		__func__, status, gsi->c_port.notify_req_queued);

	switch (status) {
	switch (status) {
	case -ECONNRESET:
	case -ECONNRESET:
	case -ESHUTDOWN:
	case -ESHUTDOWN:
@@ -2570,6 +2588,7 @@ static void gsi_suspend(struct usb_function *f)
	 */
	 */
	if (!gsi->data_interface_up) {
	if (!gsi->data_interface_up) {
		log_event_dbg("%s: suspend done\n", __func__);
		log_event_dbg("%s: suspend done\n", __func__);
		usb_gsi_check_pending_wakeup(f);
		return;
		return;
	}
	}


@@ -2579,16 +2598,7 @@ static void gsi_suspend(struct usb_function *f)
	post_event(&gsi->d_port, EVT_SUSPEND);
	post_event(&gsi->d_port, EVT_SUSPEND);
	queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
	queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
	log_event_dbg("gsi suspended");
	log_event_dbg("gsi suspended");

	usb_gsi_check_pending_wakeup(f);
	/*
	 * If host suspended bus without receiving notification request then
	 * initiate remote-wakeup. As driver won't be able to do it later since
	 * notification request is already queued.
	 */
	if (gsi->c_port.notify_req_queued && usb_gsi_remote_wakeup_allowed(f)) {
		mod_timer(&gsi->gsi_rw_timer, jiffies + msecs_to_jiffies(2000));
		log_event_dbg("%s: pending response, arm rw_timer\n", __func__);
	}
}
}


static void gsi_resume(struct usb_function *f)
static void gsi_resume(struct usb_function *f)