mmc: fixes for eMMC v4.5 discard operation
[pandora-kernel.git] / drivers / mmc / core / core.c
index b27b940..c420a9e 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/suspend.h>
+#include <linux/fault-inject.h>
+#include <linux/random.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -83,6 +85,43 @@ static void mmc_flush_scheduled_work(void)
        flush_workqueue(workqueue);
 }
 
+#ifdef CONFIG_FAIL_MMC_REQUEST
+
+/*
+ * Internal function. Inject random data errors.
+ * If mmc_data is NULL no errors are injected.
+ */
+static void mmc_should_fail_request(struct mmc_host *host,
+                                   struct mmc_request *mrq)
+{
+       struct mmc_command *cmd = mrq->cmd;
+       struct mmc_data *data = mrq->data;
+       static const int data_errors[] = {
+               -ETIMEDOUT,
+               -EILSEQ,
+               -EIO,
+       };
+
+       if (!data)
+               return;
+
+       if (cmd->error || data->error ||
+           !should_fail(&host->fail_mmc_request, data->blksz * data->blocks))
+               return;
+
+       data->error = data_errors[random32() % ARRAY_SIZE(data_errors)];
+       data->bytes_xfered = (random32() % (data->bytes_xfered >> 9)) << 9;
+}
+
+#else /* CONFIG_FAIL_MMC_REQUEST */
+
+static inline void mmc_should_fail_request(struct mmc_host *host,
+                                          struct mmc_request *mrq)
+{
+}
+
+#endif /* CONFIG_FAIL_MMC_REQUEST */
+
 /**
  *     mmc_request_done - finish processing an MMC request
  *     @host: MMC host which completed request
@@ -102,13 +141,15 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
        }
 
        if (err && cmd->retries) {
-               pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
-                       mmc_hostname(host), cmd->opcode, err);
-
-               cmd->retries--;
-               cmd->error = 0;
-               host->ops->request(host, mrq);
+               /*
+                * Request starter must handle retries - see
+                * mmc_wait_for_req_done().
+                */
+               if (mrq->done)
+                       mrq->done(mrq);
        } else {
+               mmc_should_fail_request(host, mrq);
+
                led_trigger_event(host->led, LED_OFF);
 
                pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
@@ -212,7 +253,21 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 static void mmc_wait_for_req_done(struct mmc_host *host,
                                  struct mmc_request *mrq)
 {
-       wait_for_completion(&mrq->completion);
+       struct mmc_command *cmd;
+
+       while (1) {
+               wait_for_completion(&mrq->completion);
+
+               cmd = mrq->cmd;
+               if (!cmd->error || !cmd->retries)
+                       break;
+
+               pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+                        mmc_hostname(host), cmd->opcode, cmd->error);
+               cmd->retries--;
+               cmd->error = 0;
+               host->ops->request(host, mrq);
+       }
 }
 
 /**
@@ -279,8 +334,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
                mmc_wait_for_req_done(host, host->areq->mrq);
                err = host->areq->err_check(host->card, host->areq);
                if (err) {
+                       /* post process the completed failed request */
                        mmc_post_req(host, host->areq->mrq, 0);
                        if (areq)
+                               /*
+                                * Cancel the new prepared request, because
+                                * it can't run until the failed
+                                * request has been properly handled.
+                                */
                                mmc_post_req(host, areq->mrq, -EINVAL);
 
                        host->areq = NULL;
@@ -318,6 +379,63 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 }
 EXPORT_SYMBOL(mmc_wait_for_req);
 
