diff options
Diffstat (limited to 'drivers/net/usb/asix_devices.c')
-rw-r--r-- | drivers/net/usb/asix_devices.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 792ddda1ad49..85bd5d845409 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -625,6 +625,21 @@ static void ax88772_suspend(struct usbnet *dev) asix_read_medium_status(dev, 1)); } +/* Notes on PM callbacks and locking context: + * + * - asix_suspend()/asix_resume() are invoked for both runtime PM and + * system-wide suspend/resume. For struct usb_driver the ->resume() + * callback does not receive pm_message_t, so the resume type cannot + * be distinguished here. + * + * - The MAC driver must hold RTNL when calling phylink interfaces such as + * phylink_suspend()/resume(). Those calls will also perform MDIO I/O. + * + * - Taking RTNL and doing MDIO from a runtime-PM resume callback (while + * the USB PM lock is held) is fragile. Since autosuspend brings no + * measurable power saving here, we block it by holding a PM usage + * reference in ax88772_bind(). + */ static int asix_suspend(struct usb_interface *intf, pm_message_t message) { struct usbnet *dev = usb_get_intfdata(intf); @@ -919,6 +934,13 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) if (ret) goto initphy_err; + /* Keep this interface runtime-PM active by taking a usage ref. + * Prevents runtime suspend while bound and avoids resume paths + * that could deadlock (autoresume under RTNL while USB PM lock + * is held, phylink/MDIO wants RTNL). + */ + pm_runtime_get_noresume(&intf->dev); + return 0; initphy_err: @@ -948,6 +970,8 @@ static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) phylink_destroy(priv->phylink); ax88772_mdio_unregister(priv); asix_rx_fixup_common_free(dev->driver_priv); + /* Drop the PM usage ref taken in bind() */ + pm_runtime_put(&intf->dev); } static void ax88178_unbind(struct usbnet *dev, struct usb_interface *intf) @@ -1600,6 +1624,11 @@ static struct usb_driver asix_driver = { .resume = asix_resume, .reset_resume = asix_resume, .disconnect = usbnet_disconnect, + /* usbnet enables autosuspend by default (supports_autosuspend=1). + * We keep runtime-PM active for AX88772* by taking a PM usage + * reference in ax88772_bind() (pm_runtime_get_noresume()) and + * dropping it in unbind(), which effectively blocks autosuspend. + */ .supports_autosuspend = 1, .disable_hub_initiated_lpm = 1, }; |