scsi: ufs: ufs-sysfs: Expose UFS power info
authorCan Guo <quic_cang@quicinc.com>
Thu, 2 Nov 2023 01:58:36 +0000 (18:58 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 15 Nov 2023 15:23:55 +0000 (10:23 -0500)
Having UFS power info available in sysfs makes it easier to tell the state
of the link during runtime considering we have a bunch of power saving
features and various combinations for backward compatibility.

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Can Guo <quic_cang@quicinc.com>
Link: https://lore.kernel.org/r/1698890324-7374-1-git-send-email-quic_cang@quicinc.com
Reviewed-by: Avri Altman <avri.altman@wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Documentation/ABI/testing/sysfs-driver-ufs
drivers/ufs/core/ufs-sysfs.c
include/ufs/unipro.h

index 0c7efaf62de0c00b5f481b27e547fd24a022959f..b73067bb5ea2cef0dc408f057a53e6ff9f1c535b 100644 (file)
@@ -1223,6 +1223,55 @@ Description:     This file shows the total latency (in micro seconds) of write
 
                The file is read only.
 
+What:          /sys/bus/platform/drivers/ufshcd/*/power_info/lane
+What:          /sys/bus/platform/devices/*.ufs/power_info/lane
+Date:          September 2023
+Contact:       Can Guo <quic_cang@quicinc.com>
+Description:   This file shows how many lanes are enabled on the UFS link,
+               i.e., an output 2 means UFS link is operating with 2 lanes.
+
+               The file is read only.
+
+What:          /sys/bus/platform/drivers/ufshcd/*/power_info/mode
+What:          /sys/bus/platform/devices/*.ufs/power_info/mode
+Date:          September 2023
+Contact:       Can Guo <quic_cang@quicinc.com>
+Description:   This file shows the PA power mode of UFS.
+
+               The file is read only.
+
+What:          /sys/bus/platform/drivers/ufshcd/*/power_info/rate
+What:          /sys/bus/platform/devices/*.ufs/power_info/rate
+Date:          September 2023
+Contact:       Can Guo <quic_cang@quicinc.com>
+Description:   This file shows the speed rate of UFS link.
+
+               The file is read only.
+
+What:          /sys/bus/platform/drivers/ufshcd/*/power_info/gear
+What:          /sys/bus/platform/devices/*.ufs/power_info/gear
+Date:          September 2023
+Contact:       Can Guo <quic_cang@quicinc.com>
+Description:   This file shows the gear of UFS link.
+
+               The file is read only.
+
+What:          /sys/bus/platform/drivers/ufshcd/*/power_info/dev_pm
+What:          /sys/bus/platform/devices/*.ufs/power_info/dev_pm
+Date:          September 2023
+Contact:       Can Guo <quic_cang@quicinc.com>
+Description:   This file shows the UFS device power mode.
+
+               The file is read only.
+
+What:          /sys/bus/platform/drivers/ufshcd/*/power_info/link_state
+What:          /sys/bus/platform/devices/*.ufs/power_info/link_state
+Date:          September 2023
+Contact:       Can Guo <quic_cang@quicinc.com>
+Description:   This file shows the state of UFS link.
+
+               The file is read only.
+
 What:          /sys/bus/platform/drivers/ufshcd/*/device_descriptor/wb_presv_us_en
 What:          /sys/bus/platform/devices/*.ufs/device_descriptor/wb_presv_us_en
 Date:          June 2020
index c95906443d5f9d5548ec6c03ec5b051fbbf6531e..05b10ca90b50d6d869d84db8990cac419534da2b 100644 (file)
@@ -7,9 +7,56 @@
 #include <asm/unaligned.h>
 
 #include <ufs/ufs.h>
+#include <ufs/unipro.h>
 #include "ufs-sysfs.h"
 #include "ufshcd-priv.h"
 
+static const char *ufs_pa_pwr_mode_to_string(enum ufs_pa_pwr_mode mode)
+{
+       switch (mode) {
+       case FAST_MODE:         return "FAST_MODE";
+       case SLOW_MODE:         return "SLOW_MODE";
+       case FASTAUTO_MODE:     return "FASTAUTO_MODE";
+       case SLOWAUTO_MODE:     return "SLOWAUTO_MODE";
+       default:                return "UNKNOWN";
+       }
+}
+
+static const char *ufs_hs_gear_rate_to_string(enum ufs_hs_gear_rate rate)
+{
+       switch (rate) {
+       case PA_HS_MODE_A:      return "HS_RATE_A";
+       case PA_HS_MODE_B:      return "HS_RATE_B";
+       default:                return "UNKNOWN";
+       }
+}
+
+static const char *ufs_pwm_gear_to_string(enum ufs_pwm_gear_tag gear)
+{
+       switch (gear) {
+       case UFS_PWM_G1:        return "PWM_GEAR1";
+       case UFS_PWM_G2:        return "PWM_GEAR2";
+       case UFS_PWM_G3:        return "PWM_GEAR3";
+       case UFS_PWM_G4:        return "PWM_GEAR4";
+       case UFS_PWM_G5:        return "PWM_GEAR5";
+       case UFS_PWM_G6:        return "PWM_GEAR6";
+       case UFS_PWM_G7:        return "PWM_GEAR7";
+       default:                return "UNKNOWN";
+       }
+}
+
+static const char *ufs_hs_gear_to_string(enum ufs_hs_gear_tag gear)
+{
+       switch (gear) {
+       case UFS_HS_G1: return "HS_GEAR1";
+       case UFS_HS_G2: return "HS_GEAR2";
+       case UFS_HS_G3: return "HS_GEAR3";
+       case UFS_HS_G4: return "HS_GEAR4";
+       case UFS_HS_G5: return "HS_GEAR5";
+       default:        return "UNKNOWN";
+       }
+}
+
 static const char *ufshcd_uic_link_state_to_string(
                        enum uic_link_state state)
 {
@@ -628,6 +675,78 @@ static const struct attribute_group ufs_sysfs_monitor_group = {
        .attrs = ufs_sysfs_monitor_attrs,
 };
 
+static ssize_t lane_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%u\n", hba->pwr_info.lane_rx);
+}
+
+static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%s\n", ufs_pa_pwr_mode_to_string(hba->pwr_info.pwr_rx));
+}
+
+static ssize_t rate_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%s\n", ufs_hs_gear_rate_to_string(hba->pwr_info.hs_rate));
+}
+
+static ssize_t gear_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%s\n", hba->pwr_info.hs_rate ?
+                         ufs_hs_gear_to_string(hba->pwr_info.gear_rx) :
+                         ufs_pwm_gear_to_string(hba->pwr_info.gear_rx));
+}
+
+static ssize_t dev_pm_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%s\n", ufshcd_ufs_dev_pwr_mode_to_string(hba->curr_dev_pwr_mode));
+}
+
+static ssize_t link_state_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct ufs_hba *hba = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%s\n", ufshcd_uic_link_state_to_string(hba->uic_link_state));
+}
+
+static DEVICE_ATTR_RO(lane);
+static DEVICE_ATTR_RO(mode);
+static DEVICE_ATTR_RO(rate);
+static DEVICE_ATTR_RO(gear);
+static DEVICE_ATTR_RO(dev_pm);
+static DEVICE_ATTR_RO(link_state);
+
+static struct attribute *ufs_power_info_attrs[] = {
+       &dev_attr_lane.attr,
+       &dev_attr_mode.attr,
+       &dev_attr_rate.attr,
+       &dev_attr_gear.attr,
+       &dev_attr_dev_pm.attr,
+       &dev_attr_link_state.attr,
+       NULL
+};
+
+static const struct attribute_group ufs_sysfs_power_info_group = {
+       .name = "power_info",
+       .attrs = ufs_power_info_attrs,
+};
+
 static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,
                                  enum desc_idn desc_id,
                                  u8 desc_index,
@@ -1233,6 +1352,7 @@ static const struct attribute_group *ufs_sysfs_groups[] = {
        &ufs_sysfs_default_group,
        &ufs_sysfs_capabilities_group,
        &ufs_sysfs_monitor_group,
+       &ufs_sysfs_power_info_group,
        &ufs_sysfs_device_descriptor_group,
        &ufs_sysfs_interconnect_descriptor_group,
        &ufs_sysfs_geometry_descriptor_group,
index 256eb3a43f54078e2f71699c33ce78a67f4ea7f9..360e1245fb4063b5048e2bca14acd463bcd3c3e9 100644 (file)
 #define DME_LocalAFC0ReqTimeOutVal             0xD043
 
 /* PA power modes */
-enum {
+enum ufs_pa_pwr_mode {
        FAST_MODE       = 1,
        SLOW_MODE       = 2,
        FASTAUTO_MODE   = 4,
@@ -205,7 +205,7 @@ enum {
 #define PWRMODE_RX_OFFSET      4
 
 /* PA TX/RX Frequency Series */
-enum {
+enum ufs_hs_gear_rate {
        PA_HS_MODE_A    = 1,
        PA_HS_MODE_B    = 2,
 };