mmc: allow upper layers to know immediately if card has been removed
authorChuanxiao Dong <chuanxiao.dong@intel.com>
Thu, 8 Dec 2011 09:10:27 +0000 (17:10 +0800)
committerbuildbot <buildbot@intel.com>
Mon, 26 Dec 2011 10:56:00 +0000 (02:56 -0800)
BZ: 18012

[PORT FROM UPSTREAM]

Add a function mmc_detect_card_removed() which upper layers can use to
determine immediately if a card has been removed. This function should
be called after an I/O request fails so that all queued I/O requests
can be errored out immediately instead of waiting for the card device
to be removed.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Change-Id: I3b602d69e0cc3c5a49245a35adcd227d849103b9
Signed-off-by: Chuanxiao Dong <chuanxiao.dong@intel.com>
Reviewed-on: http://android.intel.com:8080/29373
Reviewed-by: Tang, Richard <richard.tang@intel.com>
Tested-by: Sun, Jianhua <jianhua.sun@intel.com>
Reviewed-by: Zayet, AymenX <aymenx.zayet@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h

index 8ec7387..4018905 100644 (file)
@@ -101,7 +101,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
                        cmd->retries = 0;
        }
 
-       if (err && cmd->retries) {
+       if (err && cmd->retries && !mmc_card_removed(host->card)) {
                /*
                 * Request starter must handle retries - see
                 * mmc_wait_for_req_done().
@@ -206,6 +206,11 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
        init_completion(&mrq->completion);
        mrq->done = mmc_wait_done;
+       if (mmc_card_removed(host->card)) {
+               mrq->cmd->error = -ENOMEDIUM;
+               complete(&mrq->completion);
+               return;
+       }
        mmc_start_request(host, mrq);
 }
 
@@ -218,7 +223,8 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
                wait_for_completion(&mrq->completion);
 
                cmd = mrq->cmd;
-               if (!cmd->error || !cmd->retries)
+               if (!cmd->error || !cmd->retries ||
+                   mmc_card_removed(host->card))
                        break;
 
                pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
@@ -1491,6 +1497,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
+       host->detect_change = 1;
        mmc_schedule_delayed_work(&host->detect, delay);
 }
 
@@ -2083,6 +2090,43 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
        return -EIO;
 }
 
+int _mmc_detect_card_removed(struct mmc_host *host)
+{
+       int ret;
+
+       if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+               return 0;
+
+       if (!host->card || mmc_card_removed(host->card))
+               return 1;
+
+       ret = host->bus_ops->alive(host);
+       if (ret) {
+               mmc_card_set_removed(host->card);
+               pr_debug("%s: card remove detected\n", mmc_hostname(host));
+       }
+
+       return ret;
+}
+
+int mmc_detect_card_removed(struct mmc_host *host)
+{
+       struct mmc_card *card = host->card;
+
+       WARN_ON(!host->claimed);
+       /*
+        * The card will be considered unchanged unless we have been asked to
+        * detect a change or host requires polling to provide card detection.
+        */
+       if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
+               return mmc_card_removed(card);
+
+       host->detect_change = 0;
+
+       return _mmc_detect_card_removed(host);
+}
+EXPORT_SYMBOL(mmc_detect_card_removed);
+
 void mmc_rescan(struct work_struct *work)
 {
        static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
@@ -2103,6 +2147,8 @@ void mmc_rescan(struct work_struct *work)
            && !(host->caps & MMC_CAP_NONREMOVABLE))
                host->bus_ops->detect(host);
 
+       host->detect_change = 0;
+
        /*
         * Let mmc_bus_put() free the bus/bus_ops if we've found that
         * the card is no longer present.
index 14664f1..3400924 100644 (file)
@@ -24,6 +24,7 @@ struct mmc_bus_ops {
        int (*resume)(struct mmc_host *);
        int (*power_save)(struct mmc_host *);
        int (*power_restore)(struct mmc_host *);
+       int (*alive)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -59,6 +60,8 @@ void mmc_rescan(struct work_struct *work);
 void mmc_start_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
+int _mmc_detect_card_removed(struct mmc_host *host);
+
 int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
index 47efc99..14d9b32 100644 (file)
@@ -920,6 +920,14 @@ static void mmc_remove(struct mmc_host *host)
 }
 
 /*
+ * Card detection - card is alive.
+ */
+static int mmc_alive(struct mmc_host *host)
+{
+       return mmc_send_status(host->card, NULL);
+}
+
+/*
  * Card detection callback from host.
  */
 static void mmc_detect(struct mmc_host *host)
@@ -934,7 +942,7 @@ static void mmc_detect(struct mmc_host *host)
        /*
         * Just check if our card has been removed.
         */
-       err = mmc_send_status(host->card, NULL);
+       err = _mmc_detect_card_removed(host);
 
        mmc_release_host(host);
 
@@ -1035,6 +1043,7 @@ static const struct mmc_bus_ops mmc_ops = {
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_power_restore,
+       .alive = mmc_alive,
 };
 
 static const struct mmc_bus_ops mmc_ops_unsafe = {
@@ -1045,6 +1054,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
        .suspend = mmc_suspend,
        .resume = mmc_resume,
        .power_restore = mmc_power_restore,
+       .alive = mmc_alive,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
index fd9c48c..010002c 100644 (file)
@@ -1038,6 +1038,14 @@ static void mmc_sd_remove(struct mmc_host *host)
 }
 
 /*
+ * Card detection - card is alive.
+ */
+static int mmc_sd_alive(struct mmc_host *host)
+{
+       return mmc_send_status(host->card, NULL);
+}
+
+/*
  * Card detection callback from host.
  */
 static void mmc_sd_detect(struct mmc_host *host)
@@ -1057,7 +1065,7 @@ static void mmc_sd_detect(struct mmc_host *host)
         */
 #ifdef CONFIG_MMC_PARANOID_SD_INIT
        while(retries) {
-               err = mmc_send_status(host->card, NULL);
+               err = _mmc_detect_card_removed(host);
                if (err) {
                        retries--;
                        udelay(5);
@@ -1070,7 +1078,7 @@ static void mmc_sd_detect(struct mmc_host *host)
                       __func__, mmc_hostname(host), err);
        }
 #else
-       err = mmc_send_status(host->card, NULL);
+       err = _mmc_detect_card_removed(host);
 #endif
        mmc_release_host(host);
 
@@ -1158,6 +1166,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_sd_power_restore,
+       .alive = mmc_sd_alive,
 };
 
 static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
