mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] mmc: core: Modify the CMD1 transmission interval
@ 2026-08-27  9:14 Xiaojie Li
  2026-09-10  7:10 ` 李晓洁 (Xiaojie Li/13233)
  2026-09-10 13:00 ` Ulf Hansson
  0 siblings, 2 replies; 6+ messages in thread
From: Xiaojie Li @ 2026-08-27  9:14 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, Xiaojie.Li2, Wenchao.Chen, Rain.Zhang,
	Yuelin.Tang, cixi.geng

The current code's maximum udelay value is set to
64ms. Since it uses usleep_range(udelay, udelay*2),
this results in a maximum wait time of 128ms between
two consecutive CMD1 commands. For lower-performance eMMC chips,
local testing shows that compared to the old code which used
mmc_delay(10), the total time required to wait for the busy
bit in the CMD1 response to change has increased by approximately
300ms, negatively impacting the overall eMMC initialization time.

Although the current code sends the CMD1 command fewer times than
the old version, the total waiting time is significantly longer.
To address this, it's proposed to modify the CMD1 sending interval
to follow a pattern like 4ms, 6ms, 8ms, 10ms, 10ms, etc., effectively
capping the longest single wait at 10ms. Local testing confirms that
this approach can bring the total time waiting for the busy state
change very close to the performance level of the old code.

The eMMC chip used for testing: manfid= 0x00009b, name= Y0S128, mdt= 2022-10
The eMMC part number is: YMEC8B0TE2A2C3

Signed-off-by: Xiaojie Li <xiaojie.li2@unisoc.com>
---
 drivers/mmc/core/mmc_ops.c | 85 ++++++++++++++++----------------------
 1 file changed, 36 insertions(+), 49 deletions(-)

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index a952cc8265af..3076666cf2ca 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -189,64 +189,51 @@ int mmc_go_idle(struct mmc_host *host)
 	return err;
 }
 
-static int __mmc_send_op_cond_cb(void *cb_data, bool *busy)
-{
-	struct mmc_op_cond_busy_data *data = cb_data;
-	struct mmc_host *host = data->host;
-	struct mmc_command *cmd = data->cmd;
-	u32 ocr = data->ocr;
-	int err = 0;
-
-	err = mmc_wait_for_cmd(host, cmd, 0);
-	if (err)
-		return err;
-
-	if (mmc_host_is_spi(host)) {
-		if (!(cmd->resp[0] & R1_SPI_IDLE)) {
-			*busy = false;
-			return 0;
-		}
-	} else {
-		if (cmd->resp[0] & MMC_CARD_BUSY) {
-			*busy = false;
-			return 0;
-		}
-	}
-
-	*busy = true;
-
-	/*
-	 * According to eMMC specification v5.1 section 6.4.3, we
-	 * should issue CMD1 repeatedly in the idle state until
-	 * the eMMC is ready. Otherwise some eMMC devices seem to enter
-	 * the inactive mode after mmc_init_card() issued CMD0 when
-	 * the eMMC device is busy.
-	 */
-	if (!ocr && !mmc_host_is_spi(host))
-		cmd->arg = cmd->resp[0] | BIT(30);
-
-	return 0;
-}
-
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
 	struct mmc_command cmd = {};
+	unsigned int udelay = MMC_OP_COND_PERIOD_US;
+	unsigned int udelay_max = 10000;
+	unsigned long timeout = jiffies + msecs_to_jiffies(MMC_OP_COND_TIMEOUT_MS) + 1;
 	int err = 0;
-	struct mmc_op_cond_busy_data cb_data = {
-		.host = host,
-		.ocr = ocr,
-		.cmd = &cmd
-	};
 
 	cmd.opcode = MMC_SEND_OP_COND;
 	cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
 
-	err = __mmc_poll_for_busy(host, MMC_OP_COND_PERIOD_US,
-				  MMC_OP_COND_TIMEOUT_MS,
-				  &__mmc_send_op_cond_cb, &cb_data);
-	if (err)
-		return err;
+	while (!time_after(jiffies, timeout)) {
+		err = mmc_wait_for_cmd(host, &cmd, 0);
+		if (err)
+			break;
+
+		if (mmc_host_is_spi(host)) {
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else {
+			if (cmd.resp[0] & MMC_CARD_BUSY)
+				break;
+		}
+
+		/*
+		 * According to eMMC specification v5.1 section 6.4.3, we
+		 * should issue CMD1 repeatedly in the idle state until
+		 * the eMMC is ready. Otherwise some eMMC devices seem to enter
+		 * the inactive mode after mmc_init_card() issued CMD0 when
+		 * the eMMC device is busy.
+		 */
+		if (!ocr && !mmc_host_is_spi(host))
+			cmd.arg = cmd.resp[0] | BIT(30);
+
+		usleep_range(udelay, udelay + 1000);
+
+		if (udelay < udelay_max)
+			udelay += 2000;
+		else
+			udelay = udelay_max;
+	}
+
+	if (time_after(jiffies, timeout))
+		err = -ETIMEDOUT;
 
 	if (rocr && !mmc_host_is_spi(host))
 		*rocr = cmd.resp[0];
-- 
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] mmc: core: Modify the CMD1 transmission interval
  2026-08-27  9:14 [PATCH] mmc: core: Modify the CMD1 transmission interval Xiaojie Li
@ 2026-09-10  7:10 ` 李晓洁 (Xiaojie Li/13233)
  2026-09-10 13:00 ` Ulf Hansson
  1 sibling, 0 replies; 6+ messages in thread
From: 李晓洁 (Xiaojie Li/13233) @ 2026-09-10  7:10 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, 陈文超 (Wenchao Chen),
	张如泉 (Rain Zhang),
	唐月林 (Yuelin Tang),
	cixi.geng

Hi Ulf,

	Just following up on the patch below.

	Could you please let me know if there are any concerns or if further changes are needed?

Best regards,
Xiaojie.Li

-----邮件原件-----
发件人: 李晓洁 (Xiaojie Li/13233) <xiaojie.li2@unisoc.com> 
发送时间: 2026年8月27日 17:15
收件人: Ulf Hansson <ulfh@kernel.org>
抄送: linux-mmc@vger.kernel.org; linux-kernel@vger.kernel.org; 李晓洁 (Xiaojie Li/13233) <xiaojie.li2@unisoc.com>; 陈文超 (Wenchao Chen) <Wenchao.Chen@unisoc.com>; 张如泉 (Rain Zhang) <Rain.Zhang@unisoc.com>; 唐月林 (Yuelin Tang) <yuelin.tang@unisoc.com>; cixi.geng@linux.dev
主题: [PATCH] mmc: core: Modify the CMD1 transmission interval

The current code's maximum udelay value is set to 64ms. Since it uses usleep_range(udelay, udelay*2), this results in a maximum wait time of 128ms between two consecutive CMD1 commands. For lower-performance eMMC chips, local testing shows that compared to the old code which used mmc_delay(10), the total time required to wait for the busy bit in the CMD1 response to change has increased by approximately 300ms, negatively impacting the overall eMMC initialization time.

Although the current code sends the CMD1 command fewer times than the old version, the total waiting time is significantly longer.
To address this, it's proposed to modify the CMD1 sending interval to follow a pattern like 4ms, 6ms, 8ms, 10ms, 10ms, etc., effectively capping the longest single wait at 10ms. Local testing confirms that this approach can bring the total time waiting for the busy state change very close to the performance level of the old code.

The eMMC chip used for testing: manfid= 0x00009b, name= Y0S128, mdt= 2022-10 The eMMC part number is: YMEC8B0TE2A2C3

Signed-off-by: Xiaojie Li <xiaojie.li2@unisoc.com>
---
 drivers/mmc/core/mmc_ops.c | 85 ++++++++++++++++----------------------
 1 file changed, 36 insertions(+), 49 deletions(-)

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index a952cc8265af..3076666cf2ca 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -189,64 +189,51 @@ int mmc_go_idle(struct mmc_host *host)
 	return err;
 }
 
-static int __mmc_send_op_cond_cb(void *cb_data, bool *busy) -{
-	struct mmc_op_cond_busy_data *data = cb_data;
-	struct mmc_host *host = data->host;
-	struct mmc_command *cmd = data->cmd;
-	u32 ocr = data->ocr;
-	int err = 0;
-
-	err = mmc_wait_for_cmd(host, cmd, 0);
-	if (err)
-		return err;
-
-	if (mmc_host_is_spi(host)) {
-		if (!(cmd->resp[0] & R1_SPI_IDLE)) {
-			*busy = false;
-			return 0;
-		}
-	} else {
-		if (cmd->resp[0] & MMC_CARD_BUSY) {
-			*busy = false;
-			return 0;
-		}
-	}
-
-	*busy = true;
-
-	/*
-	 * According to eMMC specification v5.1 section 6.4.3, we
-	 * should issue CMD1 repeatedly in the idle state until
-	 * the eMMC is ready. Otherwise some eMMC devices seem to enter
-	 * the inactive mode after mmc_init_card() issued CMD0 when
-	 * the eMMC device is busy.
-	 */
-	if (!ocr && !mmc_host_is_spi(host))
-		cmd->arg = cmd->resp[0] | BIT(30);
-
-	return 0;
-}
-
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)  {
 	struct mmc_command cmd = {};
+	unsigned int udelay = MMC_OP_COND_PERIOD_US;
+	unsigned int udelay_max = 10000;
+	unsigned long timeout = jiffies + 
+msecs_to_jiffies(MMC_OP_COND_TIMEOUT_MS) + 1;
 	int err = 0;
-	struct mmc_op_cond_busy_data cb_data = {
-		.host = host,
-		.ocr = ocr,
-		.cmd = &cmd
-	};
 
 	cmd.opcode = MMC_SEND_OP_COND;
 	cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
 
-	err = __mmc_poll_for_busy(host, MMC_OP_COND_PERIOD_US,
-				  MMC_OP_COND_TIMEOUT_MS,
-				  &__mmc_send_op_cond_cb, &cb_data);
-	if (err)
-		return err;
+	while (!time_after(jiffies, timeout)) {
+		err = mmc_wait_for_cmd(host, &cmd, 0);
+		if (err)
+			break;
+
+		if (mmc_host_is_spi(host)) {
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else {
+			if (cmd.resp[0] & MMC_CARD_BUSY)
+				break;
+		}
+
+		/*
+		 * According to eMMC specification v5.1 section 6.4.3, we
+		 * should issue CMD1 repeatedly in the idle state until
+		 * the eMMC is ready. Otherwise some eMMC devices seem to enter
+		 * the inactive mode after mmc_init_card() issued CMD0 when
+		 * the eMMC device is busy.
+		 */
+		if (!ocr && !mmc_host_is_spi(host))
+			cmd.arg = cmd.resp[0] | BIT(30);
+
+		usleep_range(udelay, udelay + 1000);
+
+		if (udelay < udelay_max)
+			udelay += 2000;
+		else
+			udelay = udelay_max;
+	}
+
+	if (time_after(jiffies, timeout))
+		err = -ETIMEDOUT;
 
 	if (rocr && !mmc_host_is_spi(host))
 		*rocr = cmd.resp[0];
--
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] mmc: core: Modify the CMD1 transmission interval
  2026-08-27  9:14 [PATCH] mmc: core: Modify the CMD1 transmission interval Xiaojie Li
  2026-09-10  7:10 ` 李晓洁 (Xiaojie Li/13233)
@ 2026-09-10 13:00 ` Ulf Hansson
  2026-09-11  2:44   ` 答复: " 李晓洁 (Xiaojie Li/13233)
  1 sibling, 1 reply; 6+ messages in thread
From: Ulf Hansson @ 2026-09-10 13:00 UTC (permalink / raw)
  To: Xiaojie Li
  Cc: Ulf Hansson, linux-mmc, linux-kernel, Wenchao.Chen, Rain.Zhang,
	Yuelin.Tang, cixi.geng

On Thu, Aug 27, 2026 at 11:15 AM Xiaojie Li <xiaojie.li2@unisoc.com> wrote:
>
> The current code's maximum udelay value is set to
> 64ms. Since it uses usleep_range(udelay, udelay*2),
> this results in a maximum wait time of 128ms between
> two consecutive CMD1 commands. For lower-performance eMMC chips,
> local testing shows that compared to the old code which used
> mmc_delay(10), the total time required to wait for the busy
> bit in the CMD1 response to change has increased by approximately
> 300ms, negatively impacting the overall eMMC initialization time.

Okay, that's not good.

>
> Although the current code sends the CMD1 command fewer times than
> the old version, the total waiting time is significantly longer.
> To address this, it's proposed to modify the CMD1 sending interval
> to follow a pattern like 4ms, 6ms, 8ms, 10ms, 10ms, etc., effectively
> capping the longest single wait at 10ms. Local testing confirms that
> this approach can bring the total time waiting for the busy state
> change very close to the performance level of the old code.

The code you refer to has been changed and fixed several times. We
need to be careful to not break support for some other cards. Please
have a look at the below commit for better understanding.

e949dee3625e ("mmc: core: Fix busy polling for MMC_SEND_OP_COND again")
1760fdb6fe9f ("mmc: core: Restore (almost) the busy polling for
MMC_SEND_OP_COND")
76bfc7ccc2fa ("mmc: core: adjust polling interval for CMD1")

That said, let's try to figure out how to improve this. See some more
comments below.

>
> The eMMC chip used for testing: manfid= 0x00009b, name= Y0S128, mdt= 2022-10
> The eMMC part number is: YMEC8B0TE2A2C3
>
> Signed-off-by: Xiaojie Li <xiaojie.li2@unisoc.com>
> ---
>  drivers/mmc/core/mmc_ops.c | 85 ++++++++++++++++----------------------
>  1 file changed, 36 insertions(+), 49 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> index a952cc8265af..3076666cf2ca 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -189,64 +189,51 @@ int mmc_go_idle(struct mmc_host *host)
>         return err;
>  }
>
> -static int __mmc_send_op_cond_cb(void *cb_data, bool *busy)
> -{
> -       struct mmc_op_cond_busy_data *data = cb_data;
> -       struct mmc_host *host = data->host;
> -       struct mmc_command *cmd = data->cmd;
> -       u32 ocr = data->ocr;
> -       int err = 0;
> -
> -       err = mmc_wait_for_cmd(host, cmd, 0);
> -       if (err)
> -               return err;
> -
> -       if (mmc_host_is_spi(host)) {
> -               if (!(cmd->resp[0] & R1_SPI_IDLE)) {
> -                       *busy = false;
> -                       return 0;
> -               }
> -       } else {
> -               if (cmd->resp[0] & MMC_CARD_BUSY) {
> -                       *busy = false;
> -                       return 0;
> -               }
> -       }
> -
> -       *busy = true;
> -
> -       /*
> -        * According to eMMC specification v5.1 section 6.4.3, we
> -        * should issue CMD1 repeatedly in the idle state until
> -        * the eMMC is ready. Otherwise some eMMC devices seem to enter
> -        * the inactive mode after mmc_init_card() issued CMD0 when
> -        * the eMMC device is busy.
> -        */
> -       if (!ocr && !mmc_host_is_spi(host))
> -               cmd->arg = cmd->resp[0] | BIT(30);
> -
> -       return 0;
> -}
> -
>  int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
>  {
>         struct mmc_command cmd = {};
> +       unsigned int udelay = MMC_OP_COND_PERIOD_US;
> +       unsigned int udelay_max = 10000;
> +       unsigned long timeout = jiffies + msecs_to_jiffies(MMC_OP_COND_TIMEOUT_MS) + 1;
>         int err = 0;
> -       struct mmc_op_cond_busy_data cb_data = {
> -               .host = host,
> -               .ocr = ocr,
> -               .cmd = &cmd
> -       };
>
>         cmd.opcode = MMC_SEND_OP_COND;
>         cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
>         cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
>
> -       err = __mmc_poll_for_busy(host, MMC_OP_COND_PERIOD_US,
> -                                 MMC_OP_COND_TIMEOUT_MS,
> -                                 &__mmc_send_op_cond_cb, &cb_data);
> -       if (err)
> -               return err;
> +       while (!time_after(jiffies, timeout)) {
> +               err = mmc_wait_for_cmd(host, &cmd, 0);
> +               if (err)
> +                       break;
> +
> +               if (mmc_host_is_spi(host)) {
> +                       if (!(cmd.resp[0] & R1_SPI_IDLE))
> +                               break;
> +               } else {
> +                       if (cmd.resp[0] & MMC_CARD_BUSY)
> +                               break;
> +               }
> +
> +               /*
> +                * According to eMMC specification v5.1 section 6.4.3, we
> +                * should issue CMD1 repeatedly in the idle state until
> +                * the eMMC is ready. Otherwise some eMMC devices seem to enter
> +                * the inactive mode after mmc_init_card() issued CMD0 when
> +                * the eMMC device is busy.
> +                */
> +               if (!ocr && !mmc_host_is_spi(host))
> +                       cmd.arg = cmd.resp[0] | BIT(30);
> +
> +               usleep_range(udelay, udelay + 1000);
> +
> +               if (udelay < udelay_max)
> +                       udelay += 2000;
> +               else
> +                       udelay = udelay_max;
> +       }
> +
> +       if (time_after(jiffies, timeout))
> +               err = -ETIMEDOUT;

We really need to avoid open coding of busy loops like this, as it
becomes a nightmare to maintain for us.

We have moved to use __mmc_poll_for_busy() for this reason, so let's
instead try to extend it to fit better for MMC_SEND_OP_COND.

I guess the most simple approach would be to add another parameter to
__mmc_poll_for_busy(), to allow us to specify a maximum polling
period. Can you please explore that approach instead?

>
>         if (rocr && !mmc_host_is_spi(host))
>                 *rocr = cmd.resp[0];
> --
> 2.34.1
>

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 6+ messages in thread

* 答复: [PATCH] mmc: core: Modify the CMD1 transmission interval
  2026-09-10 13:00 ` Ulf Hansson
@ 2026-09-11  2:44   ` 李晓洁 (Xiaojie Li/13233)
  2026-09-11 15:46     ` Ulf Hansson
  0 siblings, 1 reply; 6+ messages in thread
From: 李晓洁 (Xiaojie Li/13233) @ 2026-09-11  2:44 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Ulf Hansson, linux-mmc, linux-kernel,
	陈文超 (Wenchao Chen),
	张如泉 (Rain Zhang),
	唐月林 (Yuelin Tang),
	cixi.geng

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.

The functions that call it are as follows:
(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()

Best regards,
Xiaojie.Li
-----邮件原件-----
发件人: Ulf Hansson <ulf.hansson@oss.qualcomm.com> 
发送时间: 2026年9月10日 21:00
收件人: 李晓洁 (Xiaojie Li/13233) <xiaojie.li2@unisoc.com>
抄送: Ulf Hansson <ulfh@kernel.org>; linux-mmc@vger.kernel.org; linux-kernel@vger.kernel.org; 陈文超 (Wenchao Chen) <Wenchao.Chen@unisoc.com>; 张如泉 (Rain Zhang) <Rain.Zhang@unisoc.com>; 唐月林 (Yuelin Tang) <yuelin.tang@unisoc.com>; cixi.geng@linux.dev
主题: 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 Thu, Aug 27, 2026 at 11:15 AM Xiaojie Li <xiaojie.li2@unisoc.com> wrote:
>
> The current code's maximum udelay value is set to 64ms. Since it uses 
> usleep_range(udelay, udelay*2), this results in a maximum wait time of 
> 128ms between two consecutive CMD1 commands. For lower-performance 
> eMMC chips, local testing shows that compared to the old code which 
> used mmc_delay(10), the total time required to wait for the busy bit 
> in the CMD1 response to change has increased by approximately 300ms, 
> negatively impacting the overall eMMC initialization time.

Okay, that's not good.

>
> Although the current code sends the CMD1 command fewer times than the 
> old version, the total waiting time is significantly longer.
> To address this, it's proposed to modify the CMD1 sending interval to 
> follow a pattern like 4ms, 6ms, 8ms, 10ms, 10ms, etc., effectively 
> capping the longest single wait at 10ms. Local testing confirms that 
> this approach can bring the total time waiting for the busy state 
> change very close to the performance level of the old code.

The code you refer to has been changed and fixed several times. We need to be careful to not break support for some other cards. Please have a look at the below commit for better understanding.

e949dee3625e ("mmc: core: Fix busy polling for MMC_SEND_OP_COND again") 1760fdb6fe9f ("mmc: core: Restore (almost) the busy polling for
MMC_SEND_OP_COND")
76bfc7ccc2fa ("mmc: core: adjust polling interval for CMD1")

That said, let's try to figure out how to improve this. See some more comments below.

>
> The eMMC chip used for testing: manfid= 0x00009b, name= Y0S128, mdt= 
> 2022-10 The eMMC part number is: YMEC8B0TE2A2C3
>
> Signed-off-by: Xiaojie Li <xiaojie.li2@unisoc.com>
> ---
>  drivers/mmc/core/mmc_ops.c | 85 
> ++++++++++++++++----------------------
>  1 file changed, 36 insertions(+), 49 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c 
> index a952cc8265af..3076666cf2ca 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -189,64 +189,51 @@ int mmc_go_idle(struct mmc_host *host)
>         return err;
>  }
>
> -static int __mmc_send_op_cond_cb(void *cb_data, bool *busy) -{
> -       struct mmc_op_cond_busy_data *data = cb_data;
> -       struct mmc_host *host = data->host;
> -       struct mmc_command *cmd = data->cmd;
> -       u32 ocr = data->ocr;
> -       int err = 0;
> -
> -       err = mmc_wait_for_cmd(host, cmd, 0);
> -       if (err)
> -               return err;
> -
> -       if (mmc_host_is_spi(host)) {
> -               if (!(cmd->resp[0] & R1_SPI_IDLE)) {
> -                       *busy = false;
> -                       return 0;
> -               }
> -       } else {
> -               if (cmd->resp[0] & MMC_CARD_BUSY) {
> -                       *busy = false;
> -                       return 0;
> -               }
> -       }
> -
> -       *busy = true;
> -
> -       /*
> -        * According to eMMC specification v5.1 section 6.4.3, we
> -        * should issue CMD1 repeatedly in the idle state until
> -        * the eMMC is ready. Otherwise some eMMC devices seem to enter
> -        * the inactive mode after mmc_init_card() issued CMD0 when
> -        * the eMMC device is busy.
> -        */
> -       if (!ocr && !mmc_host_is_spi(host))
> -               cmd->arg = cmd->resp[0] | BIT(30);
> -
> -       return 0;
> -}
> -
>  int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)  {
>         struct mmc_command cmd = {};
> +       unsigned int udelay = MMC_OP_COND_PERIOD_US;
> +       unsigned int udelay_max = 10000;
> +       unsigned long timeout = jiffies + 
> + msecs_to_jiffies(MMC_OP_COND_TIMEOUT_MS) + 1;
>         int err = 0;
> -       struct mmc_op_cond_busy_data cb_data = {
> -               .host = host,
> -               .ocr = ocr,
> -               .cmd = &cmd
> -       };
>
>         cmd.opcode = MMC_SEND_OP_COND;
>         cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
>         cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
>
> -       err = __mmc_poll_for_busy(host, MMC_OP_COND_PERIOD_US,
> -                                 MMC_OP_COND_TIMEOUT_MS,
> -                                 &__mmc_send_op_cond_cb, &cb_data);
> -       if (err)
> -               return err;
> +       while (!time_after(jiffies, timeout)) {
> +               err = mmc_wait_for_cmd(host, &cmd, 0);
> +               if (err)
> +                       break;
> +
> +               if (mmc_host_is_spi(host)) {
> +                       if (!(cmd.resp[0] & R1_SPI_IDLE))
> +                               break;
> +               } else {
> +                       if (cmd.resp[0] & MMC_CARD_BUSY)
> +                               break;
> +               }
> +
> +               /*
> +                * According to eMMC specification v5.1 section 6.4.3, we
> +                * should issue CMD1 repeatedly in the idle state until
> +                * the eMMC is ready. Otherwise some eMMC devices seem to enter
> +                * the inactive mode after mmc_init_card() issued CMD0 when
> +                * the eMMC device is busy.
> +                */
> +               if (!ocr && !mmc_host_is_spi(host))
> +                       cmd.arg = cmd.resp[0] | BIT(30);
> +
> +               usleep_range(udelay, udelay + 1000);
> +
> +               if (udelay < udelay_max)
> +                       udelay += 2000;
> +               else
> +                       udelay = udelay_max;
> +       }
> +
> +       if (time_after(jiffies, timeout))
> +               err = -ETIMEDOUT;

We really need to avoid open coding of busy loops like this, as it becomes a nightmare to maintain for us.

We have moved to use __mmc_poll_for_busy() for this reason, so let's instead try to extend it to fit better for MMC_SEND_OP_COND.

I guess the most simple approach would be to add another parameter to __mmc_poll_for_busy(), to allow us to specify a maximum polling period. Can you please explore that approach instead?

>
>         if (rocr && !mmc_host_is_spi(host))
>                 *rocr = cmd.resp[0];
> --
> 2.34.1
>

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] mmc: core: Modify the CMD1 transmission interval
  2026-09-11  2:44   ` 答复: " 李晓洁 (Xiaojie Li/13233)
@ 2026-09-11 15:46     ` Ulf Hansson
  2026-09-14  2:49       ` 李晓洁 (Xiaojie Li/13233)
  0 siblings, 1 reply; 6+ messages in thread
From: Ulf Hansson @ 2026-09-11 15:46 UTC (permalink / raw)
  To: 李晓洁 (Xiaojie Li/13233)
  Cc: Ulf Hansson, linux-mmc, linux-kernel,
	陈文超 (Wenchao Chen),
	张如泉 (Rain Zhang),
	唐月林 (Yuelin Tang),
	cixi.geng

On Fri, Sep 11, 2026 at 4:45 AM 李晓洁 (Xiaojie Li/13233)
<xiaojie.li2@unisoc.com> 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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] mmc: core: Modify the CMD1 transmission interval
  2026-09-11 15:46     ` Ulf Hansson
@ 2026-09-14  2:49       ` 李晓洁 (Xiaojie Li/13233)
  0 siblings, 0 replies; 6+ messages in thread
From: 李晓洁 (Xiaojie Li/13233) @ 2026-09-14  2:49 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Ulf Hansson, linux-mmc, linux-kernel,
	陈文超 (Wenchao Chen),
	张如泉 (Rain Zhang),
	唐月林 (Yuelin Tang),
	cixi.geng


> On Fri, Sep 11, 2026 at 4:45 AM 李晓洁 (Xiaojie Li/13233) <xiaojie.li2@unisoc.com> 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.

Understood. I will stop looking into a dedicated function and focus on extending the existing __mmc_poll_for_busy() to support CMD1's specific requirements.

I will follow up with an update once the code is debugged.

Thank you for your advice and reply.

Best regards,
Xiaojie.Li

-----邮件原件-----
发件人: Ulf Hansson <ulf.hansson@oss.qualcomm.com> 
发送时间: 2026年9月11日 23:47
收件人: 李晓洁 (Xiaojie Li/13233) <xiaojie.li2@unisoc.com>
抄送: Ulf Hansson <ulfh@kernel.org>; linux-mmc@vger.kernel.org; linux-kernel@vger.kernel.org; 陈文超 (Wenchao Chen) <Wenchao.Chen@unisoc.com>; 张如泉 (Rain Zhang) <Rain.Zhang@unisoc.com>; 唐月林 (Yuelin Tang) <yuelin.tang@unisoc.com>; cixi.geng@linux.dev
主题: 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@unisoc.com> 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

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-09-14  2:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-27  9:14 [PATCH] mmc: core: Modify the CMD1 transmission interval Xiaojie Li
2026-09-10  7:10 ` 李晓洁 (Xiaojie Li/13233)
2026-09-10 13:00 ` Ulf Hansson
2026-09-11  2:44   ` 答复: " 李晓洁 (Xiaojie Li/13233)
2026-09-11 15:46     ` Ulf Hansson
2026-09-14  2:49       ` 李晓洁 (Xiaojie Li/13233)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®