+/**
+ *     mmc_interrupt_hpi - Issue for High priority Interrupt
+ *     @card: the MMC card associated with the HPI transfer
+ *
+ *     Issued High Priority Interrupt, and check for card status
+ *     util out-of prg-state.
+ */
+int mmc_interrupt_hpi(struct mmc_card *card)
+{
+       int err;
+       u32 status;
+
+       BUG_ON(!card);
+
+       if (!card->ext_csd.hpi_en) {
+               pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
+               return 1;
+       }
+
+       mmc_claim_host(card->host);
+       err = mmc_send_status(card, &status);
+       if (err) {
+               pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
+               goto out;
+       }
+
+       /*
+        * If the card status is in PRG-state, we can send the HPI command.
+        */
+       if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
+               do {
+                       /*
+                        * We don't know when the HPI command will finish
+                        * processing, so we need to resend HPI until out
+                        * of prg-state, and keep checking the card status
+                        * with SEND_STATUS.  If a timeout error occurs when
+                        * sending the HPI command, we are already out of
+                        * prg-state.
+                        */
+                       err = mmc_send_hpi_cmd(card, &status);
+                       if (err)
+                               pr_debug("%s: abort HPI (%d error)\n",
+                                        mmc_hostname(card->host), err);
+
+                       err = mmc_send_status(card, &status);
+                       if (err)
+                               break;
+               } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
+       } else
+               pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
+
+out:
+       mmc_release_host(card->host);
+       return err;
+}
+EXPORT_SYMBOL(mmc_interrupt_hpi);
+
 /**
  *     mmc_wait_for_cmd - start a command and wait for completion
  *     @host: MMC host to start command
@@ -330,7 +448,7 @@ EXPORT_SYMBOL(mmc_wait_for_req);
  */
 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
 {
-       struct mmc_request mrq = {0};
+       struct mmc_request mrq = {NULL};
 
        WARN_ON(!host->claimed);
 
@@ -411,6 +529,18 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
                        data->timeout_clks = 0;
                }
        }
+
+       /*
+        * Some cards require longer data read timeout than indicated in CSD.
+        * Address this by setting the read timeout to a "reasonably high"
+        * value. For the cards tested, 300ms has proven enough. If necessary,
+        * this value can be increased if other problematic cards require this.
+        */
+       if (mmc_card_long_read_time(card) && data->flags & MMC_DATA_READ) {
+               data->timeout_ns = 300000000;
+               data->timeout_clks = 0;
+       }
+
        /*
         * Some cards need very high timeouts if driven in SPI mode.
         * The worst observed timeout was 900ms after writing a
@@ -1095,6 +1225,46 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
        mmc_host_clk_release(host);
 }
 
+static void mmc_poweroff_notify(struct mmc_host *host)
+{
+       struct mmc_card *card;
+       unsigned int timeout;
+       unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
+       int err = 0;
+
+       card = host->card;
+
+       /*
+        * Send power notify command only if card
+        * is mmc and notify state is powered ON
+        */
+       if (card && mmc_card_mmc(card) &&
+           (card->poweroff_notify_state == MMC_POWERED_ON)) {
+
+               if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
+                       notify_type = EXT_CSD_POWER_OFF_SHORT;
+                       timeout = card->ext_csd.generic_cmd6_time;
+                       card->poweroff_notify_state = MMC_POWEROFF_SHORT;
+               } else {
+                       notify_type = EXT_CSD_POWER_OFF_LONG;
+                       timeout = card->ext_csd.power_off_longtime;
+                       card->poweroff_notify_state = MMC_POWEROFF_LONG;
+               }
+
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_POWER_OFF_NOTIFICATION,
+                                notify_type, timeout);
+
+               if (err && err != -EBADMSG)
+                       pr_err("Device failed to respond within %d poweroff "
+                              "time. Forcefully powering down the device\n",
+                              timeout);
+
+               /* Set the card state to no notification after the poweroff */
+               card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
+       }
+}
+
 /*
  * Apply power to the MMC stack.  This is a two-stage process.
  * First, we enable power to the card without the clock running.
@@ -1119,13 +1289,11 @@ static void mmc_power_up(struct mmc_host *host)
                bit = fls(host->ocr_avail) - 1;
 
        host->ios.vdd = bit;
-       if (mmc_host_is_spi(host)) {
+       if (mmc_host_is_spi(host))
                host->ios.chip_select = MMC_CS_HIGH;
-               host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
-       } else {
+       else
                host->ios.chip_select = MMC_CS_DONTCARE;
-               host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-       }
+       host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
        host->ios.power_mode = MMC_POWER_UP;
        host->ios.bus_width = MMC_BUS_WIDTH_1;
        host->ios.timing = MMC_TIMING_LEGACY;
@@ -1151,13 +1319,15 @@ static void mmc_power_up(struct mmc_host *host)
        mmc_host_clk_release(host);
 }
 
-static void mmc_power_off(struct mmc_host *host)
+void mmc_power_off(struct mmc_host *host)
 {
        mmc_host_clk_hold(host);
 
        host->ios.clock = 0;
        host->ios.vdd = 0;
 
+       mmc_poweroff_notify(host);
+
        /*
         * Reset ocr mask to be the highest possible voltage supported for
         * this mmc host. This value will be used at next power up.
@@ -1173,6 +1343,13 @@ static void mmc_power_off(struct mmc_host *host)
        host->ios.timing = MMC_TIMING_LEGACY;
        mmc_set_ios(host);
 
+       /*
+        * Some configurations, such as the 802.11 SDIO card in the OLPC
+        * XO-1.5, require a short delay after poweroff before the card
+        * can be successfully turned on again.
+        */
+       mmc_delay(1);
+
        mmc_host_clk_release(host);
 }
 
