diff mbox series

[v3] mmc: mtk-sd: reduce CIT for better performance

Message ID 20230605060107.22044-1-wenbin.mei@mediatek.com (mailing list archive)
State New, archived
Headers show
Series [v3] mmc: mtk-sd: reduce CIT for better performance | expand

Commit Message

Wenbin Mei (梅文彬) June 5, 2023, 6:01 a.m. UTC
CQHCI_SSC1 indicates to CQE the polling period to use when using periodic
SEND_QUEUE_STATUS(CMD13) polling.
Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
frequency to get the actual time.
The default value 0x1000 that corresponds to 150us for MediaTek SoCs, let's
decrease it to 0x40 that corresponds to 2.35us, which can improve the
performance of some eMMC devices.

Signed-off-by: Wenbin Mei <wenbin.mei@mediatek.com>
---
 drivers/mmc/host/cqhci.h  |  1 +
 drivers/mmc/host/mtk-sd.c | 47 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

Comments

kernel test robot June 5, 2023, 8:43 a.m. UTC | #1
Hi Wenbin,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on ulf-hansson-mmc-mirror/next v6.4-rc5 next-20230605]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Wenbin-Mei/mmc-mtk-sd-reduce-CIT-for-better-performance/20230605-140238
base:   linus/master
patch link:    https://lore.kernel.org/r/20230605060107.22044-1-wenbin.mei%40mediatek.com
patch subject: [PATCH v3] mmc: mtk-sd: reduce CIT for better performance
config: powerpc-buildonly-randconfig-r006-20230605 (https://download.01.org/0day-ci/archive/20230605/202306051648.vkycL2Do-lkp@intel.com/config)
compiler: powerpc-linux-gcc (GCC) 12.3.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/225e46f420d48f7ad73253636a0553bd5f986435
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Wenbin-Mei/mmc-mtk-sd-reduce-CIT-for-better-performance/20230605-140238
        git checkout 225e46f420d48f7ad73253636a0553bd5f986435
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=powerpc olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=powerpc SHELL=/bin/bash drivers/mmc/host/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306051648.vkycL2Do-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from ./arch/powerpc/include/generated/asm/div64.h:1,
                    from include/linux/math.h:6,
                    from include/linux/math64.h:6,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/module.h:13,
                    from drivers/mmc/host/mtk-sd.c:7:
   drivers/mmc/host/mtk-sd.c: In function 'msdc_cqe_cit_cal':
   include/asm-generic/div64.h:222:35: warning: comparison of distinct pointer types lacks a cast
     222 |         (void)(((typeof((n)) *)0) == ((uint64_t *)0));  \
         |                                   ^~
   drivers/mmc/host/mtk-sd.c:2470:25: note: in expansion of macro 'do_div'
    2470 |                         do_div(hclk_freq, 1000);
         |                         ^~~~~~
   In file included from include/linux/build_bug.h:5,
                    from include/linux/container_of.h:5,
                    from include/linux/list.h:5,
                    from include/linux/module.h:12:
   include/asm-generic/div64.h:234:32: warning: right shift count >= width of type [-Wshift-count-overflow]
     234 |         } else if (likely(((n) >> 32) == 0)) {          \
         |                                ^~
   include/linux/compiler.h:76:45: note: in definition of macro 'likely'
      76 | # define likely(x)      __builtin_expect(!!(x), 1)
         |                                             ^
   drivers/mmc/host/mtk-sd.c:2470:25: note: in expansion of macro 'do_div'
    2470 |                         do_div(hclk_freq, 1000);
         |                         ^~~~~~
   include/asm-generic/div64.h:238:36: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
     238 |                 __rem = __div64_32(&(n), __base);       \
         |                                    ^~~~
         |                                    |
         |                                    u32 * {aka unsigned int *}
   drivers/mmc/host/mtk-sd.c:2470:25: note: in expansion of macro 'do_div'
    2470 |                         do_div(hclk_freq, 1000);
         |                         ^~~~~~
   include/asm-generic/div64.h:213:38: note: expected 'uint64_t *' {aka 'long long unsigned int *'} but argument is of type 'u32 *' {aka 'unsigned int *'}
     213 | extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
         |                            ~~~~~~~~~~^~~~~~~~
   include/asm-generic/div64.h:222:35: warning: comparison of distinct pointer types lacks a cast
     222 |         (void)(((typeof((n)) *)0) == ((uint64_t *)0));  \
         |                                   ^~
   drivers/mmc/host/mtk-sd.c:2473:25: note: in expansion of macro 'do_div'
    2473 |                         do_div(hclk_freq, 100);
         |                         ^~~~~~
   include/asm-generic/div64.h:234:32: warning: right shift count >= width of type [-Wshift-count-overflow]
     234 |         } else if (likely(((n) >> 32) == 0)) {          \
         |                                ^~
   include/linux/compiler.h:76:45: note: in definition of macro 'likely'
      76 | # define likely(x)      __builtin_expect(!!(x), 1)
         |                                             ^
   drivers/mmc/host/mtk-sd.c:2473:25: note: in expansion of macro 'do_div'
    2473 |                         do_div(hclk_freq, 100);
         |                         ^~~~~~
   include/asm-generic/div64.h:238:36: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
     238 |                 __rem = __div64_32(&(n), __base);       \
         |                                    ^~~~
         |                                    |
         |                                    u32 * {aka unsigned int *}
   drivers/mmc/host/mtk-sd.c:2473:25: note: in expansion of macro 'do_div'
    2473 |                         do_div(hclk_freq, 100);
         |                         ^~~~~~
   include/asm-generic/div64.h:213:38: note: expected 'uint64_t *' {aka 'long long unsigned int *'} but argument is of type 'u32 *' {aka 'unsigned int *'}
     213 | extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
         |                            ~~~~~~~~~~^~~~~~~~
   include/asm-generic/div64.h:222:35: warning: comparison of distinct pointer types lacks a cast
     222 |         (void)(((typeof((n)) *)0) == ((uint64_t *)0));  \
         |                                   ^~
   drivers/mmc/host/mtk-sd.c:2476:25: note: in expansion of macro 'do_div'
    2476 |                         do_div(hclk_freq, 10);
         |                         ^~~~~~
   include/asm-generic/div64.h:234:32: warning: right shift count >= width of type [-Wshift-count-overflow]
     234 |         } else if (likely(((n) >> 32) == 0)) {          \
         |                                ^~
   include/linux/compiler.h:76:45: note: in definition of macro 'likely'
      76 | # define likely(x)      __builtin_expect(!!(x), 1)
         |                                             ^
   drivers/mmc/host/mtk-sd.c:2476:25: note: in expansion of macro 'do_div'
    2476 |                         do_div(hclk_freq, 10);
         |                         ^~~~~~
   include/asm-generic/div64.h:238:36: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
     238 |                 __rem = __div64_32(&(n), __base);       \
         |                                    ^~~~
         |                                    |
         |                                    u32 * {aka unsigned int *}
   drivers/mmc/host/mtk-sd.c:2476:25: note: in expansion of macro 'do_div'
    2476 |                         do_div(hclk_freq, 10);
         |                         ^~~~~~
   include/asm-generic/div64.h:213:38: note: expected 'uint64_t *' {aka 'long long unsigned int *'} but argument is of type 'u32 *' {aka 'unsigned int *'}
     213 | extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
         |                            ~~~~~~~~~~^~~~~~~~
>> drivers/mmc/host/mtk-sd.c:2489:11: error: expected '}' before 'else'
    2489 |         } else {
         |           ^~~~
   cc1: some warnings being treated as errors


vim +2489 drivers/mmc/host/mtk-sd.c

  2453	
  2454	static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
  2455	{
  2456		struct mmc_host *mmc = mmc_from_priv(host);
  2457		struct cqhci_host *cq_host = mmc->cqe_private;
  2458		u8 itcfmul;
  2459		u32 hclk_freq;
  2460		u64 value;
  2461	
  2462		/* Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
  2463		 * frequency to get the actual time for CIT.
  2464		 */
  2465		if (host->h_clk) {
  2466			hclk_freq = clk_get_rate(host->h_clk);
  2467			itcfmul = CQHCI_CAP_ITCFMUL(cqhci_readl(cq_host, CQHCI_CAP));
  2468			switch (itcfmul) {
  2469			case 0x0:
  2470				do_div(hclk_freq, 1000);
  2471				break;
  2472			case 0x1:
  2473				do_div(hclk_freq, 100);
  2474				break;
  2475			case 0x2:
  2476				do_div(hclk_freq, 10);
  2477				break;
  2478			case 0x3:
  2479				break;
  2480			case 0x4:
  2481				hclk_freq = hclk_freq * 10;
  2482				break;
  2483			default:
  2484				host->cq_ssc1_time = 0x40;
  2485				return;
  2486			value = hclk_freq * timer_ns;
  2487			do_div(value, 1000000000ULL);
  2488			host->cq_ssc1_time = value;
> 2489		} else {
  2490			host->cq_ssc1_time = 0x40;
  2491		}
  2492	}
  2493
kernel test robot June 5, 2023, 8:43 a.m. UTC | #2
Hi Wenbin,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on ulf-hansson-mmc-mirror/next v6.4-rc5 next-20230605]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Wenbin-Mei/mmc-mtk-sd-reduce-CIT-for-better-performance/20230605-140238
base:   linus/master
patch link:    https://lore.kernel.org/r/20230605060107.22044-1-wenbin.mei%40mediatek.com
patch subject: [PATCH v3] mmc: mtk-sd: reduce CIT for better performance
config: x86_64-randconfig-a004-20230605 (https://download.01.org/0day-ci/archive/20230605/202306051634.orHLaQ9t-lkp@intel.com/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project.git 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/225e46f420d48f7ad73253636a0553bd5f986435
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Wenbin-Mei/mmc-mtk-sd-reduce-CIT-for-better-performance/20230605-140238
        git checkout 225e46f420d48f7ad73253636a0553bd5f986435
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang ~/bin/make.cross W=1 O=build_dir ARCH=x86_64 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang ~/bin/make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/mmc/host/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306051634.orHLaQ9t-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/mmc/host/mtk-sd.c:2489:4: error: expected expression
           } else {
             ^
>> drivers/mmc/host/mtk-sd.c:2495:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2513:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2539:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2549:1: error: function definition is not allowed here
   {
   ^
>> drivers/mmc/host/mtk-sd.c:2577:20: error: use of undeclared identifier 'msdc_cqe_enable'
           .enable         = msdc_cqe_enable,
                             ^
>> drivers/mmc/host/mtk-sd.c:2578:20: error: use of undeclared identifier 'msdc_cqe_disable'
           .disable        = msdc_cqe_disable,
                             ^
>> drivers/mmc/host/mtk-sd.c:2579:16: error: use of undeclared identifier 'msdc_cqe_pre_enable'; did you mean 'msdc_cqe_cit_cal'?
           .pre_enable = msdc_cqe_pre_enable,
                         ^~~~~~~~~~~~~~~~~~~
                         msdc_cqe_cit_cal
   drivers/mmc/host/mtk-sd.c:2454:13: note: 'msdc_cqe_cit_cal' declared here
   static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
               ^
>> drivers/mmc/host/mtk-sd.c:2580:18: error: use of undeclared identifier 'msdc_cqe_post_disable'
           .post_disable = msdc_cqe_post_disable,
                           ^
   drivers/mmc/host/mtk-sd.c:2585:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2616:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2668:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2892:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2920:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2947:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2978:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:2997:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:3016:1: error: function definition is not allowed here
   {
   ^
   drivers/mmc/host/mtk-sd.c:3041:1: error: function definition is not allowed here
   {
   ^
   fatal error: too many errors emitted, stopping now [-ferror-limit=]
   20 errors generated.


vim +2489 drivers/mmc/host/mtk-sd.c

  2453	
  2454	static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
  2455	{
  2456		struct mmc_host *mmc = mmc_from_priv(host);
  2457		struct cqhci_host *cq_host = mmc->cqe_private;
  2458		u8 itcfmul;
  2459		u32 hclk_freq;
  2460		u64 value;
  2461	
  2462		/* Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
  2463		 * frequency to get the actual time for CIT.
  2464		 */
  2465		if (host->h_clk) {
  2466			hclk_freq = clk_get_rate(host->h_clk);
  2467			itcfmul = CQHCI_CAP_ITCFMUL(cqhci_readl(cq_host, CQHCI_CAP));
  2468			switch (itcfmul) {
  2469			case 0x0:
  2470				do_div(hclk_freq, 1000);
  2471				break;
  2472			case 0x1:
  2473				do_div(hclk_freq, 100);
  2474				break;
  2475			case 0x2:
  2476				do_div(hclk_freq, 10);
  2477				break;
  2478			case 0x3:
  2479				break;
  2480			case 0x4:
  2481				hclk_freq = hclk_freq * 10;
  2482				break;
  2483			default:
  2484				host->cq_ssc1_time = 0x40;
  2485				return;
  2486			value = hclk_freq * timer_ns;
  2487			do_div(value, 1000000000ULL);
  2488			host->cq_ssc1_time = value;
> 2489		} else {
  2490			host->cq_ssc1_time = 0x40;
  2491		}
  2492	}
  2493	
  2494	static void msdc_cqe_enable(struct mmc_host *mmc)
> 2495	{
  2496		struct msdc_host *host = mmc_priv(mmc);
  2497		struct cqhci_host *cq_host = mmc->cqe_private;
  2498	
  2499		/* enable cmdq irq */
  2500		writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN);
  2501		/* enable busy check */
  2502		sdr_set_bits(host->base + MSDC_PATCH_BIT1, MSDC_PB1_BUSY_CHECK_SEL);
  2503		/* default write data / busy timeout 20s */
  2504		msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0);
  2505		/* default read data timeout 1s */
  2506		msdc_set_timeout(host, 1000000000ULL, 0);
  2507	
  2508		/* Set the send status command idle timer */
  2509		cqhci_writel(cq_host, host->cq_ssc1_time, CQHCI_SSC1);
  2510	}
  2511	
  2512	static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
  2513	{
  2514		struct msdc_host *host = mmc_priv(mmc);
  2515		unsigned int val = 0;
  2516	
  2517		/* disable cmdq irq */
  2518		sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INT_CMDQ);
  2519		/* disable busy check */
  2520		sdr_clr_bits(host->base + MSDC_PATCH_BIT1, MSDC_PB1_BUSY_CHECK_SEL);
  2521	
  2522		val = readl(host->base + MSDC_INT);
  2523		writel(val, host->base + MSDC_INT);
  2524	
  2525		if (recovery) {
  2526			sdr_set_field(host->base + MSDC_DMA_CTRL,
  2527				      MSDC_DMA_CTRL_STOP, 1);
  2528			if (WARN_ON(readl_poll_timeout(host->base + MSDC_DMA_CTRL, val,
  2529				!(val & MSDC_DMA_CTRL_STOP), 1, 3000)))
  2530				return;
  2531			if (WARN_ON(readl_poll_timeout(host->base + MSDC_DMA_CFG, val,
  2532				!(val & MSDC_DMA_CFG_STS), 1, 3000)))
  2533				return;
  2534			msdc_reset_hw(host);
  2535		}
  2536	}
  2537	
  2538	static void msdc_cqe_pre_enable(struct mmc_host *mmc)
  2539	{
  2540		struct cqhci_host *cq_host = mmc->cqe_private;
  2541		u32 reg;
  2542	
  2543		reg = cqhci_readl(cq_host, CQHCI_CFG);
  2544		reg |= CQHCI_ENABLE;
  2545		cqhci_writel(cq_host, reg, CQHCI_CFG);
  2546	}
  2547	
  2548	static void msdc_cqe_post_disable(struct mmc_host *mmc)
  2549	{
  2550		struct cqhci_host *cq_host = mmc->cqe_private;
  2551		u32 reg;
  2552	
  2553		reg = cqhci_readl(cq_host, CQHCI_CFG);
  2554		reg &= ~CQHCI_ENABLE;
  2555		cqhci_writel(cq_host, reg, CQHCI_CFG);
  2556	}
  2557	
  2558	static const struct mmc_host_ops mt_msdc_ops = {
  2559		.post_req = msdc_post_req,
  2560		.pre_req = msdc_pre_req,
  2561		.request = msdc_ops_request,
  2562		.set_ios = msdc_ops_set_ios,
  2563		.get_ro = mmc_gpio_get_ro,
  2564		.get_cd = msdc_get_cd,
  2565		.hs400_enhanced_strobe = msdc_hs400_enhanced_strobe,
  2566		.enable_sdio_irq = msdc_enable_sdio_irq,
  2567		.ack_sdio_irq = msdc_ack_sdio_irq,
  2568		.start_signal_voltage_switch = msdc_ops_switch_volt,
  2569		.card_busy = msdc_card_busy,
  2570		.execute_tuning = msdc_execute_tuning,
  2571		.prepare_hs400_tuning = msdc_prepare_hs400_tuning,
  2572		.execute_hs400_tuning = msdc_execute_hs400_tuning,
  2573		.card_hw_reset = msdc_hw_reset,
  2574	};
  2575	
  2576	static const struct cqhci_host_ops msdc_cmdq_ops = {
> 2577		.enable         = msdc_cqe_enable,
> 2578		.disable        = msdc_cqe_disable,
> 2579		.pre_enable = msdc_cqe_pre_enable,
> 2580		.post_disable = msdc_cqe_post_disable,
  2581	};
  2582
AngeloGioacchino Del Regno June 5, 2023, 8:48 a.m. UTC | #3
Il 05/06/23 08:01, Wenbin Mei ha scritto:
> CQHCI_SSC1 indicates to CQE the polling period to use when using periodic
> SEND_QUEUE_STATUS(CMD13) polling.
> Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
> frequency to get the actual time.
> The default value 0x1000 that corresponds to 150us for MediaTek SoCs, let's
> decrease it to 0x40 that corresponds to 2.35us, which can improve the
> performance of some eMMC devices.
> 
> Signed-off-by: Wenbin Mei <wenbin.mei@mediatek.com>

OK! That's almost good now. There's only one consideration here: if MediaTek
SoCs *require* msdc_hclk to calculate the CIT time, this means that this clock
is critical for CQHCI functionality.

If msdc_hclk is not present, CQHCI cannot work correctly... so you don't have
to cover the case in which there's no msdc_hclk clock: if that's not present,
either fail probing, or disable CQHCI.

> ---
>   drivers/mmc/host/cqhci.h  |  1 +
>   drivers/mmc/host/mtk-sd.c | 47 +++++++++++++++++++++++++++++++++++++++
>   2 files changed, 48 insertions(+)
> 
> diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h
> index ba9387ed90eb..292b89ebd978 100644
> --- a/drivers/mmc/host/cqhci.h
> +++ b/drivers/mmc/host/cqhci.h
> @@ -23,6 +23,7 @@
>   /* capabilities */
>   #define CQHCI_CAP			0x04
>   #define CQHCI_CAP_CS			0x10000000 /* Crypto Support */
> +#define CQHCI_CAP_ITCFMUL(x)		(((x) & GENMASK(15, 12)) >> 12)
>   
>   /* configuration */
>   #define CQHCI_CFG			0x08
> diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
> index edade0e54a0c..c221ef8a6992 100644
> --- a/drivers/mmc/host/mtk-sd.c
> +++ b/drivers/mmc/host/mtk-sd.c
> @@ -473,6 +473,7 @@ struct msdc_host {
>   	struct msdc_tune_para def_tune_para; /* default tune setting */
>   	struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
>   	struct cqhci_host *cq_host;
> +	u32 cq_ssc1_time;
>   };
>   
>   static const struct mtk_mmc_compatible mt2701_compat = {
> @@ -2450,9 +2451,50 @@ static void msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
>   	}
>   }
>   
> +static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)

static int msdc_cqe_cit_cal(....)

> +{
> +	struct mmc_host *mmc = mmc_from_priv(host);
> +	struct cqhci_host *cq_host = mmc->cqe_private;
> +	u8 itcfmul;
> +	u32 hclk_freq;

hclk_freq should be `unsigned long`, as that's what clk_get_rate() returns.

> +	u64 value;
> +
> +	/* Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
> +	 * frequency to get the actual time for CIT.
> +	 */

	/*
	 * On MediaTek SoCs the MSDC controller's CQE uses msdc_hclk as ITCFVAL
	 * so we multiply/divide the HCLK frequency by ITCFMUL to calculate the
	 * Send Status Command Idle Timer (CIT) value.
	 */
	if (!host->h_clk)
		return -EINVAL;

	hclk_freq = clk_get_rate(host->h_clk);
	itcfmul = CQHCI_CAP_ITFCMUL(cqhci_readl(cq_host, CQHCI_CAP));
	switch (itcfmul) {
		....
	}

> +	if (host->h_clk) {
> +		hclk_freq = clk_get_rate(host->h_clk);
> +		itcfmul = CQHCI_CAP_ITCFMUL(cqhci_readl(cq_host, CQHCI_CAP));
> +		switch (itcfmul) {
> +		case 0x0:
> +			do_div(hclk_freq, 1000);
> +			break;
> +		case 0x1:
> +			do_div(hclk_freq, 100);
> +			break;
> +		case 0x2:
> +			do_div(hclk_freq, 10);
> +			break;
> +		case 0x3:
> +			break;
> +		case 0x4:
> +			hclk_freq = hclk_freq * 10;
> +			break;
> +		default:
> +			host->cq_ssc1_time = 0x40;
> +			return;
> +		value = hclk_freq * timer_ns;
> +		do_div(value, 1000000000ULL);
> +		host->cq_ssc1_time = value;
> +	} else {
> +		host->cq_ssc1_time = 0x40;
> +	}
> +}
> +
>   static void msdc_cqe_enable(struct mmc_host *mmc)
>   {
>   	struct msdc_host *host = mmc_priv(mmc);
> +	struct cqhci_host *cq_host = mmc->cqe_private;
>   
>   	/* enable cmdq irq */
>   	writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN);
> @@ -2462,6 +2504,9 @@ static void msdc_cqe_enable(struct mmc_host *mmc)
>   	msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0);
>   	/* default read data timeout 1s */
>   	msdc_set_timeout(host, 1000000000ULL, 0);
> +
> +	/* Set the send status command idle timer */
> +	cqhci_writel(cq_host, host->cq_ssc1_time, CQHCI_SSC1);
>   }
>   
>   static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
> @@ -2803,6 +2848,8 @@ static int msdc_drv_probe(struct platform_device *pdev)
>   		/* cqhci 16bit length */
>   		/* 0 size, means 65536 so we don't have to -1 here */
>   		mmc->max_seg_size = 64 * 1024;
> +		/* Reduce CIT to 0x40 that corresponds to 2.35us */
> +		msdc_cqe_cit_cal(host, 2350);

		ret = msdc_cqe_cit_cal(...)
		if (ret)
			goto release;

