| From foo@baz Thu Mar 22 14:57:33 CET 2018 |
| From: Daniel Drake <drake@endlessm.com> |
| Date: Tue, 12 Dec 2017 10:49:02 +0000 |
| Subject: mmc: avoid removing non-removable hosts during suspend |
| |
| From: Daniel Drake <drake@endlessm.com> |
| |
| |
| [ Upstream commit de8dcc3d2c0e08e5068ee1e26fc46415c15e3637 ] |
| |
| The Weibu F3C MiniPC has an onboard AP6255 module, presenting |
| two SDIO functions on a single MMC host (Bluetooth/btsdio and |
| WiFi/brcmfmac), and the mmc layer correctly detects this as |
| non-removable. |
| |
| After suspend/resume, the wifi and bluetooth interfaces disappear |
| and do not get probed again. |
| |
| The conditions here are: |
| |
| 1. During suspend, we reach mmc_pm_notify() |
| |
| 2. mmc_pm_notify() calls mmc_sdio_pre_suspend() to see if we can |
| suspend the SDIO host. However, mmc_sdio_pre_suspend() returns |
| -ENOSYS because btsdio_driver does not have a suspend method. |
| |
| 3. mmc_pm_notify() proceeds to remove the card |
| |
| 4. Upon resume, mmc_rescan() does nothing with this host, because of |
| the rescan_entered check which aims to only scan a non-removable |
| device a single time (i.e. during boot). |
| |
| Fix the loss of functionality by detecting that we are unable to |
| suspend a non-removable host, so avoid the forced removal in that |
| case. The comment above this function already indicates that this |
| code was only intended for removable devices. |
| |
| Signed-off-by: Daniel Drake <drake@endlessm.com> |
| Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/mmc/core/core.c | 8 ++++++++ |
| 1 file changed, 8 insertions(+) |
| |
| --- a/drivers/mmc/core/core.c |
| +++ b/drivers/mmc/core/core.c |
| @@ -2791,6 +2791,14 @@ int mmc_pm_notify(struct notifier_block |
| if (!err) |
| break; |
| |
| + if (!mmc_card_is_removable(host)) { |
| + dev_warn(mmc_dev(host), |
| + "pre_suspend failed for non-removable host: " |
| + "%d\n", err); |
| + /* Avoid removing non-removable hosts */ |
| + break; |
| + } |
| + |
| /* Calling bus_ops->remove() with a claimed host can deadlock */ |
| host->bus_ops->remove(host); |
| mmc_claim_host(host); |