scsi: ufs: Add DeepSleep feature
v4 cover scsi: ufs: Add DeepSleep feature
Hi
Here is V4 of the DeepSleep feature patches.
Changes in V4:
Rebased Added new patch "scsi: ufs: Allow an error return value from ->device_reset()"
Changes in V3:
Updated sysfs doc for rpm_lvl and spm_lvl
Changes in V2:
Fix SSU command IMMED setting and consequently drop patch 2.
Adrian Hunter (2):
scsi: ufs: Add DeepSleep feature
scsi: ufs: Allow an error return value from ->device_reset()
Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++++++----------- drivers/scsi/ufs/ufs-mediatek.c | 4 ++- drivers/scsi/ufs/ufs-qcom.c | 6 +++-- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 28 +++++++++++++++++---- include/trace/events/ufs.h | 3 ++- 8 files changed, 97 insertions(+), 25 deletions(-)
Regards
Adrian
PATCH v4 1/2 scsi: ufs: Add DeepSleep feature
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption of the device, apart from power off.
In DeepSleep mode, no commands are accepted, and the only way to exit is using a hardware reset or power cycle.
This patch assumes that if a power cycle was an option, then power off would be preferable, so only exit via a hardware reset is supported.
Drivers that wish to support DeepSleep need to set a new capability flag UFSHCD_CAP_DEEPSLEEP and provide a hardware reset via the existing
->device_reset() callback.
It is assumed that UFS devices with wspecversion >= 0x310 support DeepSleep.
--- Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++-------- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 17 +++++++++- include/trace/events/ufs.h | 3 +- 6 files changed, 83 insertions(+), 18 deletions(-)
Documentation/ABI/testing/sysfs-driver-ufs +20 -14
@@ -916,21 +916,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device runtime power management level. The current driver - implementation supports 6 levels with next target states: + implementation supports 7 levels with next target states: == ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ==================================================== What: /sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_state
@@ -954,21 +957,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device system power management level. The current driver - implementation supports 6 levels with next target states: + implementation supports 7 levels with next target states: == ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ==================================================== What: /sys/bus/platform/drivers/ufshcd/*/spm_target_dev_state
drivers/scsi/ufs/ufs-sysfs.c +7 -0
@@ -28,6 +28,7 @@ static const char *ufschd_ufs_dev_pwr_mode_to_string(case UFS_ACTIVE_PWR_MODE :return "ACTIVE" ;case UFS_SLEEP_PWR_MODE :return "SLEEP" ;case UFS_POWERDOWN_PWR_MODE :return "POWERDOWN" ; +case UFS_DEEPSLEEP_PWR_MODE :return "DEEPSLEEP" ;default :return "UNKNOWN" ; } }
@@ -38,6 +39,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, bool rpm) {struct ufs_hba *hba =dev_get_drvdata (dev); +struct ufs_dev_info *dev_info = &hba->dev_info;unsigned long flags, value;if (kstrtoul (buf,0 , &value))
@@ -46,6 +48,11 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev,if (value >=UFS_PM_LVL_MAX )return -EINVAL ; +if (ufs_pm_lvl_states[value].dev_state ==UFS_DEEPSLEEP_PWR_MODE && + (!(hba->caps &UFSHCD_CAP_DEEPSLEEP ) || + !(dev_info->wspecversion >=0x310 ))) +return -EINVAL ; +spin_lock_irqsave (hba->host->host_lock, flags);if (rpm) hba->rpm_lvl = value;
drivers/scsi/ufs/ufs.h +1 -0
@@ -442,6 +442,7 @@ enum ufs_dev_pwr_mode {UFS_ACTIVE_PWR_MODE =1 ,UFS_SLEEP_PWR_MODE =2 ,UFS_POWERDOWN_PWR_MODE =3 , + UFS_DEEPSLEEP_PWR_MODE = 4, };#define UFS_WB_BUF_REMAIN_PERCENT (val) ((val) / 10)
drivers/scsi/ufs/ufshcd.c +37 -2
@@ -163,6 +163,11 @@ struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE}, +/* +* For DeepSleep, the link is first put in hibern8 and then off. +* Leaving the link in hibern8 is not supported. +*/ + {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE}, }; static inline enum ufs_dev_pwr_mode
@@ -8297,7 +8302,8 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, }/* * If autobkops is enabled, link can't be turned off because -* turning off the link would also turn off the device. +* turning off the link would also turn off the device, except in the +* case of DeepSleep where the device is expected to remain powered. */ else if ((req_link_state ==UIC_LINK_OFF_STATE ) && (!check_for_bkops || !hba->auto_bkops_enabled)) {
@@ -8307,6 +8313,9 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba,* put the link in low power mode is to send the DME end point * to device and then send the DME reset command to local * unipro. But putting the link in hibern8 is much faster. +* +* Note also that putting the link in Hibern8 is a requirement +* for entering DeepSleep. */ ret =ufshcd_uic_hibern8_enter (hba);if (ret) {
@@ -8439,6 +8448,7 @@ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)static int ufshcd_suspend (struct ufs_hba *hba,enum ufs_pm_op pm_op) {int ret =0 ; +int check_for_bkops;enum ufs_pm_level pm_lvl;enum ufs_dev_pwr_mode req_dev_pwr_mode;enum uic_link_state req_link_state;
@@ -8524,7 +8534,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) }flush_work (&hba->eeh_work); - ret =ufshcd_link_state_transition (hba, req_link_state,1 ); + +/* +* In the case of DeepSleep, the device is expected to remain powered +* with the link off, so do not check for bkops. +*/ + check_for_bkops = !ufshcd_is_ufs_dev_deepsleep (hba); + ret =ufshcd_link_state_transition (hba, req_link_state, check_for_bkops);if (ret) goto set_dev_active;
@@ -8565,11 +8581,25 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (hba->clk_scaling.is_allowed)ufshcd_resume_clkscaling (hba);ufshcd_vreg_set_hpm (hba); +/* +* Device hardware reset is required to exit DeepSleep. Also, for +* DeepSleep, the link is off so host reset and restore will be done +* further below. +*/ +if (ufshcd_is_ufs_dev_deepsleep (hba)) { +ufshcd_vops_device_reset (hba); +WARN_ON (!ufshcd_is_link_off (hba)); + }if (ufshcd_is_link_hibern8 (hba) && !ufshcd_uic_hibern8_exit (hba))ufshcd_set_link_active (hba);else if (ufshcd_is_link_off (hba))ufshcd_host_reset_and_restore (hba); set_dev_active: +/* Can also get here needing to exit DeepSleep */ +if (ufshcd_is_ufs_dev_deepsleep (hba)) { +ufshcd_vops_device_reset (hba); +ufshcd_host_reset_and_restore (hba); + }if (!ufshcd_set_dev_pwr_mode (hba,UFS_ACTIVE_PWR_MODE ))ufshcd_disable_auto_bkops (hba); enable_gating:
@@ -8631,6 +8661,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto disable_vreg; +/* For DeepSleep, the only supported option is to have the link off */ +WARN_ON (ufshcd_is_ufs_dev_deepsleep (hba) && !ufshcd_is_link_off (hba)); +if (ufshcd_is_link_hibern8 (hba)) { ret =ufshcd_uic_hibern8_exit (hba);if (!ret) {
@@ -8644,6 +8677,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)/* * A full initialization of the host and the device is * required since the link was put to off during suspend. +* Note, in the case of DeepSleep, the device will exit +* DeepSleep due to device reset. */ ret =ufshcd_reset_and_restore (hba);/*
drivers/scsi/ufs/ufshcd.h +16 -1
@@ -114,16 +114,22 @@ enum uic_link_state { ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)#define ufshcd_set_ufs_dev_poweroff (h) \ ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE) +#define ufshcd_set_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE)#define ufshcd_is_ufs_dev_active (h) \ ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)#define ufshcd_is_ufs_dev_sleep (h) \ ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)#define ufshcd_is_ufs_dev_poweroff (h) \ ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) +#define ufshcd_is_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE)/* * UFS Power management levels. -* Each level is in increasing order of power savings. +* Each level is in increasing order of power savings, except DeepSleep +* which is lower than PowerDown with power on but not PowerDown with +* power off. */ enum ufs_pm_level {UFS_PM_LVL_0 ,/* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */
@@ -132,6 +138,7 @@ enum ufs_pm_level {UFS_PM_LVL_3 ,/* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_4 ,/* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_5 ,/* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */ +UFS_PM_LVL_6 ,/* UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE */ UFS_PM_LVL_MAX };
@@ -599,6 +606,14 @@ enum ufshcd_caps {* This would increase power savings. */ UFSHCD_CAP_AGGR_POWER_COLLAPSE =1 <<9 , + +/* +* This capability allows the host controller driver to use DeepSleep, +* if it is supported by the UFS device. The host controller driver must +* support device hardware reset via the hba->device_reset() callback, +* in order to exit DeepSleep state. +*/ + UFSHCD_CAP_DEEPSLEEP = 1 << 10, }; struct ufs_hba_variant_params {
include/trace/events/ufs.h +2 -1
@@ -19,7 +19,8 @@#define UFS_PWR_MODES \ EM(UFS_ACTIVE_PWR_MODE) \ EM(UFS_SLEEP_PWR_MODE) \ - EMe(UFS_POWERDOWN_PWR_MODE) + EM(UFS_POWERDOWN_PWR_MODE) \ + EMe(UFS_DEEPSLEEP_PWR_MODE)#define UFSCHD_CLK_GATING_STATES \ EM(CLKS_OFF) \
Signature · 1 line
2.17.1
Quoted 9 lines · Adrian Hunter
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption of the device, apart from power off.
In DeepSleep mode, no commands are accepted, and the only way to exit is using a hardware reset or power cycle.
This patch assumes that if a power cycle was an option, then power off would be preferable, so only exit via a hardware reset is supported.
Quoted 8 lines
Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEPand provide a hardware reset via the existing
->device_reset() callback.It is assumed that UFS devices with wspecversion >=
0x310support DeepSleep.Signed-off-by Adrian Hunter <[email protected]>
Quoted 307 lines
--- Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++-------- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 17 +++++++++- include/trace/events/ufs.h | 3 +- 6 files changed, 83 insertions(+), 18 deletions(-)Documentation/ABI/testing/sysfs-driver-ufs +20
-14@@ -916,21 +916,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device runtime power management level. The current driver - implementation supports 6 levels with next target states: + implementation supports 7 levels with next target states: == ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ==================================================== What: /sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_state@@ -954,21 +957,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device system power management level. The current driver - implementation supports 6 levels with next target states: + implementation supports 7 levels with next target states: == ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ==================================================== What: /sys/bus/platform/drivers/ufshcd/*/spm_target_dev_statedrivers/scsi/ufs/ufs-sysfs.c +2
-0@@ -28,6 +28,7 @@ static const char *ufschd_ufs_dev_pwr_mode_to_string(case UFS_ACTIVE_PWR_MODE :return "ACTIVE" ;case UFS_SLEEP_PWR_MODE :return "SLEEP" ;case UFS_POWERDOWN_PWR_MODE :return "POWERDOWN" ; +case UFS_DEEPSLEEP_PWR_MODE :return "DEEPSLEEP" ;default :return "UNKNOWN" ; } }@@ -38,6 +39,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, bool rpm) {struct ufs_hba *hba =dev_get_drvdata (dev); +struct ufs_dev_info *dev_info = &hba->dev_info;unsigned long flags, value;drivers/scsi/ufs/ufs-sysfs.c +5
-0if (kstrtoul (buf,0 , &value))@@ -46,6 +48,11 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, if (value >= UFS_PM_LVL_MAX) return -EINVAL; +if (ufs_pm_lvl_states[value].dev_state ==UFS_DEEPSLEEP_PWR_MODE && + (!(hba->caps &UFSHCD_CAP_DEEPSLEEP ) || + !(dev_info->wspecversion >=0x310 ))) +return -EINVAL ; +spin_lock_irqsave (hba->host->host_lock, flags);if (rpm)drivers/scsi/ufs/ufs-sysfs.c +0
-0hba->rpm_lvl = value;drivers/scsi/ufs/ufs.h +1
-0@@ -442,6 +442,7 @@ enum ufs_dev_pwr_mode {UFS_ACTIVE_PWR_MODE =1 ,UFS_SLEEP_PWR_MODE =2 ,UFS_POWERDOWN_PWR_MODE =3 , + UFS_DEEPSLEEP_PWR_MODE = 4, };#define UFS_WB_BUF_REMAIN_PERCENT (val) ((val) / 10)drivers/scsi/ufs/ufshcd.c +7
-1@@ -163,6 +163,11 @@ struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE}, +/* +* For DeepSleep, the link is first put in hibern8 and then off. +* Leaving the link in hibern8 is not supported. +*/ + {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE}, }; static inline enum ufs_dev_pwr_mode@@ -8297,7 +8302,8 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, }/* * If autobkops is enabled, link can't be turned off because -* turning off the link would also turn off the device. +* turning off the link would also turn off the device, except in the +* case of DeepSleep where the device is expected to remain powered. */ else if ((req_link_state == UIC_LINK_OFF_STATE) &&drivers/scsi/ufs/ufshcd.c +3
-0(!check_for_bkops || !hba->auto_bkops_enabled)) {@@ -8307,6 +8313,9 @@ static int ufshcd_link_state_transition(structufs_hba *hba, * put the link in low power mode is to send the DME end point * to device and then send the DME reset command to local * unipro. But putting the link in hibern8 is much faster. +* +* Note also that putting the link in Hibern8 is a requirement +* for entering DeepSleep. */ ret =ufshcd_uic_hibern8_enter (hba);drivers/scsi/ufs/ufshcd.c +1
-0if (ret) {@@ -8439,6 +8448,7 @@ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)static int ufshcd_suspend (struct ufs_hba *hba,enum ufs_pm_op pm_op) {int ret =0 ; +int check_for_bkops;enum ufs_pm_level pm_lvl;enum ufs_dev_pwr_mode req_dev_pwr_mode;drivers/scsi/ufs/ufshcd.c +7
-1enum uic_link_state req_link_state;@@ -8524,7 +8534,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) }flush_work (&hba->eeh_work); - ret =ufshcd_link_state_transition (hba, req_link_state,1 ); + +/* +* In the case of DeepSleep, the device is expected to remain powered +* with the link off, so do not check for bkops. +*/ + check_for_bkops = !ufshcd_is_ufs_dev_deepsleep (hba); + ret =ufshcd_link_state_transition (hba, req_link_state, check_for_bkops);if (ret)drivers/scsi/ufs/ufshcd.c +14
-0goto set_dev_active;@@ -8565,11 +8581,25 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (hba->clk_scaling.is_allowed)ufshcd_resume_clkscaling (hba);ufshcd_vreg_set_hpm (hba); +/* +* Device hardware reset is required to exit DeepSleep. Also, for +* DeepSleep, the link is off so host reset and restore will be done +* further below. +*/ +if (ufshcd_is_ufs_dev_deepsleep (hba)) { +ufshcd_vops_device_reset (hba); +WARN_ON (!ufshcd_is_link_off (hba)); + }if (ufshcd_is_link_hibern8 (hba) && !ufshcd_uic_hibern8_exit (hba))ufshcd_set_link_active (hba);else if (ufshcd_is_link_off (hba))ufshcd_host_reset_and_restore (hba); set_dev_active: +/* Can also get here needing to exit DeepSleep */ +if (ufshcd_is_ufs_dev_deepsleep (hba)) { +ufshcd_vops_device_reset (hba); +ufshcd_host_reset_and_restore (hba); + }if (!ufshcd_set_dev_pwr_mode (hba,UFS_ACTIVE_PWR_MODE ))ufshcd_disable_auto_bkops (hba);
enable_gating:drivers/scsi/ufs/ufshcd.c +3
-0@@ -8631,6 +8661,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ret) goto disable_vreg; + /* For DeepSleep, the only supported option is to have the link off */ + WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) && !ufshcd_is_link_off(hba)); +drivers/scsi/ufs/ufshcd.c +2
-0if (ufshcd_is_link_hibern8 (hba)) { ret =ufshcd_uic_hibern8_exit (hba);if (!ret) {@@ -8644,6 +8677,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)/* * A full initialization of the host and the device is * required since the link was put to off during suspend. +* Note, in the case of DeepSleep, the device will exit +* DeepSleep due to device reset. */ ret =ufshcd_reset_and_restore (hba);drivers/scsi/ufs/ufshcd.c +0
-0/* drivers/scsi/ufs/ufshcd.h +5
-1@@ -114,16 +114,22 @@ enum uic_link_state { ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)#define ufshcd_set_ufs_dev_poweroff (h) \ ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE) +#define ufshcd_set_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE)#define ufshcd_is_ufs_dev_active (h) \ ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)#define ufshcd_is_ufs_dev_sleep (h) \ ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)#define ufshcd_is_ufs_dev_poweroff (h) \ ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) +#define ufshcd_is_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE)/* * UFS Power management levels. -* Each level is in increasing order of power savings. +* Each level is in increasing order of power savings, except DeepSleep
+ * which is lower than PowerDown with power on but not PowerDown with
+ * power off.
*/
enumufs_pm_level{drivers/scsi/ufs/ufshcd.h +5
-0UFS_PM_LVL_0, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */@@ -132,6 +138,7 @@ enum ufs_pm_level {UFS_PM_LVL_3 ,/* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_4 ,/* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_5 ,/* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */ +UFS_PM_LVL_6 ,/* UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE */ UFS_PM_LVL_MAX };@@ -599,6 +606,14 @@ enum ufshcd_caps {* This would increase power savings. */ UFSHCD_CAP_AGGR_POWER_COLLAPSE = 1 << 9, + +/* +* This capability allows the host controller driver to use DeepSleep, +* if it is supported by the UFS device. The host controller driver must
drivers/scsi/ufs/ufshcd.h +1
-0+* support device hardware reset via the hba->device_reset() callback,
drivers/scsi/ufs/ufshcd.h +3
-0+* in order to exit DeepSleep state. +*/ + UFSHCD_CAP_DEEPSLEEP = 1 << 10, };struct ufs_hba_variant_params {include/trace/events/ufs.h +2
-1@@ -19,7 +19,8 @@#define UFS_PWR_MODES \ EM(UFS_ACTIVE_PWR_MODE) \ EM(UFS_SLEEP_PWR_MODE) \ - EMe(UFS_POWERDOWN_PWR_MODE) + EM(UFS_POWERDOWN_PWR_MODE) \ + EMe(UFS_DEEPSLEEP_PWR_MODE)#define UFSCHD_CLK_GATING_STATES \ EM(CLKS_OFF) \
Hi Adrian,
Quoted 50 lines · Adrian Hunter
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption of the device, apart from power off.
In DeepSleep mode, no commands are accepted, and the only way to exit is using a hardware reset or power cycle.
This patch assumes that if a power cycle was an option, then power off would be preferable, so only exit via a hardware reset is supported.
Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEPand provide a hardware reset via the existing
->device_reset() callback.It is assumed that UFS devices with wspecversion >=
0x310support DeepSleep.Signed-off-by Adrian Hunter <[email protected]>--- Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++-------- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 17 +++++++++- include/trace/events/ufs.h | 3 +- 6 files changed, 83 insertions(+), 18 deletions(-)Documentation/ABI/testing/sysfs-driver-ufs +5
-5@@ -916,21 +916,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device runtime power management level. The current driver - implementation supports 6 levels with next target states: + implementation supports 7 levels with next target states: == ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will
Documentation/ABI/testing/sysfs-driver-ufs Date: September 2014 · line 936
Quoted 10 lines
Documentation/ABI/testing/sysfs-driver-ufs +5
-2hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted
Nitpicking, usually higher spm/rpm_lvl means better power saving. Since POWERDOWN+LINKOFF achieves the lowest power consumption, can we put DEEPSLEEP_LINKOFF to 5, and POWERDOWN_LINKOFF to 6?
Thanks,
Can Guo.
Quoted 264 lines
Documentation/ABI/testing/sysfs-driver-ufs +10
-7== ==================================================== What: /sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_state@@ -954,21 +957,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device system power management level. The current driver - implementation supports 6 levels with next target states: + implementation supports 7 levels with next target states: == ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ==================================================== What: /sys/bus/platform/drivers/ufshcd/*/spm_target_dev_statedrivers/scsi/ufs/ufs-sysfs.c +2
-0@@ -28,6 +28,7 @@ static const char *ufschd_ufs_dev_pwr_mode_to_string(case UFS_ACTIVE_PWR_MODE :return "ACTIVE" ;case UFS_SLEEP_PWR_MODE :return "SLEEP" ;case UFS_POWERDOWN_PWR_MODE :return "POWERDOWN" ; +case UFS_DEEPSLEEP_PWR_MODE :return "DEEPSLEEP" ;default :return "UNKNOWN" ; } }@@ -38,6 +39,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, bool rpm) {struct ufs_hba *hba =dev_get_drvdata (dev); +struct ufs_dev_info *dev_info = &hba->dev_info;unsigned long flags, value;drivers/scsi/ufs/ufs-sysfs.c +5
-0if (kstrtoul (buf,0 , &value))@@ -46,6 +48,11 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, if (value >= UFS_PM_LVL_MAX) return -EINVAL; +if (ufs_pm_lvl_states[value].dev_state ==UFS_DEEPSLEEP_PWR_MODE && + (!(hba->caps &UFSHCD_CAP_DEEPSLEEP ) || + !(dev_info->wspecversion >=0x310 ))) +return -EINVAL ; +spin_lock_irqsave (hba->host->host_lock, flags);if (rpm)drivers/scsi/ufs/ufs-sysfs.c +0
-0hba->rpm_lvl = value;drivers/scsi/ufs/ufs.h +1
-0@@ -442,6 +442,7 @@ enum ufs_dev_pwr_mode {UFS_ACTIVE_PWR_MODE =1 ,UFS_SLEEP_PWR_MODE =2 ,UFS_POWERDOWN_PWR_MODE =3 , + UFS_DEEPSLEEP_PWR_MODE = 4, };#define UFS_WB_BUF_REMAIN_PERCENT (val) ((val) / 10)drivers/scsi/ufs/ufshcd.c +7
-1@@ -163,6 +163,11 @@ struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE}, +/* +* For DeepSleep, the link is first put in hibern8 and then off. +* Leaving the link in hibern8 is not supported. +*/ + {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE}, }; static inline enum ufs_dev_pwr_mode@@ -8297,7 +8302,8 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, }/* * If autobkops is enabled, link can't be turned off because -* turning off the link would also turn off the device. +* turning off the link would also turn off the device, except in the +* case of DeepSleep where the device is expected to remain powered. */ else if ((req_link_state == UIC_LINK_OFF_STATE) &&drivers/scsi/ufs/ufshcd.c +3
-0(!check_for_bkops || !hba->auto_bkops_enabled)) {@@ -8307,6 +8313,9 @@ static int ufshcd_link_state_transition(structufs_hba *hba, * put the link in low power mode is to send the DME end point * to device and then send the DME reset command to local * unipro. But putting the link in hibern8 is much faster. +* +* Note also that putting the link in Hibern8 is a requirement +* for entering DeepSleep. */ ret =ufshcd_uic_hibern8_enter (hba);drivers/scsi/ufs/ufshcd.c +1
-0if (ret) {@@ -8439,6 +8448,7 @@ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)static int ufshcd_suspend (struct ufs_hba *hba,enum ufs_pm_op pm_op) {int ret =0 ; +int check_for_bkops;enum ufs_pm_level pm_lvl;enum ufs_dev_pwr_mode req_dev_pwr_mode;drivers/scsi/ufs/ufshcd.c +7
-1enum uic_link_state req_link_state;@@ -8524,7 +8534,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) }flush_work (&hba->eeh_work); - ret =ufshcd_link_state_transition (hba, req_link_state,1 ); + +/* +* In the case of DeepSleep, the device is expected to remain powered +* with the link off, so do not check for bkops. +*/ + check_for_bkops = !ufshcd_is_ufs_dev_deepsleep (hba); + ret =ufshcd_link_state_transition (hba, req_link_state, check_for_bkops);if (ret)drivers/scsi/ufs/ufshcd.c +14
-0goto set_dev_active;@@ -8565,11 +8581,25 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (hba->clk_scaling.is_allowed)ufshcd_resume_clkscaling (hba);ufshcd_vreg_set_hpm (hba); +/* +* Device hardware reset is required to exit DeepSleep. Also, for +* DeepSleep, the link is off so host reset and restore will be done +* further below. +*/ +if (ufshcd_is_ufs_dev_deepsleep (hba)) { +ufshcd_vops_device_reset (hba); +WARN_ON (!ufshcd_is_link_off (hba)); + }if (ufshcd_is_link_hibern8 (hba) && !ufshcd_uic_hibern8_exit (hba))ufshcd_set_link_active (hba);else if (ufshcd_is_link_off (hba))ufshcd_host_reset_and_restore (hba); set_dev_active: +/* Can also get here needing to exit DeepSleep */ +if (ufshcd_is_ufs_dev_deepsleep (hba)) { +ufshcd_vops_device_reset (hba); +ufshcd_host_reset_and_restore (hba); + }if (!ufshcd_set_dev_pwr_mode (hba,UFS_ACTIVE_PWR_MODE ))ufshcd_disable_auto_bkops (hba);
enable_gating:drivers/scsi/ufs/ufshcd.c +3
-0@@ -8631,6 +8661,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ret) goto disable_vreg; + /* For DeepSleep, the only supported option is to have the link off */ + WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) && !ufshcd_is_link_off(hba)); +drivers/scsi/ufs/ufshcd.c +2
-0if (ufshcd_is_link_hibern8 (hba)) { ret =ufshcd_uic_hibern8_exit (hba);if (!ret) {@@ -8644,6 +8677,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)/* * A full initialization of the host and the device is * required since the link was put to off during suspend. +* Note, in the case of DeepSleep, the device will exit +* DeepSleep due to device reset. */ ret =ufshcd_reset_and_restore (hba);drivers/scsi/ufs/ufshcd.c +0
-0/* drivers/scsi/ufs/ufshcd.h +5
-1@@ -114,16 +114,22 @@ enum uic_link_state { ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)#define ufshcd_set_ufs_dev_poweroff (h) \ ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE) +#define ufshcd_set_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE)#define ufshcd_is_ufs_dev_active (h) \ ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)#define ufshcd_is_ufs_dev_sleep (h) \ ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)#define ufshcd_is_ufs_dev_poweroff (h) \ ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) +#define ufshcd_is_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE)/* * UFS Power management levels. -* Each level is in increasing order of power savings. +* Each level is in increasing order of power savings, except DeepSleep
+ * which is lower than PowerDown with power on but not PowerDown with
+ * power off.
*/
enumufs_pm_level{drivers/scsi/ufs/ufshcd.h +5
-0UFS_PM_LVL_0, /* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */@@ -132,6 +138,7 @@ enum ufs_pm_level {UFS_PM_LVL_3 ,/* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_4 ,/* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_5 ,/* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */ +UFS_PM_LVL_6 ,/* UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE */ UFS_PM_LVL_MAX };@@ -599,6 +606,14 @@ enum ufshcd_caps {* This would increase power savings. */ UFSHCD_CAP_AGGR_POWER_COLLAPSE = 1 << 9, + +/* +* This capability allows the host controller driver to use DeepSleep, +* if it is supported by the UFS device. The host controller driver must
drivers/scsi/ufs/ufshcd.h +1
-0+* support device hardware reset via the hba->device_reset() callback,
drivers/scsi/ufs/ufshcd.h +3
-0+* in order to exit DeepSleep state. +*/ + UFSHCD_CAP_DEEPSLEEP = 1 << 10, };struct ufs_hba_variant_params {include/trace/events/ufs.h +2
-1@@ -19,7 +19,8 @@#define UFS_PWR_MODES \ EM(UFS_ACTIVE_PWR_MODE) \ EM(UFS_SLEEP_PWR_MODE) \ - EMe(UFS_POWERDOWN_PWR_MODE) + EM(UFS_POWERDOWN_PWR_MODE) \ + EMe(UFS_DEEPSLEEP_PWR_MODE)#define UFSCHD_CLK_GATING_STATES \ EM(CLKS_OFF) \
Quoted 59 lines · Can Guo
Hi Adrian,
Quoted 56 lines · Adrian Hunter
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption of the device, apart from power off.
In DeepSleep mode, no commands are accepted, and the only way to exit is using a hardware reset or power cycle.
This patch assumes that if a power cycle was an option, then power off would be preferable, so only exit via a hardware reset is supported.
Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEPand provide a hardware reset via the existing ->device_reset() callback.It is assumed that UFS devices with wspecversion >=
0x310support DeepSleep.Signed-off-by Adrian Hunter <[email protected]>---
Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++-------- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 17 +++++++++- include/trace/events/ufs.h | 3 +-6 files changed, 83 insertions(+), 18 deletions(-)Documentation/ABI/testing/sysfs-driver-ufs +0
-0@@ -916,21 +916,24 @@ Date: September 2014Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device runtime power management level. The current driver - implementation supports 6 levels with next target states:
+ implementation supports 7 levels with next target states:== ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active
- 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate
- 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active
- 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate
- 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate
- 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will
Quoted 8 lines
Quoted 4 lines
be powered off
+ 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be acceptedNitpicking, usually higher spm/rpm_lvl means better power saving. Since POWERDOWN+LINKOFF achieves the lowest power consumption, can we put
DEEPSLEEP_LINKOFFto 5, andPOWERDOWN_LINKOFFto 6?
That would break the API i.e. we shouldn't change the meaning of '5'
Also, pedantically it depends on whether regulators are provided as to whether Deep Sleep is higher/lower than PowerDown i.e. without regulators to switch off the device, it will remain in PowerDown mode which does not save as much power as Deep Sleep.
Quoted 263 lines
Thanks,
Can Guo.
Quoted 258 lines
== ====================================================
What:
/sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_stateDocumentation/ABI/testing/sysfs-driver-ufs +0
-0@@ -954,21 +957,24 @@ Date: September 2014Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device system power management level. The current driver
- implementation supports 6 levels with next target states:
+ implementation supports 7 levels with next target states:== ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active
- 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate
- 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active
- 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate
- 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate
- 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off
+ 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ====================================================What:
/sys/bus/platform/drivers/ufshcd/*/spm_target_dev_statedrivers/scsi/ufs/ufs-sysfs.c +2
-0@@ -28,6 +28,7 @@ static const char *ufschd_ufs_dev_pwr_mode_to_string( case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; case UFS_SLEEP_PWR_MODE: return "SLEEP"; case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; + case UFS_DEEPSLEEP_PWR_MODE: return "DEEPSLEEP"; default: return "UNKNOWN"; } }@@ -38,6 +39,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(structdevice *dev, bool rpm) { struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_dev_info *dev_info = &hba->dev_info; unsigned long flags, value;if (
kstrtoul(buf, 0, &value))drivers/scsi/ufs/ufs-sysfs.c +5
-0@@ -46,6 +48,11 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, if (value >= UFS_PM_LVL_MAX) return -EINVAL; + if (ufs_pm_lvl_states[value].dev_state == UFS_DEEPSLEEP_PWR_MODE && + (!(hba->caps & UFSHCD_CAP_DEEPSLEEP) || + !(dev_info->wspecversion >= 0x310))) + return -EINVAL; + spin_lock_irqsave(hba->host->host_lock, flags); if (rpm)
hba->rpm_lvl= value;drivers/scsi/ufs/ufs.h +1
-0@@ -442,6 +442,7 @@ enum ufs_dev_pwr_mode { UFS_ACTIVE_PWR_MODE = 1, UFS_SLEEP_PWR_MODE = 2, UFS_POWERDOWN_PWR_MODE = 3, + UFS_DEEPSLEEP_PWR_MODE = 4, }; #define UFS_WB_BUF_REMAIN_PERCENT(val) ((val) / 10)drivers/scsi/ufs/ufshcd.c +5
-0@@ -163,6 +163,11 @@ struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE}, + /* + * For DeepSleep, the link is first put in hibern8 and then off. + * Leaving the link in hibern8 is not supported. + */ + {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE}, };static inline enum
ufs_dev_pwr_modedrivers/scsi/ufs/ufshcd.c +2
-1@@ -8297,7 +8302,8 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, } /** If autobkops is enabled, link can't be turned off because -* turning off the link would also turn off the device. +* turning off the link would also turn off the device, except in the +* case of DeepSleep where the device is expected to remain powered. */ else if ((
req_link_state==UIC_LINK_OFF_STATE) && (!check_for_bkops || !hba->auto_bkops_enabled)) {drivers/scsi/ufs/ufshcd.c +3
-0@@ -8307,6 +8313,9 @@ static int ufshcd_link_state_transition(structufs_hba *hba, * put the link in low power mode is to send the DME end point * to device and then send the DME reset command to local * unipro. But putting the link in hibern8 is much faster. +* +* Note also that putting the link in Hibern8 is a requirement +* for entering DeepSleep. */ ret = ufshcd_uic_hibern8_enter(hba);if (ret) {
drivers/scsi/ufs/ufshcd.c +1
-0@@ -8439,6 +8448,7 @@ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba) static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) { int ret = 0; + int check_for_bkops; enum ufs_pm_level pm_lvl; enum ufs_dev_pwr_mode req_dev_pwr_mode;enum
uic_link_statereq_link_state;drivers/scsi/ufs/ufshcd.c +7
-1@@ -8524,7 +8534,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) } flush_work(&hba->eeh_work); - ret = ufshcd_link_state_transition(hba, req_link_state, 1); + + /* + * In the case of DeepSleep, the device is expected to remain powered + * with the link off, so do not check for bkops. + */ + check_for_bkops = !ufshcd_is_ufs_dev_deepsleep(hba); + ret = ufshcd_link_state_transition(hba, req_link_state, check_for_bkops); if (ret)goto
set_dev_active;drivers/scsi/ufs/ufshcd.c +9
-0@@ -8565,11 +8581,25 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (hba->clk_scaling.is_allowed) ufshcd_resume_clkscaling(hba); ufshcd_vreg_set_hpm(hba); + /* + * Device hardware reset is required to exit DeepSleep. Also, for + * DeepSleep, the link is off so host reset and restore will be done + * further below. + */ + if (ufshcd_is_ufs_dev_deepsleep(hba)) { + ufshcd_vops_device_reset(hba); + WARN_ON(!ufshcd_is_link_off(hba)); + } if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba)) ufshcd_set_link_active(hba); else if (ufshcd_is_link_off(hba)) ufshcd_host_reset_and_restore(hba);set_dev_active:
+ /* Can also get here needing to exit DeepSleep */ + if (ufshcd_is_ufs_dev_deepsleep(hba)) {
+ufshcd_vops_device_reset(hba);
+ufshcd_host_reset_and_restore(hba);
+ }
if (!ufshcd_set_dev_pwr_mode(hba,UFS_ACTIVE_PWR_MODE))ufshcd_disable_auto_bkops(hba);enable_gating:drivers/scsi/ufs/ufshcd.c +3
-0@@ -8631,6 +8661,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ret) goto disable_vreg; + /* For DeepSleep, the only supported option is to have the link off */ + WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) && !ufshcd_is_link_off(hba)); + if (ufshcd_is_link_hibern8(hba)) { ret = ufshcd_uic_hibern8_exit(hba);if (!ret) {
drivers/scsi/ufs/ufshcd.c +2
-0@@ -8644,6 +8677,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) /* * A full initialization of the host and the device is * required since the link was put to off during suspend. + * Note, in the case of DeepSleep, the device will exit + * DeepSleep due to device reset. */ ret = ufshcd_reset_and_restore(hba);/*
drivers/scsi/ufs/ufshcd.h +7
-1@@ -114,16 +114,22 @@ enum uic_link_state { ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE) #define ufshcd_set_ufs_dev_poweroff(h) \ ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE) +#define ufshcd_set_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE) #define ufshcd_is_ufs_dev_active(h) \ ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE) #define ufshcd_is_ufs_dev_sleep(h) \ ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE) #define ufshcd_is_ufs_dev_poweroff(h) \ ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) +#define ufshcd_is_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE) /* * UFS Power management levels. - * Each level is in increasing order of power savings. + * Each level is in increasing order of power savings, except DeepSleep + * which is lower than PowerDown with power on but not PowerDown with + * power off. */ enum ufs_pm_level {
UFS_PM_LVL_0, /*UFS_ACTIVE_PWR_MODE,UIC_LINK_ACTIVE_STATE*/drivers/scsi/ufs/ufshcd.h +0
-0@@ -132,6 +138,7 @@ enum ufs_pm_level {
UFS_PM_LVL_3, /*UFS_SLEEP_PWR_MODE,UIC_LINK_HIBERN8_STATE*/UFS_PM_LVL_4, /*UFS_POWERDOWN_PWR_MODE,UIC_LINK_HIBERN8_STATE*/UFS_PM_LVL_5, /*UFS_POWERDOWN_PWR_MODE,UIC_LINK_OFF_STATE*/ +UFS_PM_LVL_6, /*UFS_DEEPSLEEP_PWR_MODE,UIC_LINK_OFF_STATE*/UFS_PM_LVL_MAX
};drivers/scsi/ufs/ufshcd.h +8
-0@@ -599,6 +606,14 @@ enum ufshcd_caps {* This would increase power savings. */ UFSHCD_CAP_AGGR_POWER_COLLAPSE = 1 << 9, + + /* + * This capability allows the host controller driver to use DeepSleep, + * if it is supported by the UFS device. The host controller driver must + * support device hardware reset via the hba->device_reset() callback, + * in order to exit DeepSleep state. + */ + UFSHCD_CAP_DEEPSLEEP = 1 << 10, }; struct ufs_hba_variant_params {include/trace/events/ufs.h +2
-1@@ -19,7 +19,8 @@ #define UFS_PWR_MODES \ EM(UFS_ACTIVE_PWR_MODE) \ EM(UFS_SLEEP_PWR_MODE) \ - EMe(UFS_POWERDOWN_PWR_MODE) + EM(UFS_POWERDOWN_PWR_MODE) \ + EMe(UFS_DEEPSLEEP_PWR_MODE) #define UFSCHD_CLK_GATING_STATES \ EM(CLKS_OFF) \
Quoted 70 lines · Adrian Hunter
Quoted 60 lines · Can Guo
Hi Adrian,
Quoted 57 lines · Adrian Hunter
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption of the device, apart from power off.
In DeepSleep mode, no commands are accepted, and the only way to exit is using a hardware reset or power cycle.
This patch assumes that if a power cycle was an option, then power off would be preferable, so only exit via a hardware reset is supported.
Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEPand provide a hardware reset via the existing ->device_reset() callback.It is assumed that UFS devices with wspecversion >=
0x310support DeepSleep.Signed-off-by Adrian Hunter <[email protected]>---
Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++-------- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39
++++++++++++++++++++--
drivers/scsi/ufs/ufshcd.h | 17 +++++++++- include/trace/events/ufs.h | 3 +-6 files changed, 83 insertions(+), 18 deletions(-)Documentation/ABI/testing/sysfs-driver-ufs +0
-0@@ -916,21 +916,24 @@ Date: September 2014Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device runtime power management level. The current driver - implementation supports 6 levels with next target states:
+ implementation supports 7 levels with next target states:== ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active
- 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate
- 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active
- 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate
- 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate
- 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link willQuoted 8 lines
Quoted 4 lines
be powered off
+ 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be acceptedNitpicking, usually higher spm/rpm_lvl means better power saving. Since POWERDOWN+LINKOFF achieves the lowest power consumption, can we put
DEEPSLEEP_LINKOFFto 5, andPOWERDOWN_LINKOFFto 6?
Quoted 7 lines
That would break the API i.e. we shouldn't change the meaning of '5'
Also, pedantically it depends on whether regulators are provided as to whether Deep Sleep is higher/lower than PowerDown i.e. without regulators to switch off the device, it will remain in PowerDown mode which does not save as much power as Deep Sleep.
OK, that makes sense. The change LGTM, I gave my reivewed-by tag.
Regards,
Can Guo.
Quoted 281 lines
Quoted 281 lines
Thanks,
Can Guo.
Quoted 276 lines
== ====================================================
What:
/sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_stateDocumentation/ABI/testing/sysfs-driver-ufs +0
-0@@ -954,21 +957,24 @@ Date: September 2014Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device system power management level. The current driver
- implementation supports 6 levels with next target states:
+ implementation supports 7 levels with next target states:== ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active
- 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate
- 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active
- 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate
- 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate
- 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off
+ 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ====================================================What:
/sys/bus/platform/drivers/ufshcd/*/spm_target_dev_statedrivers/scsi/ufs/ufs-sysfs.c +1
-0@@ -28,6 +28,7 @@ static const char *ufschd_ufs_dev_pwr_mode_to_string( case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; case UFS_SLEEP_PWR_MODE: return "SLEEP"; case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; + case UFS_DEEPSLEEP_PWR_MODE: return "DEEPSLEEP"; default: return "UNKNOWN"; }}
drivers/scsi/ufs/ufs-sysfs.c +1
-0@@ -38,6 +39,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(structdevice *dev, bool rpm) { struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_dev_info *dev_info = &hba->dev_info; unsigned long flags, value;if (
kstrtoul(buf, 0, &value))drivers/scsi/ufs/ufs-sysfs.c +0
-0@@ -46,6 +48,11 @@ static inline ssize_tufs_sysfs_pm_lvl_store(struct
device *dev,
if (value >=UFS_PM_LVL_MAX)
return-EINVAL;+ if (ufs_pm_lvl_states[value].dev_state ==
UFS_DEEPSLEEP_PWR_MODE&&
+ (!(hba->caps &UFSHCD_CAP_DEEPSLEEP) ||
+ !(dev_info->wspecversion >=0x310)))
+ return-EINVAL;
+
spin_lock_irqsave(hba->host->host_lock, flags);
if (rpm)
hba->rpm_lvl= value;drivers/scsi/ufs/ufs.h +1
-0@@ -442,6 +442,7 @@ enum ufs_dev_pwr_mode { UFS_ACTIVE_PWR_MODE = 1, UFS_SLEEP_PWR_MODE = 2, UFS_POWERDOWN_PWR_MODE = 3, + UFS_DEEPSLEEP_PWR_MODE = 4, }; #define UFS_WB_BUF_REMAIN_PERCENT(val) ((val) / 10)drivers/scsi/ufs/ufshcd.c +5
-0@@ -163,6 +163,11 @@ struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE}, + /* + * For DeepSleep, the link is first put in hibern8 and then off. + * Leaving the link in hibern8 is not supported. + */ + {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE}, };static inline enum
ufs_dev_pwr_modedrivers/scsi/ufs/ufshcd.c +1
-1@@ -8297,7 +8302,8 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, } /** If autobkops is enabled, link can't be turned off because -* turning off the link would also turn off the device. +* turning off the link would also turn off the device, except in the
+ * case of DeepSleep where the device is expected to remain powered.
*/
else if ((req_link_state==UIC_LINK_OFF_STATE) && (!check_for_bkops || !hba->auto_bkops_enabled)) {drivers/scsi/ufs/ufshcd.c +2
-0@@ -8307,6 +8313,9 @@ static int ufshcd_link_state_transition(structufs_hba *hba, * put the link in low power mode is to send the DME end point * to device and then send the DME reset command to local * unipro. But putting the link in hibern8 is much faster. + * + * Note also that putting the link in Hibern8 is arequirement
+ * for entering DeepSleep.
*/
ret =ufshcd_uic_hibern8_enter(hba);
if (ret) {drivers/scsi/ufs/ufshcd.c +0
-0@@ -8439,6 +8448,7 @@ static void ufshcd_hba_vreg_set_hpm(struct
ufs_hba
*hba)
static intufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op){
int ret = 0;
+ intcheck_for_bkops;
enumufs_pm_levelpm_lvl;
enumufs_dev_pwr_modereq_dev_pwr_mode;
enumuic_link_statereq_link_state;drivers/scsi/ufs/ufshcd.c +3
-1@@ -8524,7 +8534,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) } flush_work(&hba->eeh_work); - ret = ufshcd_link_state_transition(hba, req_link_state, 1); + + /* +* In the case of DeepSleep, the device is expected to remain powered
+ * with the link off, so do not check for bkops. + */
+check_for_bkops= !ufshcd_is_ufs_dev_deepsleep(hba); + ret =ufshcd_link_state_transition(hba, req_link_state, check_for_bkops);
if (ret)
gotoset_dev_active;drivers/scsi/ufs/ufshcd.c +2
-0@@ -8565,11 +8581,25 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (hba->clk_scaling.is_allowed) ufshcd_resume_clkscaling(hba); ufshcd_vreg_set_hpm(hba); + /* +* Device hardware reset is required to exit DeepSleep. Also, for
+ * DeepSleep, the link is off so host reset and restore will be done
+ * further below.
+ */
+ if (ufshcd_is_ufs_dev_deepsleep(hba)) {
+ufshcd_vops_device_reset(hba);
+ WARN_ON(!ufshcd_is_link_off(hba));
+ }
if (ufshcd_is_link_hibern8(hba)&& !ufshcd_uic_hibern8_exit(hba))ufshcd_set_link_active(hba);
else if (ufshcd_is_link_off(hba))ufshcd_host_reset_and_restore(hba);set_dev_active:
+ /* Can also get here needing to exit DeepSleep */
+ if (ufshcd_is_ufs_dev_deepsleep(hba)) {
+ufshcd_vops_device_reset(hba);
+ufshcd_host_reset_and_restore(hba);
+ }
if (!ufshcd_set_dev_pwr_mode(hba,UFS_ACTIVE_PWR_MODE))ufshcd_disable_auto_bkops(hba);
enable_gating:drivers/scsi/ufs/ufshcd.c +1
-0@@ -8631,6 +8661,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ret) goto disable_vreg; + /* For DeepSleep, the only supported option is to have the linkoff */
+ WARN_ON(ufshcd_is_ufs_dev_deepsleep(hba) &&
!ufshcd_is_link_off(hba));
+
if (ufshcd_is_link_hibern8(hba)) {
ret =ufshcd_uic_hibern8_exit(hba);
if (!ret) {drivers/scsi/ufs/ufshcd.c +2
-0@@ -8644,6 +8677,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) /* * A full initialization of the host and the device is * required since the link was put to off during suspend. + * Note, in the case of DeepSleep, the device will exit + * DeepSleep due to device reset. */ ret = ufshcd_reset_and_restore(hba);/*
drivers/scsi/ufs/ufshcd.h +5
-1@@ -114,16 +114,22 @@ enum uic_link_state { ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE) #define ufshcd_set_ufs_dev_poweroff(h) \ ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE) +#define ufshcd_set_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE) #define ufshcd_is_ufs_dev_active(h) \ ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE) #define ufshcd_is_ufs_dev_sleep(h) \ ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE) #define ufshcd_is_ufs_dev_poweroff(h) \ ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) +#define ufshcd_is_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE) /** UFS Power management levels. -* Each level is in increasing order of power savings. +* Each level is in increasing order of power savings, except DeepSleep
+ * which is lower than PowerDown with power on but not PowerDown with
+ * power off.
*/
enumufs_pm_level{
UFS_PM_LVL_0, /*UFS_ACTIVE_PWR_MODE,UIC_LINK_ACTIVE_STATE*/drivers/scsi/ufs/ufshcd.h +0
-0@@ -132,6 +138,7 @@ enum ufs_pm_level {
UFS_PM_LVL_3, /*UFS_SLEEP_PWR_MODE,UIC_LINK_HIBERN8_STATE*/UFS_PM_LVL_4, /*UFS_POWERDOWN_PWR_MODE,UIC_LINK_HIBERN8_STATE*/UFS_PM_LVL_5, /*UFS_POWERDOWN_PWR_MODE,UIC_LINK_OFF_STATE*/ +UFS_PM_LVL_6, /*UFS_DEEPSLEEP_PWR_MODE,UIC_LINK_OFF_STATE*/UFS_PM_LVL_MAX
};drivers/scsi/ufs/ufshcd.h +4
-0@@ -599,6 +606,14 @@ enum ufshcd_caps {* This would increase power savings. */ UFSHCD_CAP_AGGR_POWER_COLLAPSE = 1 << 9, + + /* +* This capability allows the host controller driver to use DeepSleep, +* if it is supported by the UFS device. The host controller driver must
+ * support device hardware reset via thehba->device_reset()callback,
+ * in order to exit DeepSleep state.
+ */
+ UFSHCD_CAP_DEEPSLEEP = 1 << 10,
};struct
ufs_hba_variant_params{include/trace/events/ufs.h +2
-1@@ -19,7 +19,8 @@ #define UFS_PWR_MODES \ EM(UFS_ACTIVE_PWR_MODE) \ EM(UFS_SLEEP_PWR_MODE) \ - EMe(UFS_POWERDOWN_PWR_MODE) + EM(UFS_POWERDOWN_PWR_MODE) \ + EMe(UFS_DEEPSLEEP_PWR_MODE) #define UFSCHD_CLK_GATING_STATES \ EM(CLKS_OFF) \
Quoted 82 lines · Adrian Hunter
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption
of the device, apart from power off.In DeepSleep mode, no commands are accepted, and the only way to exit is
using a hardware reset or power cycle.This patch assumes that if a power cycle was an option, then power off
would be preferable, so only exit via a hardware reset is supported.Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEPand provide a hardware reset via the existing
->device_reset() callback.It is assumed that UFS devices with wspecversion >=
0x310support DeepSleep.Signed-off-by Adrian Hunter <[email protected]>--- Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++-------- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 17 +++++++++- include/trace/events/ufs.h | 3 +- 6 files changed, 83 insertions(+), 18 deletions(-)Documentation/ABI/testing/sysfs-driver-ufs +0
-1@@ -916,21 +916,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device runtime power management level. The current driver - implementation supports 6 levels with next targetstates:
Documentation/ABI/testing/sysfs-driver-ufs +1
-0+ implementation supports 7 levels with next targetstates:
== ===================================================
=Documentation/ABI/testing/sysfs-driver-ufs +9
-6- 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ====================================================
What:
/sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_stateDocumentation/ABI/testing/sysfs-driver-ufs +0
-1@@ -954,21 +957,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device system power management level. The current driver - implementation supports 6 levels with next targetstates:
Documentation/ABI/testing/sysfs-driver-ufs +1
-0+ implementation supports 7 levels with next targetstates:
Quoted 2 lines
== ===================================================
=
Hi Adrian
There doesn't have these equal sign lines in the sysfs-driver-ufs. maybe you should remove these. or add + prefix.
Thanks,
Bean
Adrian Hunter
Reviewed-by Tom Rix Reviewed-by Kajol Jain Acked-by Jonathan Cameron Acked-by Oded Gabbay Acked-by Vaibhav Jain Acked-by Cezary Rojewski Acked-by Suzuki K Poulose Acked-by Ilya Dryomov Acked-by Jonathan CorbetQuoted 83 lines · Bean Huo
Quoted 82 lines · Adrian Hunter
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption
of the device, apart from power off.In DeepSleep mode, no commands are accepted, and the only way to exit is
using a hardware reset or power cycle.This patch assumes that if a power cycle was an option, then power off
would be preferable, so only exit via a hardware reset is supported.Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEPand provide a hardware reset via the existing
->device_reset() callback.It is assumed that UFS devices with wspecversion >=
0x310support DeepSleep.Signed-off-by Adrian Hunter <[email protected]>--- Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++-------- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 17 +++++++++- include/trace/events/ufs.h | 3 +- 6 files changed, 83 insertions(+), 18 deletions(-)Documentation/ABI/testing/sysfs-driver-ufs +0
-1@@ -916,21 +916,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device runtime power management level. The current driver - implementation supports 6 levels with next targetstates:
Documentation/ABI/testing/sysfs-driver-ufs +1
-0+ implementation supports 7 levels with next targetstates:
== ===================================================
=Documentation/ABI/testing/sysfs-driver-ufs +9
-6- 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ====================================================
What:
/sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_stateDocumentation/ABI/testing/sysfs-driver-ufs +0
-1@@ -954,21 +957,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device system power management level. The current driver - implementation supports 6 levels with next targetstates:
Documentation/ABI/testing/sysfs-driver-ufs +1
-0+ implementation supports 7 levels with next targetstates:
Quoted 6 lines
Quoted 2 lines
== ===================================================
=Hi Adrian
There doesn't have these equal sign lines in the sysfs-driver-ufs. maybe you should remove these. or add + prefix.
The "=" are from the patch below which is in v5.10-rc2
commit 54a19b4d3fe0fa0a31b46cd60951e8177cac25fa
Author: Mauro Carvalho Chehab <[email protected]> Date: Fri Oct 30 08:40:50 2020 +0100
docs: ABI: cleanup several ABI documents
There are some ABI documents that, while they don't generate any warnings, they have issues when parsed by get_abi.pl script on its output result.
Address them, in order to provide a clean output.
Bean Huo
Reviewed-byQuoted 10 lines · Adrian Hunter
Quoted 9 lines
Quoted 5 lines
states:
=====================================================
=Hi Adrian
There doesn't have these equal sign lines in the sysfs-driver-ufs. maybe you should remove these. or add + prefix.
Quoted 5 lines
The "=" are from the patch below which is in v5.10-rc2
commit
54a19b4d3fe0fa0a31b46cd60951e8177cac25faAuthor: Mauro Carvalho Chehab <[email protected]> Date: Fri Oct 30 08:40:50 2020 +0100
thanks for pointing out this.
Quoted 13 lines · Adrian Hunter
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption of the device, apart from power off.
In DeepSleep mode, no commands are accepted, and the only way to exit is using a hardware reset or power cycle.
This patch assumes that if a power cycle was an option, then power off would be preferable, so only exit via a hardware reset is supported.
Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEPand provide a hardware reset via the existing
->device_reset() callback.
Quoted 5 lines
It is assumed that UFS devices with wspecversion >=
0x310support DeepSleep.Signed-off-by Adrian Hunter <[email protected]>---
Quoted 290 lines
Documentation/ABI/testing/sysfs-driver-ufs | 34 +++++++++++-------- drivers/scsi/ufs/ufs-sysfs.c | 7 ++++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd.c | 39 ++++++++++++++++++++-- drivers/scsi/ufs/ufshcd.h | 17 +++++++++- include/trace/events/ufs.h | 3 +- 6 files changed, 83 insertions(+), 18 deletions(-)Documentation/ABI/testing/sysfs-driver-ufs +20
-14@@ -916,21 +916,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device runtime power management level. The current driver - implementation supports 6 levels with next target states: + implementation supports 7 levels with next target states: == ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ==================================================== What: /sys/bus/platform/drivers/ufshcd/*/rpm_target_dev_state@@ -954,21 +957,24 @@ Date: September 2014 Contact: Subhash Jadavani <[email protected]> Description: This entry could be used to set or show the UFS device system power management level. The current driver - implementation supports 6 levels with next target states: + implementation supports 7 levels with next target states: == ==================================================== - 0 an UFS device will stay active, an UIC link will + 0 UFS device will stay active, UIC link will stay active - 1 an UFS device will stay active, an UIC link will + 1 UFS device will stay active, UIC link will hibernate - 2 an UFS device will moved to sleep, an UIC link will + 2 UFS device will be moved to sleep, UIC link will stay active - 3 an UFS device will moved to sleep, an UIC link will + 3 UFS device will be moved to sleep, UIC link will hibernate - 4 an UFS device will be powered off, an UIC link will + 4 UFS device will be powered off, UIC link will hibernate - 5 an UFS device will be powered off, an UIC link will + 5 UFS device will be powered off, UIC link will be powered off + 6 UFS device will be moved to deep sleep, UIC link + will be powered off. Note, deep sleep might not be + supported in which case this value will not be accepted == ==================================================== What: /sys/bus/platform/drivers/ufshcd/*/spm_target_dev_statedrivers/scsi/ufs/ufs-sysfs.c +7
-0@@ -28,6 +28,7 @@ static const char *ufschd_ufs_dev_pwr_mode_to_string(case UFS_ACTIVE_PWR_MODE :return "ACTIVE" ;case UFS_SLEEP_PWR_MODE :return "SLEEP" ;case UFS_POWERDOWN_PWR_MODE :return "POWERDOWN" ; +case UFS_DEEPSLEEP_PWR_MODE :return "DEEPSLEEP" ;default :return "UNKNOWN" ; } }@@ -38,6 +39,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, bool rpm) {struct ufs_hba *hba =dev_get_drvdata (dev); +struct ufs_dev_info *dev_info = &hba->dev_info;unsigned long flags, value;if (kstrtoul (buf,0 , &value))@@ -46,6 +48,11 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev,if (value >=UFS_PM_LVL_MAX )return -EINVAL ; +if (ufs_pm_lvl_states[value].dev_state ==UFS_DEEPSLEEP_PWR_MODE && + (!(hba->caps &UFSHCD_CAP_DEEPSLEEP ) || + !(dev_info->wspecversion >=0x310 ))) +return -EINVAL ; +spin_lock_irqsave (hba->host->host_lock, flags);if (rpm) hba->rpm_lvl = value;drivers/scsi/ufs/ufs.h +1
-0@@ -442,6 +442,7 @@ enum ufs_dev_pwr_mode {UFS_ACTIVE_PWR_MODE =1 ,UFS_SLEEP_PWR_MODE =2 ,UFS_POWERDOWN_PWR_MODE =3 , + UFS_DEEPSLEEP_PWR_MODE = 4, };#define UFS_WB_BUF_REMAIN_PERCENT (val) ((val) / 10)drivers/scsi/ufs/ufshcd.c +37
-2@@ -163,6 +163,11 @@ struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE}, {UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE}, +/* +* For DeepSleep, the link is first put in hibern8 and then off. +* Leaving the link in hibern8 is not supported. +*/ + {UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE}, }; static inline enum ufs_dev_pwr_mode@@ -8297,7 +8302,8 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba, }/* * If autobkops is enabled, link can't be turned off because -* turning off the link would also turn off the device. +* turning off the link would also turn off the device, except in the +* case of DeepSleep where the device is expected to remain powered. */ else if ((req_link_state ==UIC_LINK_OFF_STATE ) && (!check_for_bkops || !hba->auto_bkops_enabled)) {@@ -8307,6 +8313,9 @@ static int ufshcd_link_state_transition(struct ufs_hba *hba,* put the link in low power mode is to send the DME end point * to device and then send the DME reset command to local * unipro. But putting the link in hibern8 is much faster. +* +* Note also that putting the link in Hibern8 is a requirement +* for entering DeepSleep. */ ret =ufshcd_uic_hibern8_enter (hba);if (ret) {@@ -8439,6 +8448,7 @@ static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba)static int ufshcd_suspend (struct ufs_hba *hba,enum ufs_pm_op pm_op) {int ret =0 ; +int check_for_bkops;enum ufs_pm_level pm_lvl;enum ufs_dev_pwr_mode req_dev_pwr_mode;enum uic_link_state req_link_state;@@ -8524,7 +8534,13 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) }flush_work (&hba->eeh_work); - ret =ufshcd_link_state_transition (hba, req_link_state,1 ); + +/* +* In the case of DeepSleep, the device is expected to remain powered +* with the link off, so do not check for bkops. +*/ + check_for_bkops = !ufshcd_is_ufs_dev_deepsleep (hba); + ret =ufshcd_link_state_transition (hba, req_link_state, check_for_bkops);if (ret) goto set_dev_active;@@ -8565,11 +8581,25 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (hba->clk_scaling.is_allowed)ufshcd_resume_clkscaling (hba);ufshcd_vreg_set_hpm (hba); +/* +* Device hardware reset is required to exit DeepSleep. Also, for +* DeepSleep, the link is off so host reset and restore will be done +* further below. +*/ +if (ufshcd_is_ufs_dev_deepsleep (hba)) { +ufshcd_vops_device_reset (hba); +WARN_ON (!ufshcd_is_link_off (hba)); + }if (ufshcd_is_link_hibern8 (hba) && !ufshcd_uic_hibern8_exit (hba))ufshcd_set_link_active (hba);else if (ufshcd_is_link_off (hba))ufshcd_host_reset_and_restore (hba); set_dev_active: +/* Can also get here needing to exit DeepSleep */ +if (ufshcd_is_ufs_dev_deepsleep (hba)) { +ufshcd_vops_device_reset (hba); +ufshcd_host_reset_and_restore (hba); + }if (!ufshcd_set_dev_pwr_mode (hba,UFS_ACTIVE_PWR_MODE ))ufshcd_disable_auto_bkops (hba); enable_gating:@@ -8631,6 +8661,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)if (ret) goto disable_vreg; +/* For DeepSleep, the only supported option is to have the link off */ +WARN_ON (ufshcd_is_ufs_dev_deepsleep (hba) && !ufshcd_is_link_off (hba)); +if (ufshcd_is_link_hibern8 (hba)) { ret =ufshcd_uic_hibern8_exit (hba);if (!ret) {@@ -8644,6 +8677,8 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)/* * A full initialization of the host and the device is * required since the link was put to off during suspend. +* Note, in the case of DeepSleep, the device will exit +* DeepSleep due to device reset. */ ret =ufshcd_reset_and_restore (hba);/* drivers/scsi/ufs/ufshcd.h +16
-1@@ -114,16 +114,22 @@ enum uic_link_state { ((h)->curr_dev_pwr_mode = UFS_SLEEP_PWR_MODE)#define ufshcd_set_ufs_dev_poweroff (h) \ ((h)->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE) +#define ufshcd_set_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode = UFS_DEEPSLEEP_PWR_MODE)#define ufshcd_is_ufs_dev_active (h) \ ((h)->curr_dev_pwr_mode == UFS_ACTIVE_PWR_MODE)#define ufshcd_is_ufs_dev_sleep (h) \ ((h)->curr_dev_pwr_mode == UFS_SLEEP_PWR_MODE)#define ufshcd_is_ufs_dev_poweroff (h) \ ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) +#define ufshcd_is_ufs_dev_deepsleep (h) \ + ((h)->curr_dev_pwr_mode == UFS_DEEPSLEEP_PWR_MODE)/* * UFS Power management levels. -* Each level is in increasing order of power savings. +* Each level is in increasing order of power savings, except DeepSleep +* which is lower than PowerDown with power on but not PowerDown with +* power off. */ enum ufs_pm_level {UFS_PM_LVL_0 ,/* UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE */ @@ -132,6 +138,7 @@ enum ufs_pm_level {UFS_PM_LVL_3 ,/* UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_4 ,/* UFS_POWERDOWN_PWR_MODE, UIC_LINK_HIBERN8_STATE */ UFS_PM_LVL_5 ,/* UFS_POWERDOWN_PWR_MODE, UIC_LINK_OFF_STATE */ +UFS_PM_LVL_6 ,/* UFS_DEEPSLEEP_PWR_MODE, UIC_LINK_OFF_STATE */ UFS_PM_LVL_MAX };@@ -599,6 +606,14 @@ enum ufshcd_caps {* This would increase power savings. */ UFSHCD_CAP_AGGR_POWER_COLLAPSE =1 <<9 , + +/* +* This capability allows the host controller driver to use DeepSleep, +* if it is supported by the UFS device. The host controller driver must +* support device hardware reset via the hba->device_reset() callback, +* in order to exit DeepSleep state. +*/ + UFSHCD_CAP_DEEPSLEEP = 1 << 10, }; struct ufs_hba_variant_params {include/trace/events/ufs.h +2
-1@@ -19,7 +19,8 @@#define UFS_PWR_MODES \ EM(UFS_ACTIVE_PWR_MODE) \ EM(UFS_SLEEP_PWR_MODE) \ - EMe(UFS_POWERDOWN_PWR_MODE) + EM(UFS_POWERDOWN_PWR_MODE) \ + EMe(UFS_DEEPSLEEP_PWR_MODE)#define UFSCHD_CLK_GATING_STATES \ EM(CLKS_OFF) \
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, Linux Foundation Collaborative Project
Quoted 9 lines · Adrian Hunter
DeepSleep is a UFS v3.1 feature that achieves the lowest power consumption of the device, apart from power off.
In DeepSleep mode, no commands are accepted, and the only way to exit is using a hardware reset or power cycle.
This patch assumes that if a power cycle was an option, then power off would be preferable, so only exit via a hardware reset is supported.
Quoted 8 lines
Drivers that wish to support DeepSleep need to set a new capability flag
UFSHCD_CAP_DEEPSLEEPand provide a hardware reset via the existing
->device_reset() callback.It is assumed that UFS devices with wspecversion >=
0x310support DeepSleep.Signed-off-by Adrian Hunter <[email protected]>
PATCH v4 2/2 scsi: ufs: Allow an error return value from ->device_reset()
In reply to Adrian HunterIt is simpler for drivers to provide a ->device_reset() callback irrespective of whether the GPIO, or firmware interface necessary to do the reset, is discovered during probe.
Change ->device_reset() to return an error code. Drivers that provide the callback, but do not do the reset operation should return -EOPNOTSUPP.
--- drivers/scsi/ufs/ufs-mediatek.c | 4 +++- drivers/scsi/ufs/ufs-qcom.c | 6 ++++-- drivers/scsi/ufs/ufshcd.h | 11 +++++++---- 3 files changed, 14 insertions(+), 7 deletions(-)
drivers/scsi/ufs/ufs-mediatek.c +3 -1
@@ -743,7 +743,7 @@ static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,return ret; } -static void ufs_mtk_device_reset (struct ufs_hba *hba) +static int ufs_mtk_device_reset (struct ufs_hba *hba) {struct arm_smccc_res res;
@@ -764,6 +764,8 @@ static void ufs_mtk_device_reset(struct ufs_hba *hba)usleep_range (10000 ,15000 );dev_info (hba->dev,"device reset done\n" ); + +return 0 ; }static int ufs_mtk_link_set_hpm (struct ufs_hba *hba)
drivers/scsi/ufs/ufs-qcom.c +4 -2
@@ -1422,13 +1422,13 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)* * Toggles the (optional) reset line to reset the attached device. */ -static void ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);/* reset gpio is optional */ if (!host->device_reset) -return ; +return -EOPNOTSUPP ;/* * The UFS device shall detect reset pulses of 1us, sleep for 10us to
@@ -1439,6 +1439,8 @@ static void ufs_qcom_device_reset(struct ufs_hba *hba)gpiod_set_value_cansleep (host->device_reset,0 );usleep_range (10 ,15 ); + +return 0 ; }#if IS_ENABLED (CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND )
drivers/scsi/ufs/ufshcd.h +7 -4
@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -void (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba);void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);
@@ -1207,9 +1207,12 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)static inline void ufshcd_vops_device_reset (struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { - hba->vops->device_reset (hba); -ufshcd_set_ufs_dev_active (hba); -ufshcd_update_reg_hist (&hba->ufs_stats.dev_reset,0 ); +int err = hba->vops->device_reset (hba); + +if (!err) +ufshcd_set_ufs_dev_active (hba); +if (err != -EOPNOTSUPP ) +ufshcd_update_reg_hist (&hba->ufs_stats.dev_reset, err); } }
Signature · 1 line
2.17.1
Re: [PATCH V4 2/2] scsi: ufs: Allow an error return value from ->device_reset()
Hi Adrian,
Quoted 83 lines · Adrian Hunter
It is simpler for drivers to provide a ->device_reset() callback irrespective of whether the GPIO, or firmware interface necessary to do the reset, is discovered during probe.
Change ->device_reset() to return an error code. Drivers that provide the callback, but do not do the reset operation should return
-EOPNOTSUPP.Signed-off-by Adrian Hunter <[email protected]>--- drivers/scsi/ufs/ufs-mediatek.c | 4 +++- drivers/scsi/ufs/ufs-qcom.c | 6 ++++-- drivers/scsi/ufs/ufshcd.h | 11 +++++++---- 3 files changed, 14 insertions(+), 7 deletions(-)drivers/scsi/ufs/ufs-mediatek.c +3
-1@@ -743,7 +743,7 @@ static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,return ret; } -static void ufs_mtk_device_reset (struct ufs_hba *hba) +static int ufs_mtk_device_reset (struct ufs_hba *hba) {struct arm_smccc_res res;@@ -764,6 +764,8 @@ static void ufs_mtk_device_reset(struct ufs_hba *hba)usleep_range (10000 ,15000 );dev_info (hba->dev,"device reset done\n" ); + +return 0 ; }static int ufs_mtk_link_set_hpm (struct ufs_hba *hba)drivers/scsi/ufs/ufs-qcom.c +4
-2@@ -1422,13 +1422,13 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)* * Toggles the (optional) reset line to reset the attached device. */ -static void ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);/* reset gpio is optional */ if (!host->device_reset) -return ; +return -EOPNOTSUPP ;/* * The UFS device shall detect reset pulses of 1us, sleep for 10us to @@ -1439,6 +1439,8 @@ static void ufs_qcom_device_reset(struct ufs_hba *hba)gpiod_set_value_cansleep (host->device_reset,0 );usleep_range (10 ,15 ); + +return 0 ; }#if IS_ENABLED (CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND )drivers/scsi/ufs/ufshcd.h +1
-2@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -void (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba);void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);@@ -1207,9 +1207,12 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)static inline void ufshcd_vops_device_reset (struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { - hba->vops->device_reset (hba);
drivers/scsi/ufs/ufshcd.h static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) · line 1217
Quoted 10 lines
drivers/scsi/ufs/ufshcd.h +6
-2-ufshcd_set_ufs_dev_active (hba); -ufshcd_update_reg_hist (&hba->ufs_stats.dev_reset,0 ); +int err = hba->vops->device_reset (hba); + +if (!err) +ufshcd_set_ufs_dev_active (hba); +if (err != -EOPNOTSUPP ) +ufshcd_update_reg_hist (&hba->ufs_stats.dev_reset, err); } }
For ufs-mediatek part and related flow,
Re: [PATCH V4 2/2] scsi: ufs: Allow an error return value from ->device_reset()
In reply to Adrian HunterQuoted 9 lines · Adrian Hunter
It is simpler for drivers to provide a ->device_reset() callback irrespective of whether the GPIO, or firmware interface necessary to do the reset, is discovered during probe.
Change ->device_reset() to return an error code. Drivers that provide the callback, but do not do the reset operation should return
-EOPNOTSUPP.Signed-off-by Adrian Hunter <[email protected]>
Quoted 90 lines
--- drivers/scsi/ufs/ufs-mediatek.c | 4 +++- drivers/scsi/ufs/ufs-qcom.c | 6 ++++-- drivers/scsi/ufs/ufshcd.h | 11 +++++++---- 3 files changed, 14 insertions(+), 7 deletions(-)drivers/scsi/ufs/ufs-mediatek.c +3
-1@@ -743,7 +743,7 @@ static int ufs_mtk_link_startup_notify(structufs_hba *hba, return ret; } -static void ufs_mtk_device_reset (struct ufs_hba *hba) +static int ufs_mtk_device_reset (struct ufs_hba *hba) {struct arm_smccc_res res;@@ -764,6 +764,8 @@ static void ufs_mtk_device_reset(struct ufs_hba *hba)usleep_range (10000 ,15000 );dev_info (hba->dev,"device reset done\n" ); + +return 0 ; }static int
ufs_mtk_link_set_hpm(struct ufs_hba *hba)drivers/scsi/ufs/ufs-qcom.c +2
-2@@ -1422,13 +1422,13 @@ static void ufs_qcom_dump_dbg_regs(structufs_hba *hba) * * Toggles the (optional) reset line to reset the attached device. */ -static void ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);/* reset gpio is optional */ if (!host->device_reset) -return ; +return -EOPNOTSUPP ;/* drivers/scsi/ufs/ufs-qcom.c +2
-0* The UFS device shall detect reset pulses of 1us, sleep for 10us to @@ -1439,6 +1439,8 @@ static void ufs_qcom_device_reset(struct ufs_hba *hba)gpiod_set_value_cansleep (host->device_reset,0 );usleep_range (10 ,15 ); + +return 0 ; }#if
IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)drivers/scsi/ufs/ufshcd.h +7
-4@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -void (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba);void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);@@ -1207,9 +1207,12 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) static inline void ufshcd_vops_device_reset(struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { - hba->vops->device_reset (hba); -ufshcd_set_ufs_dev_active (hba); -ufshcd_update_reg_hist (&hba->ufs_stats.dev_reset,0 ); +int err = hba->vops->device_reset (hba); + +if (!err) +ufshcd_set_ufs_dev_active (hba); +if (err != -EOPNOTSUPP ) +ufshcd_update_reg_hist (&hba->ufs_stats.dev_reset, err); } }
Re: [PATCH V4 2/2] scsi: ufs: Allow an error return value from ->device_reset()
In reply to Adrian HunterQuoted 11 lines · Adrian Hunter
It is simpler for drivers to provide a ->device_reset() callback irrespective of whether the GPIO, or firmware interface necessary to do the
reset, is discovered during probe.Change ->device_reset() to return an error code. Drivers that provide
the callback, but do not do the reset operation should return-EOPNOTSUPP.Signed-off-by Adrian Hunter <[email protected]>
Re: [PATCH V4 2/2] scsi: ufs: Allow an error return value from ->device_reset()
In reply to Adrian HunterQuoted 8 lines · Adrian Hunter
It is simpler for drivers to provide a ->device_reset() callback irrespective of whether the GPIO, or firmware interface necessary to do the reset, is discovered during probe.
Change ->device_reset() to return an error code. Drivers that provide the callback, but do not do the reset operation should return
-EOPNOTSUPP.Signed-off-by Adrian Hunter <[email protected]>
Quoted 87 lines
--- drivers/scsi/ufs/ufs-mediatek.c | 4 +++- drivers/scsi/ufs/ufs-qcom.c | 6 ++++-- drivers/scsi/ufs/ufshcd.h | 11 +++++++---- 3 files changed, 14 insertions(+), 7 deletions(-)drivers/scsi/ufs/ufs-mediatek.c +3
-1@@ -743,7 +743,7 @@ static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,return ret; } -static void ufs_mtk_device_reset (struct ufs_hba *hba) +static int ufs_mtk_device_reset (struct ufs_hba *hba) {struct arm_smccc_res res;@@ -764,6 +764,8 @@ static void ufs_mtk_device_reset(struct ufs_hba *hba)usleep_range (10000 ,15000 );dev_info (hba->dev,"device reset done\n" ); + +return 0 ; }static int ufs_mtk_link_set_hpm (struct ufs_hba *hba)drivers/scsi/ufs/ufs-qcom.c +4
-2@@ -1422,13 +1422,13 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)* * Toggles the (optional) reset line to reset the attached device. */ -static void ufs_qcom_device_reset (struct ufs_hba *hba) +static int ufs_qcom_device_reset (struct ufs_hba *hba) {struct ufs_qcom_host *host =ufshcd_get_variant (hba);/* reset gpio is optional */ if (!host->device_reset) -return ; +return -EOPNOTSUPP ;/* * The UFS device shall detect reset pulses of 1us, sleep for 10us to @@ -1439,6 +1439,8 @@ static void ufs_qcom_device_reset(struct ufs_hba *hba)gpiod_set_value_cansleep (host->device_reset,0 );usleep_range (10 ,15 ); + +return 0 ; }#if IS_ENABLED (CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND )drivers/scsi/ufs/ufshcd.h +7
-4@@ -323,7 +323,7 @@ struct ufs_hba_variant_ops {int (*resume)(struct ufs_hba *,enum ufs_pm_op );void (*dbg_register_dump)(struct ufs_hba *hba);int (*phy_initialization)(struct ufs_hba *); -void (*device_reset)(struct ufs_hba *hba); +int (*device_reset)(struct ufs_hba *hba);void (*config_scaling_param)(struct ufs_hba *hba,struct devfreq_dev_profile *profile,void *data);@@ -1207,9 +1207,12 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)static inline void ufshcd_vops_device_reset (struct ufs_hba *hba) {if (hba->vops && hba->vops->device_reset) { - hba->vops->device_reset (hba); -ufshcd_set_ufs_dev_active (hba); -ufshcd_update_reg_hist (&hba->ufs_stats.dev_reset,0 ); +int err = hba->vops->device_reset (hba); + +if (!err) +ufshcd_set_ufs_dev_active (hba); +if (err != -EOPNOTSUPP ) +ufshcd_update_reg_hist (&hba->ufs_stats.dev_reset, err); } }
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, Linux Foundation Collaborative Project
Martin K. Petersen
AppliedAdrian,
Quoted 1 line
Here is V4 of the DeepSleep feature patches.
Applied to 5.11/scsi-staging, thanks!
I left out the sysfs ABI piece due to the conflicts. I suggest you send that piece through the doc tree.
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Martin K. Petersen
AppliedQuoted 8 lines · Adrian Hunter
Here is V4 of the DeepSleep feature patches.
Changes in V4:
Rebased Added new patch "scsi: ufs: Allow an error return value from ->device_reset()"[...]
Applied to 5.11/scsi-queue, thanks!
[1/2] scsi: ufs: Add DeepSleep feature
https://git.kernel.org/mkp/scsi/c/fe1d4c2ebcae [2/2] scsi: ufs: Allow an error return value from ->device_reset() https://git.kernel.org/mkp/scsi/c/151f1b664ffb
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering