From patchwork Tue Aug 2 19:18:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elson Serrao X-Patchwork-Id: 595073 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D998C19F2C for ; Tue, 2 Aug 2022 19:18:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230512AbiHBTSr (ORCPT ); Tue, 2 Aug 2022 15:18:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44948 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230300AbiHBTSp (ORCPT ); Tue, 2 Aug 2022 15:18:45 -0400 Received: from alexa-out.qualcomm.com (alexa-out.qualcomm.com [129.46.98.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6F82713CD9; Tue, 2 Aug 2022 12:18:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1659467924; x=1691003924; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=rQ6Hq/Z43PzcHLHa0X0VopuTrR/clg6tyIPhusfsMT4=; b=KBBy+rqnKloSuXRXUIzsQF794GpqDOmAF8cdY0KJXhoXTgZPiMb6i/2H fULkoaVPd7RzuNnTVB9iIMY/cI4m/CRaM6JuT/BGqG4BMk4PH1mdQBSKK kRVmK0YIivCNF02WoqfUa80jqEC+rMDLqM/lxbrReoq1HRCkXM04y3RJR g=; Received: from ironmsg09-lv.qualcomm.com ([10.47.202.153]) by alexa-out.qualcomm.com with ESMTP; 02 Aug 2022 12:18:42 -0700 X-QCInternal: smtphost Received: from hu-eserrao-lv.qualcomm.com (HELO hu-devc-lv-c.qualcomm.com) ([10.47.235.164]) by ironmsg09-lv.qualcomm.com with ESMTP; 02 Aug 2022 12:18:42 -0700 Received: by hu-devc-lv-c.qualcomm.com (Postfix, from userid 464172) id 7263D2106D; Tue, 2 Aug 2022 12:18:42 -0700 (PDT) From: Elson Roy Serrao To: balbi@kernel.org, gregkh@linuxfoundation.org Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, quic_wcheng@quicinc.com, quic_jackp@quicinc.com, quic_mrana@quicinc.com, Thinh.Nguyen@synopsys.com, Elson Roy Serrao Subject: [PATCH 1/5] usb: dwc3: Add remote wakeup handling Date: Tue, 2 Aug 2022 12:18:36 -0700 Message-Id: <1659467920-9095-2-git-send-email-quic_eserrao@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> References: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org An usb device can initate a remote wakeup and bring the link out of suspend as dictated by the DEVICE_REMOTE_WAKEUP feature selector. Add support to handle this packet and set the remote wakeup capability accordingly. Some hosts may take longer time to initiate the resume signaling after device triggers a remote wakeup. So improve the gadget_wakeup op to interrupt based rather than polling based by enabling link status change events. Signed-off-by: Elson Roy Serrao --- drivers/usb/dwc3/core.h | 4 +++ drivers/usb/dwc3/ep0.c | 4 +++ drivers/usb/dwc3/gadget.c | 69 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4fe4287..3306b1c 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1113,6 +1113,8 @@ struct dwc3_scratchpad_array { * address. * @num_ep_resized: carries the current number endpoints which have had its tx * fifo resized. + * @is_remote_wakeup_enabled: remote wakeup status from host perspective + * @is_gadget_wakeup: remote wakeup requested via gadget op. */ struct dwc3 { struct work_struct drd_work; @@ -1326,6 +1328,8 @@ struct dwc3 { int max_cfg_eps; int last_fifo_depth; int num_ep_resized; + bool is_remote_wakeup_enabled; + bool is_gadget_wakeup; }; #define INCRX_BURST_MODE 0 diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 197af63..4cc3d3a 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -353,6 +353,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; if (reg & DWC3_DCTL_INITU2ENA) usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; + } else { + usb_status |= dwc->is_remote_wakeup_enabled << + USB_DEVICE_REMOTE_WAKEUP; } break; @@ -473,6 +476,7 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc, switch (wValue) { case USB_DEVICE_REMOTE_WAKEUP: + dwc->is_remote_wakeup_enabled = set; break; /* * 9.4.1 says only for SS, in AddressState only for diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4366c45..d6697da 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2232,6 +2232,22 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = { /* -------------------------------------------------------------------------- */ +static void linksts_change_events_set(struct dwc3 *dwc, bool set) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_DEVTEN); + if (set) + reg |= DWC3_DEVTEN_ULSTCNGEN; + else + reg &= ~DWC3_DEVTEN_ULSTCNGEN; + + dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); + + /* Required to complete this operation before returning */ + mb(); +} + static int dwc3_gadget_get_frame(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); @@ -2270,9 +2286,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) return -EINVAL; } + linksts_change_events_set(dwc, true); + ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); if (ret < 0) { dev_err(dwc->dev, "failed to put link in Recovery\n"); + linksts_change_events_set(dwc, false); + dwc->is_gadget_wakeup = false; return ret; } @@ -2284,9 +2304,15 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); } + /* If remote wakeup is triggered from function driver, bail out. + * Since link status change events are enabled we would receive + * an U0 event when wakeup is successful. + */ + if (dwc->is_gadget_wakeup) + return -EAGAIN; + /* poll until Link State changes to ON */ retries = 20000; - while (retries--) { reg = dwc3_readl(dwc->regs, DWC3_DSTS); @@ -2295,6 +2321,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) break; } + linksts_change_events_set(dwc, false); + if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { dev_err(dwc->dev, "failed to send remote wakeup\n"); return -EINVAL; @@ -2310,7 +2338,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) int ret; spin_lock_irqsave(&dwc->lock, flags); + if (g->speed < USB_SPEED_SUPER && !dwc->is_remote_wakeup_enabled) { + dev_err(dwc->dev, "%s:remote wakeup not supported\n", __func__); + ret = -EPERM; + goto out; + } + if (dwc->is_gadget_wakeup) { + dev_err(dwc->dev, "%s: remote wakeup in progress\n", __func__); + ret = -EINVAL; + goto out; + } + dwc->is_gadget_wakeup = true; ret = __dwc3_gadget_wakeup(dwc); + +out: spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -2766,6 +2807,9 @@ static int dwc3_gadget_start(struct usb_gadget *g, spin_lock_irqsave(&dwc->lock, flags); dwc->gadget_driver = driver; + linksts_change_events_set(dwc, false); + dwc->is_remote_wakeup_enabled = false; + dwc->is_gadget_wakeup = false; spin_unlock_irqrestore(&dwc->lock, flags); return 0; @@ -2785,6 +2829,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g) spin_lock_irqsave(&dwc->lock, flags); dwc->gadget_driver = NULL; + linksts_change_events_set(dwc, false); + dwc->is_remote_wakeup_enabled = false; + dwc->is_gadget_wakeup = false; dwc->max_cfg_eps = 0; spin_unlock_irqrestore(&dwc->lock, flags); @@ -3768,6 +3815,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); dwc->connected = false; + linksts_change_events_set(dwc, false); + dwc->is_gadget_wakeup = false; } static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) @@ -3855,6 +3904,10 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_DEVADDR_MASK); dwc3_writel(dwc->regs, DWC3_DCFG, reg); + + dwc->is_remote_wakeup_enabled = false; + linksts_change_events_set(dwc, false); + dwc->is_gadget_wakeup = false; } static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) @@ -3998,8 +4051,9 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) */ } -static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) +static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, unsigned int evtinfo) { + enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; /* * TODO take core out of low power mode when that's * implemented. @@ -4010,6 +4064,8 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) dwc->gadget_driver->resume(dwc->gadget); spin_lock(&dwc->lock); } + + dwc->link_state = next; } static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, @@ -4091,6 +4147,13 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, } switch (next) { + case DWC3_LINK_STATE_U0: + if (dwc->is_gadget_wakeup) { + linksts_change_events_set(dwc, false); + dwc3_resume_gadget(dwc); + dwc->is_gadget_wakeup = false; + } + break; case DWC3_LINK_STATE_U1: if (dwc->speed == USB_SPEED_SUPER) dwc3_suspend_gadget(dwc); @@ -4159,7 +4222,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, dwc3_gadget_conndone_interrupt(dwc); break; case DWC3_DEVICE_EVENT_WAKEUP: - dwc3_gadget_wakeup_interrupt(dwc); + dwc3_gadget_wakeup_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_HIBER_REQ: if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, From patchwork Tue Aug 2 19:18:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elson Serrao X-Patchwork-Id: 595496 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 34120C00140 for ; Tue, 2 Aug 2022 19:18:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232269AbiHBTSr (ORCPT ); Tue, 2 Aug 2022 15:18:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44954 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231539AbiHBTSq (ORCPT ); Tue, 2 Aug 2022 15:18:46 -0400 Received: from alexa-out.qualcomm.com (alexa-out.qualcomm.com [129.46.98.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9B4D013D15; Tue, 2 Aug 2022 12:18:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1659467924; x=1691003924; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=CEiM39jmsZQ3Q7QvJYvHTnmSseG/w2PJb9/iJQV5ItM=; b=G1ooD7130QDJFtdZYQq/aPlorsLy4QiBCYbVdDQ6R/OTO7KgFIbrn3Kc nCWfw1xy6UY+nEXNQYqGPFS3+oERqkQPGDds3oJvRfciMNg4AfCWhF2x4 abjSuDBlgk5NUhDT/gYdqhTVm6RMKQIKfCfTZbAZEfMYjFp8kLwCSLxDT k=; Received: from ironmsg09-lv.qualcomm.com ([10.47.202.153]) by alexa-out.qualcomm.com with ESMTP; 02 Aug 2022 12:18:42 -0700 X-QCInternal: smtphost Received: from hu-eserrao-lv.qualcomm.com (HELO hu-devc-lv-c.qualcomm.com) ([10.47.235.164]) by ironmsg09-lv.qualcomm.com with ESMTP; 02 Aug 2022 12:18:42 -0700 Received: by hu-devc-lv-c.qualcomm.com (Postfix, from userid 464172) id 75857211B4; Tue, 2 Aug 2022 12:18:42 -0700 (PDT) From: Elson Roy Serrao To: balbi@kernel.org, gregkh@linuxfoundation.org Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, quic_wcheng@quicinc.com, quic_jackp@quicinc.com, quic_mrana@quicinc.com, Thinh.Nguyen@synopsys.com, Elson Roy Serrao Subject: [PATCH 2/5] usb: gadget: Add function wakeup support Date: Tue, 2 Aug 2022 12:18:37 -0700 Message-Id: <1659467920-9095-3-git-send-email-quic_eserrao@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> References: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org An interface which is in function suspend state has to send a function wakeup notification to the host in case it needs to initate any data transfer. One notable difference between this and the existing remote wakeup mechanism is that this can be called per-interface, and a UDC would need to know the particular interface number to convey in its Device Notification transaction packet. Hence, we need to introduce a new callback in the gadget_ops structure that UDC device drivers can implement. Similarly add a convenience function in the composite driver which function drivers can call. Add support to handle such requests in the composite layer and invoke the gadget op. Signed-off-by: Elson Roy Serrao --- drivers/usb/gadget/composite.c | 32 ++++++++++++++++++++++++++++++++ drivers/usb/gadget/udc/core.c | 9 +++++++++ include/linux/usb/composite.h | 1 + include/linux/usb/gadget.h | 2 ++ 4 files changed, 44 insertions(+) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 403563c..6bdce23 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -490,6 +490,38 @@ int usb_interface_id(struct usb_configuration *config, } EXPORT_SYMBOL_GPL(usb_interface_id); +int usb_func_wakeup(struct usb_function *func) +{ + int ret, id; + unsigned long flags; + + if (!func || !func->config || !func->config->cdev || + !func->config->cdev->gadget) + return -EINVAL; + + DBG(func->config->cdev, "%s function wakeup\n", func->name); + + spin_lock_irqsave(&func->config->cdev->lock, flags); + + for (id = 0; id < MAX_CONFIG_INTERFACES; id++) + if (func->config->interface[id] == func) + break; + + if (id == MAX_CONFIG_INTERFACES) { + ERROR(func->config->cdev, "Invalid function id:%d\n", id); + ret = -EINVAL; + goto err; + } + + ret = usb_gadget_func_wakeup(func->config->cdev->gadget, id); + +err: + spin_unlock_irqrestore(&func->config->cdev->lock, flags); + + return ret; +} +EXPORT_SYMBOL(usb_func_wakeup); + static u8 encode_bMaxPower(enum usb_device_speed speed, struct usb_configuration *c) { diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 7886497..fe5c504 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -816,6 +816,15 @@ int usb_gadget_activate(struct usb_gadget *gadget) } EXPORT_SYMBOL_GPL(usb_gadget_activate); +int usb_gadget_func_wakeup(struct usb_gadget *gadget, int interface_id) +{ + if (gadget->speed < USB_SPEED_SUPER || !gadget->ops->func_wakeup) + return -EOPNOTSUPP; + + return gadget->ops->func_wakeup(gadget, interface_id); +} +EXPORT_SYMBOL_GPL(usb_gadget_func_wakeup); + /* ------------------------------------------------------------------------- */ #ifdef CONFIG_HAS_DMA diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 9d27622..31b35d7 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -254,6 +254,7 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g, struct usb_function *f, int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, struct usb_ep *_ep); +int usb_func_wakeup(struct usb_function *func); #define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3ad58b7..76f9de4 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -311,6 +311,7 @@ struct usb_udc; struct usb_gadget_ops { int (*get_frame)(struct usb_gadget *); int (*wakeup)(struct usb_gadget *); + int (*func_wakeup)(struct usb_gadget *gadget, int interface_id); int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered); int (*vbus_session) (struct usb_gadget *, int is_active); int (*vbus_draw) (struct usb_gadget *, unsigned mA); @@ -612,6 +613,7 @@ int usb_gadget_disconnect(struct usb_gadget *gadget); int usb_gadget_deactivate(struct usb_gadget *gadget); int usb_gadget_activate(struct usb_gadget *gadget); int usb_gadget_check_config(struct usb_gadget *gadget); +int usb_gadget_func_wakeup(struct usb_gadget *gadget, int interface_id); #else static inline int usb_gadget_frame_number(struct usb_gadget *gadget) { return 0; } From patchwork Tue Aug 2 19:18:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elson Serrao X-Patchwork-Id: 595074 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6AD3BC00140 for ; Tue, 2 Aug 2022 19:18:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230014AbiHBTSp (ORCPT ); Tue, 2 Aug 2022 15:18:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44930 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229532AbiHBTSo (ORCPT ); Tue, 2 Aug 2022 15:18:44 -0400 Received: from alexa-out.qualcomm.com (alexa-out.qualcomm.com [129.46.98.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 877B613CCE; Tue, 2 Aug 2022 12:18:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1659467923; x=1691003923; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=Ky3hajG51y45sWKL2Azm+Pql0QLC7hUAs8rv8/gaqfw=; b=FCb9vVFYx0OvpzLtDKwrn1exv+woOqnt1TtEGIBeRiF2eDVbcHWPPbjh lTg+uK/Wcsb/aUpZkQSzb6+NvLRQJ8/BZcP1OehTqW/lgkxLNJzU7qgLk pZUBiOj5PEjBkVS0Z9wDicBBN+uP6CslvLejkDLzHTsTlUqOVfQajGQOY A=; Received: from ironmsg09-lv.qualcomm.com ([10.47.202.153]) by alexa-out.qualcomm.com with ESMTP; 02 Aug 2022 12:18:42 -0700 X-QCInternal: smtphost Received: from hu-eserrao-lv.qualcomm.com (HELO hu-devc-lv-c.qualcomm.com) ([10.47.235.164]) by ironmsg09-lv.qualcomm.com with ESMTP; 02 Aug 2022 12:18:42 -0700 Received: by hu-devc-lv-c.qualcomm.com (Postfix, from userid 464172) id 78DF9211BD; Tue, 2 Aug 2022 12:18:42 -0700 (PDT) From: Elson Roy Serrao To: balbi@kernel.org, gregkh@linuxfoundation.org Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, quic_wcheng@quicinc.com, quic_jackp@quicinc.com, quic_mrana@quicinc.com, Thinh.Nguyen@synopsys.com, Elson Roy Serrao Subject: [PATCH 3/5] usb: dwc3: Add function suspend and function wakeup support Date: Tue, 2 Aug 2022 12:18:38 -0700 Message-Id: <1659467920-9095-4-git-send-email-quic_eserrao@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> References: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org USB host sends function suspend and resume notifications to device through SET_FEATURE setup packet. This packet is directed to the interface to which function suspend/resume is intended to. Add support to handle this packet by delegating the request to composite layer. To exit from function suspend the interface needs to trigger a function wakeup in case it wants to initate a data transfer. Expose a new gadget op so that an interface can send function wakeup request to the host. Signed-off-by: Elson Roy Serrao --- drivers/usb/dwc3/core.h | 1 + drivers/usb/dwc3/ep0.c | 12 ++++-------- drivers/usb/dwc3/gadget.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 3306b1c..e08e522 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -519,6 +519,7 @@ #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04 #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI 0x05 +#define DWC3_DGCMD_XMIT_DEV 0x07 #define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09 #define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 4cc3d3a..cedc890 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -30,6 +30,8 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl); static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, dma_addr_t buf_dma, u32 len, u32 type, bool chain) @@ -365,7 +367,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ - break; + return dwc3_ep0_delegate_req(dwc, ctrl); case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); @@ -511,13 +513,7 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc, switch (wValue) { case USB_INTRF_FUNC_SUSPEND: - /* - * REVISIT: Ideally we would enable some low power mode here, - * however it's unclear what we should be doing here. - * - * For now, we're not doing anything, just making sure we return - * 0 so USB Command Verifier tests pass without any errors. - */ + ret = dwc3_ep0_delegate_req(dwc, ctrl); break; default: ret = -EINVAL; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d6697da..0b2947e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2357,6 +2357,35 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) return ret; } +static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int interface_id) +{ + int ret = 0; + u32 reg; + struct dwc3 *dwc = gadget_to_dwc(g); + + reg = dwc3_readl(dwc->regs, DWC3_DSTS); + + /* + * If the link is in LPM, first bring the link to U0 + * before triggering function wakeup. Ideally this + * needs to be expanded to other LPMs as well in + * addition to U3 + */ + if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U3) { + dwc3_gadget_wakeup(g); + return -EAGAIN; + } + + ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_XMIT_DEV, + 0x1 | (interface_id << 4)); + + if (ret) + dev_err(dwc->dev, "Function wakeup HW command failed, ret %d\n", + ret); + + return ret; +} + static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, int is_selfpowered) { @@ -2978,6 +3007,7 @@ static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable) static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, + .func_wakeup = dwc3_gadget_func_wakeup, .set_selfpowered = dwc3_gadget_set_selfpowered, .pullup = dwc3_gadget_pullup, .udc_start = dwc3_gadget_start, From patchwork Tue Aug 2 19:18:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elson Serrao X-Patchwork-Id: 595495 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1F0D3C00140 for ; Tue, 2 Aug 2022 19:20:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229684AbiHBTUD (ORCPT ); Tue, 2 Aug 2022 15:20:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45686 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230153AbiHBTTb (ORCPT ); Tue, 2 Aug 2022 15:19:31 -0400 Received: from alexa-out.qualcomm.com (alexa-out.qualcomm.com [129.46.98.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CA7D852FD3; Tue, 2 Aug 2022 12:19:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1659467962; x=1691003962; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=dp6FpXSnj7Kdrprl3gFX+M+yxPPFELr3jMZgt5ns6iE=; b=fdjZiYAK8XL5I+q2uESOvs5zcelmrxKq2uH3ubxfdHroWqjmzLpdKl8j 8OWZwKsVXM5gK/ROJrHUOeciJfcrax9sRZkGtYMH5Cf5lgkKWyrUWyKBV W28qXxSR1MHng3szYD3mhTJPpQeQT7BLL6vqan/SDDNSA6qypO5jonAlh Y=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 02 Aug 2022 12:19:22 -0700 X-QCInternal: smtphost Received: from hu-eserrao-lv.qualcomm.com (HELO hu-devc-lv-c.qualcomm.com) ([10.47.235.164]) by ironmsg08-lv.qualcomm.com with ESMTP; 02 Aug 2022 12:19:23 -0700 Received: by hu-devc-lv-c.qualcomm.com (Postfix, from userid 464172) id 7C4D5211BE; Tue, 2 Aug 2022 12:18:42 -0700 (PDT) From: Elson Roy Serrao To: balbi@kernel.org, gregkh@linuxfoundation.org Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, quic_wcheng@quicinc.com, quic_jackp@quicinc.com, quic_mrana@quicinc.com, Thinh.Nguyen@synopsys.com, Elson Roy Serrao Subject: [PATCH 4/5] usb: gadget: f_ecm: Add suspend/resume and remote wakeup support Date: Tue, 2 Aug 2022 12:18:39 -0700 Message-Id: <1659467920-9095-5-git-send-email-quic_eserrao@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> References: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org When the host sends a suspend notification to the device, handle the suspend callbacks in the function driver. Depending on the remote wakeup capability the device can either trigger a remote wakeup or wait for the host initiated resume to start data transfer again. Signed-off-by: Elson Roy Serrao --- drivers/usb/gadget/function/f_ecm.c | 22 +++++++++++ drivers/usb/gadget/function/u_ether.c | 72 +++++++++++++++++++++++++++++++++++ drivers/usb/gadget/function/u_ether.h | 4 ++ 3 files changed, 98 insertions(+) diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index ffe2486..fb1dec3 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -889,6 +889,26 @@ static struct usb_function_instance *ecm_alloc_inst(void) return &opts->func_inst; } +static void ecm_suspend(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Suspend\n"); + + gether_suspend(&ecm->port); +} + +static void ecm_resume(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Resume\n"); + + gether_resume(&ecm->port); +} + static void ecm_free(struct usb_function *f) { struct f_ecm *ecm; @@ -956,6 +976,8 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi) ecm->port.func.setup = ecm_setup; ecm->port.func.disable = ecm_disable; ecm->port.func.free_func = ecm_free; + ecm->port.func.suspend = ecm_suspend; + ecm->port.func.resume = ecm_resume; return &ecm->port.func; } diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 7887def..78391de 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -471,6 +471,18 @@ static inline int is_promisc(u16 cdc_filter) return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; } +static int ether_wakeup_host(struct gether *port) +{ + int ret = -EOPNOTSUPP; + struct usb_function *func = &port->func; + struct usb_gadget *gadget = func->config->cdev->gadget; + + if (gadget->speed < USB_SPEED_SUPER) + ret = usb_gadget_wakeup(gadget); + + return ret; +} + static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct net_device *net) { @@ -490,6 +502,25 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, in = NULL; cdc_filter = 0; } + + if (dev->port_usb->is_suspend) { + DBG(dev, "Port suspended. Triggering wakeup\n"); + retval = ether_wakeup_host(dev->port_usb); + if (retval) { + /* + * Either the remote wakeup is not yet complete or + * wakeup is not supported. In either case we cannot + * send data and hence inform the upper layer to stop + * sending data. The queue is re-started in resume + * callback once the remote wakeup is successful or when + * host initiated resume happens. + */ + netif_stop_queue(net); + spin_unlock_irqrestore(&dev->lock, flags); + return NETDEV_TX_BUSY; + } + } + spin_unlock_irqrestore(&dev->lock, flags); if (!in) { @@ -1050,6 +1081,46 @@ int gether_set_ifname(struct net_device *net, const char *name, int len) } EXPORT_SYMBOL_GPL(gether_set_ifname); +void gether_suspend(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (atomic_read(&dev->tx_qlen)) { + /* + * There is a transfer in progress. So we trigger a remote + * wakeup to inform the host. + */ + ether_wakeup_host(dev->port_usb); + return; + } + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = true; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_suspend); + +void gether_resume(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + spin_lock_irqsave(&dev->lock, flags); + + if (netif_queue_stopped(dev->net)) + netif_start_queue(dev->net); + + link->is_suspend = false; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_resume); + /* * gether_cleanup - remove Ethernet-over-USB device * Context: may sleep @@ -1212,6 +1283,7 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->lock); dev->port_usb = NULL; + link->is_suspend = false; spin_unlock(&dev->lock); } EXPORT_SYMBOL_GPL(gether_disconnect); diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 4014454..851ee10 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -79,6 +79,7 @@ struct gether { /* called on network open/close */ void (*open)(struct gether *); void (*close)(struct gether *); + bool is_suspend; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ @@ -258,6 +259,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len); void gether_cleanup(struct eth_dev *dev); +void gether_suspend(struct gether *link); +void gether_resume(struct gether *link); + /* connect/disconnect is handled by individual functions */ struct net_device *gether_connect(struct gether *); void gether_disconnect(struct gether *); From patchwork Tue Aug 2 19:18:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elson Serrao X-Patchwork-Id: 595497 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE235C19F2B for ; Tue, 2 Aug 2022 19:18:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232191AbiHBTSq (ORCPT ); Tue, 2 Aug 2022 15:18:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44928 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229696AbiHBTSo (ORCPT ); Tue, 2 Aug 2022 15:18:44 -0400 Received: from alexa-out.qualcomm.com (alexa-out.qualcomm.com [129.46.98.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8775612D28; Tue, 2 Aug 2022 12:18:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1659467923; x=1691003923; h=from:to:cc:subject:date:message-id:in-reply-to: references; bh=sBG+z2TYW905hIHdQlM191qs+E/BURDyZkyYXkH+wL4=; b=FzI0fwbbSVGYH+HLJjT+xzAtyj9A4r+gxxA2JGi+iX+SLhH0liaI8uOM MH3RmN+ntdPtipAVxK7aFGyw/Lrn6OnXDgQ3ma9tafccwpMpotYXMrRGH cSI5+hlaRjzdXvRnh4dMgAhzDYt3YsnjWVHI40FFYs+pxxae6lON/p8Fm g=; Received: from ironmsg08-lv.qualcomm.com ([10.47.202.152]) by alexa-out.qualcomm.com with ESMTP; 02 Aug 2022 12:18:43 -0700 X-QCInternal: smtphost Received: from hu-eserrao-lv.qualcomm.com (HELO hu-devc-lv-c.qualcomm.com) ([10.47.235.164]) by ironmsg08-lv.qualcomm.com with ESMTP; 02 Aug 2022 12:18:43 -0700 Received: by hu-devc-lv-c.qualcomm.com (Postfix, from userid 464172) id 7F08A211BF; Tue, 2 Aug 2022 12:18:42 -0700 (PDT) From: Elson Roy Serrao To: balbi@kernel.org, gregkh@linuxfoundation.org Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, quic_wcheng@quicinc.com, quic_jackp@quicinc.com, quic_mrana@quicinc.com, Thinh.Nguyen@synopsys.com, Elson Roy Serrao Subject: [PATCH 5/5] usb: gadget: f_ecm: Add function suspend and wakeup support Date: Tue, 2 Aug 2022 12:18:40 -0700 Message-Id: <1659467920-9095-6-git-send-email-quic_eserrao@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> References: <1659467920-9095-1-git-send-email-quic_eserrao@quicinc.com> Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org USB host sends function suspend setup packet to an interface when there is no active communication involved. Handle such requests from host so that the interface goes to function suspend state. For the device to resume data transfer it can either send a function wakeup notification or wait for the host initated function resume depending on the function wakeup capability of the device. Add support to trigger function wakeup. Signed-off-by: Elson Roy Serrao --- drivers/usb/gadget/function/f_ecm.c | 49 +++++++++++++++++++++++++++++++++-- drivers/usb/gadget/function/u_ether.c | 32 ++++++++++++++++++++--- drivers/usb/gadget/function/u_ether.h | 6 +++-- 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index fb1dec3..8bb7e3c 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -54,6 +54,8 @@ struct f_ecm { u8 notify_state; atomic_t notify_count; bool is_open; + bool func_wakeup_allowed; + bool func_is_suspended; /* FIXME is_open needs some irq-ish locking * ... possibly the same as port.ioport @@ -631,6 +633,8 @@ static void ecm_disable(struct usb_function *f) ecm->port.out_ep->desc = NULL; } + ecm->func_wakeup_allowed = false; + ecm->func_is_suspended = false; usb_ep_disable(ecm->notify); ecm->notify->desc = NULL; } @@ -894,9 +898,14 @@ static void ecm_suspend(struct usb_function *f) struct f_ecm *ecm = func_to_ecm(f); struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + if (ecm->func_is_suspended) { + DBG(cdev, "Function already suspended\n"); + return; + } + DBG(cdev, "ECM Suspend\n"); - gether_suspend(&ecm->port); + gether_suspend(&ecm->port, ecm->func_wakeup_allowed); } static void ecm_resume(struct usb_function *f) @@ -906,7 +915,41 @@ static void ecm_resume(struct usb_function *f) DBG(cdev, "ECM Resume\n"); - gether_resume(&ecm->port); + gether_resume(&ecm->port, ecm->func_is_suspended); +} + +static int ecm_get_status(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + + return (ecm->func_wakeup_allowed ? USB_INTRF_STAT_FUNC_RW : 0) | + USB_INTRF_STAT_FUNC_RW_CAP; +} + +static int ecm_func_suspend(struct usb_function *f, u8 options) +{ + bool func_wakeup_allowed; + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "func susp %u cmd\n", options); + + func_wakeup_allowed = !!(options & (USB_INTRF_FUNC_SUSPEND_RW >> 8)); + if (options & (USB_INTRF_FUNC_SUSPEND_LP >> 8)) { + ecm->func_wakeup_allowed = func_wakeup_allowed; + if (!ecm->func_is_suspended) { + ecm_suspend(f); + ecm->func_is_suspended = true; + } + } else { + if (ecm->func_is_suspended) { + ecm->func_is_suspended = false; + ecm_resume(f); + } + ecm->func_wakeup_allowed = func_wakeup_allowed; + } + + return 0; } static void ecm_free(struct usb_function *f) @@ -977,6 +1020,8 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi) ecm->port.func.disable = ecm_disable; ecm->port.func.free_func = ecm_free; ecm->port.func.suspend = ecm_suspend; + ecm->port.func.get_status = ecm_get_status; + ecm->port.func.func_suspend = ecm_func_suspend; ecm->port.func.resume = ecm_resume; return &ecm->port.func; diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 78391de..f3e1c9b 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -477,8 +477,17 @@ static int ether_wakeup_host(struct gether *port) struct usb_function *func = &port->func; struct usb_gadget *gadget = func->config->cdev->gadget; - if (gadget->speed < USB_SPEED_SUPER) + if (gadget->speed >= USB_SPEED_SUPER) { + if (!port->func_wakeup_allowed) { + DBG(port->ioport, "Function wakeup not allowed\n"); + return -EOPNOTSUPP; + } + ret = usb_func_wakeup(func); + if (ret) + port->is_wakeup_pending = true; + } else { ret = usb_gadget_wakeup(gadget); + } return ret; } @@ -1081,7 +1090,7 @@ int gether_set_ifname(struct net_device *net, const char *name, int len) } EXPORT_SYMBOL_GPL(gether_set_ifname); -void gether_suspend(struct gether *link) +void gether_suspend(struct gether *link, bool wakeup_allowed) { struct eth_dev *dev = link->ioport; unsigned long flags; @@ -1099,13 +1108,15 @@ void gether_suspend(struct gether *link) } spin_lock_irqsave(&dev->lock, flags); link->is_suspend = true; + link->func_wakeup_allowed = wakeup_allowed; spin_unlock_irqrestore(&dev->lock, flags); } EXPORT_SYMBOL_GPL(gether_suspend); -void gether_resume(struct gether *link) +void gether_resume(struct gether *link, bool func_suspend) { struct eth_dev *dev = link->ioport; + struct usb_function *func = &link->func; unsigned long flags; if (!dev) @@ -1113,6 +1124,19 @@ void gether_resume(struct gether *link) spin_lock_irqsave(&dev->lock, flags); + /* + * If the function is in USB3 Function Suspend state, resume is + * canceled. In this case resume is done by a Function Resume request. + */ + if (func_suspend) { + if (link->is_wakeup_pending) { + usb_func_wakeup(func); + link->is_wakeup_pending = false; + } + spin_unlock_irqrestore(&dev->lock, flags); + return; + } + if (netif_queue_stopped(dev->net)) netif_start_queue(dev->net); @@ -1284,6 +1308,8 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->lock); dev->port_usb = NULL; link->is_suspend = false; + link->is_wakeup_pending = false; + link->func_wakeup_allowed = false; spin_unlock(&dev->lock); } EXPORT_SYMBOL_GPL(gether_disconnect); diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 851ee10..4a6aa646 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -80,6 +80,8 @@ struct gether { void (*open)(struct gether *); void (*close)(struct gether *); bool is_suspend; + bool is_wakeup_pending; + bool func_wakeup_allowed; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ @@ -259,8 +261,8 @@ int gether_set_ifname(struct net_device *net, const char *name, int len); void gether_cleanup(struct eth_dev *dev); -void gether_suspend(struct gether *link); -void gether_resume(struct gether *link); +void gether_suspend(struct gether *link, bool wakeup_allowed); +void gether_resume(struct gether *link, bool func_suspend); /* connect/disconnect is handled by individual functions */ struct net_device *gether_connect(struct gether *);