@@ -1241,8 +1418,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
 }
 
 /*
- * Remove the current bus handler from a host. Assumes that there are
- * no interesting cards left, so the bus is powered down.
+ * Remove the current bus handler from a host.
  */
 void mmc_detach_bus(struct mmc_host *host)
 {
@@ -1259,8 +1435,6 @@ void mmc_detach_bus(struct mmc_host *host)
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       mmc_power_off(host);
-
        mmc_bus_put(host);
 }
 
@@ -1342,7 +1516,10 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
 {
        unsigned int erase_timeout;
 
-       if (card->ext_csd.erase_group_def & 1) {
+       if (arg == MMC_DISCARD_ARG ||
+           (arg == MMC_TRIM_ARG && card->ext_csd.rev >= 6)) {
+               erase_timeout = card->ext_csd.trim_timeout;
+       } else if (card->ext_csd.erase_group_def & 1) {
                /* High Capacity Erase Group Size uses HC timeouts */
                if (arg == MMC_TRIM_ARG)
                        erase_timeout = card->ext_csd.trim_timeout;
@@ -1478,9 +1655,9 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
-               printk(KERN_ERR "mmc_erase: group start error %d, "
+               pr_err("mmc_erase: group start error %d, "
                       "status %#x\n", err, cmd.resp[0]);
-               err = -EINVAL;
+               err = -EIO;
                goto out;
        }
 
@@ -1493,9 +1670,9 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
-               printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n",
+               pr_err("mmc_erase: group end error %d, status %#x\n",
                       err, cmd.resp[0]);
-               err = -EINVAL;
+               err = -EIO;
                goto out;
        }
 
@@ -1506,7 +1683,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
-               printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n",
+               pr_err("mmc_erase: erase error %d, status %#x\n",
                       err, cmd.resp[0]);
                err = -EIO;
                goto out;
@@ -1523,7 +1700,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                /* Do not retry else we can't see errors */
                err = mmc_wait_for_cmd(card->host, &cmd, 0);
                if (err || (cmd.resp[0] & 0xFDF92000)) {
-                       printk(KERN_ERR "error %d requesting status %#x\n",
+                       pr_err("error %d requesting status %#x\n",
                                err, cmd.resp[0]);
                        err = -EIO;
                        goto out;
@@ -1618,6 +1795,26 @@ int mmc_can_trim(struct mmc_card *card)
 }
 EXPORT_SYMBOL(mmc_can_trim);
 
+int mmc_can_discard(struct mmc_card *card)
+{
+       /*
+        * As there's no way to detect the discard support bit at v4.5
+        * use the s/w feature support filed.
+        */
+       if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE)
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(mmc_can_discard);
+
+int mmc_can_sanitize(struct mmc_card *card)
+{
+       if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(mmc_can_sanitize);
+
 int mmc_can_secure_erase_trim(struct mmc_card *card)
 {
        if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)
@@ -1727,6 +1924,94 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 }
 EXPORT_SYMBOL(mmc_set_blocklen);
 
+static void mmc_hw_reset_for_init(struct mmc_host *host)
+{
+       if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+               return;
+       mmc_host_clk_hold(host);
+       host->ops->hw_reset(host);
+       mmc_host_clk_release(host);
+}
+
+int mmc_can_reset(struct mmc_card *card)
+{
+       u8 rst_n_function;
+
+       if (!mmc_card_mmc(card))
+               return 0;
+       rst_n_function = card->ext_csd.rst_n_function;
+       if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
+               return 0;
+       return 1;
+}
+EXPORT_SYMBOL(mmc_can_reset);
+
+static int mmc_do_hw_reset(struct mmc_host *host, int check)
+{
+       struct mmc_card *card = host->card;
+
+       if (!host->bus_ops->power_restore)
+               return -EOPNOTSUPP;
+
+       if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+               return -EOPNOTSUPP;
+
+       if (!card)
+               return -EINVAL;
+
+       if (!mmc_can_reset(card))
+               return -EOPNOTSUPP;
+
+       mmc_host_clk_hold(host);
+       mmc_set_clock(host, host->f_init);
+
+       host->ops->hw_reset(host);
+
+       /* If the reset has happened, then a status command will fail */
+       if (check) {
+               struct mmc_command cmd = {0};
+               int err;
+
+               cmd.opcode = MMC_SEND_STATUS;
+               if (!mmc_host_is_spi(card->host))
+                       cmd.arg = card->rca << 16;
+               cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
+               err = mmc_wait_for_cmd(card->host, &cmd, 0);
+               if (!err) {
+                       mmc_host_clk_release(host);
+                       return -ENOSYS;
+               }
+       }
+
+       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
+       if (mmc_host_is_spi(host)) {
+               host->ios.chip_select = MMC_CS_HIGH;
+               host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+       } else {
+               host->ios.chip_select = MMC_CS_DONTCARE;
+               host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+       }
+       host->ios.bus_width = MMC_BUS_WIDTH_1;
+       host->ios.timing = MMC_TIMING_LEGACY;
+       mmc_set_ios(host);
+
+       mmc_host_clk_release(host);
+
+       return host->bus_ops->power_restore(host);
+}
+
+int mmc_hw_reset(struct mmc_host *host)
+{
+       return mmc_do_hw_reset(host, 0);
+}
+EXPORT_SYMBOL(mmc_hw_reset);
+
+int mmc_hw_reset_check(struct mmc_host *host)
+{
+       return mmc_do_hw_reset(host, 1);
+}
+EXPORT_SYMBOL(mmc_hw_reset_check);
+
 static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 {
        host->f_init = freq;
@@ -1737,6 +2022,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 #endif
        mmc_power_up(host);
 
+       /*
+        * Some eMMCs (with VCCQ always on) may not be reset after power up, so
+        * do a hardware reset if possible.
+        */
+       mmc_hw_reset_for_init(host);
+
        /*
         * sdio_reset sends CMD52 to reset card.  Since we do not know
         * if the card is being re-initialized, just send it.  CMD52
@@ -1845,6 +2136,7 @@ void mmc_stop_host(struct mmc_host *host)
 
                mmc_claim_host(host);
                mmc_detach_bus(host);
+               mmc_power_off(host);
                mmc_release_host(host);
                mmc_bus_put(host);
                return;
@@ -1927,7 +2219,7 @@ int mmc_card_sleep(struct mmc_host *host)
 
        mmc_bus_get(host);
 
-       if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
+       if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
                err = host->bus_ops->sleep(host);
 
        mmc_bus_put(host);
@@ -1946,6 +2238,65 @@ int mmc_card_can_sleep(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_card_can_sleep);
 
+/*
+ * Flush the cache to the non-volatile storage.
+ */
+int mmc_flush_cache(struct mmc_card *card)
+{
+       struct mmc_host *host = card->host;
+       int err = 0;
+
+       if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
+               return err;
+
+       if (mmc_card_mmc(card) &&
+                       (card->ext_csd.cache_size > 0) &&
+                       (card->ext_csd.cache_ctrl & 1)) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_FLUSH_CACHE, 1, 0);
+               if (err)
+                       pr_err("%s: cache flush error %d\n",
+                                       mmc_hostname(card->host), err);
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(mmc_flush_cache);
+
+/*
+ * Turn the cache ON/OFF.
+ * Turning the cache OFF shall trigger flushing of the data
+ * to the non-volatile storage.
+ */
+int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
+{
+       struct mmc_card *card = host->card;
+       int err = 0;
+
+       if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
+                       mmc_card_is_removable(host))
+               return err;
+
+       if (card && mmc_card_mmc(card) &&
+                       (card->ext_csd.cache_size > 0)) {
+               enable = !!enable;
+
+               if (card->ext_csd.cache_ctrl ^ enable)
+                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                       EXT_CSD_CACHE_CTRL, enable, 0);
+               if (err)
+                       pr_err("%s: cache %s error %d\n",
+                                       mmc_hostname(card->host),
+                                       enable ? "on" : "off",
+                                       err);
+               else
+                       card->ext_csd.cache_ctrl = enable;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(mmc_cache_ctrl);
+
 #ifdef CONFIG_PM
 
 /**
@@ -1960,23 +2311,47 @@ int mmc_suspend_host(struct mmc_host *host)
                cancel_delayed_work(&host->disable);
        cancel_delayed_work(&host->detect);
        mmc_flush_scheduled_work();
+       err = mmc_cache_ctrl(host, 0);
+       if (err)
+               goto out;
 
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
-               if (host->bus_ops->suspend)
-                       err = host->bus_ops->suspend(host);
-               if (err == -ENOSYS || !host->bus_ops->resume) {
-                       /*
-                        * We simply "remove" the card in this case.
-                        * It will be redetected on resume.
-                        */
-                       if (host->bus_ops->remove)
-                               host->bus_ops->remove(host);
-                       mmc_claim_host(host);
-                       mmc_detach_bus(host);
-                       mmc_release_host(host);
-                       host->pm_flags = 0;
-                       err = 0;
+
+               /*
+                * A long response time is not acceptable for device drivers
+                * when doing suspend. Prevent mmc_claim_host in the suspend
+                * sequence, to potentially wait "forever" by trying to
+                * pre-claim the host.
+                */
+               if (mmc_try_claim_host(host)) {
+                       if (host->bus_ops->suspend) {
+                               /*
+                                * For eMMC 4.5 device send notify command
+                                * before sleep, because in sleep state eMMC 4.5
+                                * devices respond to only RESET and AWAKE cmd
+                                */
+                               mmc_poweroff_notify(host);
+                               err = host->bus_ops->suspend(host);
+                       }
+                       mmc_do_release_host(host);
+
+                       if (err == -ENOSYS || !host->bus_ops->resume) {
+                               /*
+                                * We simply "remove" the card in this case.
+                                * It will be redetected on resume.
+                                */
+                               if (host->bus_ops->remove)
+                                       host->bus_ops->remove(host);
+                               mmc_claim_host(host);
+                               mmc_detach_bus(host);
+                               mmc_power_off(host);
+                               mmc_release_host(host);
+                               host->pm_flags = 0;
+                               err = 0;
+                       }
+               } else {
+                       err = -EBUSY;
                }
        }
        mmc_bus_put(host);
@@ -1984,6 +2359,7 @@ int mmc_suspend_host(struct mmc_host *host)
        if (!err && !mmc_card_keep_power(host))
                mmc_power_off(host);
 
+out:
        return err;
 }
 
@@ -2018,7 +2394,7 @@ int mmc_resume_host(struct mmc_host *host)
                BUG_ON(!host->bus_ops->resume);
                err = host->bus_ops->resume(host);
                if (err) {
-                       printk(KERN_WARNING "%s: error %d during resume "
+                       pr_warning("%s: error %d during resume "
                                            "(card was removed?)\n",
                                            mmc_hostname(host), err);
                        err = 0;
@@ -2049,6 +2425,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
 
                spin_lock_irqsave(&host->lock, flags);
                host->rescan_disable = 1;
+               host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
                spin_unlock_irqrestore(&host->lock, flags);
                cancel_delayed_work_sync(&host->detect);
 
@@ -2061,6 +2438,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
                        host->bus_ops->remove(host);
 
                mmc_detach_bus(host);
+               mmc_power_off(host);
                mmc_release_host(host);
                host->pm_flags = 0;
                break;
@@ -2071,6 +2449,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
 
                spin_lock_irqsave(&host->lock, flags);
                host->rescan_disable = 0;
+               host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
                spin_unlock_irqrestore(&host->lock, flags);
                mmc_detect_change(host, 0);