]> Pileus Git - ~andy/linux/commitdiff
mmc: Don't force card to active state when entering suspend/shutdown
authorUlf Hansson <ulf.hansson@linaro.org>
Wed, 2 Oct 2013 15:37:09 +0000 (17:37 +0200)
committerChris Ball <cjb@laptop.org>
Thu, 31 Oct 2013 00:28:40 +0000 (20:28 -0400)
By adding a card state that records if it is suspended or resumed, we
can accept asyncronus suspend/resume requests for the mmc and sd
bus_ops.

MMC_CAP_AGGRESSIVE_PM, will at request inactivity through the runtime
bus_ops callbacks, execute a suspend of the the card. In the state were
this has been done, we can receive a suspend request for the mmc bus,
which for sd and mmc forced the card to active state by a
pm_runtime_get_sync. In other words, the card was resumed and then
immediately suspended again, completely unnecessary.

Since the suspend/resume bus_ops callbacks for sd and mmc are now
capable of handling asynchronous requests, we no longer need to force
the card to active state before executing suspend. Evidently preventing
the above sequence for MMC_CAP_AGGRESSIVE_PM.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/card/block.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
include/linux/mmc/card.h

index 1a3163f1407e2093a43a6a1c61db5a9538f6a329..29d5d988a51cc6233ce71215a3d88bcc91167c94 100644 (file)
@@ -2448,7 +2448,6 @@ static int _mmc_blk_suspend(struct mmc_card *card)
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        if (md) {
-               pm_runtime_get_sync(&card->dev);
                mmc_queue_suspend(&md->queue);
                list_for_each_entry(part_md, &md->part, part) {
                        mmc_queue_suspend(&part_md->queue);
@@ -2483,7 +2482,6 @@ static int mmc_blk_resume(struct mmc_card *card)
                list_for_each_entry(part_md, &md->part, part) {
                        mmc_queue_resume(&part_md->queue);
                }
-               pm_runtime_put(&card->dev);
        }
        return 0;
 }
index 0d060227cfc1bab543f32fdc78f5d6809f4b5315..84d8694cf3694abadd9eddb43edc1c2468570f85 100644 (file)
@@ -1478,6 +1478,9 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 
        mmc_claim_host(host);
 
+       if (mmc_card_suspended(host->card))
+               goto out;
+
        if (mmc_card_doing_bkops(host->card)) {
                err = mmc_stop_bkops(host->card);
                if (err)
@@ -1497,8 +1500,10 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
                err = mmc_deselect_cards(host);
        host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
 
-       if (!err)
+       if (!err) {
                mmc_power_off(host);
+               mmc_card_set_suspended(host->card);
+       }
 out:
        mmc_release_host(host);
        return err;
@@ -1512,14 +1517,6 @@ static int mmc_suspend(struct mmc_host *host)
        return _mmc_suspend(host, true);
 }
 
-/*
- * Shutdown callback
- */
-static int mmc_shutdown(struct mmc_host *host)
-{
-       return _mmc_suspend(host, false);
-}
-
 /*
  * Resume callback from host.
  *
@@ -1528,19 +1525,45 @@ static int mmc_shutdown(struct mmc_host *host)
  */
 static int mmc_resume(struct mmc_host *host)
 {
-       int err;
+       int err = 0;
 
        BUG_ON(!host);
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
+
+       if (!mmc_card_suspended(host->card))
+               goto out;
+
        mmc_power_up(host, host->card->ocr);
        err = mmc_init_card(host, host->card->ocr, host->card);
-       mmc_release_host(host);
+       mmc_card_clr_suspended(host->card);
 
+out:
+       mmc_release_host(host);
        return err;
 }
 
+/*
+ * Shutdown callback
+ */
+static int mmc_shutdown(struct mmc_host *host)
+{
+       int err = 0;
+
+       /*
+        * In a specific case for poweroff notify, we need to resume the card
+        * before we can shutdown it properly.
+        */
+       if (mmc_can_poweroff_notify(host->card) &&
+               !(host->caps2 & MMC_CAP2_FULL_PWR_CYCLE))
+               err = mmc_resume(host);
+
+       if (!err)
+               err = _mmc_suspend(host, false);
+
+       return err;
+}
 
 /*
  * Callback for runtime_suspend.
index 6ef84d0ca178a026fbbaf79fb46fc9bce6a228bd..685796560f8b5687b4c692583f022008ffa30dba 100644 (file)
@@ -1078,13 +1078,20 @@ static int mmc_sd_suspend(struct mmc_host *host)
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
+
+       if (mmc_card_suspended(host->card))
+               goto out;
+
        if (!mmc_host_is_spi(host))
                err = mmc_deselect_cards(host);
        host->card->state &= ~MMC_STATE_HIGHSPEED;
-       if (!err)
+       if (!err) {
                mmc_power_off(host);
-       mmc_release_host(host);
+               mmc_card_set_suspended(host->card);
+       }
 
+out:
+       mmc_release_host(host);
        return err;
 }
 
@@ -1096,16 +1103,22 @@ static int mmc_sd_suspend(struct mmc_host *host)
  */
 static int mmc_sd_resume(struct mmc_host *host)
 {
-       int err;
+       int err = 0;
 
        BUG_ON(!host);
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
+
+       if (!mmc_card_suspended(host->card))
+               goto out;
+
        mmc_power_up(host, host->card->ocr);
        err = mmc_sd_init_card(host, host->card->ocr, host->card);
-       mmc_release_host(host);
+       mmc_card_clr_suspended(host->card);
 
+out:
+       mmc_release_host(host);
        return err;
 }
 
index 33d9a74f92e6c34a5e1e14618e23ee3fac774b1b..176fdf824b14733bf5a37ca48a3f7993f7544048 100644 (file)
@@ -258,6 +258,7 @@ struct mmc_card {
 #define MMC_CARD_REMOVED       (1<<7)          /* card has been removed */
 #define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
 #define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED    (1<<11)         /* card is suspended */
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -424,6 +425,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
+#define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -436,6 +438,8 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
 #define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
+#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
+#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
 
 /*
  * Quirk add/remove for MMC products.