^^^^ either fail probe, or use the eMMC/SD without CQHCI support.

Regards,
Angelo

>   	}
>   
>   	ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
kernel test robot June 5, 2023, 9:24 a.m. UTC | #4
Hi Wenbin,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on ulf-hansson-mmc-mirror/next v6.4-rc5 next-20230605]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Wenbin-Mei/mmc-mtk-sd-reduce-CIT-for-better-performance/20230605-140238
base:   linus/master
patch link:    https://lore.kernel.org/r/20230605060107.22044-1-wenbin.mei%40mediatek.com
patch subject: [PATCH v3] mmc: mtk-sd: reduce CIT for better performance
config: openrisc-randconfig-r035-20230605 (https://download.01.org/0day-ci/archive/20230605/202306051755.pR3fhYlB-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 12.3.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/225e46f420d48f7ad73253636a0553bd5f986435
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Wenbin-Mei/mmc-mtk-sd-reduce-CIT-for-better-performance/20230605-140238
        git checkout 225e46f420d48f7ad73253636a0553bd5f986435
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=openrisc olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=openrisc SHELL=/bin/bash drivers/mmc/host/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306051755.pR3fhYlB-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

   In file included from ./arch/openrisc/include/generated/asm/div64.h:1,
                    from include/linux/math.h:6,
                    from include/linux/math64.h:6,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/module.h:13,
                    from drivers/mmc/host/mtk-sd.c:7:
   drivers/mmc/host/mtk-sd.c: In function 'msdc_cqe_cit_cal':
>> include/asm-generic/div64.h:222:35: warning: comparison of distinct pointer types lacks a cast
     222 |         (void)(((typeof((n)) *)0) == ((uint64_t *)0));  \
         |                                   ^~
   drivers/mmc/host/mtk-sd.c:2470:25: note: in expansion of macro 'do_div'
    2470 |                         do_div(hclk_freq, 1000);
         |                         ^~~~~~
   In file included from include/linux/build_bug.h:5,
                    from include/linux/container_of.h:5,
                    from include/linux/list.h:5,
                    from include/linux/module.h:12:
>> include/asm-generic/div64.h:234:32: warning: right shift count >= width of type [-Wshift-count-overflow]
     234 |         } else if (likely(((n) >> 32) == 0)) {          \
         |                                ^~
   include/linux/compiler.h:76:45: note: in definition of macro 'likely'
      76 | # define likely(x)      __builtin_expect(!!(x), 1)
         |                                             ^
   drivers/mmc/host/mtk-sd.c:2470:25: note: in expansion of macro 'do_div'
    2470 |                         do_div(hclk_freq, 1000);
         |                         ^~~~~~
>> include/asm-generic/div64.h:238:36: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
     238 |                 __rem = __div64_32(&(n), __base);       \
         |                                    ^~~~
         |                                    |
         |                                    u32 * {aka unsigned int *}
   drivers/mmc/host/mtk-sd.c:2470:25: note: in expansion of macro 'do_div'
    2470 |                         do_div(hclk_freq, 1000);
         |                         ^~~~~~
   include/asm-generic/div64.h:213:38: note: expected 'uint64_t *' {aka 'long long unsigned int *'} but argument is of type 'u32 *' {aka 'unsigned int *'}
     213 | extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
         |                            ~~~~~~~~~~^~~~~~~~
>> include/asm-generic/div64.h:222:35: warning: comparison of distinct pointer types lacks a cast
     222 |         (void)(((typeof((n)) *)0) == ((uint64_t *)0));  \
         |                                   ^~
   drivers/mmc/host/mtk-sd.c:2473:25: note: in expansion of macro 'do_div'
    2473 |                         do_div(hclk_freq, 100);
         |                         ^~~~~~
>> include/asm-generic/div64.h:234:32: warning: right shift count >= width of type [-Wshift-count-overflow]
     234 |         } else if (likely(((n) >> 32) == 0)) {          \
         |                                ^~
   include/linux/compiler.h:76:45: note: in definition of macro 'likely'
      76 | # define likely(x)      __builtin_expect(!!(x), 1)
         |                                             ^
   drivers/mmc/host/mtk-sd.c:2473:25: note: in expansion of macro 'do_div'
    2473 |                         do_div(hclk_freq, 100);
         |                         ^~~~~~
>> include/asm-generic/div64.h:238:36: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
     238 |                 __rem = __div64_32(&(n), __base);       \
         |                                    ^~~~
         |                                    |
         |                                    u32 * {aka unsigned int *}
   drivers/mmc/host/mtk-sd.c:2473:25: note: in expansion of macro 'do_div'
    2473 |                         do_div(hclk_freq, 100);
         |                         ^~~~~~
   include/asm-generic/div64.h:213:38: note: expected 'uint64_t *' {aka 'long long unsigned int *'} but argument is of type 'u32 *' {aka 'unsigned int *'}
     213 | extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
         |                            ~~~~~~~~~~^~~~~~~~
>> include/asm-generic/div64.h:222:35: warning: comparison of distinct pointer types lacks a cast
     222 |         (void)(((typeof((n)) *)0) == ((uint64_t *)0));  \
         |                                   ^~
   drivers/mmc/host/mtk-sd.c:2476:25: note: in expansion of macro 'do_div'
    2476 |                         do_div(hclk_freq, 10);
         |                         ^~~~~~
>> include/asm-generic/div64.h:234:32: warning: right shift count >= width of type [-Wshift-count-overflow]
     234 |         } else if (likely(((n) >> 32) == 0)) {          \
         |                                ^~
   include/linux/compiler.h:76:45: note: in definition of macro 'likely'
      76 | # define likely(x)      __builtin_expect(!!(x), 1)
         |                                             ^
   drivers/mmc/host/mtk-sd.c:2476:25: note: in expansion of macro 'do_div'
    2476 |                         do_div(hclk_freq, 10);
         |                         ^~~~~~
>> include/asm-generic/div64.h:238:36: error: passing argument 1 of '__div64_32' from incompatible pointer type [-Werror=incompatible-pointer-types]
     238 |                 __rem = __div64_32(&(n), __base);       \
         |                                    ^~~~
         |                                    |
         |                                    u32 * {aka unsigned int *}
   drivers/mmc/host/mtk-sd.c:2476:25: note: in expansion of macro 'do_div'
    2476 |                         do_div(hclk_freq, 10);
         |                         ^~~~~~
   include/asm-generic/div64.h:213:38: note: expected 'uint64_t *' {aka 'long long unsigned int *'} but argument is of type 'u32 *' {aka 'unsigned int *'}
     213 | extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
         |                            ~~~~~~~~~~^~~~~~~~
>> drivers/mmc/host/mtk-sd.c:2489:11: error: expected '}' before 'else'
    2489 |         } else {
         |           ^~~~
   cc1: some warnings being treated as errors


vim +2489 drivers/mmc/host/mtk-sd.c

  2453	
  2454	static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
  2455	{
  2456		struct mmc_host *mmc = mmc_from_priv(host);
  2457		struct cqhci_host *cq_host = mmc->cqe_private;
  2458		u8 itcfmul;
  2459		u32 hclk_freq;
  2460		u64 value;
  2461	
  2462		/* Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
  2463		 * frequency to get the actual time for CIT.
  2464		 */
  2465		if (host->h_clk) {
  2466			hclk_freq = clk_get_rate(host->h_clk);
  2467			itcfmul = CQHCI_CAP_ITCFMUL(cqhci_readl(cq_host, CQHCI_CAP));
  2468			switch (itcfmul) {
  2469			case 0x0:
  2470				do_div(hclk_freq, 1000);
  2471				break;
  2472			case 0x1:
  2473				do_div(hclk_freq, 100);
  2474				break;
  2475			case 0x2:
  2476				do_div(hclk_freq, 10);
  2477				break;
  2478			case 0x3:
  2479				break;
  2480			case 0x4:
  2481				hclk_freq = hclk_freq * 10;
  2482				break;
  2483			default:
  2484				host->cq_ssc1_time = 0x40;
  2485				return;
  2486			value = hclk_freq * timer_ns;
  2487			do_div(value, 1000000000ULL);
  2488			host->cq_ssc1_time = value;
> 2489		} else {
  2490			host->cq_ssc1_time = 0x40;
  2491		}
  2492	}
  2493
Wenbin Mei (梅文彬) June 5, 2023, 9:42 a.m. UTC | #5
On Mon, 2023-06-05 at 10:48 +0200, AngeloGioacchino Del Regno wrote:
>  	 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>  Il 05/06/23 08:01, Wenbin Mei ha scritto:
> > CQHCI_SSC1 indicates to CQE the polling period to use when using
> periodic
> > SEND_QUEUE_STATUS(CMD13) polling.
> > Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
> > frequency to get the actual time.
> > The default value 0x1000 that corresponds to 150us for MediaTek
> SoCs, let's
> > decrease it to 0x40 that corresponds to 2.35us, which can improve
> the
> > performance of some eMMC devices.
> > 
> > Signed-off-by: Wenbin Mei <wenbin.mei@mediatek.com>
> 
> OK! That's almost good now. There's only one consideration here: if
> MediaTek
> SoCs *require* msdc_hclk to calculate the CIT time, this means that
> this clock
> is critical for CQHCI functionality.
> 
> If msdc_hclk is not present, CQHCI cannot work correctly... so you
> don't have
> to cover the case in which there's no msdc_hclk clock: if that's not
> present,
> either fail probing, or disable CQHCI.
That's right, i will remove the else case.

Begards,
Wenbin
> 
> > ---
> >   drivers/mmc/host/cqhci.h  |  1 +
> >   drivers/mmc/host/mtk-sd.c | 47
> +++++++++++++++++++++++++++++++++++++++
> >   2 files changed, 48 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h
> > index ba9387ed90eb..292b89ebd978 100644
> > --- a/drivers/mmc/host/cqhci.h
> > +++ b/drivers/mmc/host/cqhci.h
> > @@ -23,6 +23,7 @@
> >   /* capabilities */
> >   #define CQHCI_CAP0x04
> >   #define CQHCI_CAP_CS0x10000000 /* Crypto Support */
> > +#define CQHCI_CAP_ITCFMUL(x)(((x) & GENMASK(15, 12)) >> 12)
> >   
> >   /* configuration */
> >   #define CQHCI_CFG0x08
> > diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
> > index edade0e54a0c..c221ef8a6992 100644
> > --- a/drivers/mmc/host/mtk-sd.c
> > +++ b/drivers/mmc/host/mtk-sd.c
> > @@ -473,6 +473,7 @@ struct msdc_host {
> >   struct msdc_tune_para def_tune_para; /* default tune setting */
> >   struct msdc_tune_para saved_tune_para; /* tune result of
> CMD21/CMD19 */
> >   struct cqhci_host *cq_host;
> > +u32 cq_ssc1_time;
> >   };
> >   
> >   static const struct mtk_mmc_compatible mt2701_compat = {
> > @@ -2450,9 +2451,50 @@ static void
> msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
> >   }
> >   }
> >   
> > +static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
> 
> static int msdc_cqe_cit_cal(....)
> 
> > +{
> > +struct mmc_host *mmc = mmc_from_priv(host);
> > +struct cqhci_host *cq_host = mmc->cqe_private;
> > +u8 itcfmul;
> > +u32 hclk_freq;
> 
> hclk_freq should be `unsigned long`, as that's what clk_get_rate()
> returns.
> 
> > +u64 value;
> > +
> > +/* Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use
> hclk
> > + * frequency to get the actual time for CIT.
> > + */
> 
> /*
>  * On MediaTek SoCs the MSDC controller's CQE uses msdc_hclk as
> ITCFVAL
>  * so we multiply/divide the HCLK frequency by ITCFMUL to calculate
> the
>  * Send Status Command Idle Timer (CIT) value.
>  */
> if (!host->h_clk)
> return -EINVAL;
> 
> hclk_freq = clk_get_rate(host->h_clk);
> itcfmul = CQHCI_CAP_ITFCMUL(cqhci_readl(cq_host, CQHCI_CAP));
> switch (itcfmul) {
> ....
> }
> 
> > +if (host->h_clk) {
> > +hclk_freq = clk_get_rate(host->h_clk);
> > +itcfmul = CQHCI_CAP_ITCFMUL(cqhci_readl(cq_host, CQHCI_CAP));
> > +switch (itcfmul) {
> > +case 0x0:
> > +do_div(hclk_freq, 1000);
> > +break;
> > +case 0x1:
> > +do_div(hclk_freq, 100);
> > +break;
> > +case 0x2:
> > +do_div(hclk_freq, 10);
> > +break;
> > +case 0x3:
> > +break;
> > +case 0x4:
> > +hclk_freq = hclk_freq * 10;
> > +break;
> > +default:
> > +host->cq_ssc1_time = 0x40;
> > +return;
> > +value = hclk_freq * timer_ns;
> > +do_div(value, 1000000000ULL);
> > +host->cq_ssc1_time = value;
> > +} else {
> > +host->cq_ssc1_time = 0x40;
> > +}
> > +}
> > +
> >   static void msdc_cqe_enable(struct mmc_host *mmc)
> >   {
> >   struct msdc_host *host = mmc_priv(mmc);
> > +struct cqhci_host *cq_host = mmc->cqe_private;
> >   
> >   /* enable cmdq irq */
> >   writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN);
> > @@ -2462,6 +2504,9 @@ static void msdc_cqe_enable(struct mmc_host
> *mmc)
> >   msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0);
> >   /* default read data timeout 1s */
> >   msdc_set_timeout(host, 1000000000ULL, 0);
> > +
> > +/* Set the send status command idle timer */
> > +cqhci_writel(cq_host, host->cq_ssc1_time, CQHCI_SSC1);
> >   }
> >   
> >   static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
> > @@ -2803,6 +2848,8 @@ static int msdc_drv_probe(struct
> platform_device *pdev)
> >   /* cqhci 16bit length */
> >   /* 0 size, means 65536 so we don't have to -1 here */
> >   mmc->max_seg_size = 64 * 1024;
> > +/* Reduce CIT to 0x40 that corresponds to 2.35us */
> > +msdc_cqe_cit_cal(host, 2350);
> 
> ret = msdc_cqe_cit_cal(...)
> if (ret)
> goto release;
> 
> ^^^^ either fail probe, or use the eMMC/SD without CQHCI support.
> 
> Regards,
> Angelo
> 
> >   }
> >   
> >   ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
>
Wenbin Mei (梅文彬) June 6, 2023, 8:17 a.m. UTC | #6
On Mon, 2023-06-05 at 10:48 +0200, AngeloGioacchino Del Regno wrote:
>  	 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>  Il 05/06/23 08:01, Wenbin Mei ha scritto:
> > CQHCI_SSC1 indicates to CQE the polling period to use when using
> periodic
> > SEND_QUEUE_STATUS(CMD13) polling.
> > Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
> > frequency to get the actual time.
> > The default value 0x1000 that corresponds to 150us for MediaTek
> SoCs, let's
> > decrease it to 0x40 that corresponds to 2.35us, which can improve
> the
> > performance of some eMMC devices.
> > 
> > Signed-off-by: Wenbin Mei <wenbin.mei@mediatek.com>
> 
> OK! That's almost good now. There's only one consideration here: if
> MediaTek
> SoCs *require* msdc_hclk to calculate the CIT time, this means that
> this clock
> is critical for CQHCI functionality.
> 
> If msdc_hclk is not present, CQHCI cannot work correctly... so you
> don't have
> to cover the case in which there's no msdc_hclk clock: if that's not
> present,
> either fail probing, or disable CQHCI.
> 
> > ---
> >   drivers/mmc/host/cqhci.h  |  1 +
> >   drivers/mmc/host/mtk-sd.c | 47
> +++++++++++++++++++++++++++++++++++++++
> >   2 files changed, 48 insertions(+)
> > 
> > diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h
> > index ba9387ed90eb..292b89ebd978 100644
> > --- a/drivers/mmc/host/cqhci.h
> > +++ b/drivers/mmc/host/cqhci.h
> > @@ -23,6 +23,7 @@
> >   /* capabilities */
> >   #define CQHCI_CAP0x04
> >   #define CQHCI_CAP_CS0x10000000 /* Crypto Support */
> > +#define CQHCI_CAP_ITCFMUL(x)(((x) & GENMASK(15, 12)) >> 12)
> >   
> >   /* configuration */
> >   #define CQHCI_CFG0x08
> > diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
> > index edade0e54a0c..c221ef8a6992 100644
> > --- a/drivers/mmc/host/mtk-sd.c
> > +++ b/drivers/mmc/host/mtk-sd.c
> > @@ -473,6 +473,7 @@ struct msdc_host {
> >   struct msdc_tune_para def_tune_para; /* default tune setting */
> >   struct msdc_tune_para saved_tune_para; /* tune result of
> CMD21/CMD19 */
> >   struct cqhci_host *cq_host;
> > +u32 cq_ssc1_time;
> >   };
> >   
> >   static const struct mtk_mmc_compatible mt2701_compat = {
> > @@ -2450,9 +2451,50 @@ static void
> msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
> >   }
> >   }
> >   
> > +static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
> 
> static int msdc_cqe_cit_cal(....)
> 
Sorry, I missed this comment.
I think there is no need to return a value.
Becuase msdc_hclk is exist, and if not present, it will return earily.
Even if it goes to the default case in the switch flow, we will assign
a default value.
So I think it's better to return null, do you think it is okay?

