Skip to content

Commit

Permalink
[PATCH] mmc: use own work queue
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Pierre Ossman authored and Linus Torvalds committed Oct 4, 2006
1 parent 8a4da14 commit 7104e2d
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 4 deletions.
6 changes: 3 additions & 3 deletions drivers/mmc/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1166,9 +1166,9 @@ static void mmc_setup(struct mmc_host *host)
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
if (delay)
schedule_delayed_work(&host->detect, delay);
mmc_schedule_delayed_work(&host->detect, delay);
else
schedule_work(&host->detect);
mmc_schedule_work(&host->detect);
}

EXPORT_SYMBOL(mmc_detect_change);
Expand Down Expand Up @@ -1311,7 +1311,7 @@ EXPORT_SYMBOL(mmc_remove_host);
*/
void mmc_free_host(struct mmc_host *host)
{
flush_scheduled_work();
mmc_flush_scheduled_work();
mmc_free_host_sysfs(host);
}

Expand Down
4 changes: 4 additions & 0 deletions drivers/mmc/mmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
void mmc_remove_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
35 changes: 34 additions & 1 deletion drivers/mmc/mmc_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/workqueue.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
Expand Down Expand Up @@ -317,10 +318,41 @@ void mmc_free_host_sysfs(struct mmc_host *host)
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)
{
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) {
ret = class_register(&mmc_host_class);
if (ret)
Expand All @@ -333,6 +365,7 @@ static void __exit mmc_exit(void)
{
class_unregister(&mmc_host_class);
bus_unregister(&mmc_bus_type);
destroy_workqueue(workqueue);
}

module_init(mmc_init);
Expand Down

0 comments on commit 7104e2d

Please sign in to comment.