Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ulf Hansson and committed by
Chris Ball
e94cfef6 12d01d0b

+60 -14
+26 -6
drivers/mmc/card/block.c
··· 34 34 #include <linux/delay.h> 35 35 #include <linux/capability.h> 36 36 #include <linux/compat.h> 37 + #include <linux/pm_runtime.h> 37 38 38 39 #include <linux/mmc/ioctl.h> 39 40 #include <linux/mmc/card.h> ··· 225 224 md = mmc_blk_get(dev_to_disk(dev)); 226 225 card = md->queue.card; 227 226 228 - mmc_claim_host(card->host); 227 + mmc_get_card(card); 229 228 230 229 ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, 231 230 card->ext_csd.boot_ro_lock | ··· 236 235 else 237 236 card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; 238 237 239 - mmc_release_host(card->host); 238 + mmc_put_card(card); 240 239 241 240 if (!ret) { 242 241 pr_info("%s: Locking boot partition ro until next power on\n", ··· 523 522 524 523 mrq.cmd = &cmd; 525 524 526 - mmc_claim_host(card->host); 525 + mmc_get_card(card); 527 526 528 527 err = mmc_blk_part_switch(card, md); 529 528 if (err) ··· 600 599 } 601 600 602 601 cmd_rel_host: 603 - mmc_release_host(card->host); 602 + mmc_put_card(card); 604 603 605 604 cmd_done: 606 605 mmc_blk_put(md); ··· 1922 1921 1923 1922 if (req && !mq->mqrq_prev->req) 1924 1923 /* claim host only for the first request */ 1925 - mmc_claim_host(card->host); 1924 + mmc_get_card(card); 1926 1925 1927 1926 ret = mmc_blk_part_switch(card, md); 1928 1927 if (ret) { ··· 1966 1965 * In case sepecial request, there is no reentry to 1967 1966 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'. 1968 1967 */ 1969 - mmc_release_host(card->host); 1968 + mmc_put_card(card); 1970 1969 return ret; 1971 1970 } 1972 1971 ··· 2363 2362 if (mmc_add_disk(part_md)) 2364 2363 goto out; 2365 2364 } 2365 + 2366 + pm_runtime_set_autosuspend_delay(&card->dev, 3000); 2367 + pm_runtime_use_autosuspend(&card->dev); 2368 + 2369 + /* 2370 + * Don't enable runtime PM for SD-combo cards here. Leave that 2371 + * decision to be taken during the SDIO init sequence instead. 2372 + */ 2373 + if (card->type != MMC_TYPE_SD_COMBO) { 2374 + pm_runtime_set_active(&card->dev); 2375 + pm_runtime_enable(&card->dev); 2376 + } 2377 + 2366 2378 return 0; 2367 2379 2368 2380 out: ··· 2389 2375 struct mmc_blk_data *md = mmc_get_drvdata(card); 2390 2376 2391 2377 mmc_blk_remove_parts(card, md); 2378 + pm_runtime_get_sync(&card->dev); 2392 2379 mmc_claim_host(card->host); 2393 2380 mmc_blk_part_switch(card, md); 2394 2381 mmc_release_host(card->host); 2382 + if (card->type != MMC_TYPE_SD_COMBO) 2383 + pm_runtime_disable(&card->dev); 2384 + pm_runtime_put_noidle(&card->dev); 2395 2385 mmc_blk_remove_req(md); 2396 2386 mmc_set_drvdata(card, NULL); 2397 2387 } ··· 2407 2389 struct mmc_blk_data *md = mmc_get_drvdata(card); 2408 2390 2409 2391 if (md) { 2392 + pm_runtime_get_sync(&card->dev); 2410 2393 mmc_queue_suspend(&md->queue); 2411 2394 list_for_each_entry(part_md, &md->part, part) { 2412 2395 mmc_queue_suspend(&part_md->queue); ··· 2431 2412 list_for_each_entry(part_md, &md->part, part) { 2432 2413 mmc_queue_resume(&part_md->queue); 2433 2414 } 2415 + pm_runtime_put(&card->dev); 2434 2416 } 2435 2417 return 0; 2436 2418 }
+23
drivers/mmc/core/core.c
··· 971 971 EXPORT_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 + */ 977 + void mmc_get_card(struct mmc_card *card) 978 + { 979 + pm_runtime_get_sync(&card->dev); 980 + mmc_claim_host(card->host); 981 + } 982 + EXPORT_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 + */ 988 + void 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 + } 994 + EXPORT_SYMBOL(mmc_put_card); 995 + 996 + /* 974 997 * Internal function that does the actual ios call to the host driver, 975 998 * optionally printing some debug output. 976 999 */
+4 -4
drivers/mmc/core/debugfs.c
··· 258 258 u32 status; 259 259 int ret; 260 260 261 - mmc_claim_host(card->host); 261 + mmc_get_card(card); 262 262 263 263 ret = mmc_send_status(data, &status); 264 264 if (!ret) 265 265 *val = status; 266 266 267 - mmc_release_host(card->host); 267 + mmc_put_card(card); 268 268 269 269 return ret; 270 270 } ··· 291 291 goto out_free; 292 292 } 293 293 294 - mmc_claim_host(card->host); 294 + mmc_get_card(card); 295 295 err = mmc_send_ext_csd(card, ext_csd); 296 - mmc_release_host(card->host); 296 + mmc_put_card(card); 297 297 if (err) 298 298 goto out_free; 299 299
+2 -2
drivers/mmc/core/mmc.c
··· 1380 1380 BUG_ON(!host); 1381 1381 BUG_ON(!host->card); 1382 1382 1383 - mmc_claim_host(host); 1383 + mmc_get_card(host->card); 1384 1384 1385 1385 /* 1386 1386 * Just check if our card has been removed. 1387 1387 */ 1388 1388 err = _mmc_detect_card_removed(host); 1389 1389 1390 - mmc_release_host(host); 1390 + mmc_put_card(host->card); 1391 1391 1392 1392 if (err) { 1393 1393 mmc_remove(host);
+2 -2
drivers/mmc/core/sd.c
··· 1042 1042 BUG_ON(!host); 1043 1043 BUG_ON(!host->card); 1044 1044 1045 - mmc_claim_host(host); 1045 + mmc_get_card(host->card); 1046 1046 1047 1047 /* 1048 1048 * Just check if our card has been removed. 1049 1049 */ 1050 1050 err = _mmc_detect_card_removed(host); 1051 1051 1052 - mmc_release_host(host); 1052 + mmc_put_card(host->card); 1053 1053 1054 1054 if (err) { 1055 1055 mmc_sd_remove(host);
+3
include/linux/mmc/core.h
··· 190 190 extern void mmc_release_host(struct mmc_host *host); 191 191 extern int mmc_try_claim_host(struct mmc_host *host); 192 192 193 + extern void mmc_get_card(struct mmc_card *card); 194 + extern void mmc_put_card(struct mmc_card *card); 195 + 193 196 extern int mmc_flush_cache(struct mmc_card *); 194 197 195 198 extern int mmc_detect_card_removed(struct mmc_host *host);