> > +{
> > +struct mmc_host *mmc = mmc_from_priv(host);
> > +struct cqhci_host *cq_host = mmc->cqe_private;
> > +u8 itcfmul;
> > +u32 hclk_freq;
> 
> hclk_freq should be `unsigned long`, as that's what clk_get_rate()
> returns.
> 
I will change it in the v5 version.

> > +u64 value;
> > +
> > +/* Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use
> hclk
> > + * frequency to get the actual time for CIT.
> > + */
> 
> /*
>  * On MediaTek SoCs the MSDC controller's CQE uses msdc_hclk as
> ITCFVAL
>  * so we multiply/divide the HCLK frequency by ITCFMUL to calculate
> the
>  * Send Status Command Idle Timer (CIT) value.
>  */
I will change it in the v5 version.
> if (!host->h_clk)
> return -EINVAL;
> 
This change should be unnecessary, because it has been checked in
msdc_drv_probe() function.
> hclk_freq = clk_get_rate(host->h_clk);
> itcfmul = CQHCI_CAP_ITFCMUL(cqhci_readl(cq_host, CQHCI_CAP));
> switch (itcfmul) {
> ....
> }
> 
> > +if (host->h_clk) {
> > +hclk_freq = clk_get_rate(host->h_clk);
> > +itcfmul = CQHCI_CAP_ITCFMUL(cqhci_readl(cq_host, CQHCI_CAP));
> > +switch (itcfmul) {
> > +case 0x0:
> > +do_div(hclk_freq, 1000);
> > +break;
> > +case 0x1:
> > +do_div(hclk_freq, 100);
> > +break;
> > +case 0x2:
> > +do_div(hclk_freq, 10);
> > +break;
> > +case 0x3:
> > +break;
> > +case 0x4:
> > +hclk_freq = hclk_freq * 10;
> > +break;
> > +default:
> > +host->cq_ssc1_time = 0x40;
> > +return;
> > +value = hclk_freq * timer_ns;
> > +do_div(value, 1000000000ULL);
> > +host->cq_ssc1_time = value;
> > +} else {
> > +host->cq_ssc1_time = 0x40;
> > +}
> > +}
> > +
> >   static void msdc_cqe_enable(struct mmc_host *mmc)
> >   {
> >   struct msdc_host *host = mmc_priv(mmc);
> > +struct cqhci_host *cq_host = mmc->cqe_private;
> >   
> >   /* enable cmdq irq */
> >   writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN);
> > @@ -2462,6 +2504,9 @@ static void msdc_cqe_enable(struct mmc_host
> *mmc)
> >   msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0);
> >   /* default read data timeout 1s */
> >   msdc_set_timeout(host, 1000000000ULL, 0);
> > +
> > +/* Set the send status command idle timer */
> > +cqhci_writel(cq_host, host->cq_ssc1_time, CQHCI_SSC1);
> >   }
> >   
> >   static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
> > @@ -2803,6 +2848,8 @@ static int msdc_drv_probe(struct
> platform_device *pdev)
> >   /* cqhci 16bit length */
> >   /* 0 size, means 65536 so we don't have to -1 here */
> >   mmc->max_seg_size = 64 * 1024;
> > +/* Reduce CIT to 0x40 that corresponds to 2.35us */
> > +msdc_cqe_cit_cal(host, 2350);
> 
> ret = msdc_cqe_cit_cal(...)
> if (ret)
> goto release;
> 
> ^^^^ either fail probe, or use the eMMC/SD without CQHCI support.
> 
There is no need to return a value, so there will be no check here.
> Regards,
> Angelo
> 
> >   }
> >   
> >   ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
>
AngeloGioacchino Del Regno June 6, 2023, 8:59 a.m. UTC | #7
Il 06/06/23 10:17, Wenbin Mei (梅文彬) ha scritto:
> On Mon, 2023-06-05 at 10:48 +0200, AngeloGioacchino Del Regno wrote:
>>   	
>> External email : Please do not click links or open attachments until
>> you have verified the sender or the content.
>>   Il 05/06/23 08:01, Wenbin Mei ha scritto:
>>> CQHCI_SSC1 indicates to CQE the polling period to use when using
>> periodic
>>> SEND_QUEUE_STATUS(CMD13) polling.
>>> Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
>>> frequency to get the actual time.
>>> The default value 0x1000 that corresponds to 150us for MediaTek
>> SoCs, let's
>>> decrease it to 0x40 that corresponds to 2.35us, which can improve
>> the
>>> performance of some eMMC devices.
>>>
>>> Signed-off-by: Wenbin Mei <wenbin.mei@mediatek.com>
>>
>> OK! That's almost good now. There's only one consideration here: if
>> MediaTek
>> SoCs *require* msdc_hclk to calculate the CIT time, this means that
>> this clock
>> is critical for CQHCI functionality.
>>
>> If msdc_hclk is not present, CQHCI cannot work correctly... so you
>> don't have
>> to cover the case in which there's no msdc_hclk clock: if that's not
>> present,
>> either fail probing, or disable CQHCI.
>>
>>> ---
>>>    drivers/mmc/host/cqhci.h  |  1 +
>>>    drivers/mmc/host/mtk-sd.c | 47
>> +++++++++++++++++++++++++++++++++++++++
>>>    2 files changed, 48 insertions(+)
>>>
>>> diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h
>>> index ba9387ed90eb..292b89ebd978 100644
>>> --- a/drivers/mmc/host/cqhci.h
>>> +++ b/drivers/mmc/host/cqhci.h
>>> @@ -23,6 +23,7 @@
>>>    /* capabilities */
>>>    #define CQHCI_CAP0x04
>>>    #define CQHCI_CAP_CS0x10000000 /* Crypto Support */
>>> +#define CQHCI_CAP_ITCFMUL(x)(((x) & GENMASK(15, 12)) >> 12)
>>>    
>>>    /* configuration */
>>>    #define CQHCI_CFG0x08
>>> diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
>>> index edade0e54a0c..c221ef8a6992 100644
>>> --- a/drivers/mmc/host/mtk-sd.c
>>> +++ b/drivers/mmc/host/mtk-sd.c
>>> @@ -473,6 +473,7 @@ struct msdc_host {
>>>    struct msdc_tune_para def_tune_para; /* default tune setting */
>>>    struct msdc_tune_para saved_tune_para; /* tune result of
>> CMD21/CMD19 */
>>>    struct cqhci_host *cq_host;
>>> +u32 cq_ssc1_time;
>>>    };
>>>    
>>>    static const struct mtk_mmc_compatible mt2701_compat = {
>>> @@ -2450,9 +2451,50 @@ static void
>> msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
>>>    }
>>>    }
>>>    
>>> +static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
>>
>> static int msdc_cqe_cit_cal(....)
>>
> Sorry, I missed this comment.
> I think there is no need to return a value.
> Becuase msdc_hclk is exist, and if not present, it will return earily.
> Even if it goes to the default case in the switch flow, we will assign
> a default value.
> So I think it's better to return null, do you think it is okay?
> 

