mmc: core: host: only use wakelock for detect work
authorColin Cross <ccross@android.com>
Thu, 8 Sep 2011 00:28:58 +0000 (17:28 -0700)
committerColin Cross <ccross@android.com>
Thu, 8 Sep 2011 00:30:23 +0000 (17:30 -0700)
There is no need to take a wakelock for delayed lazy disable
work, it will be cancelled in the suspend handler and force
disabled.  Only take the wakelock when the detect work is
queued, and make sure to drop the wakelock if the work is
cancelled.

Change-Id: I1e507a5f98848954ea21d45e23b6192c3132a349
Signed-off-by: Colin Cross <ccross@android.com>
drivers/mmc/core/core.c
drivers/mmc/core/host.c
include/linux/mmc/host.h

index 7c3444a37070de9fffd24839990a06c2433ceacc..bbe0f2ee624b89ca0afefadbd0e9b6a27ebd941b 100644 (file)
@@ -40,7 +40,6 @@
 #include "sdio_ops.h"
 
 static struct workqueue_struct *workqueue;
-static struct wake_lock mmc_delayed_work_wake_lock;
 
 /*
  * Enabling software CRCs on the data blocks can be a significant (30%)
@@ -73,7 +72,6 @@ MODULE_PARM_DESC(
 static int mmc_schedule_delayed_work(struct delayed_work *work,
                                     unsigned long delay)
 {
-       wake_lock(&mmc_delayed_work_wake_lock);
        return queue_delayed_work(workqueue, work, delay);
 }
 
@@ -559,12 +557,9 @@ void mmc_host_deeper_disable(struct work_struct *work)
 
        /* If the host is claimed then we do not want to disable it anymore */
        if (!mmc_try_claim_host(host))
-               goto out;
+               return;
        mmc_host_do_disable(host, 1);
        mmc_do_release_host(host);
-
-out:
-       wake_unlock(&mmc_delayed_work_wake_lock);
 }
 
 /**
@@ -1198,6 +1193,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
+       wake_lock(&host->detect_wake_lock);
        mmc_schedule_delayed_work(&host->detect, delay);
 }
 
@@ -1660,11 +1656,13 @@ void mmc_rescan(struct work_struct *work)
 
  out:
        if (extend_wakelock)
-               wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2);
+               wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
        else
-               wake_unlock(&mmc_delayed_work_wake_lock);
-       if (host->caps & MMC_CAP_NEEDS_POLL)
+               wake_unlock(&host->detect_wake_lock);
+       if (host->caps & MMC_CAP_NEEDS_POLL) {
+               wake_lock(&host->detect_wake_lock);
                mmc_schedule_delayed_work(&host->detect, HZ);
+       }
 }
 
 void mmc_start_host(struct mmc_host *host)
@@ -1684,7 +1682,8 @@ void mmc_stop_host(struct mmc_host *host)
 
        if (host->caps & MMC_CAP_DISABLE)
                cancel_delayed_work(&host->disable);
-       cancel_delayed_work_sync(&host->detect);
+       if (cancel_delayed_work_sync(&host->detect))
+               wake_unlock(&host->detect_wake_lock);
        mmc_flush_scheduled_work();
 
        /* clear pm flags now and let card drivers set them as needed */
@@ -1805,7 +1804,8 @@ int mmc_suspend_host(struct mmc_host *host)
 
        if (host->caps & MMC_CAP_DISABLE)
                cancel_delayed_work(&host->disable);
-       cancel_delayed_work(&host->detect);
+       if (cancel_delayed_work(&host->detect))
+               wake_unlock(&host->detect_wake_lock);
        mmc_flush_scheduled_work();
 
        mmc_bus_get(host);
@@ -1907,7 +1907,8 @@ int mmc_pm_notify(struct notifier_block *notify_block,
                }
                host->rescan_disable = 1;
                spin_unlock_irqrestore(&host->lock, flags);
-               cancel_delayed_work_sync(&host->detect);
+               if (cancel_delayed_work_sync(&host->detect))
+                       wake_unlock(&host->detect_wake_lock);
 
                if (!host->bus_ops || host->bus_ops->suspend)
                        break;
@@ -1965,9 +1966,6 @@ static int __init mmc_init(void)
        if (!workqueue)
                return -ENOMEM;
 
-       wake_lock_init(&mmc_delayed_work_wake_lock, WAKE_LOCK_SUSPEND,
-                      "mmc_delayed_work");
-
        ret = mmc_register_bus();
        if (ret)
                goto destroy_workqueue;
@@ -1988,7 +1986,6 @@ unregister_bus:
        mmc_unregister_bus();
 destroy_workqueue:
        destroy_workqueue(workqueue);
-       wake_lock_destroy(&mmc_delayed_work_wake_lock);
 
        return ret;
 }
@@ -1999,7 +1996,6 @@ static void __exit mmc_exit(void)
        mmc_unregister_host_class();
        mmc_unregister_bus();
        destroy_workqueue(workqueue);
-       wake_lock_destroy(&mmc_delayed_work_wake_lock);
 }
 
 subsys_initcall(mmc_init);
index 84694a9410d90d139e3a29e88692fc7922878ada..facc4ea138d1efd8c435ea96460f172cc6c54bab 100644 (file)
@@ -284,6 +284,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 
        spin_lock_init(&host->lock);
        init_waitqueue_head(&host->wq);
+       wake_lock_init(&host->detect_wake_lock, WAKE_LOCK_SUSPEND,
+               kasprintf(GFP_KERNEL, "%s_detect", mmc_hostname(host)));
        INIT_DELAYED_WORK(&host->detect, mmc_rescan);
        INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
 #ifdef CONFIG_PM
@@ -383,6 +385,7 @@ void mmc_free_host(struct mmc_host *host)
        spin_lock(&mmc_host_lock);
        idr_remove(&mmc_host_idr, host->index);
        spin_unlock(&mmc_host_lock);
+       wake_lock_destroy(&host->detect_wake_lock);
 
        put_device(&host->class_dev);
 }
index 1584b5236bbc228bcaa3538f07b69d03c88e9511..2cfa8d02e719291ec40ec3807593ce2f09b90784 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <linux/leds.h>
 #include <linux/sched.h>
+#include <linux/wakelock.h>
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/pm.h>
@@ -261,6 +262,7 @@ struct mmc_host {
        int                     claim_cnt;      /* "claim" nesting count */
 
        struct delayed_work     detect;
+       struct wake_lock        detect_wake_lock;
 
        const struct mmc_bus_ops *bus_ops;      /* current bus driver */
        unsigned int            bus_refs;       /* reference counter */