mmc: sdhost: fix scheduling while atomic 57/93657/3
authorSergei Rogachev <s.rogachev@samsung.com>
Fri, 21 Oct 2016 13:24:15 +0000 (16:24 +0300)
committerInki Dae <inki.dae@samsung.com>
Thu, 8 Dec 2016 06:46:46 +0000 (22:46 -0800)
The function mmc_regulator_set_ocr() cannot be called under the spinlock,
because internally it calls regulator_disable() which uses a sleeping primitive:
regulator_dev->mutex.

The patch unlocks the spinlock sdhost_host->lock to avoid scheduling in atomic
context and prevent possible consequent live-locks.

It is done totally the same way as it is done in drivers/mmc/host/sdhci.c and
many other places.

Change-Id: I2a7b893124efb2a515a3d55706d9a292a3d27edd
Signed-off-by: Sergei Rogachev <s.rogachev@samsung.com>
drivers/mmc/host/sdhost.c

index ce1feb0..4572d27 100755 (executable)
@@ -740,7 +740,9 @@ STATIC_FUNC void sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        if (MMC_POWER_OFF == ios->power_mode) {
                                _signalVoltageOnOff(host, 0);
                                if (host->SD_pwr) {
+                                       spin_unlock_irqrestore(&host->lock, flags);
                                        mmc_regulator_set_ocr(host->mmc, host->SD_pwr, 0);
+                                       spin_lock_irqsave(&host->lock, flags);
                                }
                                _resetIOS(host);
                                host->ios.power_mode = ios->power_mode;
@@ -748,7 +750,9 @@ STATIC_FUNC void sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                                   || (MMC_POWER_UP == ios->power_mode)
                            ) {
                                if (host->SD_pwr) {
+                                       spin_unlock_irqrestore(&host->lock, flags);
                                        mmc_regulator_set_ocr(host->mmc, host->SD_pwr, ios->vdd);
+                                       spin_lock_irqsave(&host->lock, flags);
                                }
                                _signalVoltageOnOff(host, 1);
                                host->ios.power_mode = ios->power_mode;
@@ -761,7 +765,9 @@ STATIC_FUNC void sdhost_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (ios->vdd != host->ios.vdd) {
                        if (host->SD_pwr) {
                                printk("sdhost %s 3.0 %d!\n", host->deviceName, ios->vdd);
+                               spin_unlock_irqrestore(&host->lock, flags);
                                mmc_regulator_set_ocr(host->mmc, host->SD_pwr, ios->vdd);
+                               spin_lock_irqsave(&host->lock, flags);
                        }
                        host->ios.vdd = ios->vdd;
                }