Message ID | 20210504161222.101536-6-ulf.hansson@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Initital support for new power/perf features for SD cards | expand |
On Tue, May 4, 2021 at 6:12 PM Ulf Hansson <ulf.hansson@linaro.org> wrote: > After the eMMC sleep command (CMD5) has been sent, the card start signals > busy on the DAT0 line, which can be monitored to understand when it's > allowed to proceed to power off the VCC regulator. > > When MMC_CAP_WAIT_WHILE_BUSY isn't supported by the host the DAT0 line > isn't being monitored for busy completion, but instead we are waiting a > fixed period of time. The time corresponds to the sleep timeout that is > specified in the EXT_CSD register of the eMMC card. This is many cases > suboptimal, as the timeout corresponds to the worst case scenario. > > To improve the situation add support for HW busy polling through the > ->card_busy() host ops, when the host supports this. > > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Yours, Linus Walleij
On 2021/5/5 0:12, Ulf Hansson wrote: > After the eMMC sleep command (CMD5) has been sent, the card start signals > busy on the DAT0 line, which can be monitored to understand when it's > allowed to proceed to power off the VCC regulator. > > When MMC_CAP_WAIT_WHILE_BUSY isn't supported by the host the DAT0 line > isn't being monitored for busy completion, but instead we are waiting a > fixed period of time. The time corresponds to the sleep timeout that is > specified in the EXT_CSD register of the eMMC card. This is many cases > suboptimal, as the timeout corresponds to the worst case scenario. > > To improve the situation add support for HW busy polling through the > ->card_busy() host ops, when the host supports this. Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com> > > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > --- > drivers/mmc/core/mmc.c | 25 ++++++++++++++++++++----- > 1 file changed, 20 insertions(+), 5 deletions(-) > > diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c > index 63a7bd0b239c..13074aa1f605 100644 > --- a/drivers/mmc/core/mmc.c > +++ b/drivers/mmc/core/mmc.c > @@ -1905,6 +1905,14 @@ static int mmc_can_sleep(struct mmc_card *card) > return card->ext_csd.rev >= 3; > } > > +static int mmc_sleep_busy_cb(void *cb_data, bool *busy) > +{ > + struct mmc_host *host = cb_data; > + > + *busy = host->ops->card_busy(host); > + return 0; > +} > + > static int mmc_sleep(struct mmc_host *host) > { > struct mmc_command cmd = {}; > @@ -1930,13 +1938,20 @@ static int mmc_sleep(struct mmc_host *host) > goto out_release; > > /* > - * If the host does not wait while the card signals busy, then we will > - * will have to wait the sleep/awake timeout. Note, we cannot use the > - * SEND_STATUS command to poll the status because that command (and most > - * others) is invalid while the card sleeps. > + * If the host does not wait while the card signals busy, then we can > + * try to poll, but only if the host supports HW polling, as the > + * SEND_STATUS cmd is not allowed. If we can't poll, then we simply need > + * to wait the sleep/awake timeout. > */ > - if (!use_r1b_resp || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) > + if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp) > + goto out_release; > + > + if (!host->ops->card_busy) { > mmc_delay(timeout_ms); > + goto out_release; > + } > + > + err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host); > > out_release: > mmc_retune_release(host); >
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 63a7bd0b239c..13074aa1f605 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1905,6 +1905,14 @@ static int mmc_can_sleep(struct mmc_card *card) return card->ext_csd.rev >= 3; } +static int mmc_sleep_busy_cb(void *cb_data, bool *busy) +{ + struct mmc_host *host = cb_data; + + *busy = host->ops->card_busy(host); + return 0; +} + static int mmc_sleep(struct mmc_host *host) { struct mmc_command cmd = {}; @@ -1930,13 +1938,20 @@ static int mmc_sleep(struct mmc_host *host) goto out_release; /* - * If the host does not wait while the card signals busy, then we will - * will have to wait the sleep/awake timeout. Note, we cannot use the - * SEND_STATUS command to poll the status because that command (and most - * others) is invalid while the card sleeps. + * If the host does not wait while the card signals busy, then we can + * try to poll, but only if the host supports HW polling, as the + * SEND_STATUS cmd is not allowed. If we can't poll, then we simply need + * to wait the sleep/awake timeout. */ - if (!use_r1b_resp || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) + if (host->caps & MMC_CAP_WAIT_WHILE_BUSY && use_r1b_resp) + goto out_release; + + if (!host->ops->card_busy) { mmc_delay(timeout_ms); + goto out_release; + } + + err = __mmc_poll_for_busy(card, timeout_ms, &mmc_sleep_busy_cb, host); out_release: mmc_retune_release(host);
After the eMMC sleep command (CMD5) has been sent, the card start signals busy on the DAT0 line, which can be monitored to understand when it's allowed to proceed to power off the VCC regulator. When MMC_CAP_WAIT_WHILE_BUSY isn't supported by the host the DAT0 line isn't being monitored for busy completion, but instead we are waiting a fixed period of time. The time corresponds to the sleep timeout that is specified in the EXT_CSD register of the eMMC card. This is many cases suboptimal, as the timeout corresponds to the worst case scenario. To improve the situation add support for HW busy polling through the ->card_busy() host ops, when the host supports this. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> --- drivers/mmc/core/mmc.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)