[PATCH v2] mmc: core: Optimize polling delay in __mmc_poll_for_busy()

From: 李晓洁 (Xiaojie Li/13233)

Date: Mon Sep 21 2026 - 04:33:07 EST


>I think the CMD1-specific branch can be avoided altogether. The reason CMD1's tail latency is high is that __mmc_poll_for_busy() limits udelay to a maximum of 32768 and, more importantly, the sleep upper bound is udelay * 2.

>Would it be possible to parameterize the maximum delay instead? E.g.

> int __mmc_poll_for_busy(host, period_us, udelay_max_us, timeout_ms, cb, cb_data)

Hi shawn,
The __mmc_poll_for_busy function is invoked, either directly or indirectly, in numerous locations throughout the codebase.
That's why I used if (busy_cb == __mmc_send_op_cond_cb) to check for the special CMD1 handling.
As mentioned in my previous email, passing it directly as a function parameter would require modifying quite a few places.
The call sites identified so far are listed below:
(1)mmc_ops.c
(1.1) 238 err = __mmc_poll_for_busy(host, MMC_OP_COND_PERIOD_US, in mmc_send_op_cond()
(1.2)555 return __mmc_poll_for_busy(host, 0, timeout_ms, &mmc_busy_cb, &cb_data); in mmc_poll_for_busy()
(1.3)641 err = mmc_poll_for_busy(card, timeout_ms, retry_crc_err, MMC_BUSY_CMD6); in __mmc_switch()
(1.4)889 return mmc_poll_for_busy(card, busy_timeout_ms, false, MMC_BUSY_HPI); in mmc_send_hpi_cmd()
(2)block.c
(2.1)649 err = __mmc_poll_for_busy(card->host, 0, busy_timeout_ms, in __mmc_blk_ioctl_cmd()
(2.2)err = __mmc_poll_for_busy(card->host, 0, MMC_BLK_TIMEOUT_MS, in mmc_blk_card_busy()
(2.3)1746 err = mmc_poll_for_busy(card, timeout, false, MMC_BUSY_IO); in mmc_blk_fix_state()
(3)sd.c
(3.1)1711 err = __mmc_poll_for_busy(card->host, 0, SD_POWEROFF_NOTIFY_TIMEOUT_MS, in sd_poweroff_notify()
(3.2)1358 err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false, in sd_flush_cache()
(3.3)1404 err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false, in sd_enable_cache()
(3.4)1704 err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false, in sd_poweroff_notify()
(4)mmc.c
(4.1)2011 err = __mmc_poll_for_busy(host, 0, timeout_ms, &mmc_sleep_busy_cb, host); in mmc_sleep()
(5)core.c
(5.1)556 mmc_poll_for_busy(host->card, MMC_CQE_RECOVERY_TIMEOUT, true, MMC_BUSY_IO); in mmc_cqe_recovery()
(5.2)1701 err = mmc_poll_for_busy(card, busy_timeout, false, MMC_BUSY_ERASE); in mmc_do_erase()


> and limit both the backoff step and the sleep upper bound to
> udelay_max_us:

> unsigned int sleep_max = min(udelay * 2, udelay_max_us);
> usleep_range(min(udelay, udelay_max_us), sleep_max);

I'm not entirely sure about your suggested changes here. Could you provide more detailed modifications?

> Then mmc_send_op_cond() passes its own maximum delay (8ms), while all other callers keep passing 32768 so their behaviour is unchanged. That is two lines of code, no busy_cb pointer comparison, and the tail bound
> (8ms) is actually tighter than the linear +2ms schedule (10ms).

>Could you try to see if the linear step is still needed once the sleep upper bound is limited to the maximum delay?

Do you mean that I should verify this by changing the original:
usleep_range(udelay, udelay * 2);
if (udelay < udelay_max)
udelay *= 2;
to:
usleep_range(min(udelay, udelay_max_us), sleep_max);?

Best regards,
Xiaojie.Li
-----邮件原件-----
发件人: Shawn Lin <shawn.lin@xxxxxxxxx>
发送时间: 2026年9月21日 15:53
收件人: 李晓洁 (Xiaojie Li/13233) <xiaojie.li2@xxxxxxxxxx>
抄送: shawn.lin@xxxxxxxxx; Ulf Hansson <ulfh@xxxxxxxxxx>; linux-mmc@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; 陈文超 (Wenchao Chen) <Wenchao.Chen@xxxxxxxxxx>; 张如泉 (Rain Zhang) <Rain.Zhang@xxxxxxxxxx>; 唐月林 (Yuelin Tang) <yuelin.tang@xxxxxxxxxx>; cixi.geng@xxxxxxxxx; Ulf Hansson <ulf.hansson@xxxxxxxxxxxxxxxx>
主题: Re: [PATCH v2] mmc: core: Optimize polling delay in __mmc_poll_for_busy()


注意: 这封邮件来自于外部。除非你确定邮件内容安全,否则不要点击任何链接和附件。
CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.



On 2026/09/20 Sun 13:40, 李晓洁 (Xiaojie Li/13233) wrote:
>> No, that's the whole point. We don't want open coded polling loops,
>> it's just a nightmare to maintain. Please try to extend the existing
>> __mmc_poll_for_busy() instead.
>
> Hi Uffe,
>
> Following your suggestion to extend __mmc_poll_for_busy() instead of using open-coded polling loops, here is the proposed optimization.
>
> In our actual testing, we found that setting udelay_max = 8000 (8ms) is more time-efficient than udelay_max = 10000 (10ms).
> For CMD1 (SEND_OP_COND), the polling intervals are 4ms, 6ms, and 8ms, capped at a maximum of 8ms.
> Attached are the recorded per-boot phase latencies for udelay_max=8000 (8ms) and udelay_max=10000 (10ms), with timestamps in seconds.
> Please let me know if you cannot open the attachment, and I will resend it.
>
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c

I think the CMD1-specific branch can be avoided altogether. The reason CMD1's tail latency is high is that __mmc_poll_for_busy() limits udelay to a maximum of 32768 and, more importantly, the sleep upper bound is udelay * 2.

Would it be possible to parameterize the maximum delay instead? E.g.

int __mmc_poll_for_busy(host, period_us, udelay_max_us, timeout_ms, cb, cb_data)

and limit both the backoff step and the sleep upper bound to
udelay_max_us:

unsigned int sleep_max = min(udelay * 2, udelay_max_us);
usleep_range(min(udelay, udelay_max_us), sleep_max);

Then mmc_send_op_cond() passes its own maximum delay (8ms), while all other callers keep passing 32768 so their behaviour is unchanged. That is two lines of code, no busy_cb pointer comparison, and the tail bound
(8ms) is actually tighter than the linear +2ms schedule (10ms).

Could you try to see if the linear step is still needed once the sleep upper bound is limited to the maximum delay?


> index a952cc8..9c4762c 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -539,9 +539,23 @@
>
> /* Throttle the polling rate to avoid hogging the CPU. */
> if (busy) {
> - usleep_range(udelay, udelay * 2);
> - if (udelay < udelay_max)
> - udelay *= 2;
> + /*
> + * Special delay handling is required for mmc_send_op_cond;
> + * otherwise, for slower memory particles, the time required to
> + * wait for the status change will increase.
> + */
> + if (busy_cb == __mmc_send_op_cond_cb) {
> + udelay_max = 8000;
> + usleep_range(udelay, udelay + 2000);
> + if (udelay < udelay_max)
> + udelay += 2000;
> + else
> + udelay = udelay_max;
> + } else {
> + usleep_range(udelay, udelay * 2);
> + if (udelay < udelay_max)
> + udelay *= 2;
> + }
> }
> } while (busy);
>
>
> Best regards,
> Xiaojie.Li
>
> -----邮件原件-----
> 发件人: Ulf Hansson <ulf.hansson@xxxxxxxxxxxxxxxx>
> 发送时间: 2026年9月11日 23:47
> 收件人: 李晓洁 (Xiaojie Li/13233) <xiaojie.li2@xxxxxxxxxx>
> 抄送: Ulf Hansson <ulfh@xxxxxxxxxx>; linux-mmc@xxxxxxxxxxxxxxx;
> linux-kernel@xxxxxxxxxxxxxxx; 陈文超 (Wenchao Chen)
> <Wenchao.Chen@xxxxxxxxxx>; 张如泉 (Rain Zhang) <Rain.Zhang@xxxxxxxxxx>;
> 唐月林 (Yuelin Tang) <yuelin.tang@xxxxxxxxxx>; cixi.geng@xxxxxxxxx
> 主题: Re: [PATCH] mmc: core: Modify the CMD1 transmission interval
>
>
> 注意: 这封邮件来自于外部。除非你确定邮件内容安全,否则不要点击任何链接和附件。
> CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.
>
>
>
> On Fri, Sep 11, 2026 at 4:45 AM 李晓洁 (Xiaojie Li/13233) <xiaojie.li2@xxxxxxxxxx> wrote:
>>
>> Hi Uffe:
>> Thank you for your reply.
>> However, I noticed that __mmc_poll_for_busy() and mmc_poll_for_busy() are invoked either directly or indirectly by many other functions within the MMC driver.
>> Modifying them directly could potentially introduce unintended side effects.
>>
>> Would it be acceptable to implement a dedicated function specifically for CMD1? We could create a CMD1-specific variant based on the existing __mmc_poll_for_busy().
>> This approach would significantly minimize the potential impact on the rest of the codebase.
>
> No, that's the whole point. We don't want open coded polling loops,
> it's just a nightmare to maintain. Please try to extend the existing
> __mmc_poll_for_busy() instead.
>
> And next time, please don't top post.
>
> [...]
>
> Kind regards
> Uffe