Commit e94cfef6 authored by Ulf Hansson's avatar Ulf Hansson Committed by Chris Ball

mmc: block: Enable runtime pm for mmc blkdevice

Once the mmc blkdevice is being probed, runtime pm will be enabled.
By using runtime autosuspend, the power save operations can be done
when request inactivity occurs for a certain time. Right now the
selected timeout value is set to 3 s. Obviously this value will likely
need to be configurable somehow since it needs to be trimmed depending
on the power save algorithm.

For SD-combo cards, we are still leaving the enablement of runtime PM
to the SDIO init sequence since it depends on the capabilities of the
SDIO func driver.

Moreover, when the blk device is being suspended, we make sure the device
will be runtime resumed. The reason for doing this is that we want the
host suspend sequence to be unaware of any runtime power save operations
done for the card in this phase. Thus it can just handle the suspend as
the card is fully powered from a runtime perspective.

Finally, this patch prepares to make it possible to move BKOPS handling
into the runtime callbacks for the mmc bus_ops. Thus IDLE BKOPS can be
accomplished.
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 12d01d0b
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/ioctl.h> #include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
...@@ -224,7 +225,7 @@ static ssize_t power_ro_lock_store(struct device *dev, ...@@ -224,7 +225,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
md = mmc_blk_get(dev_to_disk(dev)); md = mmc_blk_get(dev_to_disk(dev));
card = md->queue.card; card = md->queue.card;
mmc_claim_host(card->host); mmc_get_card(card);
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
card->ext_csd.boot_ro_lock | card->ext_csd.boot_ro_lock |
...@@ -235,7 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev, ...@@ -235,7 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
else else
card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
mmc_release_host(card->host); mmc_put_card(card);
if (!ret) { if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n", pr_info("%s: Locking boot partition ro until next power on\n",
...@@ -522,7 +523,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -522,7 +523,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mrq.cmd = &cmd; mrq.cmd = &cmd;
mmc_claim_host(card->host); mmc_get_card(card);
err = mmc_blk_part_switch(card, md); err = mmc_blk_part_switch(card, md);
if (err) if (err)
...@@ -599,7 +600,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -599,7 +600,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
} }
cmd_rel_host: cmd_rel_host:
mmc_release_host(card->host); mmc_put_card(card);
cmd_done: cmd_done:
mmc_blk_put(md); mmc_blk_put(md);
...@@ -1921,7 +1922,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -1921,7 +1922,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (req && !mq->mqrq_prev->req) if (req && !mq->mqrq_prev->req)
/* claim host only for the first request */ /* claim host only for the first request */
mmc_claim_host(card->host); mmc_get_card(card);
ret = mmc_blk_part_switch(card, md); ret = mmc_blk_part_switch(card, md);
if (ret) { if (ret) {
...@@ -1965,7 +1966,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -1965,7 +1966,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
* In case sepecial request, there is no reentry to * In case sepecial request, there is no reentry to
* the 'mmc_blk_issue_rq' with 'mqrq_prev->req'. * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
*/ */
mmc_release_host(card->host); mmc_put_card(card);
return ret; return ret;
} }
...@@ -2362,6 +2363,19 @@ static int mmc_blk_probe(struct mmc_card *card) ...@@ -2362,6 +2363,19 @@ static int mmc_blk_probe(struct mmc_card *card)
if (mmc_add_disk(part_md)) if (mmc_add_disk(part_md))
goto out; goto out;
} }
pm_runtime_set_autosuspend_delay(&card->dev, 3000);
pm_runtime_use_autosuspend(&card->dev);
/*
* Don't enable runtime PM for SD-combo cards here. Leave that
* decision to be taken during the SDIO init sequence instead.
*/
if (card->type != MMC_TYPE_SD_COMBO) {
pm_runtime_set_active(&card->dev);
pm_runtime_enable(&card->dev);
}
return 0; return 0;
out: out:
...@@ -2375,9 +2389,13 @@ static void mmc_blk_remove(struct mmc_card *card) ...@@ -2375,9 +2389,13 @@ static void mmc_blk_remove(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card); struct mmc_blk_data *md = mmc_get_drvdata(card);
mmc_blk_remove_parts(card, md); mmc_blk_remove_parts(card, md);
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host); mmc_claim_host(card->host);
mmc_blk_part_switch(card, md); mmc_blk_part_switch(card, md);
mmc_release_host(card->host); mmc_release_host(card->host);
if (card->type != MMC_TYPE_SD_COMBO)
pm_runtime_disable(&card->dev);
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md); mmc_blk_remove_req(md);
mmc_set_drvdata(card, NULL); mmc_set_drvdata(card, NULL);
} }
...@@ -2389,6 +2407,7 @@ static int mmc_blk_suspend(struct mmc_card *card) ...@@ -2389,6 +2407,7 @@ static int mmc_blk_suspend(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card); struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) { if (md) {
pm_runtime_get_sync(&card->dev);
mmc_queue_suspend(&md->queue); mmc_queue_suspend(&md->queue);
list_for_each_entry(part_md, &md->part, part) { list_for_each_entry(part_md, &md->part, part) {
mmc_queue_suspend(&part_md->queue); mmc_queue_suspend(&part_md->queue);
...@@ -2412,6 +2431,7 @@ static int mmc_blk_resume(struct mmc_card *card) ...@@ -2412,6 +2431,7 @@ static int mmc_blk_resume(struct mmc_card *card)
list_for_each_entry(part_md, &md->part, part) { list_for_each_entry(part_md, &md->part, part) {
mmc_queue_resume(&part_md->queue); mmc_queue_resume(&part_md->queue);
} }
pm_runtime_put(&card->dev);
} }
return 0; return 0;
} }
......
...@@ -970,6 +970,29 @@ void mmc_release_host(struct mmc_host *host) ...@@ -970,6 +970,29 @@ void mmc_release_host(struct mmc_host *host)
} }
EXPORT_SYMBOL(mmc_release_host); EXPORT_SYMBOL(mmc_release_host);
/*
* This is a helper function, which fetches a runtime pm reference for the
* card device and also claims the host.
*/
void mmc_get_card(struct mmc_card *card)
{
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
}
EXPORT_SYMBOL(mmc_get_card);
/*
* This is a helper function, which releases the host and drops the runtime
* pm reference for the card device.
*/
void mmc_put_card(struct mmc_card *card)
{
mmc_release_host(card->host);
pm_runtime_mark_last_busy(&card->dev);
pm_runtime_put_autosuspend(&card->dev);
}
EXPORT_SYMBOL(mmc_put_card);
/* /*
* Internal function that does the actual ios call to the host driver, * Internal function that does the actual ios call to the host driver,
* optionally printing some debug output. * optionally printing some debug output.
......
...@@ -258,13 +258,13 @@ static int mmc_dbg_card_status_get(void *data, u64 *val) ...@@ -258,13 +258,13 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
u32 status; u32 status;
int ret; int ret;
mmc_claim_host(card->host); mmc_get_card(card);
ret = mmc_send_status(data, &status); ret = mmc_send_status(data, &status);
if (!ret) if (!ret)
*val = status; *val = status;
mmc_release_host(card->host); mmc_put_card(card);
return ret; return ret;
} }
...@@ -291,9 +291,9 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp) ...@@ -291,9 +291,9 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
goto out_free; goto out_free;
} }
mmc_claim_host(card->host); mmc_get_card(card);
err = mmc_send_ext_csd(card, ext_csd); err = mmc_send_ext_csd(card, ext_csd);
mmc_release_host(card->host); mmc_put_card(card);
if (err) if (err)
goto out_free; goto out_free;
......
...@@ -1380,14 +1380,14 @@ static void mmc_detect(struct mmc_host *host) ...@@ -1380,14 +1380,14 @@ static void mmc_detect(struct mmc_host *host)
BUG_ON(!host); BUG_ON(!host);
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_get_card(host->card);
/* /*
* Just check if our card has been removed. * Just check if our card has been removed.
*/ */
err = _mmc_detect_card_removed(host); err = _mmc_detect_card_removed(host);
mmc_release_host(host); mmc_put_card(host->card);
if (err) { if (err) {
mmc_remove(host); mmc_remove(host);
......
...@@ -1042,14 +1042,14 @@ static void mmc_sd_detect(struct mmc_host *host) ...@@ -1042,14 +1042,14 @@ static void mmc_sd_detect(struct mmc_host *host)
BUG_ON(!host); BUG_ON(!host);
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_get_card(host->card);
/* /*
* Just check if our card has been removed. * Just check if our card has been removed.
*/ */
err = _mmc_detect_card_removed(host); err = _mmc_detect_card_removed(host);
mmc_release_host(host); mmc_put_card(host->card);
if (err) { if (err) {
mmc_sd_remove(host); mmc_sd_remove(host);
......
...@@ -190,6 +190,9 @@ extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); ...@@ -190,6 +190,9 @@ extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
extern void mmc_release_host(struct mmc_host *host); extern void mmc_release_host(struct mmc_host *host);
extern int mmc_try_claim_host(struct mmc_host *host); extern int mmc_try_claim_host(struct mmc_host *host);
extern void mmc_get_card(struct mmc_card *card);
extern void mmc_put_card(struct mmc_card *card);
extern int mmc_flush_cache(struct mmc_card *); extern int mmc_flush_cache(struct mmc_card *);
extern int mmc_detect_card_removed(struct mmc_host *host); extern int mmc_detect_card_removed(struct mmc_host *host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment