mmc: host: Fix soft lockup issue
Pavan Kunapuli [Tue, 27 Aug 2013 16:34:21 +0000 (21:34 +0530)]
This patch fixes the soft lockup that could occur as a result of commit
8c226304. The mutex_unlock call from interrupt context could cause a
deadlock.

This patch partially reverts the commit 8c226304 by removing the mutex
lock/unlock calls before and after data transfers. mutex locks in
tuning implementation are still present.

This patch ensures that data transfers on all controllers triggered
while running tuning will be stopped until tuning is done inorder to
avoid the risk of any failures due to core voltage changes in tuning.

Locking needs to be extended for the transfer that is already in progress.
This will be done in subsequent patches after thorough testing.

Bug 1354967

Change-Id: Ic6bfd22ec84f24e8782d7da6e3267a7300cb267e
Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com>
Reviewed-on: http://git-master/r/266802
Reviewed-by: Mrutyunjay Sawant <msawant@nvidia.com>
Tested-by: Mrutyunjay Sawant <msawant@nvidia.com>

drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c

index 6c51a94..a79de81 100644 (file)
@@ -2392,20 +2392,13 @@ static void tegra_sdhci_post_resume(struct sdhci_host *sdhci)
 /*
  * For tegra specific tuning, core voltage has to be fixed at different
  * voltages to get the tap values. Fixing the core voltage during tuning for one
- * device might affect transfers of other SDMMC devices. To handle this, lock
- * tuning_mutex to prevent any transfers during tuning execution. This is not
- * required once tuning is done.
+ * device might affect transfers of other SDMMC devices. Check if tuning mutex
+ * is locked before starting a data transfer.
  */
 static void tegra_sdhci_get_bus(struct sdhci_host *sdhci)
 {
-       if (boot_volt_req_refcount)
-               mutex_lock(&tuning_mutex);
-}
-
-static void tegra_sdhci_release_bus(struct sdhci_host *sdhci)
-{
-       if (boot_volt_req_refcount)
-               mutex_unlock(&tuning_mutex);
+       while (mutex_is_locked(&tuning_mutex))
+               ;
 }
 
 static int show_polling_period(void *data, u64 *value)
@@ -2655,7 +2648,6 @@ static struct sdhci_ops tegra_sdhci_ops = {
        .platform_resume        = tegra_sdhci_post_resume,
        .platform_reset_exit    = tegra_sdhci_reset_exit,
        .platform_get_bus       = tegra_sdhci_get_bus,
-       .platform_release_bus   = tegra_sdhci_release_bus,
        .set_uhs_signaling      = tegra_sdhci_set_uhs_signaling,
        .switch_signal_voltage  = tegra_sdhci_signal_voltage_switch,
        .switch_signal_voltage_exit = tegra_sdhci_do_calibration,
index e84fafb..27d06a7 100644 (file)
@@ -1342,10 +1342,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                }
 
                /* For a data cmd, check for plat specific preparation */
-               spin_unlock_irqrestore(&host->lock, flags);
                if (mrq->data)
                        host->ops->platform_get_bus(host);
-               spin_lock_irqsave(&host->lock, flags);
 
                if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
                        sdhci_send_command(host, mrq->sbc);
@@ -2387,8 +2385,6 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                sdhci_dumpregs(host);
 
                return;
-       } else {
-               host->ops->platform_release_bus(host);
        }
 
        if (intmask & SDHCI_INT_DATA_TIMEOUT) {