From: Greg Kroah-Hartman Date: Tue, 22 Jul 2025 08:47:26 +0000 (+0200) Subject: 5.10-stable patches X-Git-Tag: v6.1.147~38 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bebe32f0edaa3a94724c2055d30edccbe07de692;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: usb-dwc3-qcom-don-t-leave-bcr-asserted.patch usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch usb-musb-fix-gadget-state-on-disconnect.patch --- diff --git a/queue-5.10/series b/queue-5.10/series index b23b232684..00656f2700 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -45,3 +45,6 @@ net-sched-return-null-when-htb_lookup_leaf-encounter.patch usb-hub-fix-detection-of-high-tier-usb3-devices-behind-suspended-hubs.patch usb-hub-fix-flushing-and-scheduling-of-delayed-work-that-tunes-runtime-pm.patch usb-hub-fix-flushing-of-delayed-work-used-for-post-resume-purposes.patch +usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch +usb-musb-fix-gadget-state-on-disconnect.patch +usb-dwc3-qcom-don-t-leave-bcr-asserted.patch diff --git a/queue-5.10/usb-dwc3-qcom-don-t-leave-bcr-asserted.patch b/queue-5.10/usb-dwc3-qcom-don-t-leave-bcr-asserted.patch new file mode 100644 index 0000000000..a74275cef5 --- /dev/null +++ b/queue-5.10/usb-dwc3-qcom-don-t-leave-bcr-asserted.patch @@ -0,0 +1,65 @@ +From ef8abc0ba49ce717e6bc4124e88e59982671f3b5 Mon Sep 17 00:00:00 2001 +From: Krishna Kurapati +Date: Wed, 9 Jul 2025 18:59:00 +0530 +Subject: usb: dwc3: qcom: Don't leave BCR asserted + +From: Krishna Kurapati + +commit ef8abc0ba49ce717e6bc4124e88e59982671f3b5 upstream. + +Leaving the USB BCR asserted prevents the associated GDSC to turn on. This +blocks any subsequent attempts of probing the device, e.g. after a probe +deferral, with the following showing in the log: + +[ 1.332226] usb30_prim_gdsc status stuck at 'off' + +Leave the BCR deasserted when exiting the driver to avoid this issue. + +Cc: stable +Fixes: a4333c3a6ba9 ("usb: dwc3: Add Qualcomm DWC3 glue driver") +Acked-by: Thinh Nguyen +Reviewed-by: Konrad Dybcio +Signed-off-by: Krishna Kurapati +Link: https://lore.kernel.org/r/20250709132900.3408752-1-krishna.kurapati@oss.qualcomm.com +[ adapted to individual clock management API instead of bulk clock operations ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/dwc3-qcom.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -786,13 +786,13 @@ static int dwc3_qcom_probe(struct platfo + ret = reset_control_deassert(qcom->resets); + if (ret) { + dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret); +- goto reset_assert; ++ return ret; + } + + ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np)); + if (ret) { + dev_err(dev, "failed to get clocks\n"); +- goto reset_assert; ++ return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -892,8 +892,6 @@ clk_disable: + clk_disable_unprepare(qcom->clks[i]); + clk_put(qcom->clks[i]); + } +-reset_assert: +- reset_control_assert(qcom->resets); + + return ret; + } +@@ -921,7 +919,6 @@ static int dwc3_qcom_remove(struct platf + qcom->num_clocks = 0; + + dwc3_qcom_interconnect_exit(qcom); +- reset_control_assert(qcom->resets); + + pm_runtime_allow(dev); + pm_runtime_disable(dev); diff --git a/queue-5.10/usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch b/queue-5.10/usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch new file mode 100644 index 0000000000..ed0f4e236a --- /dev/null +++ b/queue-5.10/usb-musb-add-and-use-inline-functions-musb_-get-set-_state.patch @@ -0,0 +1,532 @@ +From 21acc656a06e912341d9db66c67b58cc7ed071e7 Mon Sep 17 00:00:00 2001 +From: Paul Cercueil +Date: Wed, 26 Oct 2022 19:26:51 +0100 +Subject: usb: musb: Add and use inline functions musb_{get,set}_state + +From: Paul Cercueil + +commit 21acc656a06e912341d9db66c67b58cc7ed071e7 upstream. + +Instead of manipulating musb->xceiv->otg->state directly, use the newly +introduced musb_get_state() and musb_set_state() inline functions. + +Later, these inline functions will be modified to get rid of the +musb->xceiv dependency, which prevents the musb code from using the +generic PHY subsystem. + +Signed-off-by: Paul Cercueil +Link: https://lore.kernel.org/r/20221026182657.146630-2-paul@crapouillou.net +Stable-dep-of: 67a59f82196c ("usb: musb: fix gadget state on disconnect") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/musb/musb_core.c | 62 ++++++++++++++++++++-------------------- + drivers/usb/musb/musb_core.h | 11 +++++++ + drivers/usb/musb/musb_debugfs.c | 6 +-- + drivers/usb/musb/musb_gadget.c | 28 +++++++++--------- + drivers/usb/musb/musb_host.c | 6 +-- + drivers/usb/musb/musb_virthub.c | 18 +++++------ + 6 files changed, 71 insertions(+), 60 deletions(-) + +--- a/drivers/usb/musb/musb_core.c ++++ b/drivers/usb/musb/musb_core.c +@@ -501,7 +501,7 @@ int musb_set_host(struct musb *musb) + + init_data: + musb->is_active = 1; +- musb->xceiv->otg->state = OTG_STATE_A_IDLE; ++ musb_set_state(musb, OTG_STATE_A_IDLE); + MUSB_HST_MODE(musb); + + return error; +@@ -548,7 +548,7 @@ int musb_set_peripheral(struct musb *mus + + init_data: + musb->is_active = 0; +- musb->xceiv->otg->state = OTG_STATE_B_IDLE; ++ musb_set_state(musb, OTG_STATE_B_IDLE); + MUSB_DEV_MODE(musb); + + return error; +@@ -598,12 +598,12 @@ static void musb_otg_timer_func(struct t + unsigned long flags; + + spin_lock_irqsave(&musb->lock, flags); +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_B_WAIT_ACON: + musb_dbg(musb, + "HNP: b_wait_acon timeout; back to b_peripheral"); + musb_g_disconnect(musb); +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + musb->is_active = 0; + break; + case OTG_STATE_A_SUSPEND: +@@ -611,7 +611,7 @@ static void musb_otg_timer_func(struct t + musb_dbg(musb, "HNP: %s timeout", + usb_otg_state_string(musb->xceiv->otg->state)); + musb_platform_set_vbus(musb, 0); +- musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; ++ musb_set_state(musb, OTG_STATE_A_WAIT_VFALL); + break; + default: + musb_dbg(musb, "HNP: Unhandled mode %s", +@@ -632,7 +632,7 @@ void musb_hnp_stop(struct musb *musb) + musb_dbg(musb, "HNP: stop from %s", + usb_otg_state_string(musb->xceiv->otg->state)); + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_PERIPHERAL: + musb_g_disconnect(musb); + musb_dbg(musb, "HNP: back to %s", +@@ -642,7 +642,7 @@ void musb_hnp_stop(struct musb *musb) + musb_dbg(musb, "HNP: Disabling HR"); + if (hcd) + hcd->self.is_b_host = 0; +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + MUSB_DEV_MODE(musb); + reg = musb_readb(mbase, MUSB_POWER); + reg |= MUSB_POWER_SUSPENDM; +@@ -670,7 +670,7 @@ static void musb_handle_intr_resume(stru + usb_otg_state_string(musb->xceiv->otg->state)); + + if (devctl & MUSB_DEVCTL_HM) { +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_SUSPEND: + /* remote wakeup? */ + musb->port1_status |= +@@ -678,14 +678,14 @@ static void musb_handle_intr_resume(stru + | MUSB_PORT_STAT_RESUME; + musb->rh_timer = jiffies + + msecs_to_jiffies(USB_RESUME_TIMEOUT); +- musb->xceiv->otg->state = OTG_STATE_A_HOST; ++ musb_set_state(musb, OTG_STATE_A_HOST); + musb->is_active = 1; + musb_host_resume_root_hub(musb); + schedule_delayed_work(&musb->finish_resume_work, + msecs_to_jiffies(USB_RESUME_TIMEOUT)); + break; + case OTG_STATE_B_WAIT_ACON: +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + musb->is_active = 1; + MUSB_DEV_MODE(musb); + break; +@@ -695,10 +695,10 @@ static void musb_handle_intr_resume(stru + usb_otg_state_string(musb->xceiv->otg->state)); + } + } else { +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_SUSPEND: + /* possibly DISCONNECT is upcoming */ +- musb->xceiv->otg->state = OTG_STATE_A_HOST; ++ musb_set_state(musb, OTG_STATE_A_HOST); + musb_host_resume_root_hub(musb); + break; + case OTG_STATE_B_WAIT_ACON: +@@ -749,7 +749,7 @@ static irqreturn_t musb_handle_intr_sess + */ + musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); + musb->ep0_stage = MUSB_EP0_START; +- musb->xceiv->otg->state = OTG_STATE_A_IDLE; ++ musb_set_state(musb, OTG_STATE_A_IDLE); + MUSB_HST_MODE(musb); + musb_platform_set_vbus(musb, 1); + +@@ -776,7 +776,7 @@ static void musb_handle_intr_vbuserr(str + * REVISIT: do delays from lots of DEBUG_KERNEL checks + * make trouble here, keeping VBUS < 4.4V ? + */ +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_HOST: + /* recovery is dicey once we've gotten past the + * initial stages of enumeration, but if VBUS +@@ -832,7 +832,7 @@ static void musb_handle_intr_suspend(str + musb_dbg(musb, "SUSPEND (%s) devctl %02x", + usb_otg_state_string(musb->xceiv->otg->state), devctl); + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_PERIPHERAL: + /* We also come here if the cable is removed, since + * this silicon doesn't report ID-no-longer-grounded. +@@ -857,7 +857,7 @@ static void musb_handle_intr_suspend(str + musb_g_suspend(musb); + musb->is_active = musb->g.b_hnp_enable; + if (musb->is_active) { +- musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON; ++ musb_set_state(musb, OTG_STATE_B_WAIT_ACON); + musb_dbg(musb, "HNP: Setting timer for b_ase0_brst"); + mod_timer(&musb->otg_timer, jiffies + + msecs_to_jiffies( +@@ -870,7 +870,7 @@ static void musb_handle_intr_suspend(str + + msecs_to_jiffies(musb->a_wait_bcon)); + break; + case OTG_STATE_A_HOST: +- musb->xceiv->otg->state = OTG_STATE_A_SUSPEND; ++ musb_set_state(musb, OTG_STATE_A_SUSPEND); + musb->is_active = musb->hcd->self.b_hnp_enable; + break; + case OTG_STATE_B_HOST: +@@ -908,7 +908,7 @@ static void musb_handle_intr_connect(str + musb->port1_status |= USB_PORT_STAT_LOW_SPEED; + + /* indicate new connection to OTG machine */ +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_B_PERIPHERAL: + if (int_usb & MUSB_INTR_SUSPEND) { + musb_dbg(musb, "HNP: SUSPEND+CONNECT, now b_host"); +@@ -920,7 +920,7 @@ static void musb_handle_intr_connect(str + case OTG_STATE_B_WAIT_ACON: + musb_dbg(musb, "HNP: CONNECT, now b_host"); + b_host: +- musb->xceiv->otg->state = OTG_STATE_B_HOST; ++ musb_set_state(musb, OTG_STATE_B_HOST); + if (musb->hcd) + musb->hcd->self.is_b_host = 1; + del_timer(&musb->otg_timer); +@@ -928,7 +928,7 @@ b_host: + default: + if ((devctl & MUSB_DEVCTL_VBUS) + == (3 << MUSB_DEVCTL_VBUS_SHIFT)) { +- musb->xceiv->otg->state = OTG_STATE_A_HOST; ++ musb_set_state(musb, OTG_STATE_A_HOST); + if (hcd) + hcd->self.is_b_host = 0; + } +@@ -947,7 +947,7 @@ static void musb_handle_intr_disconnect( + usb_otg_state_string(musb->xceiv->otg->state), + MUSB_MODE(musb), devctl); + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_HOST: + case OTG_STATE_A_SUSPEND: + musb_host_resume_root_hub(musb); +@@ -965,7 +965,7 @@ static void musb_handle_intr_disconnect( + musb_root_disconnect(musb); + if (musb->hcd) + musb->hcd->self.is_b_host = 0; +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + MUSB_DEV_MODE(musb); + musb_g_disconnect(musb); + break; +@@ -1005,7 +1005,7 @@ static void musb_handle_intr_reset(struc + } else { + musb_dbg(musb, "BUS RESET as %s", + usb_otg_state_string(musb->xceiv->otg->state)); +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_SUSPEND: + musb_g_reset(musb); + fallthrough; +@@ -1024,11 +1024,11 @@ static void musb_handle_intr_reset(struc + case OTG_STATE_B_WAIT_ACON: + musb_dbg(musb, "HNP: RESET (%s), to b_peripheral", + usb_otg_state_string(musb->xceiv->otg->state)); +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + musb_g_reset(musb); + break; + case OTG_STATE_B_IDLE: +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + fallthrough; + case OTG_STATE_B_PERIPHERAL: + musb_g_reset(musb); +@@ -1215,8 +1215,8 @@ void musb_start(struct musb *musb) + * (c) peripheral initiates, using SRP + */ + if (musb->port_mode != MUSB_HOST && +- musb->xceiv->otg->state != OTG_STATE_A_WAIT_BCON && +- (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { ++ musb_get_state(musb) != OTG_STATE_A_WAIT_BCON && ++ (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { + musb->is_active = 1; + } else { + devctl |= MUSB_DEVCTL_SESSION; +@@ -1907,7 +1907,7 @@ vbus_store(struct device *dev, struct de + spin_lock_irqsave(&musb->lock, flags); + /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */ + musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ; +- if (musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON) ++ if (musb_get_state(musb) == OTG_STATE_A_WAIT_BCON) + musb->is_active = 0; + musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val)); + spin_unlock_irqrestore(&musb->lock, flags); +@@ -2078,8 +2078,8 @@ static void musb_irq_work(struct work_st + + musb_pm_runtime_check_session(musb); + +- if (musb->xceiv->otg->state != musb->xceiv_old_state) { +- musb->xceiv_old_state = musb->xceiv->otg->state; ++ if (musb_get_state(musb) != musb->xceiv_old_state) { ++ musb->xceiv_old_state = musb_get_state(musb); + sysfs_notify(&musb->controller->kobj, NULL, "mode"); + } + +@@ -2521,7 +2521,7 @@ musb_init_controller(struct device *dev, + } + + MUSB_DEV_MODE(musb); +- musb->xceiv->otg->state = OTG_STATE_B_IDLE; ++ musb_set_state(musb, OTG_STATE_B_IDLE); + + switch (musb->port_mode) { + case MUSB_HOST: +--- a/drivers/usb/musb/musb_core.h ++++ b/drivers/usb/musb/musb_core.h +@@ -592,6 +592,17 @@ static inline void musb_platform_clear_e + musb->ops->clear_ep_rxintr(musb, epnum); + } + ++static inline void musb_set_state(struct musb *musb, ++ enum usb_otg_state otg_state) ++{ ++ musb->xceiv->otg->state = otg_state; ++} ++ ++static inline enum usb_otg_state musb_get_state(struct musb *musb) ++{ ++ return musb->xceiv->otg->state; ++} ++ + /* + * gets the "dr_mode" property from DT and converts it into musb_mode + * if the property is not found or not recognized returns MUSB_OTG +--- a/drivers/usb/musb/musb_debugfs.c ++++ b/drivers/usb/musb/musb_debugfs.c +@@ -235,7 +235,7 @@ static int musb_softconnect_show(struct + u8 reg; + int connect; + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_HOST: + case OTG_STATE_A_WAIT_BCON: + pm_runtime_get_sync(musb->controller); +@@ -275,7 +275,7 @@ static ssize_t musb_softconnect_write(st + + pm_runtime_get_sync(musb->controller); + if (!strncmp(buf, "0", 1)) { +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_HOST: + musb_root_disconnect(musb); + reg = musb_readb(musb->mregs, MUSB_DEVCTL); +@@ -286,7 +286,7 @@ static ssize_t musb_softconnect_write(st + break; + } + } else if (!strncmp(buf, "1", 1)) { +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_WAIT_BCON: + /* + * musb_save_context() called in musb_runtime_suspend() +--- a/drivers/usb/musb/musb_gadget.c ++++ b/drivers/usb/musb/musb_gadget.c +@@ -1523,7 +1523,7 @@ static int musb_gadget_wakeup(struct usb + + spin_lock_irqsave(&musb->lock, flags); + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_B_PERIPHERAL: + /* NOTE: OTG state machine doesn't include B_SUSPENDED; + * that's part of the standard usb 1.1 state machine, and +@@ -1785,7 +1785,7 @@ int musb_gadget_setup(struct musb *musb) + musb->g.speed = USB_SPEED_UNKNOWN; + + MUSB_DEV_MODE(musb); +- musb->xceiv->otg->state = OTG_STATE_B_IDLE; ++ musb_set_state(musb, OTG_STATE_B_IDLE); + + /* this "gadget" abstracts/virtualizes the controller */ + musb->g.name = musb_driver_name; +@@ -1850,7 +1850,7 @@ static int musb_gadget_start(struct usb_ + musb->is_active = 1; + + otg_set_peripheral(otg, &musb->g); +- musb->xceiv->otg->state = OTG_STATE_B_IDLE; ++ musb_set_state(musb, OTG_STATE_B_IDLE); + spin_unlock_irqrestore(&musb->lock, flags); + + musb_start(musb); +@@ -1895,7 +1895,7 @@ static int musb_gadget_stop(struct usb_g + + (void) musb_gadget_vbus_draw(&musb->g, 0); + +- musb->xceiv->otg->state = OTG_STATE_UNDEFINED; ++ musb_set_state(musb, OTG_STATE_UNDEFINED); + musb_stop(musb); + otg_set_peripheral(musb->xceiv->otg, NULL); + +@@ -1926,7 +1926,7 @@ static int musb_gadget_stop(struct usb_g + void musb_g_resume(struct musb *musb) + { + musb->is_suspended = 0; +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_B_IDLE: + break; + case OTG_STATE_B_WAIT_ACON: +@@ -1952,10 +1952,10 @@ void musb_g_suspend(struct musb *musb) + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + musb_dbg(musb, "musb_g_suspend: devctl %02x", devctl); + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_B_IDLE: + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + break; + case OTG_STATE_B_PERIPHERAL: + musb->is_suspended = 1; +@@ -2001,22 +2001,22 @@ void musb_g_disconnect(struct musb *musb + spin_lock(&musb->lock); + } + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + default: + musb_dbg(musb, "Unhandled disconnect %s, setting a_idle", + usb_otg_state_string(musb->xceiv->otg->state)); +- musb->xceiv->otg->state = OTG_STATE_A_IDLE; ++ musb_set_state(musb, OTG_STATE_A_IDLE); + MUSB_HST_MODE(musb); + break; + case OTG_STATE_A_PERIPHERAL: +- musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; ++ musb_set_state(musb, OTG_STATE_A_WAIT_BCON); + MUSB_HST_MODE(musb); + break; + case OTG_STATE_B_WAIT_ACON: + case OTG_STATE_B_HOST: + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_IDLE: +- musb->xceiv->otg->state = OTG_STATE_B_IDLE; ++ musb_set_state(musb, OTG_STATE_B_IDLE); + break; + case OTG_STATE_B_SRP_INIT: + break; +@@ -2080,13 +2080,13 @@ __acquires(musb->lock) + * In that case, do not rely on devctl for setting + * peripheral mode. + */ +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + musb->g.is_a_peripheral = 0; + } else if (devctl & MUSB_DEVCTL_BDEVICE) { +- musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_B_PERIPHERAL); + musb->g.is_a_peripheral = 0; + } else { +- musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_A_PERIPHERAL); + musb->g.is_a_peripheral = 1; + } + +--- a/drivers/usb/musb/musb_host.c ++++ b/drivers/usb/musb/musb_host.c +@@ -2514,7 +2514,7 @@ static int musb_bus_suspend(struct usb_h + if (!is_host_active(musb)) + return 0; + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_SUSPEND: + return 0; + case OTG_STATE_A_WAIT_VRISE: +@@ -2524,7 +2524,7 @@ static int musb_bus_suspend(struct usb_h + */ + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) +- musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; ++ musb_set_state(musb, OTG_STATE_A_WAIT_BCON); + break; + default: + break; +@@ -2733,7 +2733,7 @@ int musb_host_setup(struct musb *musb, i + + if (musb->port_mode == MUSB_HOST) { + MUSB_HST_MODE(musb); +- musb->xceiv->otg->state = OTG_STATE_A_IDLE; ++ musb_set_state(musb, OTG_STATE_A_IDLE); + } + otg_set_host(musb->xceiv->otg, &hcd->self); + /* don't support otg protocols */ +--- a/drivers/usb/musb/musb_virthub.c ++++ b/drivers/usb/musb/musb_virthub.c +@@ -43,7 +43,7 @@ void musb_host_finish_resume(struct work + musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; + usb_hcd_poll_rh_status(musb->hcd); + /* NOTE: it might really be A_WAIT_BCON ... */ +- musb->xceiv->otg->state = OTG_STATE_A_HOST; ++ musb_set_state(musb, OTG_STATE_A_HOST); + + spin_unlock_irqrestore(&musb->lock, flags); + } +@@ -85,9 +85,9 @@ int musb_port_suspend(struct musb *musb, + musb_dbg(musb, "Root port suspended, power %02x", power); + + musb->port1_status |= USB_PORT_STAT_SUSPEND; +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_HOST: +- musb->xceiv->otg->state = OTG_STATE_A_SUSPEND; ++ musb_set_state(musb, OTG_STATE_A_SUSPEND); + musb->is_active = otg->host->b_hnp_enable; + if (musb->is_active) + mod_timer(&musb->otg_timer, jiffies +@@ -96,7 +96,7 @@ int musb_port_suspend(struct musb *musb, + musb_platform_try_idle(musb, 0); + break; + case OTG_STATE_B_HOST: +- musb->xceiv->otg->state = OTG_STATE_B_WAIT_ACON; ++ musb_set_state(musb, OTG_STATE_B_WAIT_ACON); + musb->is_active = otg->host->b_hnp_enable; + musb_platform_try_idle(musb, 0); + break; +@@ -123,7 +123,7 @@ void musb_port_reset(struct musb *musb, + u8 power; + void __iomem *mbase = musb->mregs; + +- if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) { ++ if (musb_get_state(musb) == OTG_STATE_B_IDLE) { + musb_dbg(musb, "HNP: Returning from HNP; no hub reset from b_idle"); + musb->port1_status &= ~USB_PORT_STAT_RESET; + return; +@@ -204,20 +204,20 @@ void musb_root_disconnect(struct musb *m + usb_hcd_poll_rh_status(musb->hcd); + musb->is_active = 0; + +- switch (musb->xceiv->otg->state) { ++ switch (musb_get_state(musb)) { + case OTG_STATE_A_SUSPEND: + if (otg->host->b_hnp_enable) { +- musb->xceiv->otg->state = OTG_STATE_A_PERIPHERAL; ++ musb_set_state(musb, OTG_STATE_A_PERIPHERAL); + musb->g.is_a_peripheral = 1; + break; + } + fallthrough; + case OTG_STATE_A_HOST: +- musb->xceiv->otg->state = OTG_STATE_A_WAIT_BCON; ++ musb_set_state(musb, OTG_STATE_A_WAIT_BCON); + musb->is_active = 0; + break; + case OTG_STATE_A_WAIT_VFALL: +- musb->xceiv->otg->state = OTG_STATE_B_IDLE; ++ musb_set_state(musb, OTG_STATE_B_IDLE); + break; + default: + musb_dbg(musb, "host disconnect (%s)", diff --git a/queue-5.10/usb-musb-fix-gadget-state-on-disconnect.patch b/queue-5.10/usb-musb-fix-gadget-state-on-disconnect.patch new file mode 100644 index 0000000000..b7628a63e2 --- /dev/null +++ b/queue-5.10/usb-musb-fix-gadget-state-on-disconnect.patch @@ -0,0 +1,48 @@ +From 67a59f82196c8c4f50c83329f0577acfb1349b50 Mon Sep 17 00:00:00 2001 +From: Drew Hamilton +Date: Tue, 1 Jul 2025 11:41:26 -0400 +Subject: usb: musb: fix gadget state on disconnect + +From: Drew Hamilton + +commit 67a59f82196c8c4f50c83329f0577acfb1349b50 upstream. + +When unplugging the USB cable or disconnecting a gadget in usb peripheral mode with +echo "" > /sys/kernel/config/usb_gadget//UDC, +/sys/class/udc/musb-hdrc.0/state does not change from USB_STATE_CONFIGURED. + +Testing on dwc2/3 shows they both update the state to USB_STATE_NOTATTACHED. + +Add calls to usb_gadget_set_state in musb_g_disconnect and musb_gadget_stop +to fix both cases. + +Fixes: 49401f4169c0 ("usb: gadget: introduce gadget state tracking") +Cc: stable@vger.kernel.org +Co-authored-by: Yehowshua Immanuel +Signed-off-by: Yehowshua Immanuel +Signed-off-by: Drew Hamilton +Link: https://lore.kernel.org/r/20250701154126.8543-1-drew.hamilton@zetier.com +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/musb/musb_gadget.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/usb/musb/musb_gadget.c ++++ b/drivers/usb/musb/musb_gadget.c +@@ -1909,6 +1909,7 @@ static int musb_gadget_stop(struct usb_g + * gadget driver here and have everything work; + * that currently misbehaves. + */ ++ usb_gadget_set_state(g, USB_STATE_NOTATTACHED); + + /* Force check of devctl register for PM runtime */ + schedule_delayed_work(&musb->irq_work, 0); +@@ -2017,6 +2018,7 @@ void musb_g_disconnect(struct musb *musb + case OTG_STATE_B_PERIPHERAL: + case OTG_STATE_B_IDLE: + musb_set_state(musb, OTG_STATE_B_IDLE); ++ usb_gadget_set_state(&musb->g, USB_STATE_NOTATTACHED); + break; + case OTG_STATE_B_SRP_INIT: + break;