]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
mmc: core: Fix hangs related to insert/remove of cards
authorUlf Hansson <ulf.hansson@stericsson.com>
Wed, 21 Sep 2011 18:08:13 +0000 (14:08 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 11 Nov 2011 17:35:22 +0000 (09:35 -0800)
commit 7f7e4129c23f0419257184dff6fec89d2d5a8964 upstream.

During a rescan operation mmc_attach(sd|mmc|sdio) functions are
called. The error handling in these function can trigger a detach
of the bus, which also meant a power off. This is not notified by
the rescan operation which then continues to the next attach function.

If a power off has been done, the framework must never send any
new commands to the host driver, without first doing a new power up.
This will most likely trigger any host driver to hang.

Moving power off out of detach and instead handle power off
separately when it is actually needed, solves the issue.

Signed-off-by: Ulf Hansson <ulf.hansson@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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

index 38089b25c5765b0b55af93ea65c5a8b9df896d9c..75db30e6dcfa419701e9ba64aea3b80a1edd0183 100644 (file)
@@ -1057,7 +1057,7 @@ 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);
 
@@ -1147,8 +1147,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)
 {
@@ -1165,8 +1164,6 @@ void mmc_detach_bus(struct mmc_host *host)
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       mmc_power_off(host);
-
        mmc_bus_put(host);
 }
 
@@ -1675,6 +1672,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;
@@ -1796,6 +1794,7 @@ int mmc_suspend_host(struct mmc_host *host)
                                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;
@@ -1883,6 +1882,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;
index d9411ed2a39bf6490a5a788629d45a628e14e6fe..14664f1fb16fb560c526dd30817cc10ae6db1adf 100644 (file)
@@ -43,6 +43,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
                           bool cmd11);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
+void mmc_power_off(struct mmc_host *host);
 
 static inline void mmc_delay(unsigned int ms)
 {
index aa7d1d79b8c554c143c004db5e3ef9565ca653dd..6f5ee84ec716156910fd3be4b412a1af952df13a 100644 (file)
@@ -891,6 +891,7 @@ static void mmc_detect(struct mmc_host *host)
 
                mmc_claim_host(host);
                mmc_detach_bus(host);
+               mmc_power_off(host);
                mmc_release_host(host);
        }
 }
index ff2774128aa93b1231538b1f5e014b0df987e7ca..bd8805c9e8af08954ed0f138a00c574d8fd67c3a 100644 (file)
@@ -1008,6 +1008,7 @@ static void mmc_sd_detect(struct mmc_host *host)
 
                mmc_claim_host(host);
                mmc_detach_bus(host);
+               mmc_power_off(host);
                mmc_release_host(host);
        }
 }
index 262fff0191779301232fefba02bc8c916e026b33..ac492ac974e16458bec3dfce48cc858357b8dbea 100644 (file)
@@ -597,6 +597,7 @@ out:
 
                mmc_claim_host(host);
                mmc_detach_bus(host);
+               mmc_power_off(host);
                mmc_release_host(host);
        }
 }