From 99067cf7dfcebef7c536e79112b12f8b9871bc65 Mon Sep 17 00:00:00 2001 From: Manu Gautam Date: Wed, 20 Jun 2018 16:39:58 +0530 Subject: [PATCH] usb: f_gsi: Initiate remote-wakeup if notification already queued Selective suspend of device (with remote-wakeup enabled) by host could race with device driver queuing a notification request on interrupt endpoint. Driver currently issues remote wakeup if at the time of queueing notification request device was suspended. If host suspends device right after driver queues notification request then device driver fails to initiate remote-wakeup. Fix this by initiating remote wakeup immediately after suspend if notification request already queued to controller. Change-Id: I24ce5d8302a70a1f5f68c54af0fef9f145adb97b Signed-off-by: Manu Gautam --- drivers/usb/gadget/function/f_gsi.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index b7ee8994f7ec..97a7f79d80bd 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2523,6 +2523,9 @@ static void gsi_disable(struct usb_function *f) atomic_set(&gsi->connected, 0); + del_timer(&gsi->gsi_rw_timer); + gsi->debugfs_rw_timer_enable = 0; + if (gsi->prot_id == IPA_USB_RNDIS) rndis_uninit(gsi->params); @@ -2578,6 +2581,16 @@ static void gsi_suspend(struct usb_function *f) post_event(&gsi->d_port, EVT_SUSPEND); queue_delayed_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w, 0); log_event_dbg("gsi suspended"); + + /* + * 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) @@ -2595,6 +2608,10 @@ static void gsi_resume(struct usb_function *f) gsi->func_is_suspended) return; + /* Keep timer enabled if user enabled using debugfs */ + if (!gsi->debugfs_rw_timer_enable) + del_timer(&gsi->gsi_rw_timer); + if (gsi->c_port.notify && !gsi->c_port.notify->desc) config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify);