162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (C) 2018 Western Digital Corporation 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/err.h> 562306a36Sopenharmony_ci#include <linux/string.h> 662306a36Sopenharmony_ci#include <linux/bitfield.h> 762306a36Sopenharmony_ci#include <asm/unaligned.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <ufs/ufs.h> 1062306a36Sopenharmony_ci#include "ufs-sysfs.h" 1162306a36Sopenharmony_ci#include "ufshcd-priv.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic const char *ufshcd_uic_link_state_to_string( 1462306a36Sopenharmony_ci enum uic_link_state state) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci switch (state) { 1762306a36Sopenharmony_ci case UIC_LINK_OFF_STATE: return "OFF"; 1862306a36Sopenharmony_ci case UIC_LINK_ACTIVE_STATE: return "ACTIVE"; 1962306a36Sopenharmony_ci case UIC_LINK_HIBERN8_STATE: return "HIBERN8"; 2062306a36Sopenharmony_ci case UIC_LINK_BROKEN_STATE: return "BROKEN"; 2162306a36Sopenharmony_ci default: return "UNKNOWN"; 2262306a36Sopenharmony_ci } 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic const char *ufshcd_ufs_dev_pwr_mode_to_string( 2662306a36Sopenharmony_ci enum ufs_dev_pwr_mode state) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci switch (state) { 2962306a36Sopenharmony_ci case UFS_ACTIVE_PWR_MODE: return "ACTIVE"; 3062306a36Sopenharmony_ci case UFS_SLEEP_PWR_MODE: return "SLEEP"; 3162306a36Sopenharmony_ci case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN"; 3262306a36Sopenharmony_ci case UFS_DEEPSLEEP_PWR_MODE: return "DEEPSLEEP"; 3362306a36Sopenharmony_ci default: return "UNKNOWN"; 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, 3862306a36Sopenharmony_ci struct device_attribute *attr, 3962306a36Sopenharmony_ci const char *buf, size_t count, 4062306a36Sopenharmony_ci bool rpm) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 4362306a36Sopenharmony_ci struct ufs_dev_info *dev_info = &hba->dev_info; 4462306a36Sopenharmony_ci unsigned long flags, value; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (kstrtoul(buf, 0, &value)) 4762306a36Sopenharmony_ci return -EINVAL; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (value >= UFS_PM_LVL_MAX) 5062306a36Sopenharmony_ci return -EINVAL; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (ufs_pm_lvl_states[value].dev_state == UFS_DEEPSLEEP_PWR_MODE && 5362306a36Sopenharmony_ci (!(hba->caps & UFSHCD_CAP_DEEPSLEEP) || 5462306a36Sopenharmony_ci !(dev_info->wspecversion >= 0x310))) 5562306a36Sopenharmony_ci return -EINVAL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 5862306a36Sopenharmony_ci if (rpm) 5962306a36Sopenharmony_ci hba->rpm_lvl = value; 6062306a36Sopenharmony_ci else 6162306a36Sopenharmony_ci hba->spm_lvl = value; 6262306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 6362306a36Sopenharmony_ci return count; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic ssize_t rpm_lvl_show(struct device *dev, 6762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", hba->rpm_lvl); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic ssize_t rpm_lvl_store(struct device *dev, 7562306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci return ufs_sysfs_pm_lvl_store(dev, attr, buf, count, true); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic ssize_t rpm_target_dev_state_show(struct device *dev, 8162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", ufshcd_ufs_dev_pwr_mode_to_string( 8662306a36Sopenharmony_ci ufs_pm_lvl_states[hba->rpm_lvl].dev_state)); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic ssize_t rpm_target_link_state_show(struct device *dev, 9062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", ufshcd_uic_link_state_to_string( 9562306a36Sopenharmony_ci ufs_pm_lvl_states[hba->rpm_lvl].link_state)); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic ssize_t spm_lvl_show(struct device *dev, 9962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", hba->spm_lvl); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic ssize_t spm_lvl_store(struct device *dev, 10762306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return ufs_sysfs_pm_lvl_store(dev, attr, buf, count, false); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic ssize_t spm_target_dev_state_show(struct device *dev, 11362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", ufshcd_ufs_dev_pwr_mode_to_string( 11862306a36Sopenharmony_ci ufs_pm_lvl_states[hba->spm_lvl].dev_state)); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic ssize_t spm_target_link_state_show(struct device *dev, 12262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", ufshcd_uic_link_state_to_string( 12762306a36Sopenharmony_ci ufs_pm_lvl_states[hba->spm_lvl].link_state)); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* Convert Auto-Hibernate Idle Timer register value to microseconds */ 13162306a36Sopenharmony_cistatic int ufshcd_ahit_to_us(u32 ahit) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci int timer = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, ahit); 13462306a36Sopenharmony_ci int scale = FIELD_GET(UFSHCI_AHIBERN8_SCALE_MASK, ahit); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci for (; scale > 0; --scale) 13762306a36Sopenharmony_ci timer *= UFSHCI_AHIBERN8_SCALE_FACTOR; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return timer; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* Convert microseconds to Auto-Hibernate Idle Timer register value */ 14362306a36Sopenharmony_cistatic u32 ufshcd_us_to_ahit(unsigned int timer) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci unsigned int scale; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci for (scale = 0; timer > UFSHCI_AHIBERN8_TIMER_MASK; ++scale) 14862306a36Sopenharmony_ci timer /= UFSHCI_AHIBERN8_SCALE_FACTOR; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, timer) | 15162306a36Sopenharmony_ci FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, scale); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic ssize_t auto_hibern8_show(struct device *dev, 15562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci u32 ahit; 15862306a36Sopenharmony_ci int ret; 15962306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (!ufshcd_is_auto_hibern8_supported(hba)) 16262306a36Sopenharmony_ci return -EOPNOTSUPP; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci down(&hba->host_sem); 16562306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { 16662306a36Sopenharmony_ci ret = -EBUSY; 16762306a36Sopenharmony_ci goto out; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci pm_runtime_get_sync(hba->dev); 17162306a36Sopenharmony_ci ufshcd_hold(hba); 17262306a36Sopenharmony_ci ahit = ufshcd_readl(hba, REG_AUTO_HIBERNATE_IDLE_TIMER); 17362306a36Sopenharmony_ci ufshcd_release(hba); 17462306a36Sopenharmony_ci pm_runtime_put_sync(hba->dev); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ret = sysfs_emit(buf, "%d\n", ufshcd_ahit_to_us(ahit)); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciout: 17962306a36Sopenharmony_ci up(&hba->host_sem); 18062306a36Sopenharmony_ci return ret; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic ssize_t auto_hibern8_store(struct device *dev, 18462306a36Sopenharmony_ci struct device_attribute *attr, 18562306a36Sopenharmony_ci const char *buf, size_t count) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 18862306a36Sopenharmony_ci unsigned int timer; 18962306a36Sopenharmony_ci int ret = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (!ufshcd_is_auto_hibern8_supported(hba)) 19262306a36Sopenharmony_ci return -EOPNOTSUPP; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (kstrtouint(buf, 0, &timer)) 19562306a36Sopenharmony_ci return -EINVAL; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (timer > UFSHCI_AHIBERN8_MAX) 19862306a36Sopenharmony_ci return -EINVAL; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci down(&hba->host_sem); 20162306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { 20262306a36Sopenharmony_ci ret = -EBUSY; 20362306a36Sopenharmony_ci goto out; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci ufshcd_auto_hibern8_update(hba, ufshcd_us_to_ahit(timer)); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciout: 20962306a36Sopenharmony_ci up(&hba->host_sem); 21062306a36Sopenharmony_ci return ret ? ret : count; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic ssize_t wb_on_show(struct device *dev, struct device_attribute *attr, 21462306a36Sopenharmony_ci char *buf) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", hba->dev_info.wb_enabled); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic ssize_t wb_on_store(struct device *dev, struct device_attribute *attr, 22262306a36Sopenharmony_ci const char *buf, size_t count) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 22562306a36Sopenharmony_ci unsigned int wb_enable; 22662306a36Sopenharmony_ci ssize_t res; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (!ufshcd_is_wb_allowed(hba) || (ufshcd_is_clkscaling_supported(hba) 22962306a36Sopenharmony_ci && ufshcd_enable_wb_if_scaling_up(hba))) { 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * If the platform supports UFSHCD_CAP_CLK_SCALING, turn WB 23262306a36Sopenharmony_ci * on/off will be done while clock scaling up/down. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci dev_warn(dev, "It is not allowed to configure WB!\n"); 23562306a36Sopenharmony_ci return -EOPNOTSUPP; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (kstrtouint(buf, 0, &wb_enable)) 23962306a36Sopenharmony_ci return -EINVAL; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (wb_enable != 0 && wb_enable != 1) 24262306a36Sopenharmony_ci return -EINVAL; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci down(&hba->host_sem); 24562306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { 24662306a36Sopenharmony_ci res = -EBUSY; 24762306a36Sopenharmony_ci goto out; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci ufshcd_rpm_get_sync(hba); 25162306a36Sopenharmony_ci res = ufshcd_wb_toggle(hba, wb_enable); 25262306a36Sopenharmony_ci ufshcd_rpm_put_sync(hba); 25362306a36Sopenharmony_ciout: 25462306a36Sopenharmony_ci up(&hba->host_sem); 25562306a36Sopenharmony_ci return res < 0 ? res : count; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic ssize_t enable_wb_buf_flush_show(struct device *dev, 25962306a36Sopenharmony_ci struct device_attribute *attr, 26062306a36Sopenharmony_ci char *buf) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", hba->dev_info.wb_buf_flush_enabled); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic ssize_t enable_wb_buf_flush_store(struct device *dev, 26862306a36Sopenharmony_ci struct device_attribute *attr, 26962306a36Sopenharmony_ci const char *buf, size_t count) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 27262306a36Sopenharmony_ci unsigned int enable_wb_buf_flush; 27362306a36Sopenharmony_ci ssize_t res; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (!ufshcd_is_wb_buf_flush_allowed(hba)) { 27662306a36Sopenharmony_ci dev_warn(dev, "It is not allowed to configure WB buf flushing!\n"); 27762306a36Sopenharmony_ci return -EOPNOTSUPP; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (kstrtouint(buf, 0, &enable_wb_buf_flush)) 28162306a36Sopenharmony_ci return -EINVAL; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (enable_wb_buf_flush != 0 && enable_wb_buf_flush != 1) 28462306a36Sopenharmony_ci return -EINVAL; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci down(&hba->host_sem); 28762306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { 28862306a36Sopenharmony_ci res = -EBUSY; 28962306a36Sopenharmony_ci goto out; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ufshcd_rpm_get_sync(hba); 29362306a36Sopenharmony_ci res = ufshcd_wb_toggle_buf_flush(hba, enable_wb_buf_flush); 29462306a36Sopenharmony_ci ufshcd_rpm_put_sync(hba); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ciout: 29762306a36Sopenharmony_ci up(&hba->host_sem); 29862306a36Sopenharmony_ci return res < 0 ? res : count; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic ssize_t wb_flush_threshold_show(struct device *dev, 30262306a36Sopenharmony_ci struct device_attribute *attr, 30362306a36Sopenharmony_ci char *buf) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", hba->vps->wb_flush_threshold); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic ssize_t wb_flush_threshold_store(struct device *dev, 31162306a36Sopenharmony_ci struct device_attribute *attr, 31262306a36Sopenharmony_ci const char *buf, size_t count) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 31562306a36Sopenharmony_ci unsigned int wb_flush_threshold; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (kstrtouint(buf, 0, &wb_flush_threshold)) 31862306a36Sopenharmony_ci return -EINVAL; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* The range of values for wb_flush_threshold is (0,10] */ 32162306a36Sopenharmony_ci if (wb_flush_threshold > UFS_WB_BUF_REMAIN_PERCENT(100) || 32262306a36Sopenharmony_ci wb_flush_threshold == 0) { 32362306a36Sopenharmony_ci dev_err(dev, "The value of wb_flush_threshold is invalid!\n"); 32462306a36Sopenharmony_ci return -EINVAL; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci hba->vps->wb_flush_threshold = wb_flush_threshold; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return count; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic DEVICE_ATTR_RW(rpm_lvl); 33362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(rpm_target_dev_state); 33462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(rpm_target_link_state); 33562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(spm_lvl); 33662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(spm_target_dev_state); 33762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(spm_target_link_state); 33862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(auto_hibern8); 33962306a36Sopenharmony_cistatic DEVICE_ATTR_RW(wb_on); 34062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(enable_wb_buf_flush); 34162306a36Sopenharmony_cistatic DEVICE_ATTR_RW(wb_flush_threshold); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_ufshcd_attrs[] = { 34462306a36Sopenharmony_ci &dev_attr_rpm_lvl.attr, 34562306a36Sopenharmony_ci &dev_attr_rpm_target_dev_state.attr, 34662306a36Sopenharmony_ci &dev_attr_rpm_target_link_state.attr, 34762306a36Sopenharmony_ci &dev_attr_spm_lvl.attr, 34862306a36Sopenharmony_ci &dev_attr_spm_target_dev_state.attr, 34962306a36Sopenharmony_ci &dev_attr_spm_target_link_state.attr, 35062306a36Sopenharmony_ci &dev_attr_auto_hibern8.attr, 35162306a36Sopenharmony_ci &dev_attr_wb_on.attr, 35262306a36Sopenharmony_ci &dev_attr_enable_wb_buf_flush.attr, 35362306a36Sopenharmony_ci &dev_attr_wb_flush_threshold.attr, 35462306a36Sopenharmony_ci NULL 35562306a36Sopenharmony_ci}; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_default_group = { 35862306a36Sopenharmony_ci .attrs = ufs_sysfs_ufshcd_attrs, 35962306a36Sopenharmony_ci}; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic ssize_t clock_scaling_show(struct device *dev, struct device_attribute *attr, 36262306a36Sopenharmony_ci char *buf) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", ufshcd_is_clkscaling_supported(hba)); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic ssize_t write_booster_show(struct device *dev, struct device_attribute *attr, 37062306a36Sopenharmony_ci char *buf) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", ufshcd_is_wb_allowed(hba)); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(clock_scaling); 37862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_booster); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci/* 38162306a36Sopenharmony_ci * See Documentation/ABI/testing/sysfs-driver-ufs for the semantics of this 38262306a36Sopenharmony_ci * group. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_capabilities_attrs[] = { 38562306a36Sopenharmony_ci &dev_attr_clock_scaling.attr, 38662306a36Sopenharmony_ci &dev_attr_write_booster.attr, 38762306a36Sopenharmony_ci NULL 38862306a36Sopenharmony_ci}; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_capabilities_group = { 39162306a36Sopenharmony_ci .name = "capabilities", 39262306a36Sopenharmony_ci .attrs = ufs_sysfs_capabilities_attrs, 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic ssize_t monitor_enable_show(struct device *dev, 39662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", hba->monitor.enabled); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic ssize_t monitor_enable_store(struct device *dev, 40462306a36Sopenharmony_ci struct device_attribute *attr, 40562306a36Sopenharmony_ci const char *buf, size_t count) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 40862306a36Sopenharmony_ci unsigned long value, flags; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (kstrtoul(buf, 0, &value)) 41162306a36Sopenharmony_ci return -EINVAL; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci value = !!value; 41462306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 41562306a36Sopenharmony_ci if (value == hba->monitor.enabled) 41662306a36Sopenharmony_ci goto out_unlock; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!value) { 41962306a36Sopenharmony_ci memset(&hba->monitor, 0, sizeof(hba->monitor)); 42062306a36Sopenharmony_ci } else { 42162306a36Sopenharmony_ci hba->monitor.enabled = true; 42262306a36Sopenharmony_ci hba->monitor.enabled_ts = ktime_get(); 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ciout_unlock: 42662306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 42762306a36Sopenharmony_ci return count; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic ssize_t monitor_chunk_size_show(struct device *dev, 43162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", hba->monitor.chunk_size); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic ssize_t monitor_chunk_size_store(struct device *dev, 43962306a36Sopenharmony_ci struct device_attribute *attr, 44062306a36Sopenharmony_ci const char *buf, size_t count) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 44362306a36Sopenharmony_ci unsigned long value, flags; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (kstrtoul(buf, 0, &value)) 44662306a36Sopenharmony_ci return -EINVAL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci spin_lock_irqsave(hba->host->host_lock, flags); 44962306a36Sopenharmony_ci /* Only allow chunk size change when monitor is disabled */ 45062306a36Sopenharmony_ci if (!hba->monitor.enabled) 45162306a36Sopenharmony_ci hba->monitor.chunk_size = value; 45262306a36Sopenharmony_ci spin_unlock_irqrestore(hba->host->host_lock, flags); 45362306a36Sopenharmony_ci return count; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic ssize_t read_total_sectors_show(struct device *dev, 45762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", hba->monitor.nr_sec_rw[READ]); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic ssize_t read_total_busy_show(struct device *dev, 46562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 47062306a36Sopenharmony_ci ktime_to_us(hba->monitor.total_busy[READ])); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic ssize_t read_nr_requests_show(struct device *dev, 47462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", hba->monitor.nr_req[READ]); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic ssize_t read_req_latency_avg_show(struct device *dev, 48262306a36Sopenharmony_ci struct device_attribute *attr, 48362306a36Sopenharmony_ci char *buf) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 48662306a36Sopenharmony_ci struct ufs_hba_monitor *m = &hba->monitor; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[READ]), 48962306a36Sopenharmony_ci m->nr_req[READ])); 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic ssize_t read_req_latency_max_show(struct device *dev, 49362306a36Sopenharmony_ci struct device_attribute *attr, 49462306a36Sopenharmony_ci char *buf) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 49962306a36Sopenharmony_ci ktime_to_us(hba->monitor.lat_max[READ])); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic ssize_t read_req_latency_min_show(struct device *dev, 50362306a36Sopenharmony_ci struct device_attribute *attr, 50462306a36Sopenharmony_ci char *buf) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 50962306a36Sopenharmony_ci ktime_to_us(hba->monitor.lat_min[READ])); 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic ssize_t read_req_latency_sum_show(struct device *dev, 51362306a36Sopenharmony_ci struct device_attribute *attr, 51462306a36Sopenharmony_ci char *buf) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 51962306a36Sopenharmony_ci ktime_to_us(hba->monitor.lat_sum[READ])); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic ssize_t write_total_sectors_show(struct device *dev, 52362306a36Sopenharmony_ci struct device_attribute *attr, 52462306a36Sopenharmony_ci char *buf) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", hba->monitor.nr_sec_rw[WRITE]); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic ssize_t write_total_busy_show(struct device *dev, 53262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 53762306a36Sopenharmony_ci ktime_to_us(hba->monitor.total_busy[WRITE])); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic ssize_t write_nr_requests_show(struct device *dev, 54162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", hba->monitor.nr_req[WRITE]); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic ssize_t write_req_latency_avg_show(struct device *dev, 54962306a36Sopenharmony_ci struct device_attribute *attr, 55062306a36Sopenharmony_ci char *buf) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 55362306a36Sopenharmony_ci struct ufs_hba_monitor *m = &hba->monitor; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", div_u64(ktime_to_us(m->lat_sum[WRITE]), 55662306a36Sopenharmony_ci m->nr_req[WRITE])); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic ssize_t write_req_latency_max_show(struct device *dev, 56062306a36Sopenharmony_ci struct device_attribute *attr, 56162306a36Sopenharmony_ci char *buf) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 56662306a36Sopenharmony_ci ktime_to_us(hba->monitor.lat_max[WRITE])); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic ssize_t write_req_latency_min_show(struct device *dev, 57062306a36Sopenharmony_ci struct device_attribute *attr, 57162306a36Sopenharmony_ci char *buf) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 57662306a36Sopenharmony_ci ktime_to_us(hba->monitor.lat_min[WRITE])); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic ssize_t write_req_latency_sum_show(struct device *dev, 58062306a36Sopenharmony_ci struct device_attribute *attr, 58162306a36Sopenharmony_ci char *buf) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 58662306a36Sopenharmony_ci ktime_to_us(hba->monitor.lat_sum[WRITE])); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic DEVICE_ATTR_RW(monitor_enable); 59062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(monitor_chunk_size); 59162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_total_sectors); 59262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_total_busy); 59362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_nr_requests); 59462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_req_latency_avg); 59562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_req_latency_max); 59662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_req_latency_min); 59762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(read_req_latency_sum); 59862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_total_sectors); 59962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_total_busy); 60062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_nr_requests); 60162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_req_latency_avg); 60262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_req_latency_max); 60362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_req_latency_min); 60462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(write_req_latency_sum); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_monitor_attrs[] = { 60762306a36Sopenharmony_ci &dev_attr_monitor_enable.attr, 60862306a36Sopenharmony_ci &dev_attr_monitor_chunk_size.attr, 60962306a36Sopenharmony_ci &dev_attr_read_total_sectors.attr, 61062306a36Sopenharmony_ci &dev_attr_read_total_busy.attr, 61162306a36Sopenharmony_ci &dev_attr_read_nr_requests.attr, 61262306a36Sopenharmony_ci &dev_attr_read_req_latency_avg.attr, 61362306a36Sopenharmony_ci &dev_attr_read_req_latency_max.attr, 61462306a36Sopenharmony_ci &dev_attr_read_req_latency_min.attr, 61562306a36Sopenharmony_ci &dev_attr_read_req_latency_sum.attr, 61662306a36Sopenharmony_ci &dev_attr_write_total_sectors.attr, 61762306a36Sopenharmony_ci &dev_attr_write_total_busy.attr, 61862306a36Sopenharmony_ci &dev_attr_write_nr_requests.attr, 61962306a36Sopenharmony_ci &dev_attr_write_req_latency_avg.attr, 62062306a36Sopenharmony_ci &dev_attr_write_req_latency_max.attr, 62162306a36Sopenharmony_ci &dev_attr_write_req_latency_min.attr, 62262306a36Sopenharmony_ci &dev_attr_write_req_latency_sum.attr, 62362306a36Sopenharmony_ci NULL 62462306a36Sopenharmony_ci}; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_monitor_group = { 62762306a36Sopenharmony_ci .name = "monitor", 62862306a36Sopenharmony_ci .attrs = ufs_sysfs_monitor_attrs, 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, 63262306a36Sopenharmony_ci enum desc_idn desc_id, 63362306a36Sopenharmony_ci u8 desc_index, 63462306a36Sopenharmony_ci u8 param_offset, 63562306a36Sopenharmony_ci u8 *sysfs_buf, 63662306a36Sopenharmony_ci u8 param_size) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci u8 desc_buf[8] = {0}; 63962306a36Sopenharmony_ci int ret; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (param_size > 8) 64262306a36Sopenharmony_ci return -EINVAL; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci down(&hba->host_sem); 64562306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { 64662306a36Sopenharmony_ci ret = -EBUSY; 64762306a36Sopenharmony_ci goto out; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci ufshcd_rpm_get_sync(hba); 65162306a36Sopenharmony_ci ret = ufshcd_read_desc_param(hba, desc_id, desc_index, 65262306a36Sopenharmony_ci param_offset, desc_buf, param_size); 65362306a36Sopenharmony_ci ufshcd_rpm_put_sync(hba); 65462306a36Sopenharmony_ci if (ret) { 65562306a36Sopenharmony_ci ret = -EINVAL; 65662306a36Sopenharmony_ci goto out; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci switch (param_size) { 66062306a36Sopenharmony_ci case 1: 66162306a36Sopenharmony_ci ret = sysfs_emit(sysfs_buf, "0x%02X\n", *desc_buf); 66262306a36Sopenharmony_ci break; 66362306a36Sopenharmony_ci case 2: 66462306a36Sopenharmony_ci ret = sysfs_emit(sysfs_buf, "0x%04X\n", 66562306a36Sopenharmony_ci get_unaligned_be16(desc_buf)); 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci case 4: 66862306a36Sopenharmony_ci ret = sysfs_emit(sysfs_buf, "0x%08X\n", 66962306a36Sopenharmony_ci get_unaligned_be32(desc_buf)); 67062306a36Sopenharmony_ci break; 67162306a36Sopenharmony_ci case 8: 67262306a36Sopenharmony_ci ret = sysfs_emit(sysfs_buf, "0x%016llX\n", 67362306a36Sopenharmony_ci get_unaligned_be64(desc_buf)); 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ciout: 67862306a36Sopenharmony_ci up(&hba->host_sem); 67962306a36Sopenharmony_ci return ret; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci#define UFS_DESC_PARAM(_name, _puname, _duname, _size) \ 68362306a36Sopenharmony_cistatic ssize_t _name##_show(struct device *dev, \ 68462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) \ 68562306a36Sopenharmony_ci{ \ 68662306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); \ 68762306a36Sopenharmony_ci return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \ 68862306a36Sopenharmony_ci 0, _duname##_DESC_PARAM##_puname, buf, _size); \ 68962306a36Sopenharmony_ci} \ 69062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(_name) 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci#define UFS_DEVICE_DESC_PARAM(_name, _uname, _size) \ 69362306a36Sopenharmony_ci UFS_DESC_PARAM(_name, _uname, DEVICE, _size) 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(device_type, _DEVICE_TYPE, 1); 69662306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(device_class, _DEVICE_CLASS, 1); 69762306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(device_sub_class, _DEVICE_SUB_CLASS, 1); 69862306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(protocol, _PRTCL, 1); 69962306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(number_of_luns, _NUM_LU, 1); 70062306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(number_of_wluns, _NUM_WLU, 1); 70162306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(boot_enable, _BOOT_ENBL, 1); 70262306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(descriptor_access_enable, _DESC_ACCSS_ENBL, 1); 70362306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(initial_power_mode, _INIT_PWR_MODE, 1); 70462306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(high_priority_lun, _HIGH_PR_LUN, 1); 70562306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(secure_removal_type, _SEC_RMV_TYPE, 1); 70662306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(support_security_lun, _SEC_LU, 1); 70762306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(bkops_termination_latency, _BKOP_TERM_LT, 1); 70862306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(initial_active_icc_level, _ACTVE_ICC_LVL, 1); 70962306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(specification_version, _SPEC_VER, 2); 71062306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(manufacturing_date, _MANF_DATE, 2); 71162306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(manufacturer_id, _MANF_ID, 2); 71262306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(rtt_capability, _RTT_CAP, 1); 71362306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(rtc_update, _FRQ_RTC, 2); 71462306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(ufs_features, _UFS_FEAT, 1); 71562306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(ffu_timeout, _FFU_TMT, 1); 71662306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(queue_depth, _Q_DPTH, 1); 71762306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(device_version, _DEV_VER, 2); 71862306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(number_of_secure_wpa, _NUM_SEC_WPA, 1); 71962306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(psa_max_data_size, _PSA_MAX_DATA, 4); 72062306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(psa_state_timeout, _PSA_TMT, 1); 72162306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(ext_feature_sup, _EXT_UFS_FEATURE_SUP, 4); 72262306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(wb_presv_us_en, _WB_PRESRV_USRSPC_EN, 1); 72362306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(wb_type, _WB_TYPE, 1); 72462306a36Sopenharmony_ciUFS_DEVICE_DESC_PARAM(wb_shared_alloc_units, _WB_SHARED_ALLOC_UNITS, 4); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_device_descriptor[] = { 72762306a36Sopenharmony_ci &dev_attr_device_type.attr, 72862306a36Sopenharmony_ci &dev_attr_device_class.attr, 72962306a36Sopenharmony_ci &dev_attr_device_sub_class.attr, 73062306a36Sopenharmony_ci &dev_attr_protocol.attr, 73162306a36Sopenharmony_ci &dev_attr_number_of_luns.attr, 73262306a36Sopenharmony_ci &dev_attr_number_of_wluns.attr, 73362306a36Sopenharmony_ci &dev_attr_boot_enable.attr, 73462306a36Sopenharmony_ci &dev_attr_descriptor_access_enable.attr, 73562306a36Sopenharmony_ci &dev_attr_initial_power_mode.attr, 73662306a36Sopenharmony_ci &dev_attr_high_priority_lun.attr, 73762306a36Sopenharmony_ci &dev_attr_secure_removal_type.attr, 73862306a36Sopenharmony_ci &dev_attr_support_security_lun.attr, 73962306a36Sopenharmony_ci &dev_attr_bkops_termination_latency.attr, 74062306a36Sopenharmony_ci &dev_attr_initial_active_icc_level.attr, 74162306a36Sopenharmony_ci &dev_attr_specification_version.attr, 74262306a36Sopenharmony_ci &dev_attr_manufacturing_date.attr, 74362306a36Sopenharmony_ci &dev_attr_manufacturer_id.attr, 74462306a36Sopenharmony_ci &dev_attr_rtt_capability.attr, 74562306a36Sopenharmony_ci &dev_attr_rtc_update.attr, 74662306a36Sopenharmony_ci &dev_attr_ufs_features.attr, 74762306a36Sopenharmony_ci &dev_attr_ffu_timeout.attr, 74862306a36Sopenharmony_ci &dev_attr_queue_depth.attr, 74962306a36Sopenharmony_ci &dev_attr_device_version.attr, 75062306a36Sopenharmony_ci &dev_attr_number_of_secure_wpa.attr, 75162306a36Sopenharmony_ci &dev_attr_psa_max_data_size.attr, 75262306a36Sopenharmony_ci &dev_attr_psa_state_timeout.attr, 75362306a36Sopenharmony_ci &dev_attr_ext_feature_sup.attr, 75462306a36Sopenharmony_ci &dev_attr_wb_presv_us_en.attr, 75562306a36Sopenharmony_ci &dev_attr_wb_type.attr, 75662306a36Sopenharmony_ci &dev_attr_wb_shared_alloc_units.attr, 75762306a36Sopenharmony_ci NULL, 75862306a36Sopenharmony_ci}; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_device_descriptor_group = { 76162306a36Sopenharmony_ci .name = "device_descriptor", 76262306a36Sopenharmony_ci .attrs = ufs_sysfs_device_descriptor, 76362306a36Sopenharmony_ci}; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci#define UFS_INTERCONNECT_DESC_PARAM(_name, _uname, _size) \ 76662306a36Sopenharmony_ci UFS_DESC_PARAM(_name, _uname, INTERCONNECT, _size) 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ciUFS_INTERCONNECT_DESC_PARAM(unipro_version, _UNIPRO_VER, 2); 76962306a36Sopenharmony_ciUFS_INTERCONNECT_DESC_PARAM(mphy_version, _MPHY_VER, 2); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_interconnect_descriptor[] = { 77262306a36Sopenharmony_ci &dev_attr_unipro_version.attr, 77362306a36Sopenharmony_ci &dev_attr_mphy_version.attr, 77462306a36Sopenharmony_ci NULL, 77562306a36Sopenharmony_ci}; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_interconnect_descriptor_group = { 77862306a36Sopenharmony_ci .name = "interconnect_descriptor", 77962306a36Sopenharmony_ci .attrs = ufs_sysfs_interconnect_descriptor, 78062306a36Sopenharmony_ci}; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci#define UFS_GEOMETRY_DESC_PARAM(_name, _uname, _size) \ 78362306a36Sopenharmony_ci UFS_DESC_PARAM(_name, _uname, GEOMETRY, _size) 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(raw_device_capacity, _DEV_CAP, 8); 78662306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(max_number_of_luns, _MAX_NUM_LUN, 1); 78762306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(segment_size, _SEG_SIZE, 4); 78862306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(allocation_unit_size, _ALLOC_UNIT_SIZE, 1); 78962306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(min_addressable_block_size, _MIN_BLK_SIZE, 1); 79062306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(optimal_read_block_size, _OPT_RD_BLK_SIZE, 1); 79162306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(optimal_write_block_size, _OPT_WR_BLK_SIZE, 1); 79262306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(max_in_buffer_size, _MAX_IN_BUF_SIZE, 1); 79362306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(max_out_buffer_size, _MAX_OUT_BUF_SIZE, 1); 79462306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(rpmb_rw_size, _RPMB_RW_SIZE, 1); 79562306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(dyn_capacity_resource_policy, _DYN_CAP_RSRC_PLC, 1); 79662306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(data_ordering, _DATA_ORDER, 1); 79762306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(max_number_of_contexts, _MAX_NUM_CTX, 1); 79862306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(sys_data_tag_unit_size, _TAG_UNIT_SIZE, 1); 79962306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(sys_data_tag_resource_size, _TAG_RSRC_SIZE, 1); 80062306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(secure_removal_types, _SEC_RM_TYPES, 1); 80162306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(memory_types, _MEM_TYPES, 2); 80262306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(sys_code_memory_max_alloc_units, 80362306a36Sopenharmony_ci _SCM_MAX_NUM_UNITS, 4); 80462306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(sys_code_memory_capacity_adjustment_factor, 80562306a36Sopenharmony_ci _SCM_CAP_ADJ_FCTR, 2); 80662306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(non_persist_memory_max_alloc_units, 80762306a36Sopenharmony_ci _NPM_MAX_NUM_UNITS, 4); 80862306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(non_persist_memory_capacity_adjustment_factor, 80962306a36Sopenharmony_ci _NPM_CAP_ADJ_FCTR, 2); 81062306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(enh1_memory_max_alloc_units, 81162306a36Sopenharmony_ci _ENM1_MAX_NUM_UNITS, 4); 81262306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(enh1_memory_capacity_adjustment_factor, 81362306a36Sopenharmony_ci _ENM1_CAP_ADJ_FCTR, 2); 81462306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(enh2_memory_max_alloc_units, 81562306a36Sopenharmony_ci _ENM2_MAX_NUM_UNITS, 4); 81662306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(enh2_memory_capacity_adjustment_factor, 81762306a36Sopenharmony_ci _ENM2_CAP_ADJ_FCTR, 2); 81862306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(enh3_memory_max_alloc_units, 81962306a36Sopenharmony_ci _ENM3_MAX_NUM_UNITS, 4); 82062306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(enh3_memory_capacity_adjustment_factor, 82162306a36Sopenharmony_ci _ENM3_CAP_ADJ_FCTR, 2); 82262306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(enh4_memory_max_alloc_units, 82362306a36Sopenharmony_ci _ENM4_MAX_NUM_UNITS, 4); 82462306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(enh4_memory_capacity_adjustment_factor, 82562306a36Sopenharmony_ci _ENM4_CAP_ADJ_FCTR, 2); 82662306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(wb_max_alloc_units, _WB_MAX_ALLOC_UNITS, 4); 82762306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(wb_max_wb_luns, _WB_MAX_WB_LUNS, 1); 82862306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(wb_buff_cap_adj, _WB_BUFF_CAP_ADJ, 1); 82962306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(wb_sup_red_type, _WB_SUP_RED_TYPE, 1); 83062306a36Sopenharmony_ciUFS_GEOMETRY_DESC_PARAM(wb_sup_wb_type, _WB_SUP_WB_TYPE, 1); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_geometry_descriptor[] = { 83462306a36Sopenharmony_ci &dev_attr_raw_device_capacity.attr, 83562306a36Sopenharmony_ci &dev_attr_max_number_of_luns.attr, 83662306a36Sopenharmony_ci &dev_attr_segment_size.attr, 83762306a36Sopenharmony_ci &dev_attr_allocation_unit_size.attr, 83862306a36Sopenharmony_ci &dev_attr_min_addressable_block_size.attr, 83962306a36Sopenharmony_ci &dev_attr_optimal_read_block_size.attr, 84062306a36Sopenharmony_ci &dev_attr_optimal_write_block_size.attr, 84162306a36Sopenharmony_ci &dev_attr_max_in_buffer_size.attr, 84262306a36Sopenharmony_ci &dev_attr_max_out_buffer_size.attr, 84362306a36Sopenharmony_ci &dev_attr_rpmb_rw_size.attr, 84462306a36Sopenharmony_ci &dev_attr_dyn_capacity_resource_policy.attr, 84562306a36Sopenharmony_ci &dev_attr_data_ordering.attr, 84662306a36Sopenharmony_ci &dev_attr_max_number_of_contexts.attr, 84762306a36Sopenharmony_ci &dev_attr_sys_data_tag_unit_size.attr, 84862306a36Sopenharmony_ci &dev_attr_sys_data_tag_resource_size.attr, 84962306a36Sopenharmony_ci &dev_attr_secure_removal_types.attr, 85062306a36Sopenharmony_ci &dev_attr_memory_types.attr, 85162306a36Sopenharmony_ci &dev_attr_sys_code_memory_max_alloc_units.attr, 85262306a36Sopenharmony_ci &dev_attr_sys_code_memory_capacity_adjustment_factor.attr, 85362306a36Sopenharmony_ci &dev_attr_non_persist_memory_max_alloc_units.attr, 85462306a36Sopenharmony_ci &dev_attr_non_persist_memory_capacity_adjustment_factor.attr, 85562306a36Sopenharmony_ci &dev_attr_enh1_memory_max_alloc_units.attr, 85662306a36Sopenharmony_ci &dev_attr_enh1_memory_capacity_adjustment_factor.attr, 85762306a36Sopenharmony_ci &dev_attr_enh2_memory_max_alloc_units.attr, 85862306a36Sopenharmony_ci &dev_attr_enh2_memory_capacity_adjustment_factor.attr, 85962306a36Sopenharmony_ci &dev_attr_enh3_memory_max_alloc_units.attr, 86062306a36Sopenharmony_ci &dev_attr_enh3_memory_capacity_adjustment_factor.attr, 86162306a36Sopenharmony_ci &dev_attr_enh4_memory_max_alloc_units.attr, 86262306a36Sopenharmony_ci &dev_attr_enh4_memory_capacity_adjustment_factor.attr, 86362306a36Sopenharmony_ci &dev_attr_wb_max_alloc_units.attr, 86462306a36Sopenharmony_ci &dev_attr_wb_max_wb_luns.attr, 86562306a36Sopenharmony_ci &dev_attr_wb_buff_cap_adj.attr, 86662306a36Sopenharmony_ci &dev_attr_wb_sup_red_type.attr, 86762306a36Sopenharmony_ci &dev_attr_wb_sup_wb_type.attr, 86862306a36Sopenharmony_ci NULL, 86962306a36Sopenharmony_ci}; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_geometry_descriptor_group = { 87262306a36Sopenharmony_ci .name = "geometry_descriptor", 87362306a36Sopenharmony_ci .attrs = ufs_sysfs_geometry_descriptor, 87462306a36Sopenharmony_ci}; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci#define UFS_HEALTH_DESC_PARAM(_name, _uname, _size) \ 87762306a36Sopenharmony_ci UFS_DESC_PARAM(_name, _uname, HEALTH, _size) 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ciUFS_HEALTH_DESC_PARAM(eol_info, _EOL_INFO, 1); 88062306a36Sopenharmony_ciUFS_HEALTH_DESC_PARAM(life_time_estimation_a, _LIFE_TIME_EST_A, 1); 88162306a36Sopenharmony_ciUFS_HEALTH_DESC_PARAM(life_time_estimation_b, _LIFE_TIME_EST_B, 1); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_health_descriptor[] = { 88462306a36Sopenharmony_ci &dev_attr_eol_info.attr, 88562306a36Sopenharmony_ci &dev_attr_life_time_estimation_a.attr, 88662306a36Sopenharmony_ci &dev_attr_life_time_estimation_b.attr, 88762306a36Sopenharmony_ci NULL, 88862306a36Sopenharmony_ci}; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_health_descriptor_group = { 89162306a36Sopenharmony_ci .name = "health_descriptor", 89262306a36Sopenharmony_ci .attrs = ufs_sysfs_health_descriptor, 89362306a36Sopenharmony_ci}; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci#define UFS_POWER_DESC_PARAM(_name, _uname, _index) \ 89662306a36Sopenharmony_cistatic ssize_t _name##_index##_show(struct device *dev, \ 89762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) \ 89862306a36Sopenharmony_ci{ \ 89962306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); \ 90062306a36Sopenharmony_ci return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_POWER, 0, \ 90162306a36Sopenharmony_ci PWR_DESC##_uname##_0 + _index * 2, buf, 2); \ 90262306a36Sopenharmony_ci} \ 90362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(_name##_index) 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 0); 90662306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 1); 90762306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 2); 90862306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 3); 90962306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 4); 91062306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 5); 91162306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 6); 91262306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 7); 91362306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 8); 91462306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 9); 91562306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 10); 91662306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 11); 91762306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 12); 91862306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 13); 91962306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 14); 92062306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vcc, _ACTIVE_LVLS_VCC, 15); 92162306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 0); 92262306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 1); 92362306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 2); 92462306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 3); 92562306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 4); 92662306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 5); 92762306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 6); 92862306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 7); 92962306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 8); 93062306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 9); 93162306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 10); 93262306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 11); 93362306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 12); 93462306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 13); 93562306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 14); 93662306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq, _ACTIVE_LVLS_VCCQ, 15); 93762306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 0); 93862306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 1); 93962306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 2); 94062306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 3); 94162306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 4); 94262306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 5); 94362306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 6); 94462306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 7); 94562306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 8); 94662306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 9); 94762306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 10); 94862306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 11); 94962306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 12); 95062306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 13); 95162306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 14); 95262306a36Sopenharmony_ciUFS_POWER_DESC_PARAM(active_icc_levels_vccq2, _ACTIVE_LVLS_VCCQ2, 15); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_power_descriptor[] = { 95562306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc0.attr, 95662306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc1.attr, 95762306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc2.attr, 95862306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc3.attr, 95962306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc4.attr, 96062306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc5.attr, 96162306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc6.attr, 96262306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc7.attr, 96362306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc8.attr, 96462306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc9.attr, 96562306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc10.attr, 96662306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc11.attr, 96762306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc12.attr, 96862306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc13.attr, 96962306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc14.attr, 97062306a36Sopenharmony_ci &dev_attr_active_icc_levels_vcc15.attr, 97162306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq0.attr, 97262306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq1.attr, 97362306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq2.attr, 97462306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq3.attr, 97562306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq4.attr, 97662306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq5.attr, 97762306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq6.attr, 97862306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq7.attr, 97962306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq8.attr, 98062306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq9.attr, 98162306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq10.attr, 98262306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq11.attr, 98362306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq12.attr, 98462306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq13.attr, 98562306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq14.attr, 98662306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq15.attr, 98762306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq20.attr, 98862306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq21.attr, 98962306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq22.attr, 99062306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq23.attr, 99162306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq24.attr, 99262306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq25.attr, 99362306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq26.attr, 99462306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq27.attr, 99562306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq28.attr, 99662306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq29.attr, 99762306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq210.attr, 99862306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq211.attr, 99962306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq212.attr, 100062306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq213.attr, 100162306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq214.attr, 100262306a36Sopenharmony_ci &dev_attr_active_icc_levels_vccq215.attr, 100362306a36Sopenharmony_ci NULL, 100462306a36Sopenharmony_ci}; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_power_descriptor_group = { 100762306a36Sopenharmony_ci .name = "power_descriptor", 100862306a36Sopenharmony_ci .attrs = ufs_sysfs_power_descriptor, 100962306a36Sopenharmony_ci}; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci#define UFS_STRING_DESCRIPTOR(_name, _pname) \ 101262306a36Sopenharmony_cistatic ssize_t _name##_show(struct device *dev, \ 101362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) \ 101462306a36Sopenharmony_ci{ \ 101562306a36Sopenharmony_ci u8 index; \ 101662306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); \ 101762306a36Sopenharmony_ci int ret; \ 101862306a36Sopenharmony_ci int desc_len = QUERY_DESC_MAX_SIZE; \ 101962306a36Sopenharmony_ci u8 *desc_buf; \ 102062306a36Sopenharmony_ci \ 102162306a36Sopenharmony_ci down(&hba->host_sem); \ 102262306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { \ 102362306a36Sopenharmony_ci up(&hba->host_sem); \ 102462306a36Sopenharmony_ci return -EBUSY; \ 102562306a36Sopenharmony_ci } \ 102662306a36Sopenharmony_ci desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_ATOMIC); \ 102762306a36Sopenharmony_ci if (!desc_buf) { \ 102862306a36Sopenharmony_ci up(&hba->host_sem); \ 102962306a36Sopenharmony_ci return -ENOMEM; \ 103062306a36Sopenharmony_ci } \ 103162306a36Sopenharmony_ci ufshcd_rpm_get_sync(hba); \ 103262306a36Sopenharmony_ci ret = ufshcd_query_descriptor_retry(hba, \ 103362306a36Sopenharmony_ci UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \ 103462306a36Sopenharmony_ci 0, 0, desc_buf, &desc_len); \ 103562306a36Sopenharmony_ci if (ret) { \ 103662306a36Sopenharmony_ci ret = -EINVAL; \ 103762306a36Sopenharmony_ci goto out; \ 103862306a36Sopenharmony_ci } \ 103962306a36Sopenharmony_ci index = desc_buf[DEVICE_DESC_PARAM##_pname]; \ 104062306a36Sopenharmony_ci kfree(desc_buf); \ 104162306a36Sopenharmony_ci desc_buf = NULL; \ 104262306a36Sopenharmony_ci ret = ufshcd_read_string_desc(hba, index, &desc_buf, \ 104362306a36Sopenharmony_ci SD_ASCII_STD); \ 104462306a36Sopenharmony_ci if (ret < 0) \ 104562306a36Sopenharmony_ci goto out; \ 104662306a36Sopenharmony_ci ret = sysfs_emit(buf, "%s\n", desc_buf); \ 104762306a36Sopenharmony_ciout: \ 104862306a36Sopenharmony_ci ufshcd_rpm_put_sync(hba); \ 104962306a36Sopenharmony_ci kfree(desc_buf); \ 105062306a36Sopenharmony_ci up(&hba->host_sem); \ 105162306a36Sopenharmony_ci return ret; \ 105262306a36Sopenharmony_ci} \ 105362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(_name) 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ciUFS_STRING_DESCRIPTOR(manufacturer_name, _MANF_NAME); 105662306a36Sopenharmony_ciUFS_STRING_DESCRIPTOR(product_name, _PRDCT_NAME); 105762306a36Sopenharmony_ciUFS_STRING_DESCRIPTOR(oem_id, _OEM_ID); 105862306a36Sopenharmony_ciUFS_STRING_DESCRIPTOR(serial_number, _SN); 105962306a36Sopenharmony_ciUFS_STRING_DESCRIPTOR(product_revision, _PRDCT_REV); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_string_descriptors[] = { 106262306a36Sopenharmony_ci &dev_attr_manufacturer_name.attr, 106362306a36Sopenharmony_ci &dev_attr_product_name.attr, 106462306a36Sopenharmony_ci &dev_attr_oem_id.attr, 106562306a36Sopenharmony_ci &dev_attr_serial_number.attr, 106662306a36Sopenharmony_ci &dev_attr_product_revision.attr, 106762306a36Sopenharmony_ci NULL, 106862306a36Sopenharmony_ci}; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_string_descriptors_group = { 107162306a36Sopenharmony_ci .name = "string_descriptors", 107262306a36Sopenharmony_ci .attrs = ufs_sysfs_string_descriptors, 107362306a36Sopenharmony_ci}; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic inline bool ufshcd_is_wb_flags(enum flag_idn idn) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci return idn >= QUERY_FLAG_IDN_WB_EN && 107862306a36Sopenharmony_ci idn <= QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8; 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci#define UFS_FLAG(_name, _uname) \ 108262306a36Sopenharmony_cistatic ssize_t _name##_show(struct device *dev, \ 108362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) \ 108462306a36Sopenharmony_ci{ \ 108562306a36Sopenharmony_ci bool flag; \ 108662306a36Sopenharmony_ci u8 index = 0; \ 108762306a36Sopenharmony_ci int ret; \ 108862306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); \ 108962306a36Sopenharmony_ci \ 109062306a36Sopenharmony_ci down(&hba->host_sem); \ 109162306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { \ 109262306a36Sopenharmony_ci up(&hba->host_sem); \ 109362306a36Sopenharmony_ci return -EBUSY; \ 109462306a36Sopenharmony_ci } \ 109562306a36Sopenharmony_ci if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname)) \ 109662306a36Sopenharmony_ci index = ufshcd_wb_get_query_index(hba); \ 109762306a36Sopenharmony_ci ufshcd_rpm_get_sync(hba); \ 109862306a36Sopenharmony_ci ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG, \ 109962306a36Sopenharmony_ci QUERY_FLAG_IDN##_uname, index, &flag); \ 110062306a36Sopenharmony_ci ufshcd_rpm_put_sync(hba); \ 110162306a36Sopenharmony_ci if (ret) { \ 110262306a36Sopenharmony_ci ret = -EINVAL; \ 110362306a36Sopenharmony_ci goto out; \ 110462306a36Sopenharmony_ci } \ 110562306a36Sopenharmony_ci ret = sysfs_emit(buf, "%s\n", flag ? "true" : "false"); \ 110662306a36Sopenharmony_ciout: \ 110762306a36Sopenharmony_ci up(&hba->host_sem); \ 110862306a36Sopenharmony_ci return ret; \ 110962306a36Sopenharmony_ci} \ 111062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(_name) 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ciUFS_FLAG(device_init, _FDEVICEINIT); 111362306a36Sopenharmony_ciUFS_FLAG(permanent_wpe, _PERMANENT_WPE); 111462306a36Sopenharmony_ciUFS_FLAG(power_on_wpe, _PWR_ON_WPE); 111562306a36Sopenharmony_ciUFS_FLAG(bkops_enable, _BKOPS_EN); 111662306a36Sopenharmony_ciUFS_FLAG(life_span_mode_enable, _LIFE_SPAN_MODE_ENABLE); 111762306a36Sopenharmony_ciUFS_FLAG(phy_resource_removal, _FPHYRESOURCEREMOVAL); 111862306a36Sopenharmony_ciUFS_FLAG(busy_rtc, _BUSY_RTC); 111962306a36Sopenharmony_ciUFS_FLAG(disable_fw_update, _PERMANENTLY_DISABLE_FW_UPDATE); 112062306a36Sopenharmony_ciUFS_FLAG(wb_enable, _WB_EN); 112162306a36Sopenharmony_ciUFS_FLAG(wb_flush_en, _WB_BUFF_FLUSH_EN); 112262306a36Sopenharmony_ciUFS_FLAG(wb_flush_during_h8, _WB_BUFF_FLUSH_DURING_HIBERN8); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_device_flags[] = { 112562306a36Sopenharmony_ci &dev_attr_device_init.attr, 112662306a36Sopenharmony_ci &dev_attr_permanent_wpe.attr, 112762306a36Sopenharmony_ci &dev_attr_power_on_wpe.attr, 112862306a36Sopenharmony_ci &dev_attr_bkops_enable.attr, 112962306a36Sopenharmony_ci &dev_attr_life_span_mode_enable.attr, 113062306a36Sopenharmony_ci &dev_attr_phy_resource_removal.attr, 113162306a36Sopenharmony_ci &dev_attr_busy_rtc.attr, 113262306a36Sopenharmony_ci &dev_attr_disable_fw_update.attr, 113362306a36Sopenharmony_ci &dev_attr_wb_enable.attr, 113462306a36Sopenharmony_ci &dev_attr_wb_flush_en.attr, 113562306a36Sopenharmony_ci &dev_attr_wb_flush_during_h8.attr, 113662306a36Sopenharmony_ci NULL, 113762306a36Sopenharmony_ci}; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_flags_group = { 114062306a36Sopenharmony_ci .name = "flags", 114162306a36Sopenharmony_ci .attrs = ufs_sysfs_device_flags, 114262306a36Sopenharmony_ci}; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistatic inline bool ufshcd_is_wb_attrs(enum attr_idn idn) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci return idn >= QUERY_ATTR_IDN_WB_FLUSH_STATUS && 114762306a36Sopenharmony_ci idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci#define UFS_ATTRIBUTE(_name, _uname) \ 115162306a36Sopenharmony_cistatic ssize_t _name##_show(struct device *dev, \ 115262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) \ 115362306a36Sopenharmony_ci{ \ 115462306a36Sopenharmony_ci struct ufs_hba *hba = dev_get_drvdata(dev); \ 115562306a36Sopenharmony_ci u32 value; \ 115662306a36Sopenharmony_ci int ret; \ 115762306a36Sopenharmony_ci u8 index = 0; \ 115862306a36Sopenharmony_ci \ 115962306a36Sopenharmony_ci down(&hba->host_sem); \ 116062306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { \ 116162306a36Sopenharmony_ci up(&hba->host_sem); \ 116262306a36Sopenharmony_ci return -EBUSY; \ 116362306a36Sopenharmony_ci } \ 116462306a36Sopenharmony_ci if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname)) \ 116562306a36Sopenharmony_ci index = ufshcd_wb_get_query_index(hba); \ 116662306a36Sopenharmony_ci ufshcd_rpm_get_sync(hba); \ 116762306a36Sopenharmony_ci ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, \ 116862306a36Sopenharmony_ci QUERY_ATTR_IDN##_uname, index, 0, &value); \ 116962306a36Sopenharmony_ci ufshcd_rpm_put_sync(hba); \ 117062306a36Sopenharmony_ci if (ret) { \ 117162306a36Sopenharmony_ci ret = -EINVAL; \ 117262306a36Sopenharmony_ci goto out; \ 117362306a36Sopenharmony_ci } \ 117462306a36Sopenharmony_ci ret = sysfs_emit(buf, "0x%08X\n", value); \ 117562306a36Sopenharmony_ciout: \ 117662306a36Sopenharmony_ci up(&hba->host_sem); \ 117762306a36Sopenharmony_ci return ret; \ 117862306a36Sopenharmony_ci} \ 117962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(_name) 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ciUFS_ATTRIBUTE(boot_lun_enabled, _BOOT_LU_EN); 118262306a36Sopenharmony_ciUFS_ATTRIBUTE(current_power_mode, _POWER_MODE); 118362306a36Sopenharmony_ciUFS_ATTRIBUTE(active_icc_level, _ACTIVE_ICC_LVL); 118462306a36Sopenharmony_ciUFS_ATTRIBUTE(ooo_data_enabled, _OOO_DATA_EN); 118562306a36Sopenharmony_ciUFS_ATTRIBUTE(bkops_status, _BKOPS_STATUS); 118662306a36Sopenharmony_ciUFS_ATTRIBUTE(purge_status, _PURGE_STATUS); 118762306a36Sopenharmony_ciUFS_ATTRIBUTE(max_data_in_size, _MAX_DATA_IN); 118862306a36Sopenharmony_ciUFS_ATTRIBUTE(max_data_out_size, _MAX_DATA_OUT); 118962306a36Sopenharmony_ciUFS_ATTRIBUTE(reference_clock_frequency, _REF_CLK_FREQ); 119062306a36Sopenharmony_ciUFS_ATTRIBUTE(configuration_descriptor_lock, _CONF_DESC_LOCK); 119162306a36Sopenharmony_ciUFS_ATTRIBUTE(max_number_of_rtt, _MAX_NUM_OF_RTT); 119262306a36Sopenharmony_ciUFS_ATTRIBUTE(exception_event_control, _EE_CONTROL); 119362306a36Sopenharmony_ciUFS_ATTRIBUTE(exception_event_status, _EE_STATUS); 119462306a36Sopenharmony_ciUFS_ATTRIBUTE(ffu_status, _FFU_STATUS); 119562306a36Sopenharmony_ciUFS_ATTRIBUTE(psa_state, _PSA_STATE); 119662306a36Sopenharmony_ciUFS_ATTRIBUTE(psa_data_size, _PSA_DATA_SIZE); 119762306a36Sopenharmony_ciUFS_ATTRIBUTE(wb_flush_status, _WB_FLUSH_STATUS); 119862306a36Sopenharmony_ciUFS_ATTRIBUTE(wb_avail_buf, _AVAIL_WB_BUFF_SIZE); 119962306a36Sopenharmony_ciUFS_ATTRIBUTE(wb_life_time_est, _WB_BUFF_LIFE_TIME_EST); 120062306a36Sopenharmony_ciUFS_ATTRIBUTE(wb_cur_buf, _CURR_WB_BUFF_SIZE); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_attributes[] = { 120462306a36Sopenharmony_ci &dev_attr_boot_lun_enabled.attr, 120562306a36Sopenharmony_ci &dev_attr_current_power_mode.attr, 120662306a36Sopenharmony_ci &dev_attr_active_icc_level.attr, 120762306a36Sopenharmony_ci &dev_attr_ooo_data_enabled.attr, 120862306a36Sopenharmony_ci &dev_attr_bkops_status.attr, 120962306a36Sopenharmony_ci &dev_attr_purge_status.attr, 121062306a36Sopenharmony_ci &dev_attr_max_data_in_size.attr, 121162306a36Sopenharmony_ci &dev_attr_max_data_out_size.attr, 121262306a36Sopenharmony_ci &dev_attr_reference_clock_frequency.attr, 121362306a36Sopenharmony_ci &dev_attr_configuration_descriptor_lock.attr, 121462306a36Sopenharmony_ci &dev_attr_max_number_of_rtt.attr, 121562306a36Sopenharmony_ci &dev_attr_exception_event_control.attr, 121662306a36Sopenharmony_ci &dev_attr_exception_event_status.attr, 121762306a36Sopenharmony_ci &dev_attr_ffu_status.attr, 121862306a36Sopenharmony_ci &dev_attr_psa_state.attr, 121962306a36Sopenharmony_ci &dev_attr_psa_data_size.attr, 122062306a36Sopenharmony_ci &dev_attr_wb_flush_status.attr, 122162306a36Sopenharmony_ci &dev_attr_wb_avail_buf.attr, 122262306a36Sopenharmony_ci &dev_attr_wb_life_time_est.attr, 122362306a36Sopenharmony_ci &dev_attr_wb_cur_buf.attr, 122462306a36Sopenharmony_ci NULL, 122562306a36Sopenharmony_ci}; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_cistatic const struct attribute_group ufs_sysfs_attributes_group = { 122862306a36Sopenharmony_ci .name = "attributes", 122962306a36Sopenharmony_ci .attrs = ufs_sysfs_attributes, 123062306a36Sopenharmony_ci}; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic const struct attribute_group *ufs_sysfs_groups[] = { 123362306a36Sopenharmony_ci &ufs_sysfs_default_group, 123462306a36Sopenharmony_ci &ufs_sysfs_capabilities_group, 123562306a36Sopenharmony_ci &ufs_sysfs_monitor_group, 123662306a36Sopenharmony_ci &ufs_sysfs_device_descriptor_group, 123762306a36Sopenharmony_ci &ufs_sysfs_interconnect_descriptor_group, 123862306a36Sopenharmony_ci &ufs_sysfs_geometry_descriptor_group, 123962306a36Sopenharmony_ci &ufs_sysfs_health_descriptor_group, 124062306a36Sopenharmony_ci &ufs_sysfs_power_descriptor_group, 124162306a36Sopenharmony_ci &ufs_sysfs_string_descriptors_group, 124262306a36Sopenharmony_ci &ufs_sysfs_flags_group, 124362306a36Sopenharmony_ci &ufs_sysfs_attributes_group, 124462306a36Sopenharmony_ci NULL, 124562306a36Sopenharmony_ci}; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci#define UFS_LUN_DESC_PARAM(_pname, _puname, _duname, _size) \ 124862306a36Sopenharmony_cistatic ssize_t _pname##_show(struct device *dev, \ 124962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) \ 125062306a36Sopenharmony_ci{ \ 125162306a36Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); \ 125262306a36Sopenharmony_ci struct ufs_hba *hba = shost_priv(sdev->host); \ 125362306a36Sopenharmony_ci u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); \ 125462306a36Sopenharmony_ci if (!ufs_is_valid_unit_desc_lun(&hba->dev_info, lun)) \ 125562306a36Sopenharmony_ci return -EINVAL; \ 125662306a36Sopenharmony_ci return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \ 125762306a36Sopenharmony_ci lun, _duname##_DESC_PARAM##_puname, buf, _size); \ 125862306a36Sopenharmony_ci} \ 125962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(_pname) 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci#define UFS_UNIT_DESC_PARAM(_name, _uname, _size) \ 126262306a36Sopenharmony_ci UFS_LUN_DESC_PARAM(_name, _uname, UNIT, _size) 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(lu_enable, _LU_ENABLE, 1); 126562306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(boot_lun_id, _BOOT_LUN_ID, 1); 126662306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(lun_write_protect, _LU_WR_PROTECT, 1); 126762306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(lun_queue_depth, _LU_Q_DEPTH, 1); 126862306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(psa_sensitive, _PSA_SENSITIVE, 1); 126962306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(lun_memory_type, _MEM_TYPE, 1); 127062306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(data_reliability, _DATA_RELIABILITY, 1); 127162306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(logical_block_size, _LOGICAL_BLK_SIZE, 1); 127262306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(logical_block_count, _LOGICAL_BLK_COUNT, 8); 127362306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(erase_block_size, _ERASE_BLK_SIZE, 4); 127462306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(provisioning_type, _PROVISIONING_TYPE, 1); 127562306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(physical_memory_resourse_count, _PHY_MEM_RSRC_CNT, 8); 127662306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(context_capabilities, _CTX_CAPABILITIES, 2); 127762306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(large_unit_granularity, _LARGE_UNIT_SIZE_M1, 1); 127862306a36Sopenharmony_ciUFS_UNIT_DESC_PARAM(wb_buf_alloc_units, _WB_BUF_ALLOC_UNITS, 4); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_unit_descriptor[] = { 128162306a36Sopenharmony_ci &dev_attr_lu_enable.attr, 128262306a36Sopenharmony_ci &dev_attr_boot_lun_id.attr, 128362306a36Sopenharmony_ci &dev_attr_lun_write_protect.attr, 128462306a36Sopenharmony_ci &dev_attr_lun_queue_depth.attr, 128562306a36Sopenharmony_ci &dev_attr_psa_sensitive.attr, 128662306a36Sopenharmony_ci &dev_attr_lun_memory_type.attr, 128762306a36Sopenharmony_ci &dev_attr_data_reliability.attr, 128862306a36Sopenharmony_ci &dev_attr_logical_block_size.attr, 128962306a36Sopenharmony_ci &dev_attr_logical_block_count.attr, 129062306a36Sopenharmony_ci &dev_attr_erase_block_size.attr, 129162306a36Sopenharmony_ci &dev_attr_provisioning_type.attr, 129262306a36Sopenharmony_ci &dev_attr_physical_memory_resourse_count.attr, 129362306a36Sopenharmony_ci &dev_attr_context_capabilities.attr, 129462306a36Sopenharmony_ci &dev_attr_large_unit_granularity.attr, 129562306a36Sopenharmony_ci &dev_attr_wb_buf_alloc_units.attr, 129662306a36Sopenharmony_ci NULL, 129762306a36Sopenharmony_ci}; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic umode_t ufs_unit_descriptor_is_visible(struct kobject *kobj, struct attribute *attr, int n) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 130262306a36Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 130362306a36Sopenharmony_ci u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); 130462306a36Sopenharmony_ci umode_t mode = attr->mode; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (lun == UFS_UPIU_BOOT_WLUN || lun == UFS_UPIU_UFS_DEVICE_WLUN) 130762306a36Sopenharmony_ci /* Boot and device WLUN have no unit descriptors */ 130862306a36Sopenharmony_ci mode = 0; 130962306a36Sopenharmony_ci if (lun == UFS_UPIU_RPMB_WLUN && attr == &dev_attr_wb_buf_alloc_units.attr) 131062306a36Sopenharmony_ci mode = 0; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci return mode; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ciconst struct attribute_group ufs_sysfs_unit_descriptor_group = { 131762306a36Sopenharmony_ci .name = "unit_descriptor", 131862306a36Sopenharmony_ci .attrs = ufs_sysfs_unit_descriptor, 131962306a36Sopenharmony_ci .is_visible = ufs_unit_descriptor_is_visible, 132062306a36Sopenharmony_ci}; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_cistatic ssize_t dyn_cap_needed_attribute_show(struct device *dev, 132362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci u32 value; 132662306a36Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 132762306a36Sopenharmony_ci struct ufs_hba *hba = shost_priv(sdev->host); 132862306a36Sopenharmony_ci u8 lun = ufshcd_scsi_to_upiu_lun(sdev->lun); 132962306a36Sopenharmony_ci int ret; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci down(&hba->host_sem); 133262306a36Sopenharmony_ci if (!ufshcd_is_user_access_allowed(hba)) { 133362306a36Sopenharmony_ci ret = -EBUSY; 133462306a36Sopenharmony_ci goto out; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci ufshcd_rpm_get_sync(hba); 133862306a36Sopenharmony_ci ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR, 133962306a36Sopenharmony_ci QUERY_ATTR_IDN_DYN_CAP_NEEDED, lun, 0, &value); 134062306a36Sopenharmony_ci ufshcd_rpm_put_sync(hba); 134162306a36Sopenharmony_ci if (ret) { 134262306a36Sopenharmony_ci ret = -EINVAL; 134362306a36Sopenharmony_ci goto out; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci ret = sysfs_emit(buf, "0x%08X\n", value); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ciout: 134962306a36Sopenharmony_ci up(&hba->host_sem); 135062306a36Sopenharmony_ci return ret; 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dyn_cap_needed_attribute); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic struct attribute *ufs_sysfs_lun_attributes[] = { 135562306a36Sopenharmony_ci &dev_attr_dyn_cap_needed_attribute.attr, 135662306a36Sopenharmony_ci NULL, 135762306a36Sopenharmony_ci}; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ciconst struct attribute_group ufs_sysfs_lun_attributes_group = { 136062306a36Sopenharmony_ci .attrs = ufs_sysfs_lun_attributes, 136162306a36Sopenharmony_ci}; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_civoid ufs_sysfs_add_nodes(struct device *dev) 136462306a36Sopenharmony_ci{ 136562306a36Sopenharmony_ci int ret; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ret = sysfs_create_groups(&dev->kobj, ufs_sysfs_groups); 136862306a36Sopenharmony_ci if (ret) 136962306a36Sopenharmony_ci dev_err(dev, 137062306a36Sopenharmony_ci "%s: sysfs groups creation failed (err = %d)\n", 137162306a36Sopenharmony_ci __func__, ret); 137262306a36Sopenharmony_ci} 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_civoid ufs_sysfs_remove_nodes(struct device *dev) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci sysfs_remove_groups(&dev->kobj, ufs_sysfs_groups); 137762306a36Sopenharmony_ci} 1378