@@ -1166,6 +1175,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .suspend = mmc_sd_suspend,
        .resume = mmc_sd_resume,
        .power_restore = mmc_sd_power_restore,
+       .alive = mmc_sd_alive,
 };
 
 static void mmc_sd_attach_bus_ops(struct mmc_host *host)
index a2c1c4d..19f0143 100644 (file)
@@ -572,6 +572,14 @@ static void mmc_sdio_remove(struct mmc_host *host)
 }
 
 /*
+ * Card detection - card is alive.
+ */
+static int mmc_sdio_alive(struct mmc_host *host)
+{
+       return mmc_select_card(host->card);
+}
+
+/*
  * Card detection callback from host.
  */
 static void mmc_sdio_detect(struct mmc_host *host)
@@ -593,7 +601,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
        /*
         * Just check if our card has been removed.
         */
-       err = mmc_select_card(host->card);
+       err = _mmc_detect_card_removed(host);
 
        mmc_release_host(host);
 
@@ -771,6 +779,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
        .suspend = mmc_sdio_suspend,
        .resume = mmc_sdio_resume,
        .power_restore = mmc_sdio_power_restore,
+       .alive = mmc_sdio_alive,
 };
 
 
index 1568a9a..9ede2a7 100644 (file)
@@ -187,6 +187,8 @@ struct mmc_card {
 #define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
 #define MMC_STATE_NEED_BKOPS   (1<<7)          /* card need to do BKOPS */
 #define MMC_STATE_DOING_BKOPS  (1<<8)          /* card is doing BKOPS */
+#define MMC_CARD_REMOVED       (1<<9)          /* card has been removed */
+
        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 */
@@ -324,6 +326,8 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
 #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #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_need_bkops(c) ((c)->state & MMC_STATE_NEED_BKOPS)
 #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
 
@@ -334,6 +338,8 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
+
 #define mmc_card_set_need_bkops(c)     ((c)->state |= MMC_STATE_NEED_BKOPS)
 #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
 
index 86064a9..49f8705 100644 (file)
@@ -175,6 +175,8 @@ extern void mmc_release_host(struct mmc_host *host);
 extern void mmc_do_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);
 
+extern int mmc_detect_card_removed(struct mmc_host *host);
+
 /**
  *     mmc_claim_host - exclusively claim a host
  *     @host: mmc host to claim
index a4971fc..bcb7e39 100644 (file)
@@ -321,6 +321,8 @@ struct mmc_host {
        int                     claim_cnt;      /* "claim" nesting count */
 
        struct delayed_work     detect;
+       int                     detect_change;  /* card detect flag */
+
        struct wake_lock        detect_wake_lock;
 
        const struct mmc_bus_ops *bus_ops;      /* current bus driver */