From 62c8dce6e1b42fe6ee356550a3092ca2db90ec22 Mon Sep 17 00:00:00 2001 From: Krishna Konda Date: Mon, 29 Jun 2015 19:20:05 -0700 Subject: [PATCH] mmc: core: Update PON based on the system state As per eMMC specification, the PON (Power Off Notification) must be sent by host to the card before turning off the power. This will allow card to prepare itself for the power off and may even reduce the initialization of eMMC upon next boot-up. Send long PON during system power off and send short PON during system reboot to reduce the reboot latency. Change-Id: If4188b8b80aaa0e6c4e00e1807aa9589d5e7efdb Signed-off-by: Sahitya Tummala Signed-off-by: Krishna Konda [subhashj@codeaurora.org: fixed trivial merge conflicts] Signed-off-by: Subhash Jadavani --- drivers/mmc/card/block.c | 4 ++++ drivers/mmc/core/mmc.c | 22 ++++++++++++---------- include/linux/mmc/card.h | 9 +++++++-- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 7c8e0a601cd4..b9febc75c64e 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -4056,6 +4056,10 @@ static int _mmc_blk_suspend(struct mmc_card *card) static void mmc_blk_shutdown(struct mmc_card *card) { _mmc_blk_suspend(card); + + /* send power off notification */ + if (mmc_card_mmc(card)) + mmc_send_pon(card); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b0353f88f990..7ce9d3c01226 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1431,10 +1431,7 @@ static int mmc_reboot_notify(struct notifier_block *notify_block, struct mmc_card *card = container_of( notify_block, struct mmc_card, reboot_notify); - if (event != SYS_RESTART) - card->issue_long_pon = true; - else - card->issue_long_pon = false; + card->pon_type = (event != SYS_RESTART) ? MMC_LONG_PON : MMC_SHRT_PON; return NOTIFY_OK; } @@ -2255,19 +2252,24 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) return err; } -int mmc_send_long_pon(struct mmc_card *card) +int mmc_send_pon(struct mmc_card *card) { int err = 0; struct mmc_host *host = card->host; + if (!mmc_can_poweroff_notify(card)) + goto out; + mmc_claim_host(host); - if (card->issue_long_pon && mmc_can_poweroff_notify(card)) { + if (card->pon_type & MMC_LONG_PON) err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_LONG); - if (err) - pr_warning("%s: error %d sending Long PON", - mmc_hostname(host), err); - } + else if (card->pon_type & MMC_SHRT_PON) + err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT); + if (err) + pr_warn("%s: error %d sending PON type %u", + mmc_hostname(host), err, card->pon_type); mmc_release_host(host); +out: return err; } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 2430ba0e1182..c8faf8b146ee 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -324,6 +324,11 @@ struct mmc_bkops_info { bool needs_manual; }; +enum mmc_pon_type { + MMC_LONG_PON = 1, + MMC_SHRT_PON, +}; + /* * MMC device */ @@ -411,7 +416,7 @@ struct mmc_card { struct mmc_wr_pack_stats wr_pack_stats; /* packed commands stats*/ struct notifier_block reboot_notify; - bool issue_long_pon; + enum mmc_pon_type pon_type; u8 *cached_ext_csd; bool cmdq_init; struct mmc_bkops_info bkops; @@ -691,6 +696,6 @@ extern void mmc_fixup_device(struct mmc_card *card, extern struct mmc_wr_pack_stats *mmc_blk_get_packed_statistics( struct mmc_card *card); extern void mmc_blk_init_packed_statistics(struct mmc_card *card); -extern int mmc_send_long_pon(struct mmc_card *card); +extern int mmc_send_pon(struct mmc_card *card); extern void mmc_blk_cmdq_req_done(struct mmc_request *mrq); #endif /* LINUX_MMC_CARD_H */