Skip to content

Commit 3d3c4cd

Browse files
oleremPaolo Abeni
authored andcommitted
net: usb: asix: hold PM usage ref to avoid PM/MDIO + RTNL deadlock
Prevent USB runtime PM (autosuspend) for AX88772* in bind. usbnet enables runtime PM (autosuspend) by default, so disabling it via the usb_driver flag is ineffective. On AX88772B, autosuspend shows no measurable power saving with current driver (no link partner, admin up/down). The ~0.453 W -> ~0.248 W drop on v6.1 comes from phylib powering the PHY off on admin-down, not from USB autosuspend. The real hazard is that with runtime PM enabled, ndo_open() (under RTNL) may synchronously trigger autoresume (usb_autopm_get_interface()) into asix_resume() while the USB PM lock is held. Resume paths then invoke phylink/phylib and MDIO, which also expect RTNL, leading to possible deadlocks or PM lock vs MDIO wake issues. To avoid this, keep the device runtime-PM active by taking a usage reference in ax88772_bind() and dropping it in unbind(). A non-zero PM usage count blocks runtime suspend regardless of userspace policy (.../power/control - pm_runtime_allow/forbid), making this approach robust against sysfs overrides. Holding a runtime-PM usage ref does not affect system-wide suspend; system sleep/resume callbacks continue to run as before. Fixes: 4a2c721 ("net: usb: asix: ax88772: manage PHY PM from MAC") Reported-by: Hubert Wiśniewski <[email protected]> Closes: https://lore.kernel.org/all/[email protected] Tested-by: Hubert Wiśniewski <[email protected]> Reported-by: Marek Szyprowski <[email protected]> Closes: https://lore.kernel.org/all/[email protected] Cc: [email protected] Signed-off-by: Oleksij Rempel <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent b615879 commit 3d3c4cd

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

drivers/net/usb/asix_devices.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,21 @@ static void ax88772_suspend(struct usbnet *dev)
625625
asix_read_medium_status(dev, 1));
626626
}
627627

628+
/* Notes on PM callbacks and locking context:
629+
*
630+
* - asix_suspend()/asix_resume() are invoked for both runtime PM and
631+
* system-wide suspend/resume. For struct usb_driver the ->resume()
632+
* callback does not receive pm_message_t, so the resume type cannot
633+
* be distinguished here.
634+
*
635+
* - The MAC driver must hold RTNL when calling phylink interfaces such as
636+
* phylink_suspend()/resume(). Those calls will also perform MDIO I/O.
637+
*
638+
* - Taking RTNL and doing MDIO from a runtime-PM resume callback (while
639+
* the USB PM lock is held) is fragile. Since autosuspend brings no
640+
* measurable power saving here, we block it by holding a PM usage
641+
* reference in ax88772_bind().
642+
*/
628643
static int asix_suspend(struct usb_interface *intf, pm_message_t message)
629644
{
630645
struct usbnet *dev = usb_get_intfdata(intf);
@@ -919,6 +934,13 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
919934
if (ret)
920935
goto initphy_err;
921936

937+
/* Keep this interface runtime-PM active by taking a usage ref.
938+
* Prevents runtime suspend while bound and avoids resume paths
939+
* that could deadlock (autoresume under RTNL while USB PM lock
940+
* is held, phylink/MDIO wants RTNL).
941+
*/
942+
pm_runtime_get_noresume(&intf->dev);
943+
922944
return 0;
923945

924946
initphy_err:
@@ -948,6 +970,8 @@ static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)
948970
phylink_destroy(priv->phylink);
949971
ax88772_mdio_unregister(priv);
950972
asix_rx_fixup_common_free(dev->driver_priv);
973+
/* Drop the PM usage ref taken in bind() */
974+
pm_runtime_put(&intf->dev);
951975
}
952976

953977
static void ax88178_unbind(struct usbnet *dev, struct usb_interface *intf)
@@ -1600,6 +1624,11 @@ static struct usb_driver asix_driver = {
16001624
.resume = asix_resume,
16011625
.reset_resume = asix_resume,
16021626
.disconnect = usbnet_disconnect,
1627+
/* usbnet enables autosuspend by default (supports_autosuspend=1).
1628+
* We keep runtime-PM active for AX88772* by taking a PM usage
1629+
* reference in ax88772_bind() (pm_runtime_get_noresume()) and
1630+
* dropping it in unbind(), which effectively blocks autosuspend.
1631+
*/
16031632
.supports_autosuspend = 1,
16041633
.disable_hub_initiated_lpm = 1,
16051634
};

0 commit comments

Comments
 (0)