During frequency scaling operations, the host can reads the frequency
constraint configured in the PM QoS framework and updates the target
frequency accordingly.
Signed-off-by: Wang Jianzheng <wangjianzheng@vivo.com>
---
drivers/ufs/core/ufshcd.c | 44 +++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 9a43102b2b21..1a9bcbc9dab0 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -1546,6 +1546,47 @@ static void ufshcd_clk_scaling_resume_work(struct work_struct *work)
devfreq_resume_device(hba->devfreq);
}
+#ifdef CONFIG_PM
+static void ufshcd_pm_qos_freq_read_value(struct ufs_hba *hba,
+ unsigned long *freq)
+{
+ struct Scsi_Host *shost = hba->host;
+ struct scsi_device *sdev;
+ struct request_queue *q;
+ struct ufs_clk_info *clki;
+ s32 min_qos_freq;
+
+ if (!shost)
+ return;
+
+ shost_for_each_device(sdev, shost) {
+ if (!sdev)
+ continue;
+
+ q = sdev->request_queue;
+ if (IS_ERR_OR_NULL(q))
+ continue;
+
+ if (q->disk && !IS_ERR_OR_NULL(q->dev)) {
+ if (q->disk->dev_freq_timeout) {
+ min_qos_freq = dev_pm_qos_read_value(q->dev,
+ DEV_PM_QOS_MIN_FREQUENCY);
+ clki = list_first_entry(&hba->clk_list_head,
+ struct ufs_clk_info, list);
+ if (min_qos_freq > clki->max_freq)
+ *freq = clki->max_freq;
+ }
+ }
+ }
+}
+#else
+static void ufshcd_pm_qos_freq_read_value(struct ufs_hba *hba,
+ unsigned long *freq)
+{
+ return;
+}
+#endif
+
static int ufshcd_devfreq_target(struct device *dev,
unsigned long *freq, u32 flags)
{
@@ -1559,6 +1600,9 @@ static int ufshcd_devfreq_target(struct device *dev,
if (!ufshcd_is_clkscaling_supported(hba))
return -EINVAL;
+ /* Select the frequency based on the DEV_PM_QOS_MIN_FREQUENCY */
+ ufshcd_pm_qos_freq_read_value(hba, freq);
+
if (hba->use_pm_opp) {
struct dev_pm_opp *opp;
--
2.34.1