[PATCH v2 2/2] usb: musb: gadget: fix MUSB_DEVCTL race condition in set_vbus

From: Lucas Martins Alves

Date: Thu Jul 16 2026 - 11:11:28 EST


From: Lucas Martins Alves <lucas.alves@xxxxxxxxxxxxxxx>

During gadget initialization, musb_gadget_start() releases musb->lock,
enables interrupts via musb_start(), and then invokes
musb_platform_set_vbus(musb, 1) in a lockless context.

If musb_interrupt() fires concurrently, it will take musb->lock and
modify MUSB_DEVCTL. Those changes could be silently overwritten when
the callback writes back the stale cached devctl value, causing state
corruption due to the unlocked read-modify-write race condition.

Fix this by acquiring musb->lock before calling musb_platform_set_vbus()
in musb_gadget_start(). This ensures the register operation is atomic
with respect to concurrent interrupt handlers, preventing the RMW race
condition while avoiding deadlock scenarios where this function is called
from interrupt context (which already holds the lock).

Signed-off-by: Lucas Martins Alves <lucas.alves@xxxxxxxxxxxxxxx>
---
drivers/usb/musb/musb_gadget.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 016d3f3fc1e0..8eca252423e9 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1857,8 +1857,11 @@ static int musb_gadget_start(struct usb_gadget *g,
* handles power budgeting ... this way also
* ensures HdrcStart is indirectly called.
*/
- if (musb->xceiv && musb->xceiv->last_event == USB_EVENT_ID)
+ if (musb->xceiv && musb->xceiv->last_event == USB_EVENT_ID) {
+ spin_lock_irqsave(&musb->lock, flags);
musb_platform_set_vbus(musb, 1);
+ spin_unlock_irqrestore(&musb->lock, flags);
+ }

pm_runtime_put_autosuspend(musb->controller);

--
2.53.0