mbox series

[v4,0/8] Support Multi-frequency scale for UFS

Message ID 20250210100212.855127-1-quic_ziqichen@quicinc.com
Headers show
Series Support Multi-frequency scale for UFS | expand

Message

Ziqi Chen Feb. 10, 2025, 10:02 a.m. UTC
With OPP V2 enabled, devfreq can scale clocks amongst multiple frequency
plans. However, the gear speed is only toggled between min and max during
clock scaling. Enable multi-level gear scaling by mapping clock frequencies
to gear speeds, so that when devfreq scales clock frequencies we can put
the UFS link at the appropraite gear speeds accordingly.

This series has been tested on below platforms -
sm8550 mtp + UFS3.1
SM8650 MTP + UFS3.1
SM8750 MTP + UFS4.0

Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-HDK
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8650-HDK 

v1 -> v2:
1. Withdraw old patch 8/8 "ARM: dts: msm: Use Operation Points V2 for UFS on SM8650"
2. Add new patch 8/8 "ABI: sysfs-driver-ufs: Add missing UFS sysfs addributes"
3. Modify commit message for  "scsi: ufs: core: Pass target_freq to clk_scale_notify() vops" and "scsi: ufs: qcom: Pass target_freq to clk scale pre and post change"
4. In "scsi: ufs: qcom: Pass target_freq to clk scale pre and post change", use common Macro HZ_PER_MHZ in function ufs_qcom_set_core_clk_ctrl()
5. In "scsi: ufs: qcom: Implement the freq_to_gear_speed() vops", print out freq and gear info as debugging message
6. In "scsi: ufs: core: Enable multi-level gear scaling", rename the lable "do_pmc" to "config_pwr_mode"
7. In "scsi: ufs: core: Toggle Write Booster during clock", initialize the local variables "wb_en" as "false"

v2 -> v3:
1. Change 'vops' to 'vop' in all commit message
2. keep the indentation consistent for clk_scale_notify() definition.
3. In "scsi: ufs: core: Add a vop to map clock frequency to gear speed", "scsi: ufs: qcom: Implement the freq_to_gear_speed() vop"
   and "scsi: ufs: core: Enable multi-level gear scaling", remove the parameter 'gear' and use it as return result in function freq_to_gear_speed()
4. In "scsi: ufs: qcom: Implement the freq_to_gear_speed(), removed the variable 'ret' in function ufs_qcom_freq_to_gear_speed()
5. In "scsi: ufs: core: Enable multi-level gear scaling", use assignment instead memcpy() in function ufshcd_scale_gear()
6. Improve the grammar of attributes' descriptions in “ABI: sysfs-driver-ufs: Add missing UFS sysfs attributes”
7. Typo fixed for some commit messages.

v3 -> v4:
1. In "scsi: ufs: core: Toggle Write Booster during clock scaling base on gear speed":
	a. Add comment for default initialized wb_gear
	b. Remove the unnecessary variable “wb_en" in function ufshcd_clock_scaling_unprepare()
2. Typo fixed for commit message of "scsi: ufs: core: Enable multi-level gear scaling"
3. Make the description words are more standardized in "ABI: sysfs-driver-ufs: Add missing UFS sysfs attributes"

Can Guo (6):
  scsi: ufs: core: Pass target_freq to clk_scale_notify() vop
  scsi: ufs: qcom: Pass target_freq to clk scale pre and post change
  scsi: ufs: core: Add a vop to map clock frequency to gear speed

Can Guo (6):
  scsi: ufs: core: Pass target_freq to clk_scale_notify() vop
  scsi: ufs: qcom: Pass target_freq to clk scale pre and post change
  scsi: ufs: core: Add a vop to map clock frequency to gear speed
  scsi: ufs: qcom: Implement the freq_to_gear_speed() vop
  scsi: ufs: core: Enable multi-level gear scaling
  scsi: ufs: core: Toggle Write Booster during clock scaling base on
    gear speed

