Skip to content

Commit f9aa411

Browse files
Thinh Nguyengregkh
authored andcommitted
usb: dwc3: Properly set system wakeup
If the device is configured for system wakeup, then make sure that the xHCI driver knows about it and make sure to permit wakeup only at the appropriate time. For host mode, if the controller goes through the dwc3 code path, then a child xHCI platform device is created. Make sure the platform device also inherits the wakeup setting for xHCI to enable remote wakeup. For device mode, make sure to disable system wakeup if no gadget driver is bound. We may experience unwanted system wakeup due to the wakeup signal from the controller PMU detecting connection/disconnection when in low power (D3). E.g. In the case of Steam Deck, the PCI PME prevents the system staying in suspend. Cc: stable@vger.kernel.org Reported-by: Guilherme G. Piccoli <gpiccoli@igalia.com> Closes: https://lore.kernel.org/linux-usb/70a7692d-647c-9be7-00a6-06fc60f77294@igalia.com/T/#mf00d6669c2eff7b308d1162acd1d66c09f0853c7 Fixes: d07e881 ("usb: dwc3: add xHCI Host support") Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Tested-by: Sanath S <Sanath.S@amd.com> Tested-by: Guilherme G. Piccoli <gpiccoli@igalia.com> # Steam Deck Link: https://lore.kernel.org/r/667cfda7009b502e08462c8fb3f65841d103cc0a.1709865476.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent fdada0d commit f9aa411

4 files changed

Lines changed: 25 additions & 0 deletions

File tree

drivers/usb/dwc3/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
15191519
else
15201520
dwc->sysdev = dwc->dev;
15211521

1522+
dwc->sys_wakeup = device_may_wakeup(dwc->sysdev);
1523+
15221524
ret = device_property_read_string(dev, "usb-psy-name", &usb_psy_name);
15231525
if (ret >= 0) {
15241526
dwc->usb_psy = power_supply_get_by_name(usb_psy_name);

drivers/usb/dwc3/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,7 @@ struct dwc3_scratchpad_array {
11331133
* 3 - Reserved
11341134
* @dis_metastability_quirk: set to disable metastability quirk.
11351135
* @dis_split_quirk: set to disable split boundary.
1136+
* @sys_wakeup: set if the device may do system wakeup.
11361137
* @wakeup_configured: set if the device is configured for remote wakeup.
11371138
* @suspended: set to track suspend event due to U3/L2.
11381139
* @imod_interval: set the interrupt moderation interval in 250ns
@@ -1357,6 +1358,7 @@ struct dwc3 {
13571358

13581359
unsigned dis_split_quirk:1;
13591360
unsigned async_callbacks:1;
1361+
unsigned sys_wakeup:1;
13601362
unsigned wakeup_configured:1;
13611363
unsigned suspended:1;
13621364

drivers/usb/dwc3/gadget.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2955,6 +2955,9 @@ static int dwc3_gadget_start(struct usb_gadget *g,
29552955
dwc->gadget_driver = driver;
29562956
spin_unlock_irqrestore(&dwc->lock, flags);
29572957

2958+
if (dwc->sys_wakeup)
2959+
device_wakeup_enable(dwc->sysdev);
2960+
29582961
return 0;
29592962
}
29602963

@@ -2970,6 +2973,9 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
29702973
struct dwc3 *dwc = gadget_to_dwc(g);
29712974
unsigned long flags;
29722975

2976+
if (dwc->sys_wakeup)
2977+
device_wakeup_disable(dwc->sysdev);
2978+
29732979
spin_lock_irqsave(&dwc->lock, flags);
29742980
dwc->gadget_driver = NULL;
29752981
dwc->max_cfg_eps = 0;
@@ -4651,6 +4657,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
46514657
else
46524658
dwc3_gadget_set_speed(dwc->gadget, dwc->maximum_speed);
46534659

4660+
/* No system wakeup if no gadget driver bound */
4661+
if (dwc->sys_wakeup)
4662+
device_wakeup_disable(dwc->sysdev);
4663+
46544664
return 0;
46554665

46564666
err5:

drivers/usb/dwc3/host.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ int dwc3_host_init(struct dwc3 *dwc)
173173
goto err;
174174
}
175175

176+
if (dwc->sys_wakeup) {
177+
/* Restore wakeup setting if switched from device */
178+
device_wakeup_enable(dwc->sysdev);
179+
180+
/* Pass on wakeup setting to the new xhci platform device */
181+
device_init_wakeup(&xhci->dev, true);
182+
}
183+
176184
return 0;
177185
err:
178186
platform_device_put(xhci);
@@ -181,6 +189,9 @@ int dwc3_host_init(struct dwc3 *dwc)
181189

182190
void dwc3_host_exit(struct dwc3 *dwc)
183191
{
192+
if (dwc->sys_wakeup)
193+
device_init_wakeup(&dwc->xhci->dev, false);
194+
184195
platform_device_unregister(dwc->xhci);
185196
dwc->xhci = NULL;
186197
}

0 commit comments

Comments
 (0)