summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Drozdov <denys.drozdov@toradex.com>2021-07-15 13:56:30 +0300
committerDenys Drozdov <denys.drozdov@toradex.com>2021-07-15 13:56:30 +0300
commita9729c9288e7f599d96b298d24fe038eb44bd4eb (patch)
tree85ee26335ce85a05dcb5906b8e8e879ea0562a5e
parent7e70ac3f06a59f9ef58810675082da53e9d9dc3c (diff)
parent909767eaf44d67f51a0eba5dc9260ca43851363c (diff)
Merge branch '5.4-2.3.x-imx' of https://github.com/Freescale/linux-fslc into 5.4-2.3.x-imx
-rw-r--r--drivers/mmc/core/core.c74
-rw-r--r--drivers/mmc/core/core.h8
-rw-r--r--drivers/mmc/core/host.c44
-rw-r--r--drivers/mmc/core/sdio.c28
-rw-r--r--include/linux/mmc/host.h3
5 files changed, 59 insertions, 98 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 833b6eecc426..986fc225f19a 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2394,80 +2394,6 @@ void mmc_stop_host(struct mmc_host *host)
mmc_release_host(host);
}
-#ifdef CONFIG_PM_SLEEP
-/* Do the card removal on suspend if card is assumed removeable
- * Do that in pm notifier while userspace isn't yet frozen, so we will be able
- to sync the card.
-*/
-static int mmc_pm_notify(struct notifier_block *notify_block,
- unsigned long mode, void *unused)
-{
- struct mmc_host *host = container_of(
- notify_block, struct mmc_host, pm_notify);
- unsigned long flags;
- int err = 0;
-
- switch (mode) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- case PM_RESTORE_PREPARE:
- spin_lock_irqsave(&host->lock, flags);
- host->rescan_disable = 1;
- spin_unlock_irqrestore(&host->lock, flags);
- cancel_delayed_work_sync(&host->detect);
-
- if (!host->bus_ops)
- break;
-
- /* Validate prerequisites for suspend */
- if (host->bus_ops->pre_suspend)
- err = host->bus_ops->pre_suspend(host);
- 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);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- host->pm_flags = 0;
- break;
-
- case PM_POST_SUSPEND:
- case PM_POST_HIBERNATION:
- case PM_POST_RESTORE:
-
- spin_lock_irqsave(&host->lock, flags);
- host->rescan_disable = 0;
- spin_unlock_irqrestore(&host->lock, flags);
- _mmc_detect_change(host, 0, false);
-
- }
-
- return 0;
-}
-
-void mmc_register_pm_notifier(struct mmc_host *host)
-{
- host->pm_notify.notifier_call = mmc_pm_notify;
- register_pm_notifier(&host->pm_notify);
-}
-
-void mmc_unregister_pm_notifier(struct mmc_host *host)
-{
- unregister_pm_notifier(&host->pm_notify);
-}
-#endif
-
/*
* mmc_first_nonreserved_index() - get the first index that
* is not reserved
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 21ffc7ecbe78..09a11032d635 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -95,14 +95,6 @@ int mmc_execute_tuning(struct mmc_card *card);
int mmc_hs200_to_hs400(struct mmc_card *card);
int mmc_hs400_to_hs200(struct mmc_card *card);
-#ifdef CONFIG_PM_SLEEP
-void mmc_register_pm_notifier(struct mmc_host *host);
-void mmc_unregister_pm_notifier(struct mmc_host *host);
-#else
-static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
-static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
-#endif
-
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 6a3fe88033bd..b077e071505a 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -33,6 +33,42 @@
static DEFINE_IDA(mmc_host_ida);
+#ifdef CONFIG_PM_SLEEP
+static int mmc_host_class_prepare(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+ /*
+ * It's safe to access the bus_ops pointer, as both userspace and the
+ * workqueue for detecting cards are frozen at this point.
+ */
+ if (!host->bus_ops)
+ return 0;
+
+ /* Validate conditions for system suspend. */
+ if (host->bus_ops->pre_suspend)
+ return host->bus_ops->pre_suspend(host);
+
+ return 0;
+}
+
+static void mmc_host_class_complete(struct device *dev)
+{
+ struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+ _mmc_detect_change(host, 0, false);
+}
+
+static const struct dev_pm_ops mmc_host_class_dev_pm_ops = {
+ .prepare = mmc_host_class_prepare,
+ .complete = mmc_host_class_complete,
+};
+
+#define MMC_HOST_CLASS_DEV_PM_OPS (&mmc_host_class_dev_pm_ops)
+#else
+#define MMC_HOST_CLASS_DEV_PM_OPS NULL
+#endif
+
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
@@ -43,6 +79,7 @@ static void mmc_host_classdev_release(struct device *dev)
static struct class mmc_host_class = {
.name = "mmc_host",
.dev_release = mmc_host_classdev_release,
+ .pm = MMC_HOST_CLASS_DEV_PM_OPS,
};
int mmc_register_host_class(void)
@@ -294,8 +331,6 @@ int mmc_of_parse(struct mmc_host *host)
if (device_property_read_bool(dev, "wakeup-source") ||
device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
- if (device_property_read_bool(dev, "pm-ignore-notify"))
- host->pm_caps |= MMC_PM_IGNORE_PM_NOTIFY;
if (device_property_read_bool(dev, "mmc-ddr-3_3v"))
host->caps |= MMC_CAP_3_3V_DDR;
if (device_property_read_bool(dev, "mmc-ddr-1_8v"))
@@ -487,9 +522,6 @@ int mmc_add_host(struct mmc_host *host)
#endif
mmc_start_host(host);
- if (!(host->pm_caps& MMC_PM_IGNORE_PM_NOTIFY))
- mmc_register_pm_notifier(host);
-
return 0;
}
@@ -505,8 +537,6 @@ EXPORT_SYMBOL(mmc_add_host);
*/
void mmc_remove_host(struct mmc_host *host)
{
- if (!(host->pm_caps& MMC_PM_IGNORE_PM_NOTIFY))
- mmc_unregister_pm_notifier(host);
mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 8d36f7bd780b..3627c9d6452e 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -925,21 +925,37 @@ out:
*/
static int mmc_sdio_pre_suspend(struct mmc_host *host)
{
- int i, err = 0;
+ int i;
for (i = 0; i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
- if (!pmops || !pmops->suspend || !pmops->resume) {
+ if (!pmops || !pmops->suspend || !pmops->resume)
/* force removal of entire card in that case */
- err = -ENOSYS;
- break;
- }
+ goto remove;
}
}
- return err;
+ return 0;
+
+remove:
+ if (!mmc_card_is_removable(host)) {
+ dev_warn(mmc_dev(host),
+ "missing suspend/resume ops for non-removable SDIO card\n");
+ /* Don't remove a non-removable card - we can't re-detect it. */
+ return 0;
+ }
+
+ /* Remove the SDIO card and let it be re-detected later on. */
+ mmc_sdio_remove(host);
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_power_off(host);
+ mmc_release_host(host);
+ host->pm_flags = 0;
+
+ return 0;
}
/*
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 4c5eb3aa8e72..a0e1cf1bef4e 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -281,9 +281,6 @@ struct mmc_host {
u32 ocr_avail_sdio; /* SDIO-specific OCR */
u32 ocr_avail_sd; /* SD-specific OCR */
u32 ocr_avail_mmc; /* MMC-specific OCR */
-#ifdef CONFIG_PM_SLEEP
- struct notifier_block pm_notify;
-#endif
u32 max_current_330;
u32 max_current_300;
u32 max_current_180;