mmc: core: abort rescan if suspend is triggered

There could be a race between suspend and mmc_rescan as follows:
At resume:
-> mmc_pm_notify
  -> mmc_rescan is scheduled

Suspend is triggered:
-> mmc_pm_notify
   -> wait for mmc_rescan/cancel it
      -> rescan acquires wakelock if card is detected
         so as to give user-space a chance to respond
-> PM framework cancels suspend since wakelock is active

Hence, release the wake-lock if its active in suspend prepare
and check for rescan_disable before acquiring wake-lock.
This prefers suspend over notifying the user-space of the status
of the card, which is fine since with suspend user-space is frozen
too.

CRs-fixed: 655281
Change-Id: I83783589f9b541d3af73931e9a7b0b144a25538e
Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
This commit is contained in:
Asutosh Das 2014-05-05 14:31:11 +05:30
parent 354e25a674
commit c865639f10
2 changed files with 23 additions and 9 deletions

View File

@ -3411,7 +3411,8 @@ void mmc_rescan(struct work_struct *work)
mmc_release_host(host);
mmc_rpm_release(host, &host->class_dev);
out:
if (extend_wakelock)
/* only extend the wakelock, if suspend has not started yet */
if (extend_wakelock && !host->rescan_disable)
wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
if (host->caps & MMC_CAP_NEEDS_POLL)
@ -3812,16 +3813,15 @@ int mmc_pm_notify(struct notifier_block *notify_block,
spin_unlock_irqrestore(&host->lock, flags);
break;
}
/* since its suspending anyway, disable rescan */
host->rescan_disable = 1;
spin_unlock_irqrestore(&host->lock, flags);
/* Wait for pending detect work to be completed */
if (!(host->caps & MMC_CAP_NEEDS_POLL))
flush_work(&host->detect.work);
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 1;
spin_unlock_irqrestore(&host->lock, flags);
/*
* In some cases, the detect work might be scheduled
* just before rescan_disable is set to true.
@ -3829,6 +3829,13 @@ int mmc_pm_notify(struct notifier_block *notify_block,
*/
cancel_delayed_work_sync(&host->detect);
/*
* It is possible that the wake-lock has been acquired, since
* its being suspended, release the wakelock
*/
if (wake_lock_active(&host->detect_wake_lock))
wake_unlock(&host->detect_wake_lock);
if (!host->bus_ops || host->bus_ops->suspend)
break;

View File

@ -1380,7 +1380,11 @@ int mmc_attach_sd(struct mmc_host *host)
*/
#ifdef CONFIG_MMC_PARANOID_SD_INIT
retries = 5;
while (retries) {
/*
* Some bad cards may take a long time to init, give preference to
* suspend in those cases.
*/
while (retries && !host->rescan_disable) {
err = mmc_sd_init_card(host, host->ocr, NULL);
if (err) {
retries--;
@ -1398,6 +1402,9 @@ int mmc_attach_sd(struct mmc_host *host)
mmc_hostname(host), err);
goto err;
}
if (host->rescan_disable)
goto err;
#else
err = mmc_sd_init_card(host, host->ocr, NULL);
if (err)
@ -1421,9 +1428,9 @@ remove_card:
mmc_claim_host(host);
err:
mmc_detach_bus(host);
pr_err("%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err);
if (err)
pr_err("%s: error %d whilst initialising SD card: rescan: %d\n",
mmc_hostname(host), err, host->rescan_disable);
return err;
}