Yeah ignore this comment; I've noticed that HCLK is already mandatory, otherwise
the probe function will fail earlier anyway.

Thanks,
Angelo
diff mbox series

Patch

diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h
index ba9387ed90eb..292b89ebd978 100644
--- a/drivers/mmc/host/cqhci.h
+++ b/drivers/mmc/host/cqhci.h
@@ -23,6 +23,7 @@ 
 /* capabilities */
 #define CQHCI_CAP			0x04
 #define CQHCI_CAP_CS			0x10000000 /* Crypto Support */
+#define CQHCI_CAP_ITCFMUL(x)		(((x) & GENMASK(15, 12)) >> 12)
 
 /* configuration */
 #define CQHCI_CFG			0x08
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index edade0e54a0c..c221ef8a6992 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -473,6 +473,7 @@  struct msdc_host {
 	struct msdc_tune_para def_tune_para; /* default tune setting */
 	struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
 	struct cqhci_host *cq_host;
+	u32 cq_ssc1_time;
 };
 
 static const struct mtk_mmc_compatible mt2701_compat = {
@@ -2450,9 +2451,50 @@  static void msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
 	}
 }
 
+static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
+{
+	struct mmc_host *mmc = mmc_from_priv(host);
+	struct cqhci_host *cq_host = mmc->cqe_private;
+	u8 itcfmul;
+	u32 hclk_freq;
+	u64 value;
+
+	/* Since MSDC CQE uses msdc_hclk as ITCFVAL, so driver should use hclk
+	 * frequency to get the actual time for CIT.
+	 */
+	if (host->h_clk) {
+		hclk_freq = clk_get_rate(host->h_clk);
+		itcfmul = CQHCI_CAP_ITCFMUL(cqhci_readl(cq_host, CQHCI_CAP));
+		switch (itcfmul) {
+		case 0x0:
+			do_div(hclk_freq, 1000);
+			break;
+		case 0x1:
+			do_div(hclk_freq, 100);
+			break;
+		case 0x2:
+			do_div(hclk_freq, 10);
+			break;
+		case 0x3:
+			break;
+		case 0x4:
+			hclk_freq = hclk_freq * 10;
+			break;
+		default:
+			host->cq_ssc1_time = 0x40;
+			return;
+		value = hclk_freq * timer_ns;
+		do_div(value, 1000000000ULL);
+		host->cq_ssc1_time = value;
+	} else {
+		host->cq_ssc1_time = 0x40;
+	}
+}
+
 static void msdc_cqe_enable(struct mmc_host *mmc)
 {
 	struct msdc_host *host = mmc_priv(mmc);
+	struct cqhci_host *cq_host = mmc->cqe_private;
 
 	/* enable cmdq irq */
 	writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN);
@@ -2462,6 +2504,9 @@  static void msdc_cqe_enable(struct mmc_host *mmc)
 	msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0);
 	/* default read data timeout 1s */
 	msdc_set_timeout(host, 1000000000ULL, 0);
+
+	/* Set the send status command idle timer */
+	cqhci_writel(cq_host, host->cq_ssc1_time, CQHCI_SSC1);
 }
 
 static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
@@ -2803,6 +2848,8 @@  static int msdc_drv_probe(struct platform_device *pdev)
 		/* cqhci 16bit length */
 		/* 0 size, means 65536 so we don't have to -1 here */
 		mmc->max_seg_size = 64 * 1024;
+		/* Reduce CIT to 0x40 that corresponds to 2.35us */
+		msdc_cqe_cit_cal(host, 2350);
 	}
 
 	ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,