Merge patch series "devfreq: check the get_cur_freq() return value and use it in ufshcd"

Bean Huo <beanhuo@iokpp.de> says:

The devfreq core has three users of the optional ->get_cur_freq()
callback. Two of them check the return value, the third one does not
and passes an uninitialized frequency to the transition notifiers when
the callback fails. Patch 1 fixes that.

Patch 2 writes down what a driver is expected to return from the
callback. Today this has to be found by reading the devfreq core.

Patch 3 records the frequency the controller starts at.
ufshcd_init_clocks() puts the controller at its highest frequency, but
nothing writes that down, so clk_scaling.target_freq stays 0 and
devfreq starts with previous_freq at 0 as well. With use_pm_opp this
makes ufshcd_devfreq_get_dev_status() report 0 Hz, the ondemand
governor then asks for the maximum frequency, and
ufshcd_devfreq_target() runs a full ufshcd_devfreq_scale() that holds
up the queue for up to a second only to set the same OPP and the same
gear again.

Patch 4 adds the ->get_cur_freq() callback to ufshcd. Without it the
cur_freq attribute shows the last frequency the governor selected,
which is wrong whenever the controller is scaled outside the governor,
for example after writing 0 to clkscale_enable.

The patches touch two subsystems. Patches 1 and 2 are for the devfreq
tree, patches 3 and 4 are for the SCSI tree. The two halves are
independent, at build time and at run time, and can be applied in
either order.

Patch was tested on a Radxa Dragon Q6A (1d84000.ufshc):

  before "echo 0 > clkscale_enable":  cur_freq 75000000, target_freq 75000000
  after  "echo 0 > clkscale_enable":  cur_freq 300000000, target_freq 75000000

Without it both files report 75000000 and keep doing so for as long as
clock scaling stays disabled. A 4 GiB direct read after enabling clock
scaling again counted the transitions in trans_stat and attributed
time to the 300000000 state, so the frequency the callback returns is
one that devfreq recognises.

One thing to be aware of: devfreq_monitor_resume() copies
previous_freq from the callback, but it does not call
devfreq_update_status(). A frequency change made while the governor
was suspended therefore does not show up as a transition. That is how
devfreq behaves today and this series does not change it.

Link: https://patch.msgid.link/20260907192140.2701755-1-beanhuo@iokpp.de
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
Martin K. Petersen (Oracle) 2026-09-09 22:28:06 -04:00
commit 1b800ac9e2

View File

@ -1681,11 +1681,6 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev,
if (!scaling->window_start_t)
goto start_window;
/*
* If current frequency is 0, then the ondemand governor considers
* there's no initial frequency set. And it always requests to set
* to max. frequency.
*/
if (hba->use_pm_opp) {
stat->current_frequency = hba->clk_scaling.target_freq;
} else {
@ -1716,6 +1711,26 @@ static int ufshcd_devfreq_get_dev_status(struct device *dev,
return 0;
}
static int ufshcd_devfreq_get_cur_freq(struct device *dev, unsigned long *freq)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
if (!ufshcd_is_clkscaling_supported(hba))
return -EINVAL;
if (hba->use_pm_opp) {
*freq = hba->clk_scaling.target_freq;
} else {
struct ufs_clk_info *clki;
clki = list_first_entry(&hba->clk_list_head,
struct ufs_clk_info, list);
*freq = clki->curr_freq;
}
return 0;
}
static int ufshcd_devfreq_init(struct ufs_hba *hba)
{
struct list_head *clk_list = &hba->clk_list_head;
@ -1727,12 +1742,21 @@ static int ufshcd_devfreq_init(struct ufs_hba *hba)
if (list_empty(clk_list))
return 0;
clki = list_first_entry(clk_list, struct ufs_clk_info, list);
if (!hba->use_pm_opp) {
clki = list_first_entry(clk_list, struct ufs_clk_info, list);
dev_pm_opp_add(hba->dev, clki->min_freq, 0);
dev_pm_opp_add(hba->dev, clki->max_freq, 0);
}
/*
* ufshcd_init_clocks() has already set the clocks to the highest
* frequency, and nothing has changed them since. Save that frequency,
* so that devfreq and the clock scaling code know where we start.
*/
hba->clk_scaling.target_freq = clki->max_freq;
hba->vps->devfreq_profile.initial_freq = clki->max_freq;
ufshcd_vops_config_scaling_param(hba, &hba->vps->devfreq_profile,
&hba->vps->ondemand_data);
devfreq = devfreq_add_device(hba->dev,
@ -9612,6 +9636,7 @@ static struct ufs_hba_variant_params ufs_hba_vps = {
.devfreq_profile.polling_ms = 100,
.devfreq_profile.target = ufshcd_devfreq_target,
.devfreq_profile.get_dev_status = ufshcd_devfreq_get_dev_status,
.devfreq_profile.get_cur_freq = ufshcd_devfreq_get_cur_freq,
.ondemand_data.upthreshold = 70,
.ondemand_data.downdifferential = 5,
};