Skip to content

Commit 2777e73

Browse files
Maramaina Nareshmartinkpetersen
authored andcommitted
scsi: ufs: core: Add CPU latency QoS support for UFS driver
Register UFS driver to CPU latency PM QoS framework to improve UFS device random I/O performance. PM QoS initialization will insert new QoS request into the CPU latency QoS list with the maximum latency PM_QOS_DEFAULT_VALUE value. The UFS driver will vote for performance mode on scale up and power save mode for scale down. If clock scaling feature is not enabled then voting will be based on clock on or off condition. Also provide a sysfs interface to enable/disable PM QoS feature. tiotest benchmark tool I/O performance results on sm8550 platform: 1. Without PM QoS support Type (Speed in) | Average of 18 iterations Random Write(IPOS) | 41065.13 Random Read(IPOS) | 37101.3 2. With PM QoS support Type (Speed in) | Average of 18 iterations Random Write(IPOS) | 46784.9 Random Read(IPOS) | 42943.4 (Improvement with PM QoS = ~15%). Reviewed-by: Peter Wang <peter.wang@mediatek.com> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Co-developed-by: Nitin Rawat <quic_nitirawa@quicinc.com> Signed-off-by: Nitin Rawat <quic_nitirawa@quicinc.com> Co-developed-by: Naveen Kumar Goud Arepalli <quic_narepall@quicinc.com> Signed-off-by: Naveen Kumar Goud Arepalli <quic_narepall@quicinc.com> Signed-off-by: Maramaina Naresh <quic_mnaresh@quicinc.com> Link: https://lore.kernel.org/r/20231219123706.6463-2-quic_mnaresh@quicinc.com Reviewed-by: Bart Van Assche <bvanassche@acm.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 6613476 commit 2777e73

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

drivers/ufs/core/ufs-sysfs.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,53 @@ static ssize_t wb_flush_threshold_store(struct device *dev,
405405
return count;
406406
}
407407

408+
/**
409+
* pm_qos_enable_show - sysfs handler to show pm qos enable value
410+
* @dev: device associated with the UFS controller
411+
* @attr: sysfs attribute handle
412+
* @buf: buffer for sysfs file
413+
*
414+
* Print 1 if PM QoS feature is enabled, 0 if disabled.
415+
*
416+
* Returns number of characters written to @buf.
417+
*/
418+
static ssize_t pm_qos_enable_show(struct device *dev,
419+
struct device_attribute *attr, char *buf)
420+
{
421+
struct ufs_hba *hba = dev_get_drvdata(dev);
422+
423+
return sysfs_emit(buf, "%d\n", hba->pm_qos_enabled);
424+
}
425+
426+
/**
427+
* pm_qos_enable_store - sysfs handler to store value
428+
* @dev: device associated with the UFS controller
429+
* @attr: sysfs attribute handle
430+
* @buf: buffer for sysfs file
431+
* @count: stores buffer characters count
432+
*
433+
* Input 0 to disable PM QoS and 1 value to enable.
434+
* Default state: 1
435+
*
436+
* Return: number of characters written to @buf on success, < 0 upon failure.
437+
*/
438+
static ssize_t pm_qos_enable_store(struct device *dev,
439+
struct device_attribute *attr, const char *buf, size_t count)
440+
{
441+
struct ufs_hba *hba = dev_get_drvdata(dev);
442+
bool value;
443+
444+
if (kstrtobool(buf, &value))
445+
return -EINVAL;
446+
447+
if (value)
448+
ufshcd_pm_qos_init(hba);
449+
else
450+
ufshcd_pm_qos_exit(hba);
451+
452+
return count;
453+
}
454+
408455
static DEVICE_ATTR_RW(rpm_lvl);
409456
static DEVICE_ATTR_RO(rpm_target_dev_state);
410457
static DEVICE_ATTR_RO(rpm_target_link_state);
@@ -416,6 +463,7 @@ static DEVICE_ATTR_RW(wb_on);
416463
static DEVICE_ATTR_RW(enable_wb_buf_flush);
417464
static DEVICE_ATTR_RW(wb_flush_threshold);
418465
static DEVICE_ATTR_RW(rtc_update_ms);
466+
static DEVICE_ATTR_RW(pm_qos_enable);
419467

420468
static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
421469
&dev_attr_rpm_lvl.attr,
@@ -429,6 +477,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
429477
&dev_attr_enable_wb_buf_flush.attr,
430478
&dev_attr_wb_flush_threshold.attr,
431479
&dev_attr_rtc_update_ms.attr,
480+
&dev_attr_pm_qos_enable.attr,
432481
NULL
433482
};
434483

drivers/ufs/core/ufshcd.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,48 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
10141014
return ufshcd_get_local_unipro_ver(hba) < UFS_UNIPRO_VER_1_6;
10151015
}
10161016

1017+
/**
1018+
* ufshcd_pm_qos_init - initialize PM QoS request
1019+
* @hba: per adapter instance
1020+
*/
1021+
void ufshcd_pm_qos_init(struct ufs_hba *hba)
1022+
{
1023+
1024+
if (hba->pm_qos_enabled)
1025+
return;
1026+
1027+
cpu_latency_qos_add_request(&hba->pm_qos_req, PM_QOS_DEFAULT_VALUE);
1028+
1029+
if (cpu_latency_qos_request_active(&hba->pm_qos_req))
1030+
hba->pm_qos_enabled = true;
1031+
}
1032+
1033+
/**
1034+
* ufshcd_pm_qos_exit - remove request from PM QoS
1035+
* @hba: per adapter instance
1036+
*/
1037+
void ufshcd_pm_qos_exit(struct ufs_hba *hba)
1038+
{
1039+
if (!hba->pm_qos_enabled)
1040+
return;
1041+
1042+
cpu_latency_qos_remove_request(&hba->pm_qos_req);
1043+
hba->pm_qos_enabled = false;
1044+
}
1045+
1046+
/**
1047+
* ufshcd_pm_qos_update - update PM QoS request
1048+
* @hba: per adapter instance
1049+
* @on: If True, vote for perf PM QoS mode otherwise power save mode
1050+
*/
1051+
static void ufshcd_pm_qos_update(struct ufs_hba *hba, bool on)
1052+
{
1053+
if (!hba->pm_qos_enabled)
1054+
return;
1055+
1056+
cpu_latency_qos_update_request(&hba->pm_qos_req, on ? 0 : PM_QOS_DEFAULT_VALUE);
1057+
}
1058+
10171059
/**
10181060
* ufshcd_set_clk_freq - set UFS controller clock frequencies
10191061
* @hba: per adapter instance
@@ -1160,8 +1202,11 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, unsigned long freq,
11601202
hba->devfreq->previous_freq);
11611203
else
11621204
ufshcd_set_clk_freq(hba, !scale_up);
1205+
goto out;
11631206
}
11641207

1208+
ufshcd_pm_qos_update(hba, scale_up);
1209+
11651210
out:
11661211
trace_ufshcd_profile_clk_scaling(dev_name(hba->dev),
11671212
(scale_up ? "up" : "down"),
@@ -9279,6 +9324,8 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
92799324
if (ret)
92809325
return ret;
92819326

9327+
if (!ufshcd_is_clkscaling_supported(hba))
9328+
ufshcd_pm_qos_update(hba, on);
92829329
out:
92839330
if (ret) {
92849331
list_for_each_entry(clki, head, list) {
@@ -9456,6 +9503,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
94569503
static void ufshcd_hba_exit(struct ufs_hba *hba)
94579504
{
94589505
if (hba->is_powered) {
9506+
ufshcd_pm_qos_exit(hba);
94599507
ufshcd_exit_clk_scaling(hba);
94609508
ufshcd_exit_clk_gating(hba);
94619509
if (hba->eh_wq)
@@ -10108,6 +10156,7 @@ static int ufshcd_suspend(struct ufs_hba *hba)
1010810156
ufshcd_vreg_set_lpm(hba);
1010910157
/* Put the host controller in low power mode if possible */
1011010158
ufshcd_hba_vreg_set_lpm(hba);
10159+
ufshcd_pm_qos_update(hba, false);
1011110160
return ret;
1011210161
}
1011310162

@@ -10654,6 +10703,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
1065410703
ufs_sysfs_add_nodes(hba->dev);
1065510704

1065610705
device_enable_async_suspend(dev);
10706+
ufshcd_pm_qos_init(hba);
1065710707
return 0;
1065810708

1065910709
free_tmf_queue:

include/ufs/ufshcd.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,8 @@ enum ufshcd_mcq_opr {
914914
* @dev_cmd_queue: Queue for issuing device management commands
915915
* @mcq_opr: MCQ operation and runtime registers
916916
* @ufs_rtc_update_work: A work for UFS RTC periodic update
917+
* @pm_qos_req: PM QoS request handle
918+
* @pm_qos_enabled: flag to check if pm qos is enabled
917919
*/
918920
struct ufs_hba {
919921
void __iomem *mmio_base;
@@ -1080,6 +1082,8 @@ struct ufs_hba {
10801082
struct ufshcd_mcq_opr_info_t mcq_opr[OPR_MAX];
10811083

10821084
struct delayed_work ufs_rtc_update_work;
1085+
struct pm_qos_request pm_qos_req;
1086+
bool pm_qos_enabled;
10831087
};
10841088

10851089
/**
@@ -1400,6 +1404,8 @@ int ufshcd_suspend_prepare(struct device *dev);
14001404
int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm);
14011405
void ufshcd_resume_complete(struct device *dev);
14021406
bool ufshcd_is_hba_active(struct ufs_hba *hba);
1407+
void ufshcd_pm_qos_init(struct ufs_hba *hba);
1408+
void ufshcd_pm_qos_exit(struct ufs_hba *hba);
14031409

14041410
/* Wrapper functions for safely calling variant operations */
14051411
static inline int ufshcd_vops_init(struct ufs_hba *hba)

0 commit comments

Comments
 (0)