]> Pileus Git - ~andy/linux/blobdiff - drivers/mmc/core/core.c
Merge remote-tracking branch 'spi/fix/setup' into spi-linus
[~andy/linux] / drivers / mmc / core / core.c
index c40396f23202d607a089f414a6afa224d16d0948..49a5bca418bdb7a6edf24669a9821851b9593aa9 100644 (file)
@@ -402,6 +402,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
                        context_info->is_done_rcv = false;
                        context_info->is_new_req = false;
                        cmd = mrq->cmd;
+
                        if (!cmd->error || !cmd->retries ||
                            mmc_card_removed(host->card)) {
                                err = host->areq->err_check(host->card,
@@ -436,6 +437,24 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
                wait_for_completion(&mrq->completion);
 
                cmd = mrq->cmd;
+
+               /*
+                * If host has timed out waiting for the sanitize
+                * to complete, card might be still in programming state
+                * so let's try to bring the card out of programming
+                * state.
+                */
+               if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
+                       if (!mmc_interrupt_hpi(host->card)) {
+                               pr_warning("%s: %s: Interrupted sanitize\n",
+                                          mmc_hostname(host), __func__);
+                               cmd->error = 0;
+                               break;
+                       } else {
+                               pr_err("%s: %s: Failed to interrupt sanitize\n",
+                                      mmc_hostname(host), __func__);
+                       }
+               }
                if (!cmd->error || !cmd->retries ||
                    mmc_card_removed(host->card))
                        break;
@@ -951,6 +970,29 @@ void mmc_release_host(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_release_host);
 
+/*
+ * This is a helper function, which fetches a runtime pm reference for the
+ * card device and also claims the host.
+ */
+void mmc_get_card(struct mmc_card *card)
+{
+       pm_runtime_get_sync(&card->dev);
+       mmc_claim_host(card->host);
+}
+EXPORT_SYMBOL(mmc_get_card);
+
+/*
+ * This is a helper function, which releases the host and drops the runtime
+ * pm reference for the card device.
+ */
+void mmc_put_card(struct mmc_card *card)
+{
+       mmc_release_host(card->host);
+       pm_runtime_mark_last_busy(&card->dev);
+       pm_runtime_put_autosuspend(&card->dev);
+}
+EXPORT_SYMBOL(mmc_put_card);
+
 /*
  * Internal function that does the actual ios call to the host driver,
  * optionally printing some debug output.
@@ -1459,7 +1501,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
  * If a host does all the power sequencing itself, ignore the
  * initial MMC_POWER_UP stage.
  */
-static void mmc_power_up(struct mmc_host *host)
+void mmc_power_up(struct mmc_host *host)
 {
        int bit;
 
@@ -2325,14 +2367,13 @@ int mmc_detect_card_removed(struct mmc_host *host)
         * The card will be considered unchanged unless we have been asked to
         * detect a change or host requires polling to provide card detection.
         */
-       if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
-           !(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
+       if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
                return ret;
 
        host->detect_change = 0;
        if (!ret) {
                ret = _mmc_detect_card_removed(host);
-               if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
+               if (ret && (host->caps & MMC_CAP_NEEDS_POLL)) {
                        /*
                         * Schedule a detect work as soon as possible to let a
                         * rescan handle the card removal.
@@ -2442,9 +2483,7 @@ void mmc_stop_host(struct mmc_host *host)
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
                /* Calling bus_ops->remove() with a claimed host can deadlock */
-               if (host->bus_ops->remove)
-                       host->bus_ops->remove(host);
-
+               host->bus_ops->remove(host);
                mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_power_off(host);
@@ -2509,52 +2548,6 @@ int mmc_power_restore_host(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_power_restore_host);
 
-int mmc_card_awake(struct mmc_host *host)
-{
-       int err = -ENOSYS;
-
-       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-               return 0;
-
-       mmc_bus_get(host);
-
-       if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
-               err = host->bus_ops->awake(host);
-
-       mmc_bus_put(host);
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_card_awake);
-
-int mmc_card_sleep(struct mmc_host *host)
-{
-       int err = -ENOSYS;
-
-       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-               return 0;
-
-       mmc_bus_get(host);
-
-       if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
-               err = host->bus_ops->sleep(host);
-
-       mmc_bus_put(host);
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_card_sleep);
-
-int mmc_card_can_sleep(struct mmc_host *host)
-{
-       struct mmc_card *card = host->card;
-
-       if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
-               return 1;
-       return 0;
-}
-EXPORT_SYMBOL(mmc_card_can_sleep);
-
 /*
  * Flush the cache to the non-volatile storage.
  */
@@ -2626,48 +2619,9 @@ EXPORT_SYMBOL(mmc_cache_ctrl);
  */
 int mmc_suspend_host(struct mmc_host *host)
 {
-       int err = 0;
-
-       cancel_delayed_work(&host->detect);
-       mmc_flush_scheduled_work();
-
-       mmc_bus_get(host);
-       if (host->bus_ops && !host->bus_dead) {
-               if (host->bus_ops->suspend) {
-                       if (mmc_card_doing_bkops(host->card)) {
-                               err = mmc_stop_bkops(host->card);
-                               if (err)
-                                       goto out;
-                       }
-                       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.  (Calling
-                        * bus_ops->remove() with a claimed host can
-                        * deadlock.)
-                        */
-                       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;
-               }
-       }
-       mmc_bus_put(host);
-
-       if (!err && !mmc_card_keep_power(host))
-               mmc_power_off(host);
-
-out:
-       return err;
+       /* This function is deprecated */
+       return 0;
 }
-
 EXPORT_SYMBOL(mmc_suspend_host);
 
 /**
@@ -2676,39 +2630,8 @@ EXPORT_SYMBOL(mmc_suspend_host);
  */
 int mmc_resume_host(struct mmc_host *host)
 {
-       int err = 0;
-
-       mmc_bus_get(host);
-       if (host->bus_ops && !host->bus_dead) {
-               if (!mmc_card_keep_power(host)) {
-                       mmc_power_up(host);
-                       mmc_select_voltage(host, host->ocr);
-                       /*
-                        * Tell runtime PM core we just powered up the card,
-                        * since it still believes the card is powered off.
-                        * Note that currently runtime PM is only enabled
-                        * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
-                        */
-                       if (mmc_card_sdio(host->card) &&
-                           (host->caps & MMC_CAP_POWER_OFF_CARD)) {
-                               pm_runtime_disable(&host->card->dev);
-                               pm_runtime_set_active(&host->card->dev);
-                               pm_runtime_enable(&host->card->dev);
-                       }
-               }
-               BUG_ON(!host->bus_ops->resume);
-               err = host->bus_ops->resume(host);
-               if (err) {
-                       pr_warning("%s: error %d during resume "
-                                           "(card was removed?)\n",
-                                           mmc_hostname(host), err);
-                       err = 0;
-               }
-       }
-       host->pm_flags &= ~MMC_PM_KEEP_POWER;
-       mmc_bus_put(host);
-
-       return err;
+       /* This function is deprecated */
+       return 0;
 }
 EXPORT_SYMBOL(mmc_resume_host);
 
@@ -2727,29 +2650,22 @@ int mmc_pm_notify(struct notifier_block *notify_block,
        switch (mode) {
        case PM_HIBERNATION_PREPARE:
        case PM_SUSPEND_PREPARE:
-               if (host->card && mmc_card_mmc(host->card) &&
-                   mmc_card_doing_bkops(host->card)) {
-                       err = mmc_stop_bkops(host->card);
-                       if (err) {
-                               pr_err("%s: didn't stop bkops\n",
-                                       mmc_hostname(host));
-                               return err;
-                       }
-                       mmc_card_clr_doing_bkops(host->card);
-               }
-
                spin_lock_irqsave(&host->lock, flags);
                host->rescan_disable = 1;
                spin_unlock_irqrestore(&host->lock, flags);
                cancel_delayed_work_sync(&host->detect);
 
-               if (!host->bus_ops || host->bus_ops->suspend)
+               if (!host->bus_ops)
                        break;
 
-               /* Calling bus_ops->remove() with a claimed host can deadlock */
-               if (host->bus_ops->remove)
-                       host->bus_ops->remove(host);
+               /* Validate prerequisites for suspend */
+               if (host->bus_ops->pre_suspend)
+                       err = host->bus_ops->pre_suspend(host);
+               if (!err && host->bus_ops->suspend)
+                       break;
 
+               /* Calling bus_ops->remove() with a claimed host can deadlock */
+               host->bus_ops->remove(host);
                mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_power_off(host);