Commit 7104e2d5 authored by Pierre Ossman's avatar Pierre Ossman Committed by Linus Torvalds

[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: default avatarPierre Ossman <drzeus@drzeus.cx>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 8a4da143
...@@ -1166,9 +1166,9 @@ static void mmc_setup(struct mmc_host *host) ...@@ -1166,9 +1166,9 @@ static void mmc_setup(struct mmc_host *host)
void mmc_detect_change(struct mmc_host *host, unsigned long delay) void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{ {
if (delay) if (delay)
schedule_delayed_work(&host->detect, delay); mmc_schedule_delayed_work(&host->detect, delay);
else else
schedule_work(&host->detect); mmc_schedule_work(&host->detect);
} }
EXPORT_SYMBOL(mmc_detect_change); EXPORT_SYMBOL(mmc_detect_change);
...@@ -1311,7 +1311,7 @@ EXPORT_SYMBOL(mmc_remove_host); ...@@ -1311,7 +1311,7 @@ EXPORT_SYMBOL(mmc_remove_host);
*/ */
void mmc_free_host(struct mmc_host *host) void mmc_free_host(struct mmc_host *host)
{ {
flush_scheduled_work(); mmc_flush_scheduled_work();
mmc_free_host_sysfs(host); mmc_free_host_sysfs(host);
} }
......
...@@ -18,4 +18,8 @@ struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev); ...@@ -18,4 +18,8 @@ struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
int mmc_add_host_sysfs(struct mmc_host *host); int mmc_add_host_sysfs(struct mmc_host *host);
void mmc_remove_host_sysfs(struct mmc_host *host); void mmc_remove_host_sysfs(struct mmc_host *host);
void mmc_free_host_sysfs(struct mmc_host *host); void mmc_free_host_sysfs(struct mmc_host *host);
int mmc_schedule_work(struct work_struct *work);
int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay);
void mmc_flush_scheduled_work(void);
#endif #endif
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/workqueue.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
...@@ -317,10 +318,41 @@ void mmc_free_host_sysfs(struct mmc_host *host) ...@@ -317,10 +318,41 @@ void mmc_free_host_sysfs(struct mmc_host *host)
class_device_put(&host->class_dev); class_device_put(&host->class_dev);
} }
static struct workqueue_struct *workqueue;
/*
* Internal function. Schedule work in the MMC work queue.
*/
int mmc_schedule_work(struct work_struct *work)
{
return queue_work(workqueue, work);
}
/*
* Internal function. Schedule delayed work in the MMC work queue.
*/
int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay)
{
return queue_delayed_work(workqueue, work, delay);
}
/*
* Internal function. Flush all scheduled work from the MMC work queue.
*/
void mmc_flush_scheduled_work(void)
{
flush_workqueue(workqueue);
}
static int __init mmc_init(void) static int __init mmc_init(void)
{ {
int ret = bus_register(&mmc_bus_type); int ret;
workqueue = create_singlethread_workqueue("kmmcd");
if (!workqueue)
return -ENOMEM;
ret = bus_register(&mmc_bus_type);
if (ret == 0) { if (ret == 0) {
ret = class_register(&mmc_host_class); ret = class_register(&mmc_host_class);
if (ret) if (ret)
...@@ -333,6 +365,7 @@ static void __exit mmc_exit(void) ...@@ -333,6 +365,7 @@ static void __exit mmc_exit(void)
{ {
class_unregister(&mmc_host_class); class_unregister(&mmc_host_class);
bus_unregister(&mmc_bus_type); bus_unregister(&mmc_bus_type);
destroy_workqueue(workqueue);
} }
module_init(mmc_init); module_init(mmc_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment