mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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:
commit
1b800ac9e2
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user