Skip to content

Commit 2699704

Browse files
Prashanth Ksmb49
authored andcommitted
usb: dwc3: gadget: Make gadget_wakeup asynchronous
BugLink: https://bugs.launchpad.net/bugs/2115252 commit 2372f1c upstream. 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 <[email protected]> Fixes: 92c08a8 ("usb: dwc3: Add function suspend and function wakeup support") Signed-off-by: Prashanth K <[email protected]> Acked-by: Thinh Nguyen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Manuel Diewald <[email protected]> Signed-off-by: Stefan Bader <[email protected]>
1 parent 057aa52 commit 2699704

File tree

2 files changed

+27
-37
lines changed

2 files changed

+27
-37
lines changed

drivers/usb/dwc3/core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,9 @@ struct dwc3_scratchpad_array {
11641164
* @gsbuscfg0_reqinfo: store GSBUSCFG0.DATRDREQINFO, DESRDREQINFO,
11651165
* DATWRREQINFO, and DESWRREQINFO value passed from
11661166
* glue driver.
1167+
* @wakeup_pending_funcs: Indicates whether any interface has requested for
1168+
* function wakeup in bitmap format where bit position
1169+
* represents interface_id.
11671170
*/
11681171
struct dwc3 {
11691172
struct work_struct drd_work;
@@ -1394,6 +1397,7 @@ struct dwc3 {
13941397
int num_ep_resized;
13951398
struct dentry *debug_root;
13961399
u32 gsbuscfg0_reqinfo;
1400+
u32 wakeup_pending_funcs;
13971401
};
13981402

13991403
#define INCRX_BURST_MODE 0

drivers/usb/dwc3/gadget.c

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,6 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd,
276276
return ret;
277277
}
278278

279-
static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async);
280-
281279
/**
282280
* dwc3_send_gadget_ep_cmd - issue an endpoint command
283281
* @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)
23592357
return __dwc3_gadget_get_frame(dwc);
23602358
}
23612359

2362-
static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async)
2360+
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
23632361
{
2364-
int retries;
2365-
23662362
int ret;
23672363
u32 reg;
23682364

@@ -2390,8 +2386,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async)
23902386
return -EINVAL;
23912387
}
23922388

2393-
if (async)
2394-
dwc3_gadget_enable_linksts_evts(dwc, true);
2389+
dwc3_gadget_enable_linksts_evts(dwc, true);
23952390

23962391
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
23972392
if (ret < 0) {
@@ -2410,27 +2405,8 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async)
24102405

24112406
/*
24122407
* Since link status change events are enabled we will receive
2413-
* an U0 event when wakeup is successful. So bail out.
2408+
* an U0 event when wakeup is successful.
24142409
*/
2415-
if (async)
2416-
return 0;
2417-
2418-
/* poll until Link State changes to ON */
2419-
retries = 20000;
2420-
2421-
while (retries--) {
2422-
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
2423-
2424-
/* in HS, means ON */
2425-
if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
2426-
break;
2427-
}
2428-
2429-
if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
2430-
dev_err(dwc->dev, "failed to send remote wakeup\n");
2431-
return -EINVAL;
2432-
}
2433-
24342410
return 0;
24352411
}
24362412

@@ -2451,7 +2427,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
24512427
spin_unlock_irqrestore(&dwc->lock, flags);
24522428
return -EINVAL;
24532429
}
2454-
ret = __dwc3_gadget_wakeup(dwc, true);
2430+
ret = __dwc3_gadget_wakeup(dwc);
24552431

24562432
spin_unlock_irqrestore(&dwc->lock, flags);
24572433

@@ -2479,14 +2455,10 @@ static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id)
24792455
*/
24802456
link_state = dwc3_gadget_get_link_state(dwc);
24812457
if (link_state == DWC3_LINK_STATE_U3) {
2482-
ret = __dwc3_gadget_wakeup(dwc, false);
2483-
if (ret) {
2484-
spin_unlock_irqrestore(&dwc->lock, flags);
2485-
return -EINVAL;
2486-
}
2487-
dwc3_resume_gadget(dwc);
2488-
dwc->suspended = false;
2489-
dwc->link_state = DWC3_LINK_STATE_U0;
2458+
dwc->wakeup_pending_funcs |= BIT(intf_id);
2459+
ret = __dwc3_gadget_wakeup(dwc);
2460+
spin_unlock_irqrestore(&dwc->lock, flags);
2461+
return ret;
24902462
}
24912463

24922464
ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION,
@@ -4314,6 +4286,8 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
43144286
{
43154287
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
43164288
unsigned int pwropt;
4289+
int ret;
4290+
int intf_id;
43174291

43184292
/*
43194293
* WORKAROUND: DWC3 < 2.50a have an issue when configured without
@@ -4389,7 +4363,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
43894363

43904364
switch (next) {
43914365
case DWC3_LINK_STATE_U0:
4392-
if (dwc->gadget->wakeup_armed) {
4366+
if (dwc->gadget->wakeup_armed || dwc->wakeup_pending_funcs) {
43934367
dwc3_gadget_enable_linksts_evts(dwc, false);
43944368
dwc3_resume_gadget(dwc);
43954369
dwc->suspended = false;
@@ -4412,6 +4386,18 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
44124386
}
44134387

44144388
dwc->link_state = next;
4389+
4390+
/* Proceed with func wakeup if any interfaces that has requested */
4391+
while (dwc->wakeup_pending_funcs && (next == DWC3_LINK_STATE_U0)) {
4392+
intf_id = ffs(dwc->wakeup_pending_funcs) - 1;
4393+
ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION,
4394+
DWC3_DGCMDPAR_DN_FUNC_WAKE |
4395+
DWC3_DGCMDPAR_INTF_SEL(intf_id));
4396+
if (ret)
4397+
dev_err(dwc->dev, "Failed to send DN wake for intf %d\n", intf_id);
4398+
4399+
dwc->wakeup_pending_funcs &= ~BIT(intf_id);
4400+
}
44154401
}
44164402

44174403
static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc,

0 commit comments

Comments
 (0)