diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 0a33bee5c29f..c52186c77972 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -1880,18 +1880,42 @@ static int queue_notification_request(struct f_gsi *gsi) { int ret; unsigned long flags; + struct usb_function *func = &gsi->function; + struct usb_request *req = gsi->c_port.notify_req; + struct usb_ep *ep = gsi->c_port.notify; + struct usb_gadget *gadget = func->config->cdev->gadget; - if (!gsi->func_is_suspended) { - ret = usb_ep_queue(gsi->c_port.notify, - gsi->c_port.notify_req, GFP_ATOMIC); - } else { - if (gsi->func_wakeup_allowed) - ret = usb_func_wakeup(&gsi->function); + if (gsi->c_port.is_suspended) { + /*For remote wakeup, queue the req from gsi_resume*/ + spin_lock_irqsave(&gsi->c_port.lock, flags); + gsi->c_port.notify_req_queued = false; + spin_unlock_irqrestore(&gsi->c_port.lock, flags); + + if (gsi->rwake_inprogress) { + log_event_dbg("%s remote-wakeup in progress\n", + __func__); + return -EBUSY; + } + + if (!usb_gsi_remote_wakeup_allowed(func)) { + log_event_dbg("%s remote-wakeup not capable\n", + __func__); + return -EOPNOTSUPP; + } + + log_event_dbg("%s wakeup host\n", __func__); + if (gadget->speed >= USB_SPEED_SUPER + && gsi->func_is_suspended) + ret = usb_func_wakeup(func); else - ret = -EOPNOTSUPP; + ret = usb_gadget_wakeup(gadget); + + gsi->rwake_inprogress = true; + return ret; } - if (ret < 0 || gsi->func_is_suspended) { + ret = usb_ep_queue(ep, req, GFP_ATOMIC); + if (ret < 0) { spin_lock_irqsave(&gsi->c_port.lock, flags); gsi->c_port.notify_req_queued = false; spin_unlock_irqrestore(&gsi->c_port.lock, flags); @@ -2523,6 +2547,7 @@ static int gsi_set_alt(struct usb_function *f, unsigned int intf, gsi->data_id, gsi->data_interface_up); } + gsi->c_port.is_suspended = false; atomic_set(&gsi->connected, 1); /* send 0 len pkt to qti to notify state change */ @@ -2606,6 +2631,7 @@ static void gsi_suspend(struct usb_function *f) return; } + gsi->c_port.is_suspended = true; block_db = true; usb_gsi_ep_op(gsi->d_port.in_ep, (void *)&block_db, GSI_EP_OP_SET_CLR_BLOCK_DBL); @@ -2646,6 +2672,8 @@ static void gsi_resume(struct usb_function *f) if (gsi->c_port.notify && !gsi->c_port.notify->desc) config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); + gsi->c_port.is_suspended = false; + /* Check any pending cpkt, and queue immediately on resume */ gsi_ctrl_send_notification(gsi); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 45f636fcbf4e..ecf72a8fe3b5 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -202,6 +202,7 @@ struct gsi_ctrl_port { atomic_t ctrl_online; bool is_open; + bool is_suspended; wait_queue_head_t read_wq;