Ziqi Chen (2):
  scsi: ufs: core: Check if scaling up is required when disable clkscale
  ABI: sysfs-driver-ufs: Add missing UFS sysfs attributes

 Documentation/ABI/testing/sysfs-driver-ufs | 33 ++++++++++
 drivers/ufs/core/ufshcd-priv.h             | 15 ++++-
 drivers/ufs/core/ufshcd.c                  | 71 +++++++++++++++++-----
 drivers/ufs/host/ufs-mediatek.c            |  1 +
 drivers/ufs/host/ufs-qcom.c                | 62 ++++++++++++++-----
 include/ufs/ufshcd.h                       |  9 ++-
 6 files changed, 156 insertions(+), 35 deletions(-)

Comments

Bean Huo Feb. 10, 2025, 6:24 p.m. UTC | #1
On Mon, 2025-02-10 at 18:02 +0800, Ziqi Chen wrote:
> Add UFS driver sysfs attributes clkscale_enable, clkgate_enable and
> clkgate_delay_ms to this doucment.

"doucment" → "document"

> 
> Signed-off-by: Ziqi Chen <quic_ziqichen@quicinc.com>


Reviewed-by: Bean Huo <beanhuo@micron.com>
Peter Wang (王信友) Feb. 11, 2025, 3:52 a.m. UTC | #2
On Mon, 2025-02-10 at 18:02 +0800, Ziqi Chen wrote:
> 
> diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
> index d7aca9e61684..f51d425696e7 100644
> --- a/include/ufs/ufshcd.h
> +++ b/include/ufs/ufshcd.h
> @@ -344,8 +344,8 @@ struct ufs_hba_variant_ops {
>         void    (*exit)(struct ufs_hba *);
>         u32     (*get_ufs_hci_version)(struct ufs_hba *);
>         int     (*set_dma_mask)(struct ufs_hba *);
> -       int     (*clk_scale_notify)(struct ufs_hba *, bool,
> -                                   enum ufs_notify_change_status);
> +       int (*clk_scale_notify)(struct ufs_hba *, bool, unsigned
> long,
> +                                                       enum
> ufs_notify_change_status);
> 

Hi Ziqi,

Please keep the identation consistent.

Thanks.
Peter




>         int     (*setup_clocks)(struct ufs_hba *, bool,
>                                 enum ufs_notify_change_status);
>         int     (*hce_enable_notify)(struct ufs_hba *,
> --
> 2.34.1
>
Ziqi Chen Feb. 11, 2025, 10:04 a.m. UTC | #3
On 2/11/2025 11:52 AM, Peter Wang (王信友) wrote:
> On Mon, 2025-02-10 at 18:02 +0800, Ziqi Chen wrote:
>>
>> diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h
>> index d7aca9e61684..f51d425696e7 100644
>> --- a/include/ufs/ufshcd.h
>> +++ b/include/ufs/ufshcd.h
>> @@ -344,8 +344,8 @@ struct ufs_hba_variant_ops {
>>          void    (*exit)(struct ufs_hba *);
>>          u32     (*get_ufs_hci_version)(struct ufs_hba *);
>>          int     (*set_dma_mask)(struct ufs_hba *);
>> -       int     (*clk_scale_notify)(struct ufs_hba *, bool,
>> -                                   enum ufs_notify_change_status);
>> +       int (*clk_scale_notify)(struct ufs_hba *, bool, unsigned
>> long,
>> +                                                       enum
>> ufs_notify_change_status);
>>
> 
> Hi Ziqi,
> 
> Please keep the identation consistent.
> 
> Thanks.
> Peter

Sure, thank Peter.

-Ziqi
> 
> 
> 
> 
>>          int     (*setup_clocks)(struct ufs_hba *, bool,
>>                                  enum ufs_notify_change_status);
>>          int     (*hce_enable_notify)(struct ufs_hba *,
>> --
>> 2.34.1
>>
>
Ziqi Chen Feb. 11, 2025, 10:28 a.m. UTC | #4
On 2/11/2025 5:28 PM, Peter Wang (王信友) wrote:
> On Mon, 2025-02-10 at 18:02 +0800, Ziqi Chen wrote:
>>
>> External email : Please do not click links or open attachments until
>> you have verified the sender or the content.
>>
>>
>> From: Can Guo <quic_cang@quicinc.com>
>>
>> With OPP V2 enabled, devfreq can scale clocks amongst multiple
>> frequency
>> plans. However, the gear speed is only toggled between min and max
>> during
>> clock scaling. Enable multi-level gear scaling by mapping clock
>> frequencies
>> to gear speeds, so that when devfreq scales clock frequencies we can
>> put
>> the UFS link at the appropriate gear speeds accordingly.
>>
>> Signed-off-by: Can Guo <quic_cang@quicinc.com>
>> Co-developed-by: Ziqi Chen <quic_ziqichen@quicinc.com>
>> Signed-off-by: Ziqi Chen <quic_ziqichen@quicinc.com>
>> Reviewed-by: Bean Huo <beanhuo@micron.com>
>> Reviewed-by: Bart Van Assche <bvanassche@acm.org>
>> Tested-by: Neil Armstrong <neil.armstrong@linaro.org>
>> ---
>>
>> v1 -> v2:
>> Rename the lable "do_pmc" to "config_pwr_mode".
>>
>> v2 -> v3:
>> Use assignment instead memcpy() in function ufshcd_scale_gear().
>>
>> v3 -> v4:
>> Typo fixed for commit message.
>> ---
>>   drivers/ufs/core/ufshcd.c | 51 +++++++++++++++++++++++++++++++------
>> --
>>   1 file changed, 41 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
>> index 8d295cc827cc..ebab897080a6 100644
>> --- a/drivers/ufs/core/ufshcd.c
>> +++ b/drivers/ufs/core/ufshcd.c
>> @@ -1308,16 +1308,26 @@ static int
>> ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba,
>>   /**
>>    * ufshcd_scale_gear - scale up/down UFS gear
>>    * @hba: per adapter instance
>> + * @target_gear: target gear to scale to
>>    * @scale_up: True for scaling up gear and false for scaling down
>>    *
>>    * Return: 0 for success; -EBUSY if scaling can't happen at this
>> time;
>>    * non-zero for any other errors.
>>    */
>> -static int ufshcd_scale_gear(struct ufs_hba *hba, bool scale_up)
>> +static int ufshcd_scale_gear(struct ufs_hba *hba, u32 target_gear,
>> bool scale_up)
>>   {
>>          int ret = 0;
>>          struct ufs_pa_layer_attr new_pwr_info;
>>
>> +       if (target_gear) {
>> +               new_pwr_info = hba->pwr_info;
>> +               new_pwr_info.gear_tx = target_gear;
>> +               new_pwr_info.gear_rx = target_gear;
>> +
>> +               goto config_pwr_mode;
>> +       }
>> +
>> +       /* Legacy gear scaling, in case vops_freq_to_gear_speed() is
>> not implemented */
>>          if (scale_up) {
>>                  memcpy(&new_pwr_info, &hba-
>>> clk_scaling.saved_pwr_info,
>>                         sizeof(struct ufs_pa_layer_attr));
>> @@ -1338,6 +1348,7 @@ static int ufshcd_scale_gear(struct ufs_hba
>> *hba, bool scale_up)
>>                  }
>>          }
>>
>> +config_pwr_mode:
>>          /* check if the power mode needs to be changed or not? */
>>          ret = ufshcd_config_pwr_mode(hba, &new_pwr_info);
>>          if (ret)
>> @@ -1408,15 +1419,26 @@ static void
>> ufshcd_clock_scaling_unprepare(struct ufs_hba *hba, int err, bool sc
>>   static int ufshcd_devfreq_scale(struct ufs_hba *hba, unsigned long
>> freq,
>>                                  bool scale_up)
>>   {
>> +       u32 old_gear = hba->pwr_info.gear_rx;
>> +       int new_gear = 0;
>>          int ret = 0;
>>
>> +       new_gear = ufshcd_vops_freq_to_gear_speed(hba, freq);
>> +       if (new_gear < 0)
>> +               /*
>> +                * return negative value means that the
>> vops_freq_to_gear_speed() is not
>> +                * implemented or didn't find matched gear speed,
>> assign '0' to new_gear
>> +                * to switch to legacy gear scaling sequence in
>> ufshcd_scale_gear().
>> +                */
>> +               new_gear = 0;
>> +
>>
> 
> Hi Ziqi,
> 
> I think remove help function is better.
> No need change new_gear type when use.
> The readability is higher, and no need add that large amount comments.
> 
>         u32_new_gear = 0;
>         if (hba->vops && hba->vops->freq_to_gear_speed)
>                 new_gear = hba->vops->freq_to_gear_speed(hba, freq);
> 
> 
> Thanks.
> Peter
> 
> 
Hi Peter,

Thanks, Peter.
Frankly, I also think this way has low readability. However, keep the 
u32 type for new_gear is OK to me. But this vop would lose the ability 
to indicate the error types. All types of error can only return "0".

However, we don't need to deal with various types of errors up to now, I 
can submit a new version to change back the new_gear and vop return 
value type to u32 and make correspondingly change in patch 3/8 and 4/8.

-Ziqi

> 
>>          ret = ufshcd_clock_scaling_prepare(hba, 1 * USEC_PER_SEC);
>>          if (ret)
>>                  return ret;
>>
>>          /* scale down the gear before scaling down clocks */
>>          if (!scale_up) {
>> -               ret = ufshcd_scale_gear(hba, false);
>> +               ret = ufshcd_scale_gear(hba, (u32)new_gear, false);
>>                  if (ret)
>>                          goto out_unprepare;
>>          }
>> @@ -1424,13 +1446,13 @@ static int ufshcd_devfreq_scale(struct
>> ufs_hba *hba, unsigned long freq,
>>          ret = ufshcd_scale_clks(hba, freq, scale_up);
>>          if (ret) {
>>                  if (!scale_up)
>> -                       ufshcd_scale_gear(hba, true);
>> +                       ufshcd_scale_gear(hba, old_gear, true);
>>                  goto out_unprepare;
>>          }
>>
>>          /* scale up the gear after scaling up clocks */
>>          if (scale_up) {
>> -               ret = ufshcd_scale_gear(hba, true);
>> +               ret = ufshcd_scale_gear(hba, (u32)new_gear, true);
>>                  if (ret) {
>>                          ufshcd_scale_clks(hba, hba->devfreq-
>>> previous_freq,
>>                                            false);
>> @@ -1723,6 +1745,8 @@ static ssize_t
>> ufshcd_clkscale_enable_store(struct device *dev,
>>                  struct device_attribute *attr, const char *buf,
>> size_t count)
>>   {
>>          struct ufs_hba *hba = dev_get_drvdata(dev);
>> +       struct ufs_clk_info *clki;
>> +       unsigned long freq;
>>          u32 value;
>>          int err = 0;
>>
>> @@ -1746,14 +1770,21 @@ static ssize_t
>> ufshcd_clkscale_enable_store(struct device *dev,
>>
>>          if (value) {
>>                  ufshcd_resume_clkscaling(hba);
>> -       } else {
>> -               ufshcd_suspend_clkscaling(hba);
>> -               err = ufshcd_devfreq_scale(hba, ULONG_MAX, true);
>> -               if (err)
>> -                       dev_err(hba->dev, "%s: failed to scale clocks
>> up %d\n",
>> -                                       __func__, err);
>> +               goto out_rel;
>>          }
>>
>> +       clki = list_first_entry(&hba->clk_list_head, struct
>> ufs_clk_info, list);
>> +       freq = clki->max_freq;
>> +
>> +       ufshcd_suspend_clkscaling(hba);
>> +       err = ufshcd_devfreq_scale(hba, freq, true);
>> +       if (err)
>> +               dev_err(hba->dev, "%s: failed to scale clocks up
>> %d\n",
>> +                               __func__, err);
>> +       else
>> +               hba->clk_scaling.target_freq = freq;
>> +
>> +out_rel:
>>          ufshcd_release(hba);
>>          ufshcd_rpm_put_sync(hba);
>>   out:
>> --
>> 2.34.1
>>
>