mmc: core: Prevent too long response times for suspend
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / core / core.c
index fe65bb377e258c66946f9f9c6ef0f218d66abe72..5278ffb20e74bbba9b5508e008171165ad296f16 100644 (file)
@@ -2294,21 +2294,33 @@ int mmc_suspend_host(struct mmc_host *host)
 
        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_power_off(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)
+                               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_power_off(host);
+                               mmc_release_host(host);
+                               host->pm_flags = 0;
+                               err = 0;
+                       }
+                       mmc_do_release_host(host);
+               } else {
+                       err = -EBUSY;
                }
        }
        mmc_bus_put(host);