tegra_xudc_vbus_notify() queues usb_role_sw_work. The notifier is registered with usb_register_notifier(), while devm_usb_get_phy_by_node() is passed NULL, so devres never unregisters it. vbus_nb lives in the devm allocation, so a later PHY event calls it after xudc is freed. Unregister the notifier before cancel_work_sync(). That waits for in-flight callbacks, and the existing cancel drains the last work. This issue was identified during our ongoing static-analysis research while reviewing kernel code. Fixes: 2582d629c9e0 ("usb: gadget: xudc: Refactor update data role work") Cc: stable@vger.kernel.org Assisted-by: LLM Co-developed-by: Ijae Kim Signed-off-by: Ijae Kim Signed-off-by: Myeonghun Pak --- Changes in v2: - Unregister the VBUS notifier before cancel_work_sync(). It queues usb_role_sw_work and is not devres-managed. drivers/usb/gadget/udc/tegra-xudc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index e9d33be02866..a0585a1f19f0 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -3926,6 +3926,12 @@ static void tegra_xudc_remove(struct platform_device *pdev) pm_runtime_get_sync(xudc->dev); + for (i = 0; i < xudc->soc->num_phys; i++) { + if (xudc->usbphy[i]) + usb_unregister_notifier(xudc->usbphy[i], + &xudc->vbus_nb); + } + cancel_delayed_work_sync(&xudc->plc_reset_work); cancel_work_sync(&xudc->usb_role_sw_work); -- 2.53.0 The devm port-status IRQ stays registered through remove() and can queue port_reset_war_work and plc_reset_work after cancel_delayed_work_sync() returns. remove() never stops the first. disable_delayed_work_sync() drains both and rejects a later queue. usb_role_sw_work stays on cancel_work_sync(). The PHY notifier is its producer and is unregistered before this cancel. This issue was identified during our ongoing static-analysis research while reviewing kernel code. Fixes: 49db427232fe ("usb: gadget: Add UDC driver for tegra XUSB device mode controller") Cc: stable@vger.kernel.org # 6.10+ Assisted-by: LLM Co-developed-by: Ijae Kim Signed-off-by: Ijae Kim Signed-off-by: Myeonghun Pak --- Changes in v2: - Keep the Fixes tag on one line. (Thierry Reding) - Disable plc_reset_work too. The port-status IRQ can requeue it. (Thierry Reding) drivers/usb/gadget/udc/tegra-xudc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index a0585a1f19f0..dd0a033b4a7f 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -3932,7 +3932,8 @@ static void tegra_xudc_remove(struct platform_device *pdev) &xudc->vbus_nb); } - cancel_delayed_work_sync(&xudc->plc_reset_work); + disable_delayed_work_sync(&xudc->port_reset_war_work); + disable_delayed_work_sync(&xudc->plc_reset_work); cancel_work_sync(&xudc->usb_role_sw_work); usb_del_gadget_udc(&xudc->gadget); -- 2.53.0