]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
usb: gadget: tegra-xudc: fix PM use count underflow
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Fri, 1 Aug 2025 17:40:41 +0000 (18:40 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Aug 2025 15:15:45 +0000 (17:15 +0200)
Upon resume from system suspend, the PM runtime core issues the
following warning:

tegra-xudc 3550000.usb: Runtime PM usage count underflow!

This is because tegra_xudc_resume() unconditionally calls
schedule_work(&xudc->usb_role_sw_work) whether or not anything has
changed, which causes tegra_xudc_device_mode_off() to be called
even when we're already in that mode.

Keep track of the current state of "device_mode", and only schedule
this work if it has changed from the hardware state on resume.

Signed-off-by: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
Link: https://lore.kernel.org/r/E1uhtkH-007KDZ-JT@rmk-PC.armlinux.org.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/udc/tegra-xudc.c

index 2957316fd3d003e8444a825a72d228b7db06febe..1d3085cc9d2228b1577476c9d3ce06d1ab5865c9 100644 (file)
@@ -502,6 +502,7 @@ struct tegra_xudc {
        struct clk_bulk_data *clks;
 
        bool device_mode;
+       bool current_device_mode;
        struct work_struct usb_role_sw_work;
 
        struct phy **usb3_phy;
@@ -715,6 +716,8 @@ static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc)
 
        phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG,
                         USB_ROLE_DEVICE);
+
+       xudc->current_device_mode = true;
 }
 
 static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
@@ -725,6 +728,8 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
 
        dev_dbg(xudc->dev, "device mode off\n");
 
+       xudc->current_device_mode = false;
+
        connected = !!(xudc_readl(xudc, PORTSC) & PORTSC_CCS);
 
        reinit_completion(&xudc->disconnect_complete);
@@ -4044,10 +4049,10 @@ static int __maybe_unused tegra_xudc_resume(struct device *dev)
 
        spin_lock_irqsave(&xudc->lock, flags);
        xudc->suspended = false;
+       if (xudc->device_mode != xudc->current_device_mode)
+               schedule_work(&xudc->usb_role_sw_work);
        spin_unlock_irqrestore(&xudc->lock, flags);
 
-       schedule_work(&xudc->usb_role_sw_work);
-
        pm_runtime_enable(dev);
 
        return 0;