aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/usb.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-09-19 10:14:07 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-28 18:36:44 -0400
commitbd859281c09b4318153dc7222b5e9052aad83b61 (patch)
treec56c116b7720aae3dc5192f115444d16a5c21e58 /drivers/usb/core/usb.c
parent6a9fb060393e04a79973f95925f4f6587442e9c7 (diff)
USB: create new workqueue thread for USB autosuspend
This patch (as787) creates a new workqueue thread to handle delayed USB autosuspend requests. Previously the code used keventd. However it turns out that the hub driver's suspend routine calls flush_scheduled_work(), making it a poor candidate for running in keventd (the call immediately deadlocks). The solution is to use a new thread instead of keventd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core/usb.c')
-rw-r--r--drivers/usb/core/usb.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 60ef4ef0101a..239f8e5d247f 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -33,6 +33,7 @@
33#include <linux/smp_lock.h> 33#include <linux/smp_lock.h>
34#include <linux/usb.h> 34#include <linux/usb.h>
35#include <linux/mutex.h> 35#include <linux/mutex.h>
36#include <linux/workqueue.h>
36 37
37#include <asm/io.h> 38#include <asm/io.h>
38#include <asm/scatterlist.h> 39#include <asm/scatterlist.h>
@@ -47,6 +48,8 @@ const char *usbcore_name = "usbcore";
47 48
48static int nousb; /* Disable USB when built into kernel image */ 49static int nousb; /* Disable USB when built into kernel image */
49 50
51struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */
52
50 53
51/** 54/**
52 * usb_ifnum_to_if - get the interface object with a given interface number 55 * usb_ifnum_to_if - get the interface object with a given interface number
@@ -170,9 +173,9 @@ static void usb_release_dev(struct device *dev)
170 173
171 udev = to_usb_device(dev); 174 udev = to_usb_device(dev);
172 175
173#ifdef CONFIG_PM 176#ifdef CONFIG_USB_SUSPEND
174 cancel_delayed_work(&udev->autosuspend); 177 cancel_delayed_work(&udev->autosuspend);
175 flush_scheduled_work(); 178 flush_workqueue(ksuspend_usb_wq);
176#endif 179#endif
177 usb_destroy_configuration(udev); 180 usb_destroy_configuration(udev);
178 usb_put_hcd(bus_to_hcd(udev->bus)); 181 usb_put_hcd(bus_to_hcd(udev->bus));
@@ -184,6 +187,28 @@ static void usb_release_dev(struct device *dev)
184 187
185#ifdef CONFIG_PM 188#ifdef CONFIG_PM
186 189
190static int ksuspend_usb_init(void)
191{
192 ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd");
193 if (!ksuspend_usb_wq)
194 return -ENOMEM;
195 return 0;
196}
197
198static void ksuspend_usb_cleanup(void)
199{
200 destroy_workqueue(ksuspend_usb_wq);
201}
202
203#else
204
205#define ksuspend_usb_init() 0
206#define ksuspend_usb_cleanup() do {} while (0)
207
208#endif
209
210#ifdef CONFIG_USB_SUSPEND
211
187/* usb_autosuspend_work - callback routine to autosuspend a USB device */ 212/* usb_autosuspend_work - callback routine to autosuspend a USB device */
188static void usb_autosuspend_work(void *_udev) 213static void usb_autosuspend_work(void *_udev)
189{ 214{
@@ -195,6 +220,11 @@ static void usb_autosuspend_work(void *_udev)
195 mutex_unlock(&udev->pm_mutex); 220 mutex_unlock(&udev->pm_mutex);
196} 221}
197 222
223#else
224
225static void usb_autosuspend_work(void *_udev)
226{}
227
198#endif 228#endif
199 229
200/** 230/**
@@ -976,9 +1006,12 @@ static int __init usb_init(void)
976 return 0; 1006 return 0;
977 } 1007 }
978 1008
1009 retval = ksuspend_usb_init();
1010 if (retval)
1011 goto out;
979 retval = bus_register(&usb_bus_type); 1012 retval = bus_register(&usb_bus_type);
980 if (retval) 1013 if (retval)
981 goto out; 1014 goto bus_register_failed;
982 retval = usb_host_init(); 1015 retval = usb_host_init();
983 if (retval) 1016 if (retval)
984 goto host_init_failed; 1017 goto host_init_failed;
@@ -1014,6 +1047,8 @@ major_init_failed:
1014 usb_host_cleanup(); 1047 usb_host_cleanup();
1015host_init_failed: 1048host_init_failed:
1016 bus_unregister(&usb_bus_type); 1049 bus_unregister(&usb_bus_type);
1050bus_register_failed:
1051 ksuspend_usb_cleanup();
1017out: 1052out:
1018 return retval; 1053 return retval;
1019} 1054}
@@ -1035,6 +1070,7 @@ static void __exit usb_exit(void)
1035 usb_hub_cleanup(); 1070 usb_hub_cleanup();
1036 usb_host_cleanup(); 1071 usb_host_cleanup();
1037 bus_unregister(&usb_bus_type); 1072 bus_unregister(&usb_bus_type);
1073 ksuspend_usb_cleanup();
1038} 1074}
1039 1075
1040subsys_initcall(usb_init); 1076subsys_initcall(usb_init);