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

mmc: core: Support aggressive power management for (e)MMC/SD

Aggressive power management is suitable when saving power is
essential. At request inactivity timeout, aka pm runtime
autosuspend timeout, the card will be suspended.

Once a new request arrives, the card will be re-initalized and
thus the first request will suffer from a latency. This latency
is card-specific, experiments has shown in general that SD-cards
has quite poor initialization time, around 300ms-1100ms. eMMC is
not surprisingly far better but still a couple of hundreds of ms
has been observed.

Except for the request latency, it is important to know that
suspending the card will also prevent the card from executing
internal house-keeping operations in idle mode. This could mean
degradation in performance.

To use this feature make sure the request inactivity timeout is
chosen carefully. This has not been done as a part of this patch.

Enable this feature by using host cap MMC_CAP_AGGRESSIVE_PM and
by setting CONFIG_MMC_UNSAFE_RESUME.

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
c4d770d7 e94cfef6

+100 -1
+50
drivers/mmc/core/mmc.c
··· 1454 1454 return err; 1455 1455 } 1456 1456 1457 + 1458 + /* 1459 + * Callback for runtime_suspend. 1460 + */ 1461 + static int mmc_runtime_suspend(struct mmc_host *host) 1462 + { 1463 + int err; 1464 + 1465 + if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) 1466 + return 0; 1467 + 1468 + mmc_claim_host(host); 1469 + 1470 + err = mmc_suspend(host); 1471 + if (err) { 1472 + pr_err("%s: error %d doing aggessive suspend\n", 1473 + mmc_hostname(host), err); 1474 + goto out; 1475 + } 1476 + mmc_power_off(host); 1477 + 1478 + out: 1479 + mmc_release_host(host); 1480 + return err; 1481 + } 1482 + 1483 + /* 1484 + * Callback for runtime_resume. 1485 + */ 1486 + static int mmc_runtime_resume(struct mmc_host *host) 1487 + { 1488 + int err; 1489 + 1490 + if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) 1491 + return 0; 1492 + 1493 + mmc_claim_host(host); 1494 + 1495 + mmc_power_up(host); 1496 + err = mmc_resume(host); 1497 + if (err) 1498 + pr_err("%s: error %d doing aggessive resume\n", 1499 + mmc_hostname(host), err); 1500 + 1501 + mmc_release_host(host); 1502 + return 0; 1503 + } 1504 + 1457 1505 static int mmc_power_restore(struct mmc_host *host) 1458 1506 { 1459 1507 int ret; ··· 1562 1514 .detect = mmc_detect, 1563 1515 .suspend = mmc_suspend, 1564 1516 .resume = mmc_resume, 1517 + .runtime_suspend = mmc_runtime_suspend, 1518 + .runtime_resume = mmc_runtime_resume, 1565 1519 .power_restore = mmc_power_restore, 1566 1520 .alive = mmc_alive, 1567 1521 };
+49
drivers/mmc/core/sd.c
··· 1100 1100 return err; 1101 1101 } 1102 1102 1103 + /* 1104 + * Callback for runtime_suspend. 1105 + */ 1106 + static int mmc_sd_runtime_suspend(struct mmc_host *host) 1107 + { 1108 + int err; 1109 + 1110 + if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) 1111 + return 0; 1112 + 1113 + mmc_claim_host(host); 1114 + 1115 + err = mmc_sd_suspend(host); 1116 + if (err) { 1117 + pr_err("%s: error %d doing aggessive suspend\n", 1118 + mmc_hostname(host), err); 1119 + goto out; 1120 + } 1121 + mmc_power_off(host); 1122 + 1123 + out: 1124 + mmc_release_host(host); 1125 + return err; 1126 + } 1127 + 1128 + /* 1129 + * Callback for runtime_resume. 1130 + */ 1131 + static int mmc_sd_runtime_resume(struct mmc_host *host) 1132 + { 1133 + int err; 1134 + 1135 + if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) 1136 + return 0; 1137 + 1138 + mmc_claim_host(host); 1139 + 1140 + mmc_power_up(host); 1141 + err = mmc_sd_resume(host); 1142 + if (err) 1143 + pr_err("%s: error %d doing aggessive resume\n", 1144 + mmc_hostname(host), err); 1145 + 1146 + mmc_release_host(host); 1147 + return 0; 1148 + } 1149 + 1103 1150 static int mmc_sd_power_restore(struct mmc_host *host) 1104 1151 { 1105 1152 int ret; ··· 1171 1124 static const struct mmc_bus_ops mmc_sd_ops_unsafe = { 1172 1125 .remove = mmc_sd_remove, 1173 1126 .detect = mmc_sd_detect, 1127 + .runtime_suspend = mmc_sd_runtime_suspend, 1128 + .runtime_resume = mmc_sd_runtime_resume, 1174 1129 .suspend = mmc_sd_suspend, 1175 1130 .resume = mmc_sd_resume, 1176 1131 .power_restore = mmc_sd_power_restore,
+1 -1
include/linux/mmc/host.h
··· 239 239 #define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */ 240 240 #define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */ 241 241 #define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */ 242 - 242 + #define MMC_CAP_AGGRESSIVE_PM (1 << 7) /* Suspend (e)MMC/SD at idle */ 243 243 #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ 244 244 #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ 245 245 #define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */