| From 7f7e4129c23f0419257184dff6fec89d2d5a8964 Mon Sep 17 00:00:00 2001 |
| From: Ulf Hansson <ulf.hansson@stericsson.com> |
| Date: Wed, 21 Sep 2011 14:08:13 -0400 |
| Subject: mmc: core: Fix hangs related to insert/remove of cards |
| |
| From: Ulf Hansson <ulf.hansson@stericsson.com> |
| |
| 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 | 10 +++++----- |
| drivers/mmc/core/core.h | 1 + |
| drivers/mmc/core/mmc.c | 1 + |
| drivers/mmc/core/sd.c | 1 + |
| drivers/mmc/core/sdio.c | 1 + |
| 5 files changed, 9 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/mmc/core/core.c |
| +++ b/drivers/mmc/core/core.c |
| @@ -1151,7 +1151,7 @@ static void mmc_power_up(struct mmc_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); |
| |
| @@ -1241,8 +1241,7 @@ void mmc_attach_bus(struct mmc_host *hos |
| } |
| |
| /* |
| - * 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 +1258,6 @@ void mmc_detach_bus(struct mmc_host *hos |
| |
| spin_unlock_irqrestore(&host->lock, flags); |
| |
| - mmc_power_off(host); |
| - |
| mmc_bus_put(host); |
| } |
| |
| @@ -1845,6 +1842,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; |
| @@ -1974,6 +1972,7 @@ int mmc_suspend_host(struct mmc_host *ho |
| 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; |
| @@ -2061,6 +2060,7 @@ int mmc_pm_notify(struct notifier_block |
| host->bus_ops->remove(host); |
| |
| mmc_detach_bus(host); |
| + mmc_power_off(host); |
| mmc_release_host(host); |
| host->pm_flags = 0; |
| break; |
| --- a/drivers/mmc/core/core.h |
| +++ b/drivers/mmc/core/core.h |
| @@ -43,6 +43,7 @@ int mmc_set_signal_voltage(struct mmc_ho |
| 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) |
| { |
| --- a/drivers/mmc/core/mmc.c |
| +++ b/drivers/mmc/core/mmc.c |
| @@ -891,6 +891,7 @@ static void mmc_detect(struct mmc_host * |
| |
| mmc_claim_host(host); |
| mmc_detach_bus(host); |
| + mmc_power_off(host); |
| mmc_release_host(host); |
| } |
| } |
| --- a/drivers/mmc/core/sd.c |
| +++ b/drivers/mmc/core/sd.c |
| @@ -1043,6 +1043,7 @@ static void mmc_sd_detect(struct mmc_hos |
| |
| mmc_claim_host(host); |
| mmc_detach_bus(host); |
| + mmc_power_off(host); |
| mmc_release_host(host); |
| } |
| } |
| --- a/drivers/mmc/core/sdio.c |
| +++ b/drivers/mmc/core/sdio.c |
| @@ -597,6 +597,7 @@ out: |
| |
| mmc_claim_host(host); |
| mmc_detach_bus(host); |
| + mmc_power_off(host); |
| mmc_release_host(host); |
| } |
| } |