From 718f2b7a95149d0d6a39ed0965daf402f696e9cd Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Thu, 28 Jan 2021 15:41:15 -0800 Subject: [PATCH] usb: gsi: Retry USB function wakeup if USB is into low power mode Consider case where USB is into low power mode after receiving USB function suspend from host. To invoke function remote wakeup USB controller is rerquired to bring out of low power mode. Hence once USB controller and USB bus is resumed, perform USB function wakeup from composite_resume() context to resume USB function on host side. Change-Id: Id5103f0e7bf3d324cd6c206d1d6214f6d6c107a4 Signed-off-by: Mayank Rana --- drivers/usb/gadget/function/f_gsi.c | 18 ++++++++++++++---- drivers/usb/gadget/function/f_gsi.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index c52186c77972..57f6c6af6f92 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -163,6 +163,8 @@ static int gsi_wakeup_host(struct f_gsi *gsi) if ((gadget->speed >= USB_SPEED_SUPER) && (gsi->func_is_suspended)) { log_event_dbg("%s: Calling usb_func_wakeup", __func__); ret = usb_func_wakeup(func); + if (ret == -EAGAIN) + gsi->func_wakeup_pending = true; } else { log_event_dbg("%s: Calling usb_gadget_wakeup", __func__); ret = usb_gadget_wakeup(gadget); @@ -1905,9 +1907,11 @@ static int queue_notification_request(struct f_gsi *gsi) log_event_dbg("%s wakeup host\n", __func__); if (gadget->speed >= USB_SPEED_SUPER - && gsi->func_is_suspended) + && gsi->func_is_suspended) { ret = usb_func_wakeup(func); - else + if (ret == -EAGAIN) + gsi->func_wakeup_pending = true; + } else ret = usb_gadget_wakeup(gadget); gsi->rwake_inprogress = true; @@ -2548,6 +2552,7 @@ static int gsi_set_alt(struct usb_function *f, unsigned int intf, } gsi->c_port.is_suspended = false; + gsi->func_wakeup_pending = false; atomic_set(&gsi->connected, 1); /* send 0 len pkt to qti to notify state change */ @@ -2662,8 +2667,13 @@ static void gsi_resume(struct usb_function *f) * canceled. In this case resume is done by a Function Resume request. */ if ((cdev->gadget->speed >= USB_SPEED_SUPER) && - gsi->func_is_suspended) + gsi->func_is_suspended) { + if (gsi->func_wakeup_pending) { + usb_func_wakeup(&gsi->function); + gsi->func_wakeup_pending = false; + } return; + } /* Keep timer enabled if user enabled using debugfs */ if (!gsi->debugfs_rw_timer_enable) @@ -3332,7 +3342,7 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) rmnet_gsi_string_defs[0].id = 0; mbim_gsi_string_defs[0].id = 0; qdss_gsi_string_defs[0].id = 0; - + gsi->func_wakeup_pending = false; if (gsi->prot_id == IPA_USB_RNDIS) { gsi->d_port.sm_state = STATE_UNINITIALIZED; rndis_deregister(gsi->params); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index ecf72a8fe3b5..b1e212131104 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -275,6 +275,7 @@ struct f_gsi { /* function suspend status */ bool func_is_suspended; bool func_wakeup_allowed; + bool func_wakeup_pending; const struct usb_endpoint_descriptor *in_ep_desc_backup; const struct usb_endpoint_descriptor *out_ep_desc_backup;