[PATCH v2 3/5] usb: dwc2: hcd: fix possible successive vbus supply enables
From: Fabrice Gasnier
Date: Tue Oct 13 2026 - 10:51:29 EST
External VBUS supply may have already been enabled, before entering
dwc2_hcd_reinit (e.g. the controller is in host mode, without any device
plugged).
This results in vbus enable count to increase every time this occurs.
As consequence, dwc2_vbus_supply_exit won't disable vbus upon suspend
request.
Fix this by reading PWR bit before and after dwc2_hcd_reinit() call.
Fixes: cd7cd0e6cedf ("usb: dwc2: fix unbalanced use of external vbus-supply")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@xxxxxxxxxxx>
---
Changes in v2:
- Add a vbus_was_off boolean to check explicitly an off-on transition
on port power, to enable vbus supply, instead of relying an XOR check
that would be symmetric, e.g. wrongly enable it in case it gets switched
off (1 to 0) as reported by Sashiko.
---
drivers/usb/dwc2/hcd.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index cd0dc876b421..05d5d7265e42 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -4249,6 +4249,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
struct usb_bus *bus = hcd_to_bus(hcd);
unsigned long flags;
+ bool vbus_was_off;
u32 hprt0;
int ret;
@@ -4264,11 +4265,13 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
return 0; /* why 0 ?? */
}
+ vbus_was_off = !(dwc2_read_hprt0(hsotg) & HPRT0_PWR);
+
dwc2_hcd_reinit(hsotg);
hprt0 = dwc2_read_hprt0(hsotg);
/* Has vbus power been turned on in dwc2_core_host_init ? */
- if (hprt0 & HPRT0_PWR) {
+ if (vbus_was_off && (hprt0 & HPRT0_PWR)) {
/* Enable external vbus supply before resuming root hub */
spin_unlock_irqrestore(&hsotg->lock, flags);
ret = dwc2_vbus_supply_init(hsotg);
--
2.43.0