Loading drivers/scsi/ufs/ufs.h +11 −1 Original line number Diff line number Diff line Loading @@ -151,8 +151,9 @@ enum ufs_desc_def_size { QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, QUERY_DESC_UNIT_DEF_SIZE = 0x23, QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44, QUERY_DESC_GEOMETRY_DEF_SIZE = 0x48, QUERY_DESC_POWER_DEF_SIZE = 0x62, QUERY_DESC_HEALTH_DEF_SIZE = 0x25, }; /* Unit descriptor parameters offsets in bytes*/ Loading Loading @@ -206,6 +207,15 @@ enum device_desc_param { DEVICE_DESC_PARAM_FRQ_RTC = 0x1D, }; /* Health descriptor parameters offsets in bytes*/ enum health_desc_param { HEALTH_DESC_PARAM_LEN = 0x0, HEALTH_DESC_PARAM_TYPE = 0x1, HEALTH_DESC_PARAM_EOL_INFO = 0x2, HEALTH_DESC_PARAM_LIFE_TIME_EST_A = 0x3, HEALTH_DESC_PARAM_LIFE_TIME_EST_B = 0x4, }; /* * Logical Unit Write Protect * 00h: LU not write protected Loading drivers/scsi/ufs/ufshcd.c +106 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ #include <linux/nls.h> #include <linux/of.h> #include <linux/blkdev.h> #include <asm/unaligned.h> #include "ufshcd.h" #include "ufs_quirks.h" #include "unipro.h" Loading Loading @@ -4520,6 +4522,9 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, case QUERY_DESC_IDN_STRING: *desc_len = QUERY_DESC_MAX_SIZE; break; case QUERY_DESC_IDN_HEALTH: *desc_len = hba->desc_size.hlth_desc; break; case QUERY_DESC_IDN_RFU_0: case QUERY_DESC_IDN_RFU_1: *desc_len = 0; Loading Loading @@ -8560,6 +8565,11 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba) &hba->desc_size.geom_desc); if (err) hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0, &hba->desc_size.hlth_desc); if (err) hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; } static void ufshcd_def_desc_sizes(struct ufs_hba *hba) Loading @@ -8570,6 +8580,7 @@ static void ufshcd_def_desc_sizes(struct ufs_hba *hba) hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; } static void ufshcd_apply_pm_quirks(struct ufs_hba *hba) Loading Loading @@ -10690,16 +10701,111 @@ static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba) dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n"); } static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, u8 desc_index, u8 param_offset, u8 *sysfs_buf, u8 param_size) { u8 desc_buf[8] = {0}; int ret; if (param_size > 8) return -EINVAL; pm_runtime_get_sync(hba->dev); ret = ufshcd_read_desc_param(hba, desc_id, desc_index, param_offset, desc_buf, param_size); pm_runtime_put_sync(hba->dev); if (ret) return -EINVAL; switch (param_size) { case 1: ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%02X\n", *desc_buf); break; case 2: ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%04X\n", get_unaligned_be16(desc_buf)); break; case 4: ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%08X\n", get_unaligned_be32(desc_buf)); break; case 8: ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%016llX\n", get_unaligned_be64(desc_buf)); break; } return ret; } #define UFS_DESC_PARAM(_name, _puname, _duname, _size) \ static ssize_t _name##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct ufs_hba *hba = dev_get_drvdata(dev); \ return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \ 0, _duname##_DESC_PARAM##_puname, buf, _size); \ } \ static DEVICE_ATTR_RO(_name) #define UFS_HEALTH_DESC_PARAM(_name, _uname, _size) \ UFS_DESC_PARAM(_name, _uname, HEALTH, _size) UFS_HEALTH_DESC_PARAM(eol_info, _EOL_INFO, 1); UFS_HEALTH_DESC_PARAM(life_time_estimation_a, _LIFE_TIME_EST_A, 1); UFS_HEALTH_DESC_PARAM(life_time_estimation_b, _LIFE_TIME_EST_B, 1); static struct attribute *ufs_sysfs_health_descriptor[] = { &dev_attr_eol_info.attr, &dev_attr_life_time_estimation_a.attr, &dev_attr_life_time_estimation_b.attr, NULL, }; static const struct attribute_group ufs_sysfs_health_descriptor_group = { .name = "health_descriptor", .attrs = ufs_sysfs_health_descriptor, }; static const struct attribute_group *ufs_sysfs_groups[] = { &ufs_sysfs_health_descriptor_group, NULL, }; static void ufshcd_add_desc_sysfs_nodes(struct device *dev) { int ret; ret = sysfs_create_groups(&dev->kobj, ufs_sysfs_groups); if (ret) dev_err(dev, "%s: sysfs groups creation failed (err = %d)\n", __func__, ret); } static void ufshcd_remove_desc_sysfs_nodes(struct device *dev) { sysfs_remove_groups(&dev->kobj, ufs_sysfs_groups); } static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba) { ufshcd_add_rpm_lvl_sysfs_nodes(hba); ufshcd_add_spm_lvl_sysfs_nodes(hba); ufshcd_add_desc_sysfs_nodes(hba->dev); } static inline void ufshcd_remove_sysfs_nodes(struct ufs_hba *hba) { device_remove_file(hba->dev, &hba->rpm_lvl_attr); device_remove_file(hba->dev, &hba->spm_lvl_attr); ufshcd_remove_desc_sysfs_nodes(hba->dev); } static void __ufshcd_shutdown_clkscaling(struct ufs_hba *hba) Loading drivers/scsi/ufs/ufshcd.h +1 −0 Original line number Diff line number Diff line Loading @@ -259,6 +259,7 @@ struct ufs_desc_size { int interc_desc; int unit_desc; int conf_desc; int hlth_desc; }; /** Loading include/uapi/scsi/ufs/ufs.h +2 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,8 @@ enum desc_idn { QUERY_DESC_IDN_RFU_1 = 0x6, QUERY_DESC_IDN_GEOMETRY = 0x7, QUERY_DESC_IDN_POWER = 0x8, QUERY_DESC_IDN_RFU_2 = 0x9, QUERY_DESC_IDN_HEALTH = 0x9, QUERY_DESC_IDN_RFU_2 = 0x0A, QUERY_DESC_IDN_MAX, }; Loading Loading
drivers/scsi/ufs/ufs.h +11 −1 Original line number Diff line number Diff line Loading @@ -151,8 +151,9 @@ enum ufs_desc_def_size { QUERY_DESC_CONFIGURATION_DEF_SIZE = 0x90, QUERY_DESC_UNIT_DEF_SIZE = 0x23, QUERY_DESC_INTERCONNECT_DEF_SIZE = 0x06, QUERY_DESC_GEOMETRY_DEF_SIZE = 0x44, QUERY_DESC_GEOMETRY_DEF_SIZE = 0x48, QUERY_DESC_POWER_DEF_SIZE = 0x62, QUERY_DESC_HEALTH_DEF_SIZE = 0x25, }; /* Unit descriptor parameters offsets in bytes*/ Loading Loading @@ -206,6 +207,15 @@ enum device_desc_param { DEVICE_DESC_PARAM_FRQ_RTC = 0x1D, }; /* Health descriptor parameters offsets in bytes*/ enum health_desc_param { HEALTH_DESC_PARAM_LEN = 0x0, HEALTH_DESC_PARAM_TYPE = 0x1, HEALTH_DESC_PARAM_EOL_INFO = 0x2, HEALTH_DESC_PARAM_LIFE_TIME_EST_A = 0x3, HEALTH_DESC_PARAM_LIFE_TIME_EST_B = 0x4, }; /* * Logical Unit Write Protect * 00h: LU not write protected Loading
drivers/scsi/ufs/ufshcd.c +106 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,8 @@ #include <linux/nls.h> #include <linux/of.h> #include <linux/blkdev.h> #include <asm/unaligned.h> #include "ufshcd.h" #include "ufs_quirks.h" #include "unipro.h" Loading Loading @@ -4520,6 +4522,9 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, case QUERY_DESC_IDN_STRING: *desc_len = QUERY_DESC_MAX_SIZE; break; case QUERY_DESC_IDN_HEALTH: *desc_len = hba->desc_size.hlth_desc; break; case QUERY_DESC_IDN_RFU_0: case QUERY_DESC_IDN_RFU_1: *desc_len = 0; Loading Loading @@ -8560,6 +8565,11 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba) &hba->desc_size.geom_desc); if (err) hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0, &hba->desc_size.hlth_desc); if (err) hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; } static void ufshcd_def_desc_sizes(struct ufs_hba *hba) Loading @@ -8570,6 +8580,7 @@ static void ufshcd_def_desc_sizes(struct ufs_hba *hba) hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; } static void ufshcd_apply_pm_quirks(struct ufs_hba *hba) Loading Loading @@ -10690,16 +10701,111 @@ static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba) dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n"); } static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, u8 desc_index, u8 param_offset, u8 *sysfs_buf, u8 param_size) { u8 desc_buf[8] = {0}; int ret; if (param_size > 8) return -EINVAL; pm_runtime_get_sync(hba->dev); ret = ufshcd_read_desc_param(hba, desc_id, desc_index, param_offset, desc_buf, param_size); pm_runtime_put_sync(hba->dev); if (ret) return -EINVAL; switch (param_size) { case 1: ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%02X\n", *desc_buf); break; case 2: ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%04X\n", get_unaligned_be16(desc_buf)); break; case 4: ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%08X\n", get_unaligned_be32(desc_buf)); break; case 8: ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%016llX\n", get_unaligned_be64(desc_buf)); break; } return ret; } #define UFS_DESC_PARAM(_name, _puname, _duname, _size) \ static ssize_t _name##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct ufs_hba *hba = dev_get_drvdata(dev); \ return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \ 0, _duname##_DESC_PARAM##_puname, buf, _size); \ } \ static DEVICE_ATTR_RO(_name) #define UFS_HEALTH_DESC_PARAM(_name, _uname, _size) \ UFS_DESC_PARAM(_name, _uname, HEALTH, _size) UFS_HEALTH_DESC_PARAM(eol_info, _EOL_INFO, 1); UFS_HEALTH_DESC_PARAM(life_time_estimation_a, _LIFE_TIME_EST_A, 1); UFS_HEALTH_DESC_PARAM(life_time_estimation_b, _LIFE_TIME_EST_B, 1); static struct attribute *ufs_sysfs_health_descriptor[] = { &dev_attr_eol_info.attr, &dev_attr_life_time_estimation_a.attr, &dev_attr_life_time_estimation_b.attr, NULL, }; static const struct attribute_group ufs_sysfs_health_descriptor_group = { .name = "health_descriptor", .attrs = ufs_sysfs_health_descriptor, }; static const struct attribute_group *ufs_sysfs_groups[] = { &ufs_sysfs_health_descriptor_group, NULL, }; static void ufshcd_add_desc_sysfs_nodes(struct device *dev) { int ret; ret = sysfs_create_groups(&dev->kobj, ufs_sysfs_groups); if (ret) dev_err(dev, "%s: sysfs groups creation failed (err = %d)\n", __func__, ret); } static void ufshcd_remove_desc_sysfs_nodes(struct device *dev) { sysfs_remove_groups(&dev->kobj, ufs_sysfs_groups); } static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba) { ufshcd_add_rpm_lvl_sysfs_nodes(hba); ufshcd_add_spm_lvl_sysfs_nodes(hba); ufshcd_add_desc_sysfs_nodes(hba->dev); } static inline void ufshcd_remove_sysfs_nodes(struct ufs_hba *hba) { device_remove_file(hba->dev, &hba->rpm_lvl_attr); device_remove_file(hba->dev, &hba->spm_lvl_attr); ufshcd_remove_desc_sysfs_nodes(hba->dev); } static void __ufshcd_shutdown_clkscaling(struct ufs_hba *hba) Loading
drivers/scsi/ufs/ufshcd.h +1 −0 Original line number Diff line number Diff line Loading @@ -259,6 +259,7 @@ struct ufs_desc_size { int interc_desc; int unit_desc; int conf_desc; int hlth_desc; }; /** Loading
include/uapi/scsi/ufs/ufs.h +2 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,8 @@ enum desc_idn { QUERY_DESC_IDN_RFU_1 = 0x6, QUERY_DESC_IDN_GEOMETRY = 0x7, QUERY_DESC_IDN_POWER = 0x8, QUERY_DESC_IDN_RFU_2 = 0x9, QUERY_DESC_IDN_HEALTH = 0x9, QUERY_DESC_IDN_RFU_2 = 0x0A, QUERY_DESC_IDN_MAX, }; Loading