mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Adrian Hunter <adrian.hunter@intel.com>
To: Changhuang Liang <changhuang.liang@starfivetech.com>,
	Asutosh Das <quic_asutoshd@quicinc.com>,
	Ritesh Harjani <ritesh.list@gmail.com>,
	"Ulf Hansson" <ulfh@kernel.org>,
	Shawn Lin <shawn.lin@rock-chips.com>
Cc: <linux-mmc@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 1/2] mmc: cqhci: Add support for setting command idle time in nanoseconds
Date: Thu, 5 Nov 2026 09:27:09 +0200	[thread overview]
Message-ID: <2e57a04a-71d6-416d-a49a-c7d78318ff79@intel.com> (raw)
In-Reply-To: <20261104112657.110536-2-changhuang.liang@starfivetech.com>

On 04/11/2026 13:26, Changhuang Liang wrote:
> Add a helper that derives the internal timer clock frequency (ITCF) of
> the CQE from the ITCFMUL and ITCFVAL fields of the CQHCI capabilities
> register, and export cqhci_set_cmd_idle_time() to let host drivers
> program the Send Status Command Idle Timer (CIT) in CQHCI_SSC1 using a
> value in nanoseconds.
> 
> The CIT defines how long the bus has to be idle, in internal timer clock
> cycles, before the CQE issues CMD13 to poll the Queue Status Register.
> Its reset value is controller specific and can be far from optimal, so
> host drivers may need to tune it for their platform. Doing the
> conversion in the core avoids every host driver re-implementing the
> ITCFMUL/ITCFVAL decoding.

Should probably have asked this before, but why calculate it at
runtime?  If you know the hardware, then you already know what
the value is going to be?

> 
> The requested time is rounded up to whole clock cycles so that the
> programmed idle time is never shorter than requested. The helper returns
> -EOPNOTSUPP when the controller does not report a usable ITCF and
> -ERANGE when the result does not fit the 16-bit CIT field, so callers
> can report the failure instead of silently running with the reset
> default.
> 
> Record the cit value in cqhci_set_cmd_idle_time(), and if cit is non-zero,
> program it into the register on every call to __cqhci_enable().
> 
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> ---
>  drivers/mmc/host/cqhci-core.c | 64 +++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/cqhci.h      |  8 +++++
>  2 files changed, 72 insertions(+)
> 
> diff --git a/drivers/mmc/host/cqhci-core.c b/drivers/mmc/host/cqhci-core.c
> index a466cd88b043..bfa5d8b79145 100644
> --- a/drivers/mmc/host/cqhci-core.c
> +++ b/drivers/mmc/host/cqhci-core.c
> @@ -12,6 +12,7 @@
>  #include <linux/scatterlist.h>
>  #include <linux/platform_device.h>
>  #include <linux/ktime.h>
> +#include <linux/units.h>
>  
>  #include <linux/mmc/mmc.h>
>  #include <linux/mmc/host.h>
> @@ -279,6 +280,14 @@ static void __cqhci_enable(struct cqhci_host *cq_host)
>  	cqhci_writel(cq_host, upper_32_bits(cq_host->desc_dma_base),
>  		     CQHCI_TDLBAU);
>  
> +	if (cq_host->cit) {
> +		u32 ssc1 = cqhci_readl(cq_host, CQHCI_SSC1);
> +
> +		ssc1 &= ~CQHCI_SSC1_CIT_MASK;
> +		ssc1 |= FIELD_PREP(CQHCI_SSC1_CIT_MASK, cq_host->cit);
> +		cqhci_writel(cq_host, ssc1, CQHCI_SSC1);
> +	}
> +
>  	cqhci_writel(cq_host, cq_host->rca, CQHCI_SSC2);
>  
>  	cqhci_set_irqs(cq_host, 0);
> @@ -1163,6 +1172,59 @@ struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev)
>  }
>  EXPORT_SYMBOL(cqhci_pltfm_init);
>  
> +static u64 cqhci_itcfmul_to_hz(u32 itcfmul)
> +{
> +	/* CQHCI_CAP.ITCFMUL: 0 = 1 kHz, 1 = 10 kHz, ..., 4 = 10 MHz, others reserved */
> +	if (itcfmul > 4)
> +		return 0;
> +
> +	return HZ_PER_KHZ * int_pow(10, itcfmul);
> +}
> +
> +static void cqhci_itcf_init(struct cqhci_host *cq_host)
> +{
> +	u32 cap = cqhci_readl(cq_host, CQHCI_CAP);
> +	u64 itcf;
> +
> +	itcf = cqhci_itcfmul_to_hz(CQHCI_ITCFMUL(cap)) * CQHCI_ITCFVAL(cap);
> +	if (!itcf || itcf > U32_MAX) {
> +		pr_debug("%s: cqhci: internal timer clock frequency not available (CAP 0x%08x)\n",
> +			 mmc_hostname(cq_host->mmc), cap);
> +		return;
> +	}
> +
> +	cq_host->itcf_hz = itcf;
> +}
> +
> +/**
> + * cqhci_set_cmd_idle_time - program the Send Status Command Idle Timer (CIT)
> + * @cq_host: CQHCI host
> + * @ns: idle time in nanoseconds
> + *
> + * Set the number of internal timer clock cycles the CQE waits on an idle bus
> + * before issuing CMD13 to poll the Queue Status Register. The cycle count is
> + * rounded up so that the resulting idle time is never shorter than @ns.
> + *
> + * Return: 0 on success, -EOPNOTSUPP if the controller does not report its
> + * internal timer clock frequency, or -ERANGE if @ns does not fit the CIT field.
> + */
> +int cqhci_set_cmd_idle_time(struct cqhci_host *cq_host, u32 ns)
> +{
> +	u64 cit;
> +
> +	if (!cq_host->itcf_hz)
> +		return -EOPNOTSUPP;
> +
> +	cit = DIV_ROUND_UP_ULL((u64)cq_host->itcf_hz * ns, NSEC_PER_SEC);
> +	if (!cit || cit > FIELD_MAX(CQHCI_SSC1_CIT_MASK))
> +		return -ERANGE;
> +
> +	cq_host->cit = cit;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(cqhci_set_cmd_idle_time);
> +
>  static unsigned int cqhci_ver_major(struct cqhci_host *cq_host)
>  {
>  	return CQHCI_VER_MAJOR(cqhci_readl(cq_host, CQHCI_VER));
> @@ -1207,6 +1269,8 @@ int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc,
>  		goto out_err;
>  	}
>  
> +	cqhci_itcf_init(cq_host);
> +
>  	spin_lock_init(&cq_host->lock);
>  
>  	init_completion(&cq_host->halt_comp);
> diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h
> index 8fbbc48c3f85..e6840a8f4798 100644
> --- a/drivers/mmc/host/cqhci.h
> +++ b/drivers/mmc/host/cqhci.h
> @@ -26,6 +26,8 @@
>  #define CQHCI_CAP_CS			0x10000000 /* Crypto Support */
>  #define CQHCI_CAP_ITCFMUL		GENMASK(15, 12)
>  #define CQHCI_ITCFMUL(x)		FIELD_GET(CQHCI_CAP_ITCFMUL, (x))
> +#define CQHCI_CAP_ITCFVAL		GENMASK(9, 0)
> +#define CQHCI_ITCFVAL(x)		FIELD_GET(CQHCI_CAP_ITCFVAL, (x))
>  
>  /* configuration */
>  #define CQHCI_CFG			0x08
> @@ -234,6 +236,11 @@ struct cqhci_host {
>  	int num_slots;
>  	int qcnt;
>  
> +	/* Internal Timer Clock Frequency (Hz), 0 if not reported by CQHCI_CAP */
> +	u32 itcf_hz;
> +	/* Send Status Command Idle Timer in ITCF cycles, 0 keeps the default */
> +	u16 cit;
> +
>  	u32 dcmd_slot;
>  	u32 caps;
>  #define CQHCI_TASK_DESC_SZ_128		0x1
> @@ -318,6 +325,7 @@ struct platform_device;
>  irqreturn_t cqhci_irq(struct mmc_host *mmc, int cmd_error, int data_error);
>  int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64);
>  struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev);
> +int cqhci_set_cmd_idle_time(struct cqhci_host *cq_host, u32 ns);
>  int cqhci_deactivate(struct mmc_host *mmc);
>  void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, bool dma64);
>  static inline int cqhci_suspend(struct mmc_host *mmc)


  reply	other threads:[~2026-11-05  7:27 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04 11:26 [PATCH v2 0/2] Improve eMMC performance for the StarFive JHB100 SoC Changhuang Liang
2026-11-04 11:26 ` [PATCH v2 1/2] mmc: cqhci: Add support for setting command idle time in nanoseconds Changhuang Liang
2026-11-05  7:27   ` Adrian Hunter [this message]
2026-11-05 10:04     ` Changhuang Liang
2026-11-04 11:26 ` [PATCH v2 2/2] mmc: sdhci-of-dwcmshc: Set CQHCI command idle time for StarFive JHB100 Changhuang Liang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2e57a04a-71d6-416d-a49a-c7d78318ff79@intel.com \
    --to=adrian.hunter@intel.com \
    --cc=changhuang.liang@starfivetech.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=quic_asutoshd@quicinc.com \
    --cc=ritesh.list@gmail.com \
    --cc=shawn.lin@rock-chips.com \
    --cc=ulfh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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®