[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>
This commit is contained in:
parent
8a4da1430f
commit
7104e2d5a8
|
@ -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);
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
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 @@
|
||||||
#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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
Reference in New Issue