aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2013-05-02 08:02:38 -0400
committerChris Ball <cjb@laptop.org>2013-05-26 14:23:16 -0400
commite94cfef698aae6b209d8918dd319312e4b02118d (patch)
treebbf4978bf665c480608317d0544967f6600b21a3
parent12d01d0b813b93e7bde1b5f468b5c85aa8b33590 (diff)
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: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/card/block.c32
-rw-r--r--drivers/mmc/core/core.c23
-rw-r--r--drivers/mmc/core/debugfs.c8
-rw-r--r--drivers/mmc/core/mmc.c4
-rw-r--r--drivers/mmc/core/sd.c4
-rw-r--r--include/linux/mmc/core.h3
6 files changed, 60 insertions, 14 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 80b05b280241..c900d2818aa7 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -34,6 +34,7 @@
34#include <linux/delay.h> 34#include <linux/delay.h>
35#include <linux/capability.h> 35#include <linux/capability.h>
36#include <linux/compat.h> 36#include <linux/compat.h>
37#include <linux/pm_runtime.h>
37 38
38#include <linux/mmc/ioctl.h> 39#include <linux/mmc/ioctl.h>
39#include <linux/mmc/card.h> 40#include <linux/mmc/card.h>
@@ -224,7 +225,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
224 md = mmc_blk_get(dev_to_disk(dev)); 225 md = mmc_blk_get(dev_to_disk(dev));
225 card = md->queue.card; 226 card = md->queue.card;
226 227
227 mmc_claim_host(card->host); 228 mmc_get_card(card);
228 229
229 ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, 230 ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
230 card->ext_csd.boot_ro_lock | 231 card->ext_csd.boot_ro_lock |
@@ -235,7 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
235 else 236 else
236 card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; 237 card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
237 238
238 mmc_release_host(card->host); 239 mmc_put_card(card);
239 240
240 if (!ret) { 241 if (!ret) {
241 pr_info("%s: Locking boot partition ro until next power on\n", 242 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 523
523 mrq.cmd = &cmd; 524 mrq.cmd = &cmd;
524 525
525 mmc_claim_host(card->host); 526 mmc_get_card(card);
526 527
527 err = mmc_blk_part_switch(card, md); 528 err = mmc_blk_part_switch(card, md);
528 if (err) 529 if (err)
@@ -599,7 +600,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
599 } 600 }
600 601
601cmd_rel_host: 602cmd_rel_host:
602 mmc_release_host(card->host); 603 mmc_put_card(card);
603 604
604cmd_done: 605cmd_done:
605 mmc_blk_put(md); 606 mmc_blk_put(md);
@@ -1921,7 +1922,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
1921 1922
1922 if (req && !mq->mqrq_prev->req) 1923 if (req && !mq->mqrq_prev->req)
1923 /* claim host only for the first request */ 1924 /* claim host only for the first request */
1924 mmc_claim_host(card->host); 1925 mmc_get_card(card);
1925 1926
1926 ret = mmc_blk_part_switch(card, md); 1927 ret = mmc_blk_part_switch(card, md);
1927 if (ret) { 1928 if (ret) {
@@ -1965,7 +1966,7 @@ out:
1965 * In case sepecial request, there is no reentry to 1966 * In case sepecial request, there is no reentry to
1966 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'. 1967 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
1967 */ 1968 */
1968 mmc_release_host(card->host); 1969 mmc_put_card(card);
1969 return ret; 1970 return ret;
1970} 1971}
1971 1972
@@ -2362,6 +2363,19 @@ static int mmc_blk_probe(struct mmc_card *card)
2362 if (mmc_add_disk(part_md)) 2363 if (mmc_add_disk(part_md))
2363 goto out; 2364 goto out;
2364 } 2365 }
2366
2367 pm_runtime_set_autosuspend_delay(&card->dev, 3000);
2368 pm_runtime_use_autosuspend(&card->dev);
2369
2370 /*
2371 * Don't enable runtime PM for SD-combo cards here. Leave that
2372 * decision to be taken during the SDIO init sequence instead.
2373 */
2374 if (card->type != MMC_TYPE_SD_COMBO) {
2375 pm_runtime_set_active(&card->dev);
2376 pm_runtime_enable(&card->dev);
2377 }
2378
2365 return 0; 2379 return 0;
2366 2380
2367 out: 2381 out:
@@ -2375,9 +2389,13 @@ static void mmc_blk_remove(struct mmc_card *card)
2375 struct mmc_blk_data *md = mmc_get_drvdata(card); 2389 struct mmc_blk_data *md = mmc_get_drvdata(card);
2376 2390
2377 mmc_blk_remove_parts(card, md); 2391 mmc_blk_remove_parts(card, md);
2392 pm_runtime_get_sync(&card->dev);
2378 mmc_claim_host(card->host); 2393 mmc_claim_host(card->host);
2379 mmc_blk_part_switch(card, md); 2394 mmc_blk_part_switch(card, md);
2380 mmc_release_host(card->host); 2395 mmc_release_host(card->host);
2396 if (card->type != MMC_TYPE_SD_COMBO)
2397 pm_runtime_disable(&card->dev);
2398 pm_runtime_put_noidle(&card->dev);
2381 mmc_blk_remove_req(md); 2399 mmc_blk_remove_req(md);
2382 mmc_set_drvdata(card, NULL); 2400 mmc_set_drvdata(card, NULL);
2383} 2401}
@@ -2389,6 +2407,7 @@ static int mmc_blk_suspend(struct mmc_card *card)
2389 struct mmc_blk_data *md = mmc_get_drvdata(card); 2407 struct mmc_blk_data *md = mmc_get_drvdata(card);
2390 2408
2391 if (md) { 2409 if (md) {
2410 pm_runtime_get_sync(&card->dev);
2392 mmc_queue_suspend(&md->queue); 2411 mmc_queue_suspend(&md->queue);
2393 list_for_each_entry(part_md, &md->part, part) { 2412 list_for_each_entry(part_md, &md->part, part) {
2394 mmc_queue_suspend(&part_md->queue); 2413 mmc_queue_suspend(&part_md->queue);
@@ -2412,6 +2431,7 @@ static int mmc_blk_resume(struct mmc_card *card)
2412 list_for_each_entry(part_md, &md->part, part) { 2431 list_for_each_entry(part_md, &md->part, part) {
2413 mmc_queue_resume(&part_md->queue); 2432 mmc_queue_resume(&part_md->queue);
2414 } 2433 }
2434 pm_runtime_put(&card->dev);
2415 } 2435 }
2416 return 0; 2436 return 0;
2417} 2437}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index dc0cb5929c64..0f86144b0c51 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -971,6 +971,29 @@ void mmc_release_host(struct mmc_host *host)
971EXPORT_SYMBOL(mmc_release_host); 971EXPORT_SYMBOL(mmc_release_host);
972 972
973/* 973/*
974 * This is a helper function, which fetches a runtime pm reference for the
975 * card device and also claims the host.
976 */
977void mmc_get_card(struct mmc_card *card)
978{
979 pm_runtime_get_sync(&card->dev);
980 mmc_claim_host(card->host);
981}
982EXPORT_SYMBOL(mmc_get_card);
983
984/*
985 * This is a helper function, which releases the host and drops the runtime
986 * pm reference for the card device.
987 */
988void mmc_put_card(struct mmc_card *card)
989{
990 mmc_release_host(card->host);
991 pm_runtime_mark_last_busy(&card->dev);
992 pm_runtime_put_autosuspend(&card->dev);
993}
994EXPORT_SYMBOL(mmc_put_card);
995
996/*
974 * Internal function that does the actual ios call to the host driver, 997 * Internal function that does the actual ios call to the host driver,
975 * optionally printing some debug output. 998 * optionally printing some debug output.
976 */ 999 */
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 35c2f85b1956..54829c0ed000 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -258,13 +258,13 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
258 u32 status; 258 u32 status;
259 int ret; 259 int ret;
260 260
261 mmc_claim_host(card->host); 261 mmc_get_card(card);
262 262
263 ret = mmc_send_status(data, &status); 263 ret = mmc_send_status(data, &status);
264 if (!ret) 264 if (!ret)
265 *val = status; 265 *val = status;
266 266
267 mmc_release_host(card->host); 267 mmc_put_card(card);
268 268
269 return ret; 269 return ret;
270} 270}
@@ -291,9 +291,9 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
291 goto out_free; 291 goto out_free;
292 } 292 }
293 293
294 mmc_claim_host(card->host); 294 mmc_get_card(card);
295 err = mmc_send_ext_csd(card, ext_csd); 295 err = mmc_send_ext_csd(card, ext_csd);
296 mmc_release_host(card->host); 296 mmc_put_card(card);
297 if (err) 297 if (err)
298 goto out_free; 298 goto out_free;
299 299
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a0469cf7933f..903f38150180 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1380,14 +1380,14 @@ static void mmc_detect(struct mmc_host *host)
1380 BUG_ON(!host); 1380 BUG_ON(!host);
1381 BUG_ON(!host->card); 1381 BUG_ON(!host->card);
1382 1382
1383 mmc_claim_host(host); 1383 mmc_get_card(host->card);
1384 1384
1385 /* 1385 /*
1386 * Just check if our card has been removed. 1386 * Just check if our card has been removed.
1387 */ 1387 */
1388 err = _mmc_detect_card_removed(host); 1388 err = _mmc_detect_card_removed(host);
1389 1389
1390 mmc_release_host(host); 1390 mmc_put_card(host->card);
1391 1391
1392 if (err) { 1392 if (err) {
1393 mmc_remove(host); 1393 mmc_remove(host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 8373d2288bb1..17fa2d271dd4 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1042,14 +1042,14 @@ static void mmc_sd_detect(struct mmc_host *host)
1042 BUG_ON(!host); 1042 BUG_ON(!host);
1043 BUG_ON(!host->card); 1043 BUG_ON(!host->card);
1044 1044
1045 mmc_claim_host(host); 1045 mmc_get_card(host->card);
1046 1046
1047 /* 1047 /*
1048 * Just check if our card has been removed. 1048 * Just check if our card has been removed.
1049 */ 1049 */
1050 err = _mmc_detect_card_removed(host); 1050 err = _mmc_detect_card_removed(host);
1051 1051
1052 mmc_release_host(host); 1052 mmc_put_card(host->card);
1053 1053
1054 if (err) { 1054 if (err) {
1055 mmc_sd_remove(host); 1055 mmc_sd_remove(host);
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index bd06ff566bfc..443243b241d5 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -190,6 +190,9 @@ extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
190extern void mmc_release_host(struct mmc_host *host); 190extern void mmc_release_host(struct mmc_host *host);
191extern int mmc_try_claim_host(struct mmc_host *host); 191extern int mmc_try_claim_host(struct mmc_host *host);
192 192
193extern void mmc_get_card(struct mmc_card *card);
194extern void mmc_put_card(struct mmc_card *card);
195
193extern int mmc_flush_cache(struct mmc_card *); 196extern int mmc_flush_cache(struct mmc_card *);
194 197
195extern int mmc_detect_card_removed(struct mmc_host *host); 198extern int mmc_detect_card_removed(struct mmc_host *host);