* [PATCH v2 0/3] Fixes for USB3 CV Chapter 9.15 tests
@ 2025-04-22 10:32 Prashanth K
2025-04-22 10:32 ` [PATCH v2 1/3] usb: gadget: f_ecm: Add get_status callback Prashanth K
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Prashanth K @ 2025-04-22 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Thinh Nguyen, Kees Bakker, William McVicker,
Marek Szyprowski
Cc: linux-usb, linux-kernel, Prashanth K
While performing USB3 Command Verifier Chapter 9 tests, failures
were observed during 9.15 ("Function Remote Wakeup Enabled Test").
This is due to the following reasons,
1. Interfaces were incorrectly reporting as remote wakeup capable
when host requested GET_STATUS.
2. Remote wakeup failures from DWC3 driver due to timeouts.
Address them through this series.
Changes in v2:
- Don't advertise func wakeup capability if USB_CONFIG_ATT_WAKEUP
is not set in bmAttributes.
- Refactored func wakeup logic in linksts_change_interrupt().
Prashanth K (3):
usb: gadget: f_ecm: Add get_status callback
usb: gadget: Use get_status callback to set remote wakeup capability
usb: dwc3: gadget: Make gadget_wakeup asynchronous
drivers/usb/dwc3/core.h | 4 ++
drivers/usb/dwc3/gadget.c | 60 +++++++++++------------------
drivers/usb/gadget/composite.c | 12 +++---
drivers/usb/gadget/function/f_ecm.c | 7 ++++
4 files changed, 39 insertions(+), 44 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v2 1/3] usb: gadget: f_ecm: Add get_status callback 2025-04-22 10:32 [PATCH v2 0/3] Fixes for USB3 CV Chapter 9.15 tests Prashanth K @ 2025-04-22 10:32 ` Prashanth K 2025-04-22 22:13 ` Thinh Nguyen 2025-04-22 10:32 ` [PATCH v2 2/3] usb: gadget: Use get_status callback to set remote wakeup capability Prashanth K 2025-04-22 10:32 ` [PATCH v2 3/3] usb: dwc3: gadget: Make gadget_wakeup asynchronous Prashanth K 2 siblings, 1 reply; 7+ messages in thread From: Prashanth K @ 2025-04-22 10:32 UTC (permalink / raw) To: Greg Kroah-Hartman, Thinh Nguyen, Kees Bakker, William McVicker, Marek Szyprowski Cc: linux-usb, linux-kernel, Prashanth K, stable When host sends GET_STATUS to ECM interface, handle the request from the function driver. Since the interface is wakeup capable, set the corresponding bit, and set RW bit if the function is already armed for wakeup by the host. Cc: stable@kernel.org Fixes: 481c225c4802 ("usb: gadget: Handle function suspend feature selector") Signed-off-by: Prashanth K <prashanth.k@oss.qualcomm.com> --- drivers/usb/gadget/function/f_ecm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index 80841de845b0..027226325039 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -892,6 +892,12 @@ static void ecm_resume(struct usb_function *f) gether_resume(&ecm->port); } +static int ecm_get_status(struct usb_function *f) +{ + return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) | + USB_INTRF_STAT_FUNC_RW_CAP; +} + static void ecm_free(struct usb_function *f) { struct f_ecm *ecm; @@ -960,6 +966,7 @@ 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.resume = ecm_resume; return &ecm->port.func; -- 2.25.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/3] usb: gadget: f_ecm: Add get_status callback 2025-04-22 10:32 ` [PATCH v2 1/3] usb: gadget: f_ecm: Add get_status callback Prashanth K @ 2025-04-22 22:13 ` Thinh Nguyen 0 siblings, 0 replies; 7+ messages in thread From: Thinh Nguyen @ 2025-04-22 22:13 UTC (permalink / raw) To: Prashanth K Cc: Greg Kroah-Hartman, Thinh Nguyen, Kees Bakker, William McVicker, Marek Szyprowski, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, stable@kernel.org On Tue, Apr 22, 2025, Prashanth K wrote: > When host sends GET_STATUS to ECM interface, handle the request > from the function driver. Since the interface is wakeup capable, > set the corresponding bit, and set RW bit if the function is > already armed for wakeup by the host. > > Cc: stable@kernel.org > Fixes: 481c225c4802 ("usb: gadget: Handle function suspend feature selector") > Signed-off-by: Prashanth K <prashanth.k@oss.qualcomm.com> > --- > drivers/usb/gadget/function/f_ecm.c | 7 +++++++ > 1 file changed, 7 insertions(+) > > diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c > index 80841de845b0..027226325039 100644 > --- a/drivers/usb/gadget/function/f_ecm.c > +++ b/drivers/usb/gadget/function/f_ecm.c > @@ -892,6 +892,12 @@ static void ecm_resume(struct usb_function *f) > gether_resume(&ecm->port); > } > > +static int ecm_get_status(struct usb_function *f) > +{ > + return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) | > + USB_INTRF_STAT_FUNC_RW_CAP; > +} > + > static void ecm_free(struct usb_function *f) > { > struct f_ecm *ecm; > @@ -960,6 +966,7 @@ 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.resume = ecm_resume; > > return &ecm->port.func; > -- > 2.25.1 > Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Thanks, Thinh ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/3] usb: gadget: Use get_status callback to set remote wakeup capability 2025-04-22 10:32 [PATCH v2 0/3] Fixes for USB3 CV Chapter 9.15 tests Prashanth K 2025-04-22 10:32 ` [PATCH v2 1/3] usb: gadget: f_ecm: Add get_status callback Prashanth K @ 2025-04-22 10:32 ` Prashanth K 2025-04-22 22:15 ` Thinh Nguyen 2025-04-22 10:32 ` [PATCH v2 3/3] usb: dwc3: gadget: Make gadget_wakeup asynchronous Prashanth K 2 siblings, 1 reply; 7+ messages in thread From: Prashanth K @ 2025-04-22 10:32 UTC (permalink / raw) To: Greg Kroah-Hartman, Thinh Nguyen, Kees Bakker, William McVicker, Marek Szyprowski Cc: linux-usb, linux-kernel, Prashanth K, stable Currently when the host sends GET_STATUS request for an interface, we use get_status callbacks to set/clear remote wakeup capability of that interface. And if get_status callback isn't present for that interface, then we assume its remote wakeup capability based on bmAttributes. Now consider a scenario, where we have a USB configuration with multiple interfaces (say ECM + ADB), here ECM is remote wakeup capable and as of now ADB isn't. And bmAttributes will indicate the device as wakeup capable. With the current implementation, when host sends GET_STATUS request for both interfaces, we will set FUNC_RW_CAP for both. This results in USB3 CV Chapter 9.15 (Function Remote Wakeup Test) failures as host expects remote wakeup from both interfaces. The above scenario is just an example, and the failure can be observed if we use configuration with any interface except ECM. Hence avoid configuring remote wakeup capability from composite driver based on bmAttributes, instead use get_status callbacks and let the function drivers decide this. Cc: stable@kernel.org Fixes: 481c225c4802 ("usb: gadget: Handle function suspend feature selector") Signed-off-by: Prashanth K <prashanth.k@oss.qualcomm.com> --- drivers/usb/gadget/composite.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 869ad99afb48..8dbc132a505e 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2011,15 +2011,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (f->get_status) { status = f->get_status(f); + if (status < 0) break; - } else { - /* Set D0 and D1 bits based on func wakeup capability */ - if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) { - status |= USB_INTRF_STAT_FUNC_RW_CAP; - if (f->func_wakeup_armed) - status |= USB_INTRF_STAT_FUNC_RW; - } + + /* if D5 is not set, then device is not wakeup capable */ + if (!(f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP)) + status &= ~(USB_INTRF_STAT_FUNC_RW_CAP | USB_INTRF_STAT_FUNC_RW); } put_unaligned_le16(status & 0x0000ffff, req->buf); -- 2.25.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 2/3] usb: gadget: Use get_status callback to set remote wakeup capability 2025-04-22 10:32 ` [PATCH v2 2/3] usb: gadget: Use get_status callback to set remote wakeup capability Prashanth K @ 2025-04-22 22:15 ` Thinh Nguyen 0 siblings, 0 replies; 7+ messages in thread From: Thinh Nguyen @ 2025-04-22 22:15 UTC (permalink / raw) To: Prashanth K Cc: Greg Kroah-Hartman, Thinh Nguyen, Kees Bakker, William McVicker, Marek Szyprowski, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, stable@kernel.org On Tue, Apr 22, 2025, Prashanth K wrote: > Currently when the host sends GET_STATUS request for an interface, > we use get_status callbacks to set/clear remote wakeup capability > of that interface. And if get_status callback isn't present for > that interface, then we assume its remote wakeup capability based > on bmAttributes. > > Now consider a scenario, where we have a USB configuration with > multiple interfaces (say ECM + ADB), here ECM is remote wakeup > capable and as of now ADB isn't. And bmAttributes will indicate > the device as wakeup capable. With the current implementation, > when host sends GET_STATUS request for both interfaces, we will > set FUNC_RW_CAP for both. This results in USB3 CV Chapter 9.15 > (Function Remote Wakeup Test) failures as host expects remote > wakeup from both interfaces. > > The above scenario is just an example, and the failure can be > observed if we use configuration with any interface except ECM. > Hence avoid configuring remote wakeup capability from composite > driver based on bmAttributes, instead use get_status callbacks > and let the function drivers decide this. > > Cc: stable@kernel.org > Fixes: 481c225c4802 ("usb: gadget: Handle function suspend feature selector") > Signed-off-by: Prashanth K <prashanth.k@oss.qualcomm.com> > --- > drivers/usb/gadget/composite.c | 12 +++++------- > 1 file changed, 5 insertions(+), 7 deletions(-) > > diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c > index 869ad99afb48..8dbc132a505e 100644 > --- a/drivers/usb/gadget/composite.c > +++ b/drivers/usb/gadget/composite.c > @@ -2011,15 +2011,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) > > if (f->get_status) { > status = f->get_status(f); > + > if (status < 0) > break; > - } else { > - /* Set D0 and D1 bits based on func wakeup capability */ > - if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) { > - status |= USB_INTRF_STAT_FUNC_RW_CAP; > - if (f->func_wakeup_armed) > - status |= USB_INTRF_STAT_FUNC_RW; > - } > + > + /* if D5 is not set, then device is not wakeup capable */ > + if (!(f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP)) > + status &= ~(USB_INTRF_STAT_FUNC_RW_CAP | USB_INTRF_STAT_FUNC_RW); > } > > put_unaligned_le16(status & 0x0000ffff, req->buf); > -- > 2.25.1 > Reviewed-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Thanks, Thinh ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 3/3] usb: dwc3: gadget: Make gadget_wakeup asynchronous 2025-04-22 10:32 [PATCH v2 0/3] Fixes for USB3 CV Chapter 9.15 tests Prashanth K 2025-04-22 10:32 ` [PATCH v2 1/3] usb: gadget: f_ecm: Add get_status callback Prashanth K 2025-04-22 10:32 ` [PATCH v2 2/3] usb: gadget: Use get_status callback to set remote wakeup capability Prashanth K @ 2025-04-22 10:32 ` Prashanth K 2025-04-22 22:11 ` Thinh Nguyen 2 siblings, 1 reply; 7+ messages in thread From: Prashanth K @ 2025-04-22 10:32 UTC (permalink / raw) To: Greg Kroah-Hartman, Thinh Nguyen, Kees Bakker, William McVicker, Marek Szyprowski Cc: linux-usb, linux-kernel, Prashanth K, stable Currently gadget_wakeup() waits for U0 synchronously if it was called from func_wakeup(), this is because we need to send the function wakeup command soon after the link is active. And the call is made synchronous by polling DSTS continuosly for 20000 times in __dwc3_gadget_wakeup(). But it observed that sometimes the link is not active even after polling 20K times, leading to remote wakeup failures. Adding a small delay between each poll helps, but that won't guarantee resolution in future. Hence make the gadget_wakeup completely asynchronous. Since multiple interfaces can issue a function wakeup at once, add a new variable wakeup_pending_funcs which will indicate the functions that has issued func_wakup, this is represented in a bitmap format. If the link is in U3, dwc3_gadget_func_wakeup() will set the bit corresponding to interface_id and bail out. Once link comes back to U0, linksts_change irq is triggered, where the function wakeup command is sent based on bitmap. Cc: stable@kernel.org Fixes: 92c08a84b53e ("usb: dwc3: Add function suspend and function wakeup support") Signed-off-by: Prashanth K <prashanth.k@oss.qualcomm.com> --- drivers/usb/dwc3/core.h | 4 +++ drivers/usb/dwc3/gadget.c | 60 +++++++++++++++------------------------ 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index aaa39e663f60..27eae4cf223d 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1164,6 +1164,9 @@ struct dwc3_scratchpad_array { * @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO, * DATWRREQINFO, and DESWRREQINFO value passed from * glue driver. + * @wakeup_pending_funcs: Indicates whether any interface has requested for + * function wakeup in bitmap format where bit position + * represents interface_id. */ struct dwc3 { struct work_struct drd_work; @@ -1394,6 +1397,7 @@ struct dwc3 { int num_ep_resized; struct dentry *debug_root; u32 gsbuscfg0_reqinfo; + u32 wakeup_pending_funcs; }; #define INCRX_BURST_MODE 0 diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 47e73c4ed62d..69ec9cf57663 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -276,8 +276,6 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, return ret; } -static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async); - /** * dwc3_send_gadget_ep_cmd - issue an endpoint command * @dep: the endpoint to which the command is going to be issued @@ -2359,10 +2357,8 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) return __dwc3_gadget_get_frame(dwc); } -static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) +static int __dwc3_gadget_wakeup(struct dwc3 *dwc) { - int retries; - int ret; u32 reg; @@ -2390,8 +2386,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) return -EINVAL; } - if (async) - dwc3_gadget_enable_linksts_evts(dwc, true); + dwc3_gadget_enable_linksts_evts(dwc, true); ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); if (ret < 0) { @@ -2410,27 +2405,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) /* * Since link status change events are enabled we will receive - * an U0 event when wakeup is successful. So bail out. + * an U0 event when wakeup is successful. */ - if (async) - return 0; - - /* poll until Link State changes to ON */ - retries = 20000; - - while (retries--) { - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - - /* in HS, means ON */ - if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0) - break; - } - - if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { - dev_err(dwc->dev, "failed to send remote wakeup\n"); - return -EINVAL; - } - return 0; } @@ -2451,7 +2427,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } - ret = __dwc3_gadget_wakeup(dwc, true); + ret = __dwc3_gadget_wakeup(dwc); spin_unlock_irqrestore(&dwc->lock, flags); @@ -2479,14 +2455,10 @@ static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id) */ link_state = dwc3_gadget_get_link_state(dwc); if (link_state == DWC3_LINK_STATE_U3) { - ret = __dwc3_gadget_wakeup(dwc, false); - if (ret) { - spin_unlock_irqrestore(&dwc->lock, flags); - return -EINVAL; - } - dwc3_resume_gadget(dwc); - dwc->suspended = false; - dwc->link_state = DWC3_LINK_STATE_U0; + dwc->wakeup_pending_funcs |= BIT(intf_id); + ret = __dwc3_gadget_wakeup(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); + return ret; } ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION, @@ -4353,6 +4325,8 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, { enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; unsigned int pwropt; + int ret; + int intf_id; /* * WORKAROUND: DWC3 < 2.50a have an issue when configured without @@ -4428,7 +4402,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, switch (next) { case DWC3_LINK_STATE_U0: - if (dwc->gadget->wakeup_armed) { + if (dwc->gadget->wakeup_armed || dwc->wakeup_pending_funcs) { dwc3_gadget_enable_linksts_evts(dwc, false); dwc3_resume_gadget(dwc); dwc->suspended = false; @@ -4451,6 +4425,18 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, } dwc->link_state = next; + + /* Proceed with func wakeup if any interfaces that has requested */ + while (dwc->wakeup_pending_funcs && (next == DWC3_LINK_STATE_U0)) { + intf_id = ffs(dwc->wakeup_pending_funcs) - 1; + ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION, + DWC3_DGCMDPAR_DN_FUNC_WAKE | + DWC3_DGCMDPAR_INTF_SEL(intf_id)); + if (ret) + dev_err(dwc->dev, "Failed to send DN wake for intf %d\n", intf_id); + + dwc->wakeup_pending_funcs &= ~BIT(intf_id); + } } static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc, -- 2.25.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 3/3] usb: dwc3: gadget: Make gadget_wakeup asynchronous 2025-04-22 10:32 ` [PATCH v2 3/3] usb: dwc3: gadget: Make gadget_wakeup asynchronous Prashanth K @ 2025-04-22 22:11 ` Thinh Nguyen 0 siblings, 0 replies; 7+ messages in thread From: Thinh Nguyen @ 2025-04-22 22:11 UTC (permalink / raw) To: Prashanth K Cc: Greg Kroah-Hartman, Thinh Nguyen, Kees Bakker, William McVicker, Marek Szyprowski, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, stable@kernel.org On Tue, Apr 22, 2025, Prashanth K wrote: > Currently gadget_wakeup() waits for U0 synchronously if it was > called from func_wakeup(), this is because we need to send the > function wakeup command soon after the link is active. And the > call is made synchronous by polling DSTS continuosly for 20000 > times in __dwc3_gadget_wakeup(). But it observed that sometimes > the link is not active even after polling 20K times, leading to > remote wakeup failures. Adding a small delay between each poll > helps, but that won't guarantee resolution in future. Hence make > the gadget_wakeup completely asynchronous. > > Since multiple interfaces can issue a function wakeup at once, > add a new variable wakeup_pending_funcs which will indicate the > functions that has issued func_wakup, this is represented in a > bitmap format. If the link is in U3, dwc3_gadget_func_wakeup() > will set the bit corresponding to interface_id and bail out. > Once link comes back to U0, linksts_change irq is triggered, > where the function wakeup command is sent based on bitmap. > > Cc: stable@kernel.org > Fixes: 92c08a84b53e ("usb: dwc3: Add function suspend and function wakeup support") > Signed-off-by: Prashanth K <prashanth.k@oss.qualcomm.com> > --- > drivers/usb/dwc3/core.h | 4 +++ > drivers/usb/dwc3/gadget.c | 60 +++++++++++++++------------------------ > 2 files changed, 27 insertions(+), 37 deletions(-) > > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h > index aaa39e663f60..27eae4cf223d 100644 > --- a/drivers/usb/dwc3/core.h > +++ b/drivers/usb/dwc3/core.h > @@ -1164,6 +1164,9 @@ struct dwc3_scratchpad_array { > * @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO, > * DATWRREQINFO, and DESWRREQINFO value passed from > * glue driver. > + * @wakeup_pending_funcs: Indicates whether any interface has requested for > + * function wakeup in bitmap format where bit position > + * represents interface_id. > */ > struct dwc3 { > struct work_struct drd_work; > @@ -1394,6 +1397,7 @@ struct dwc3 { > int num_ep_resized; > struct dentry *debug_root; > u32 gsbuscfg0_reqinfo; > + u32 wakeup_pending_funcs; > }; > > #define INCRX_BURST_MODE 0 > diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c > index 47e73c4ed62d..69ec9cf57663 100644 > --- a/drivers/usb/dwc3/gadget.c > +++ b/drivers/usb/dwc3/gadget.c > @@ -276,8 +276,6 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, > return ret; > } > > -static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async); > - > /** > * dwc3_send_gadget_ep_cmd - issue an endpoint command > * @dep: the endpoint to which the command is going to be issued > @@ -2359,10 +2357,8 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) > return __dwc3_gadget_get_frame(dwc); > } > > -static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) > +static int __dwc3_gadget_wakeup(struct dwc3 *dwc) > { > - int retries; > - > int ret; > u32 reg; > > @@ -2390,8 +2386,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) > return -EINVAL; > } > > - if (async) > - dwc3_gadget_enable_linksts_evts(dwc, true); > + dwc3_gadget_enable_linksts_evts(dwc, true); > > ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); > if (ret < 0) { > @@ -2410,27 +2405,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) > > /* > * Since link status change events are enabled we will receive > - * an U0 event when wakeup is successful. So bail out. > + * an U0 event when wakeup is successful. > */ > - if (async) > - return 0; > - > - /* poll until Link State changes to ON */ > - retries = 20000; > - > - while (retries--) { > - reg = dwc3_readl(dwc->regs, DWC3_DSTS); > - > - /* in HS, means ON */ > - if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0) > - break; > - } > - > - if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { > - dev_err(dwc->dev, "failed to send remote wakeup\n"); > - return -EINVAL; > - } > - > return 0; > } > > @@ -2451,7 +2427,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) > spin_unlock_irqrestore(&dwc->lock, flags); > return -EINVAL; > } > - ret = __dwc3_gadget_wakeup(dwc, true); > + ret = __dwc3_gadget_wakeup(dwc); > > spin_unlock_irqrestore(&dwc->lock, flags); > > @@ -2479,14 +2455,10 @@ static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id) > */ > link_state = dwc3_gadget_get_link_state(dwc); > if (link_state == DWC3_LINK_STATE_U3) { > - ret = __dwc3_gadget_wakeup(dwc, false); > - if (ret) { > - spin_unlock_irqrestore(&dwc->lock, flags); > - return -EINVAL; > - } > - dwc3_resume_gadget(dwc); > - dwc->suspended = false; > - dwc->link_state = DWC3_LINK_STATE_U0; > + dwc->wakeup_pending_funcs |= BIT(intf_id); > + ret = __dwc3_gadget_wakeup(dwc); > + spin_unlock_irqrestore(&dwc->lock, flags); > + return ret; > } > > ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION, > @@ -4353,6 +4325,8 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, > { > enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; > unsigned int pwropt; > + int ret; > + int intf_id; > > /* > * WORKAROUND: DWC3 < 2.50a have an issue when configured without > @@ -4428,7 +4402,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, > > switch (next) { > case DWC3_LINK_STATE_U0: > - if (dwc->gadget->wakeup_armed) { > + if (dwc->gadget->wakeup_armed || dwc->wakeup_pending_funcs) { > dwc3_gadget_enable_linksts_evts(dwc, false); > dwc3_resume_gadget(dwc); > dwc->suspended = false; > @@ -4451,6 +4425,18 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, > } > > dwc->link_state = next; > + > + /* Proceed with func wakeup if any interfaces that has requested */ > + while (dwc->wakeup_pending_funcs && (next == DWC3_LINK_STATE_U0)) { > + intf_id = ffs(dwc->wakeup_pending_funcs) - 1; > + ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION, > + DWC3_DGCMDPAR_DN_FUNC_WAKE | > + DWC3_DGCMDPAR_INTF_SEL(intf_id)); > + if (ret) > + dev_err(dwc->dev, "Failed to send DN wake for intf %d\n", intf_id); > + > + dwc->wakeup_pending_funcs &= ~BIT(intf_id); > + } > } > > static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc, > -- > 2.25.1 > Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Thanks, Thinh ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-04-22 22:15 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-04-22 10:32 [PATCH v2 0/3] Fixes for USB3 CV Chapter 9.15 tests Prashanth K 2025-04-22 10:32 ` [PATCH v2 1/3] usb: gadget: f_ecm: Add get_status callback Prashanth K 2025-04-22 22:13 ` Thinh Nguyen 2025-04-22 10:32 ` [PATCH v2 2/3] usb: gadget: Use get_status callback to set remote wakeup capability Prashanth K 2025-04-22 22:15 ` Thinh Nguyen 2025-04-22 10:32 ` [PATCH v2 3/3] usb: dwc3: gadget: Make gadget_wakeup asynchronous Prashanth K 2025-04-22 22:11 ` Thinh Nguyen
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox