summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/ufs/ufs-sysfs.c
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2020-11-03 16:14:02 +0200
committerMartin K. Petersen <martin.petersen@oracle.com>2020-11-04 23:03:28 -0500
commitfe1d4c2ebcae994dffe8673cc3cba10102d15d11 (patch)
tree1c0acec2f96d93c6aa4471d0d6fbd1989115afd7 /drivers/scsi/ufs/ufs-sysfs.c
parent1f889b58716a5f5e3e4fe0e6742c1a4472f29ac1 (diff)
downloadlinux-stable-fe1d4c2ebcae994dffe8673cc3cba10102d15d11.tar.gz
linux-stable-fe1d4c2ebcae994dffe8673cc3cba10102d15d11.tar.bz2
linux-stable-fe1d4c2ebcae994dffe8673cc3cba10102d15d11.zip
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. [mkp: dropped sysfs ABI doc due to conflicts] Link: https://lore.kernel.org/r/20201103141403.2142-2-adrian.hunter@intel.com Reviewed-by: Bean Huo <beanhuo@micron.com> Reviewed-by: Asutosh Das <asutoshd@codeaurora.org> Reviewed-by: Stanley Chu <stanley.chu@mediatek.com> Reviewed-by: Can Guo <cang@codeaurora.org> Acked-by: Jonathan Corbet <corbet@lwn.net> Acked-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/ufs/ufs-sysfs.c')
-rw-r--r--drivers/scsi/ufs/ufs-sysfs.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index bdcd27faa054..08e72b7eef6a 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -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;