aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2006-10-04 05:15:41 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-04 10:55:15 -0400
commit7104e2d5a85b4b786d6a63568beffe1e185547bb (patch)
tree1478b1076a66476a121e687dd9547d5c08d9c3ba /drivers/mmc
parent8a4da1430f7f2a16df3be9c7b5d55ba4e75b708c (diff)
[PATCH] mmc: use own work queue
The MMC layer uses the standard work queue for doing card detection. As this queue is shared with other crucial subsystems, the effects of a long (and perhaps buggy) detection can cause the system to be unusable. E.g. the keyboard stops working while the detection routine is running. The solution is to add a specific mmc work queue to run the detection code in. This is similar to how other subsystems handle detection (a full kernel thread is the most common theme). Signed-off-by: Pierre Ossman <drzeus@drzeus.cx> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/mmc.c6
-rw-r--r--drivers/mmc/mmc.h4
-rw-r--r--drivers/mmc/mmc_sysfs.c35
3 files changed, 41 insertions, 4 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 5b9caa7978d3..ee8863c123e3 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1166,9 +1166,9 @@ static void mmc_setup(struct mmc_host *host)
1166void mmc_detect_change(struct mmc_host *host, unsigned long delay) 1166void mmc_detect_change(struct mmc_host *host, unsigned long delay)
1167{ 1167{
1168 if (delay) 1168 if (delay)
1169 schedule_delayed_work(&host->detect, delay); 1169 mmc_schedule_delayed_work(&host->detect, delay);
1170 else 1170 else
1171 schedule_work(&host->detect); 1171 mmc_schedule_work(&host->detect);
1172} 1172}
1173 1173
1174EXPORT_SYMBOL(mmc_detect_change); 1174EXPORT_SYMBOL(mmc_detect_change);
@@ -1311,7 +1311,7 @@ EXPORT_SYMBOL(mmc_remove_host);
1311 */ 1311 */
1312void mmc_free_host(struct mmc_host *host) 1312void mmc_free_host(struct mmc_host *host)
1313{ 1313{
1314 flush_scheduled_work(); 1314 mmc_flush_scheduled_work();
1315 mmc_free_host_sysfs(host); 1315 mmc_free_host_sysfs(host);
1316} 1316}
1317 1317
diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h
index 97bae00292fa..cd5e0ab3d84b 100644
--- a/drivers/mmc/mmc.h
+++ b/drivers/mmc/mmc.h
@@ -18,4 +18,8 @@ struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
18int mmc_add_host_sysfs(struct mmc_host *host); 18int mmc_add_host_sysfs(struct mmc_host *host);
19void mmc_remove_host_sysfs(struct mmc_host *host); 19void mmc_remove_host_sysfs(struct mmc_host *host);
20void mmc_free_host_sysfs(struct mmc_host *host); 20void mmc_free_host_sysfs(struct mmc_host *host);
21
22int mmc_schedule_work(struct work_struct *work);
23int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay);
24void mmc_flush_scheduled_work(void);
21#endif 25#endif
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index a2a35fd946ee..10cc9734eaa0 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -13,6 +13,7 @@
13#include <linux/init.h> 13#include <linux/init.h>
14#include <linux/device.h> 14#include <linux/device.h>
15#include <linux/idr.h> 15#include <linux/idr.h>
16#include <linux/workqueue.h>
16 17
17#include <linux/mmc/card.h> 18#include <linux/mmc/card.h>
18#include <linux/mmc/host.h> 19#include <linux/mmc/host.h>
@@ -317,10 +318,41 @@ void mmc_free_host_sysfs(struct mmc_host *host)
317 class_device_put(&host->class_dev); 318 class_device_put(&host->class_dev);
318} 319}
319 320
321static struct workqueue_struct *workqueue;
322
323/*
324 * Internal function. Schedule work in the MMC work queue.
325 */
326int mmc_schedule_work(struct work_struct *work)
327{
328 return queue_work(workqueue, work);
329}
330
331/*
332 * Internal function. Schedule delayed work in the MMC work queue.
333 */
334int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay)
335{
336 return queue_delayed_work(workqueue, work, delay);
337}
338
339/*
340 * Internal function. Flush all scheduled work from the MMC work queue.
341 */
342void mmc_flush_scheduled_work(void)
343{
344 flush_workqueue(workqueue);
345}
320 346
321static int __init mmc_init(void) 347static int __init mmc_init(void)
322{ 348{
323 int ret = bus_register(&mmc_bus_type); 349 int ret;
350
351 workqueue = create_singlethread_workqueue("kmmcd");
352 if (!workqueue)
353 return -ENOMEM;
354
355 ret = bus_register(&mmc_bus_type);
324 if (ret == 0) { 356 if (ret == 0) {
325 ret = class_register(&mmc_host_class); 357 ret = class_register(&mmc_host_class);
326 if (ret) 358 if (ret)
@@ -333,6 +365,7 @@ static void __exit mmc_exit(void)
333{ 365{
334 class_unregister(&mmc_host_class); 366 class_unregister(&mmc_host_class);
335 bus_unregister(&mmc_bus_type); 367 bus_unregister(&mmc_bus_type);
368 destroy_workqueue(workqueue);
336} 369}
337 370
338module_init(mmc_init); 371module_init(mmc_init);