diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e277258df382..8969e42434b9 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1681,7 +1681,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) spin_unlock_irq (&hcd_root_hub_lock); #ifdef CONFIG_PM - flush_workqueue(ksuspend_usb_wq); + cancel_work_sync(&hcd->wakeup_work); #endif mutex_lock(&usb_bus_list_lock); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index caaa46f2dec7..24f10a19dbdb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1158,6 +1158,30 @@ static void release_address(struct usb_device *udev) } } +#ifdef CONFIG_USB_SUSPEND + +static void usb_stop_pm(struct usb_device *udev) +{ + /* Synchronize with the ksuspend thread to prevent any more + * autosuspend requests from being submitted, and decrement + * the parent's count of unsuspended children. + */ + usb_pm_lock(udev); + if (udev->parent && !udev->discon_suspended) + usb_autosuspend_device(udev->parent); + usb_pm_unlock(udev); + + /* Stop any autosuspend requests already submitted */ + cancel_rearming_delayed_work(&udev->autosuspend); +} + +#else + +static inline void usb_stop_pm(struct usb_device *udev) +{ } + +#endif + /** * usb_disconnect - disconnect a device (usbcore-internal) * @pdev: pointer to device being disconnected @@ -1224,13 +1248,7 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; spin_unlock_irq(&device_state_lock); - /* Decrement the parent's count of unsuspended children */ - if (udev->parent) { - usb_pm_lock(udev); - if (!udev->discon_suspended) - usb_autosuspend_device(udev->parent); - usb_pm_unlock(udev); - } + usb_stop_pm(udev); put_device(&udev->dev); } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 80627b6a2bf9..4a6299bd0047 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -184,10 +184,6 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); -#ifdef CONFIG_USB_SUSPEND - cancel_delayed_work(&udev->autosuspend); - flush_workqueue(ksuspend_usb_wq); -#endif usb_destroy_configuration(udev); usb_put_hcd(bus_to_hcd(udev->bus)); kfree(udev->product);