Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=d5d4db704b962773c03ee3beb3258b6450611e66
Commit:     d5d4db704b962773c03ee3beb3258b6450611e66
Parent:     c420bc9f09a0926b708c3edb27eacba434a4f4ba
Author:     Alan Stern <[EMAIL PROTECTED]>
AuthorDate: Tue May 29 16:34:52 2007 -0400
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue May 29 13:39:07 2007 -0700

    USB: replace flush_workqueue with cancel_sync_work
    
    This patch (as912) replaces a couple of calls to flush_workqueue()
    with cancel_sync_work() and cancel_rearming_delayed_work().  Using a
    more directed approach allows us to avoid some nasty deadlocks.  The
    prime example occurs when a first-level device (the parent is a root
    hub) is removed while at the same time the root hub gets a remote
    wakeup request.  khubd would try to flush the autosuspend workqueue
    while holding the root-hub's lock, and the remote-wakeup workqueue
    routine would be waiting to lock the root hub.
    
    The patch also reorganizes the power management portion of
    usb_disconnect(), separating it out into its own routine.  The
    autosuspend workqueue entry is cancelled immediately instead of
    waiting for the device's release routine.  In addition,
    synchronization with the autosuspend thread is carried out even for
    root hubs (an oversight in the original code).
    
    Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
    Cc: Andrew Morton <[EMAIL PROTECTED]>
    Cc: Greg KH <[EMAIL PROTECTED]>
    Cc: Mark Lord <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 drivers/usb/core/hcd.c |    2 +-
 drivers/usb/core/hub.c |   32 +++++++++++++++++++++++++-------
 drivers/usb/core/usb.c |    4 ----
 3 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e277258..8969e42 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 caaa46f..24f10a1 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 80627b6..4a6299b 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);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to