mmc: core: Disable card detect during shutdown
It's seems prone to problems by allowing card detect and its corresponding mmc_rescan() work to run, during platform shutdown. For example, we may end up turning off the power while initializing a card, which potentially could damage it. To avoid this scenario, let's add ->shutdown_pre() callback for the mmc host class device and then turn of the card detect from there. Reported-by: Al Cooper <alcooperx@gmail.com> Suggested-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20211203141555.105351-1-ulf.hansson@linaro.org
This commit is contained in:
Родитель
4fc7261dba
Коммит
66c915d09b
|
@ -2264,7 +2264,7 @@ void mmc_start_host(struct mmc_host *host)
|
||||||
_mmc_detect_change(host, 0, false);
|
_mmc_detect_change(host, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mmc_stop_host(struct mmc_host *host)
|
void __mmc_stop_host(struct mmc_host *host)
|
||||||
{
|
{
|
||||||
if (host->slot.cd_irq >= 0) {
|
if (host->slot.cd_irq >= 0) {
|
||||||
mmc_gpio_set_cd_wake(host, false);
|
mmc_gpio_set_cd_wake(host, false);
|
||||||
|
@ -2273,6 +2273,11 @@ void mmc_stop_host(struct mmc_host *host)
|
||||||
|
|
||||||
host->rescan_disable = 1;
|
host->rescan_disable = 1;
|
||||||
cancel_delayed_work_sync(&host->detect);
|
cancel_delayed_work_sync(&host->detect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmc_stop_host(struct mmc_host *host)
|
||||||
|
{
|
||||||
|
__mmc_stop_host(host);
|
||||||
|
|
||||||
/* clear pm flags now and let card drivers set them as needed */
|
/* clear pm flags now and let card drivers set them as needed */
|
||||||
host->pm_flags = 0;
|
host->pm_flags = 0;
|
||||||
|
|
|
@ -70,6 +70,7 @@ static inline void mmc_delay(unsigned int ms)
|
||||||
|
|
||||||
void mmc_rescan(struct work_struct *work);
|
void mmc_rescan(struct work_struct *work);
|
||||||
void mmc_start_host(struct mmc_host *host);
|
void mmc_start_host(struct mmc_host *host);
|
||||||
|
void __mmc_stop_host(struct mmc_host *host);
|
||||||
void mmc_stop_host(struct mmc_host *host);
|
void mmc_stop_host(struct mmc_host *host);
|
||||||
|
|
||||||
void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
|
void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
|
||||||
|
|
|
@ -80,9 +80,18 @@ static void mmc_host_classdev_release(struct device *dev)
|
||||||
kfree(host);
|
kfree(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mmc_host_classdev_shutdown(struct device *dev)
|
||||||
|
{
|
||||||
|
struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
||||||
|
|
||||||
|
__mmc_stop_host(host);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct class mmc_host_class = {
|
static struct class mmc_host_class = {
|
||||||
.name = "mmc_host",
|
.name = "mmc_host",
|
||||||
.dev_release = mmc_host_classdev_release,
|
.dev_release = mmc_host_classdev_release,
|
||||||
|
.shutdown_pre = mmc_host_classdev_shutdown,
|
||||||
.pm = MMC_HOST_CLASS_DEV_PM_OPS,
|
.pm = MMC_HOST_CLASS_DEV_PM_OPS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче