aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2013-10-02 11:37:09 -0400
committerChris Ball <cjb@laptop.org>2013-10-30 20:28:40 -0400
commit9ec775f7efd6d17084b4f361804d2030d50fca0e (patch)
tree96e83ec6405aa185bbb7cf8f1fa819ffaafd76ad
parent0c04c6274fbc56c40649472e0076e949ecbc75ce (diff)
mmc: Don't force card to active state when entering suspend/shutdown
By adding a card state that records if it is suspended or resumed, we can accept asyncronus suspend/resume requests for the mmc and sd bus_ops. MMC_CAP_AGGRESSIVE_PM, will at request inactivity through the runtime bus_ops callbacks, execute a suspend of the the card. In the state were this has been done, we can receive a suspend request for the mmc bus, which for sd and mmc forced the card to active state by a pm_runtime_get_sync. In other words, the card was resumed and then immediately suspended again, completely unnecessary. Since the suspend/resume bus_ops callbacks for sd and mmc are now capable of handling asynchronous requests, we no longer need to force the card to active state before executing suspend. Evidently preventing the above sequence for MMC_CAP_AGGRESSIVE_PM. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/mmc/core/mmc.c45
-rw-r--r--drivers/mmc/core/sd.c21
-rw-r--r--include/linux/mmc/card.h4
4 files changed, 55 insertions, 17 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1a3163f1407e..29d5d988a51c 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2448,7 +2448,6 @@ static int _mmc_blk_suspend(struct mmc_card *card)
2448 struct mmc_blk_data *md = mmc_get_drvdata(card); 2448 struct mmc_blk_data *md = mmc_get_drvdata(card);
2449 2449
2450 if (md) { 2450 if (md) {
2451 pm_runtime_get_sync(&card->dev);
2452 mmc_queue_suspend(&md->queue); 2451 mmc_queue_suspend(&md->queue);
2453 list_for_each_entry(part_md, &md->part, part) { 2452 list_for_each_entry(part_md, &md->part, part) {
2454 mmc_queue_suspend(&part_md->queue); 2453 mmc_queue_suspend(&part_md->queue);
@@ -2483,7 +2482,6 @@ static int mmc_blk_resume(struct mmc_card *card)
2483 list_for_each_entry(part_md, &md->part, part) { 2482 list_for_each_entry(part_md, &md->part, part) {
2484 mmc_queue_resume(&part_md->queue); 2483 mmc_queue_resume(&part_md->queue);
2485 } 2484 }
2486 pm_runtime_put(&card->dev);
2487 } 2485 }
2488 return 0; 2486 return 0;
2489} 2487}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0d060227cfc1..84d8694cf369 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1478,6 +1478,9 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
1478 1478
1479 mmc_claim_host(host); 1479 mmc_claim_host(host);
1480 1480
1481 if (mmc_card_suspended(host->card))
1482 goto out;
1483
1481 if (mmc_card_doing_bkops(host->card)) { 1484 if (mmc_card_doing_bkops(host->card)) {
1482 err = mmc_stop_bkops(host->card); 1485 err = mmc_stop_bkops(host->card);
1483 if (err) 1486 if (err)
@@ -1497,8 +1500,10 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
1497 err = mmc_deselect_cards(host); 1500 err = mmc_deselect_cards(host);
1498 host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); 1501 host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
1499 1502
1500 if (!err) 1503 if (!err) {
1501 mmc_power_off(host); 1504 mmc_power_off(host);
1505 mmc_card_set_suspended(host->card);
1506 }
1502out: 1507out:
1503 mmc_release_host(host); 1508 mmc_release_host(host);
1504 return err; 1509 return err;
@@ -1513,14 +1518,6 @@ static int mmc_suspend(struct mmc_host *host)
1513} 1518}
1514 1519
1515/* 1520/*
1516 * Shutdown callback
1517 */
1518static int mmc_shutdown(struct mmc_host *host)
1519{
1520 return _mmc_suspend(host, false);
1521}
1522
1523/*
1524 * Resume callback from host. 1521 * Resume callback from host.
1525 * 1522 *
1526 * This function tries to determine if the same card is still present 1523 * This function tries to determine if the same card is still present
@@ -1528,19 +1525,45 @@ static int mmc_shutdown(struct mmc_host *host)
1528 */ 1525 */
1529static int mmc_resume(struct mmc_host *host) 1526static int mmc_resume(struct mmc_host *host)
1530{ 1527{
1531 int err; 1528 int err = 0;
1532 1529
1533 BUG_ON(!host); 1530 BUG_ON(!host);
1534 BUG_ON(!host->card); 1531 BUG_ON(!host->card);
1535 1532
1536 mmc_claim_host(host); 1533 mmc_claim_host(host);
1534
1535 if (!mmc_card_suspended(host->card))
1536 goto out;
1537
1537 mmc_power_up(host, host->card->ocr); 1538 mmc_power_up(host, host->card->ocr);
1538 err = mmc_init_card(host, host->card->ocr, host->card); 1539 err = mmc_init_card(host, host->card->ocr, host->card);
1539 mmc_release_host(host); 1540 mmc_card_clr_suspended(host->card);
1540 1541
1542out:
1543 mmc_release_host(host);
1541 return err; 1544 return err;
1542} 1545}
1543 1546
1547/*
1548 * Shutdown callback
1549 */
1550static int mmc_shutdown(struct mmc_host *host)
1551{
1552 int err = 0;
1553
1554 /*
1555 * In a specific case for poweroff notify, we need to resume the card
1556 * before we can shutdown it properly.
1557 */
1558 if (mmc_can_poweroff_notify(host->card) &&
1559 !(host->caps2 & MMC_CAP2_FULL_PWR_CYCLE))
1560 err = mmc_resume(host);
1561
1562 if (!err)
1563 err = _mmc_suspend(host, false);
1564
1565 return err;
1566}
1544 1567
1545/* 1568/*
1546 * Callback for runtime_suspend. 1569 * Callback for runtime_suspend.
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 6ef84d0ca178..685796560f8b 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1078,13 +1078,20 @@ static int mmc_sd_suspend(struct mmc_host *host)
1078 BUG_ON(!host->card); 1078 BUG_ON(!host->card);
1079 1079
1080 mmc_claim_host(host); 1080 mmc_claim_host(host);
1081
1082 if (mmc_card_suspended(host->card))
1083 goto out;
1084
1081 if (!mmc_host_is_spi(host)) 1085 if (!mmc_host_is_spi(host))
1082 err = mmc_deselect_cards(host); 1086 err = mmc_deselect_cards(host);
1083 host->card->state &= ~MMC_STATE_HIGHSPEED; 1087 host->card->state &= ~MMC_STATE_HIGHSPEED;
1084 if (!err) 1088 if (!err) {
1085 mmc_power_off(host); 1089 mmc_power_off(host);
1086 mmc_release_host(host); 1090 mmc_card_set_suspended(host->card);
1091 }
1087 1092
1093out:
1094 mmc_release_host(host);
1088 return err; 1095 return err;
1089} 1096}
1090 1097
@@ -1096,16 +1103,22 @@ static int mmc_sd_suspend(struct mmc_host *host)
1096 */ 1103 */
1097static int mmc_sd_resume(struct mmc_host *host) 1104static int mmc_sd_resume(struct mmc_host *host)
1098{ 1105{
1099 int err; 1106 int err = 0;
1100 1107
1101 BUG_ON(!host); 1108 BUG_ON(!host);
1102 BUG_ON(!host->card); 1109 BUG_ON(!host->card);
1103 1110
1104 mmc_claim_host(host); 1111 mmc_claim_host(host);
1112
1113 if (!mmc_card_suspended(host->card))
1114 goto out;
1115
1105 mmc_power_up(host, host->card->ocr); 1116 mmc_power_up(host, host->card->ocr);
1106 err = mmc_sd_init_card(host, host->card->ocr, host->card); 1117 err = mmc_sd_init_card(host, host->card->ocr, host->card);
1107 mmc_release_host(host); 1118 mmc_card_clr_suspended(host->card);
1108 1119
1120out:
1121 mmc_release_host(host);
1109 return err; 1122 return err;
1110} 1123}
1111 1124
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 33d9a74f92e6..176fdf824b14 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -258,6 +258,7 @@ struct mmc_card {
258#define MMC_CARD_REMOVED (1<<7) /* card has been removed */ 258#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
259#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ 259#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
260#define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */ 260#define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */