On 02/06, Stanislav Nijnikov wrote: > This patch introduces attribute group to show existing sysfs entries. > > Signed-off-by: Stanislav Nijnikov <stanislav.nijnikov@xxxxxxx> > --- > drivers/scsi/ufs/Makefile | 3 +- > drivers/scsi/ufs/ufs-sysfs.c | 156 +++++++++++++++++++++++++++++++++++++++++++ > drivers/scsi/ufs/ufs-sysfs.h | 14 ++++ > drivers/scsi/ufs/ufshcd.c | 156 ++----------------------------------------- > drivers/scsi/ufs/ufshcd.h | 2 + > 5 files changed, 178 insertions(+), 153 deletions(-) > create mode 100644 drivers/scsi/ufs/ufs-sysfs.c > create mode 100644 drivers/scsi/ufs/ufs-sysfs.h > > diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile > index 9310c6c..918f579 100644 > --- a/drivers/scsi/ufs/Makefile > +++ b/drivers/scsi/ufs/Makefile > @@ -3,6 +3,7 @@ > obj-$(CONFIG_SCSI_UFS_DWC_TC_PCI) += tc-dwc-g210-pci.o ufshcd-dwc.o tc-dwc-g210.o > obj-$(CONFIG_SCSI_UFS_DWC_TC_PLATFORM) += tc-dwc-g210-pltfrm.o ufshcd-dwc.o tc-dwc-g210.o > obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o > -obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o > +obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o > +ufshcd-core-objs := ufshcd.o ufs-sysfs.o > obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o > obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o > diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c > new file mode 100644 > index 0000000..ce8dcb6 > --- /dev/null > +++ b/drivers/scsi/ufs/ufs-sysfs.c > @@ -0,0 +1,156 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +// Copyright (C) 2018 Western Digital Corporation > + > +#include <linux/err.h> > +#include <linux/string.h> > + > +#include "ufs-sysfs.h" > + > +static const char *ufschd_uic_link_state_to_string( > + enum uic_link_state state) > +{ > + switch (state) { > + case UIC_LINK_OFF_STATE: return "OFF"; > + case UIC_LINK_ACTIVE_STATE: return "ACTIVE"; > + case UIC_LINK_HIBERN8_STATE: return "HIBERN8"; > + default: return "UNKNOWN"; > + } > +} > + > +static const char *ufschd_ufs_dev_pwr_mode_to_string( > + enum ufs_dev_pwr_mode state) > +{ > + switch (state) { > + case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; > + case UFS_SLEEP_PWR_MODE: return "SLEEP"; > + case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; > + default: return "UNKNOWN"; > + } > +} > + > +static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count, > + bool rpm) > +{ > + struct ufs_hba *hba = dev_get_drvdata(dev); > + unsigned long flags, value; > + > + if (kstrtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value >= UFS_PM_LVL_MAX) > + return -EINVAL; > + > + spin_lock_irqsave(hba->host->host_lock, flags); > + if (rpm) > + hba->rpm_lvl = value; > + else > + hba->spm_lvl = value; > + spin_unlock_irqrestore(hba->host->host_lock, flags); > + return count; > +} > + > +static ssize_t rpm_lvl_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct ufs_hba *hba = dev_get_drvdata(dev); > + int curr_len; > + u8 lvl; > + > + curr_len = snprintf(buf, PAGE_SIZE, > + "\nCurrent Runtime PM level [%d] => dev_state [%s] link_state [%s]\n", > + hba->rpm_lvl, > + ufschd_ufs_dev_pwr_mode_to_string( > + ufs_pm_lvl_states[hba->rpm_lvl].dev_state), > + ufschd_uic_link_state_to_string( > + ufs_pm_lvl_states[hba->rpm_lvl].link_state)); If there is no objection regarding to backward compatibility, can we also clean this up by adding multiple entries having single string each, as Greg recommended? For example, /rpm_level 1 /rpm_dev_state ACTIVE /rpm_link_state HIBERN8 /spm_level 2 /spm_dev_state SLEEP /spm_link_state ACTIVE /avail_dev_states 0:ACTIVE 1:ACTIVE 2:SLEEP 3:SLEEP 4:POWERDOWN 5:POWERDOWN /avail_link_states 0:ACTIVE 1:HIBERN8 2:ACTIVE 3:HIBERN8 4:HIBERN8 5:OFF Thanks, > + > + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), > + "\nAll available Runtime PM levels info:\n"); > + for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) > + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), > + "\tRuntime PM level [%d] => dev_state [%s] link_state [%s]\n", > + lvl, > + ufschd_ufs_dev_pwr_mode_to_string( > + ufs_pm_lvl_states[lvl].dev_state), > + ufschd_uic_link_state_to_string( > + ufs_pm_lvl_states[lvl].link_state)); > + > + return curr_len; > +} > + > +static ssize_t rpm_lvl_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t count) > +{ > + return ufs_sysfs_pm_lvl_store(dev, attr, buf, count, true); > +} > + > +static ssize_t spm_lvl_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct ufs_hba *hba = dev_get_drvdata(dev); > + int curr_len; > + u8 lvl; > + > + curr_len = snprintf(buf, PAGE_SIZE, > + "\nCurrent System PM level [%d] => dev_state [%s] link_state [%s]\n", > + hba->spm_lvl, > + ufschd_ufs_dev_pwr_mode_to_string( > + ufs_pm_lvl_states[hba->spm_lvl].dev_state), > + ufschd_uic_link_state_to_string( > + ufs_pm_lvl_states[hba->spm_lvl].link_state)); > + > + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), > + "\nAll available System PM levels info:\n"); > + for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) > + curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), > + "\tSystem PM level [%d] => dev_state [%s] link_state [%s]\n", > + lvl, > + ufschd_ufs_dev_pwr_mode_to_string( > + ufs_pm_lvl_states[lvl].dev_state), > + ufschd_uic_link_state_to_string( > + ufs_pm_lvl_states[lvl].link_state)); > + > + return curr_len; > +} > + > +static ssize_t spm_lvl_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t count) > +{ > + return ufs_sysfs_pm_lvl_store(dev, attr, buf, count, false); > +} > + > +static DEVICE_ATTR_RW(rpm_lvl); > +static DEVICE_ATTR_RW(spm_lvl); > + > +static struct attribute *ufs_sysfs_ufshcd_attrs[] = { > + &dev_attr_rpm_lvl.attr, > + &dev_attr_spm_lvl.attr, > + NULL > +}; > + > +static const struct attribute_group ufs_sysfs_default_group = { > + .attrs = ufs_sysfs_ufshcd_attrs, > +}; > + > +static const struct attribute_group *ufs_sysfs_groups[] = { > + &ufs_sysfs_default_group, > + NULL, > +}; > + > +void ufs_sysfs_add_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); > +} > + > +void ufs_sysfs_remove_nodes(struct device *dev) > +{ > + sysfs_remove_groups(&dev->kobj, ufs_sysfs_groups); > +} > diff --git a/drivers/scsi/ufs/ufs-sysfs.h b/drivers/scsi/ufs/ufs-sysfs.h > new file mode 100644 > index 0000000..4a984ca > --- /dev/null > +++ b/drivers/scsi/ufs/ufs-sysfs.h > @@ -0,0 +1,14 @@ > +/* SPDX-License-Identifier: GPL-2.0-only > + * Copyright (C) 2018 Western Digital Corporation > + */ > + > +#ifndef __UFS_SYSFS_H__ > +#define __UFS_SYSFS_H__ > + > +#include <linux/sysfs.h> > + > +#include "ufshcd.h" > + > +void ufs_sysfs_add_nodes(struct device *dev); > +void ufs_sysfs_remove_nodes(struct device *dev); > +#endif > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c > index a355d98..e7621a0a 100644 > --- a/drivers/scsi/ufs/ufshcd.c > +++ b/drivers/scsi/ufs/ufshcd.c > @@ -44,6 +44,7 @@ > #include "ufshcd.h" > #include "ufs_quirks.h" > #include "unipro.h" > +#include "ufs-sysfs.h" > > #define CREATE_TRACE_POINTS > #include <trace/events/ufs.h> > @@ -150,7 +151,7 @@ enum { > #define ufshcd_is_ufs_dev_poweroff(h) \ > ((h)->curr_dev_pwr_mode == UFS_POWERDOWN_PWR_MODE) > > -static struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { > +struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { > {UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE}, > {UFS_ACTIVE_PWR_MODE, UIC_LINK_HIBERN8_STATE}, > {UFS_SLEEP_PWR_MODE, UIC_LINK_ACTIVE_STATE}, > @@ -813,28 +814,6 @@ static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) > ? false : true; > } > > -static const char *ufschd_uic_link_state_to_string( > - enum uic_link_state state) > -{ > - switch (state) { > - case UIC_LINK_OFF_STATE: return "OFF"; > - case UIC_LINK_ACTIVE_STATE: return "ACTIVE"; > - case UIC_LINK_HIBERN8_STATE: return "HIBERN8"; > - default: return "UNKNOWN"; > - } > -} > - > -static const char *ufschd_ufs_dev_pwr_mode_to_string( > - enum ufs_dev_pwr_mode state) > -{ > - switch (state) { > - case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; > - case UFS_SLEEP_PWR_MODE: return "SLEEP"; > - case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; > - default: return "UNKNOWN"; > - } > -} > - > u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba) > { > /* HCI version 1.0 and 1.1 supports UniPro 1.41 */ > @@ -7585,133 +7564,6 @@ int ufshcd_runtime_idle(struct ufs_hba *hba) > } > EXPORT_SYMBOL(ufshcd_runtime_idle); > > -static inline ssize_t ufshcd_pm_lvl_store(struct device *dev, > - struct device_attribute *attr, > - const char *buf, size_t count, > - bool rpm) > -{ > - struct ufs_hba *hba = dev_get_drvdata(dev); > - unsigned long flags, value; > - > - if (kstrtoul(buf, 0, &value)) > - return -EINVAL; > - > - if (value >= UFS_PM_LVL_MAX) > - return -EINVAL; > - > - spin_lock_irqsave(hba->host->host_lock, flags); > - if (rpm) > - hba->rpm_lvl = value; > - else > - hba->spm_lvl = value; > - spin_unlock_irqrestore(hba->host->host_lock, flags); > - return count; > -} > - > -static ssize_t ufshcd_rpm_lvl_show(struct device *dev, > - struct device_attribute *attr, char *buf) > -{ > - struct ufs_hba *hba = dev_get_drvdata(dev); > - int curr_len; > - u8 lvl; > - > - curr_len = snprintf(buf, PAGE_SIZE, > - "\nCurrent Runtime PM level [%d] => dev_state [%s] link_state [%s]\n", > - hba->rpm_lvl, > - ufschd_ufs_dev_pwr_mode_to_string( > - ufs_pm_lvl_states[hba->rpm_lvl].dev_state), > - ufschd_uic_link_state_to_string( > - ufs_pm_lvl_states[hba->rpm_lvl].link_state)); > - > - curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), > - "\nAll available Runtime PM levels info:\n"); > - for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) > - curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), > - "\tRuntime PM level [%d] => dev_state [%s] link_state [%s]\n", > - lvl, > - ufschd_ufs_dev_pwr_mode_to_string( > - ufs_pm_lvl_states[lvl].dev_state), > - ufschd_uic_link_state_to_string( > - ufs_pm_lvl_states[lvl].link_state)); > - > - return curr_len; > -} > - > -static ssize_t ufshcd_rpm_lvl_store(struct device *dev, > - struct device_attribute *attr, const char *buf, size_t count) > -{ > - return ufshcd_pm_lvl_store(dev, attr, buf, count, true); > -} > - > -static void ufshcd_add_rpm_lvl_sysfs_nodes(struct ufs_hba *hba) > -{ > - hba->rpm_lvl_attr.show = ufshcd_rpm_lvl_show; > - hba->rpm_lvl_attr.store = ufshcd_rpm_lvl_store; > - sysfs_attr_init(&hba->rpm_lvl_attr.attr); > - hba->rpm_lvl_attr.attr.name = "rpm_lvl"; > - hba->rpm_lvl_attr.attr.mode = 0644; > - if (device_create_file(hba->dev, &hba->rpm_lvl_attr)) > - dev_err(hba->dev, "Failed to create sysfs for rpm_lvl\n"); > -} > - > -static ssize_t ufshcd_spm_lvl_show(struct device *dev, > - struct device_attribute *attr, char *buf) > -{ > - struct ufs_hba *hba = dev_get_drvdata(dev); > - int curr_len; > - u8 lvl; > - > - curr_len = snprintf(buf, PAGE_SIZE, > - "\nCurrent System PM level [%d] => dev_state [%s] link_state [%s]\n", > - hba->spm_lvl, > - ufschd_ufs_dev_pwr_mode_to_string( > - ufs_pm_lvl_states[hba->spm_lvl].dev_state), > - ufschd_uic_link_state_to_string( > - ufs_pm_lvl_states[hba->spm_lvl].link_state)); > - > - curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), > - "\nAll available System PM levels info:\n"); > - for (lvl = UFS_PM_LVL_0; lvl < UFS_PM_LVL_MAX; lvl++) > - curr_len += snprintf((buf + curr_len), (PAGE_SIZE - curr_len), > - "\tSystem PM level [%d] => dev_state [%s] link_state [%s]\n", > - lvl, > - ufschd_ufs_dev_pwr_mode_to_string( > - ufs_pm_lvl_states[lvl].dev_state), > - ufschd_uic_link_state_to_string( > - ufs_pm_lvl_states[lvl].link_state)); > - > - return curr_len; > -} > - > -static ssize_t ufshcd_spm_lvl_store(struct device *dev, > - struct device_attribute *attr, const char *buf, size_t count) > -{ > - return ufshcd_pm_lvl_store(dev, attr, buf, count, false); > -} > - > -static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba) > -{ > - hba->spm_lvl_attr.show = ufshcd_spm_lvl_show; > - hba->spm_lvl_attr.store = ufshcd_spm_lvl_store; > - sysfs_attr_init(&hba->spm_lvl_attr.attr); > - hba->spm_lvl_attr.attr.name = "spm_lvl"; > - hba->spm_lvl_attr.attr.mode = 0644; > - if (device_create_file(hba->dev, &hba->spm_lvl_attr)) > - dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n"); > -} > - > -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); > -} > - > -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_shutdown - shutdown routine > * @hba: per adapter instance > @@ -7749,7 +7601,7 @@ EXPORT_SYMBOL(ufshcd_shutdown); > */ > void ufshcd_remove(struct ufs_hba *hba) > { > - ufshcd_remove_sysfs_nodes(hba); > + ufs_sysfs_remove_nodes(hba->dev); > scsi_remove_host(hba->host); > /* disable interrupts */ > ufshcd_disable_intr(hba, hba->intr_mask); > @@ -7996,7 +7848,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) > ufshcd_set_ufs_dev_active(hba); > > async_schedule(ufshcd_async_scan, hba); > - ufshcd_add_sysfs_nodes(hba); > + ufs_sysfs_add_nodes(hba->dev); > > return 0; > > diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h > index 1332e54..53e2779 100644 > --- a/drivers/scsi/ufs/ufshcd.h > +++ b/drivers/scsi/ufs/ufshcd.h > @@ -985,4 +985,6 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) > hba->vops->dbg_register_dump(hba); > } > > +extern struct ufs_pm_lvl_states ufs_pm_lvl_states[]; > + > #endif /* End of Header */ > -- > 2.7.4