Skip to content

Commit ae7795a

Browse files
Huan Tangmartinkpetersen
authored andcommitted
scsi: ufs: core: Add HID support
Follow JESD220G, support HID(Host Initiated Defragmentation) through sysfs, the relevant sysfs nodes are as follows: 1. analysis_trigger 2. defrag_trigger 3. fragmented_size 4. defrag_size 5. progress_ratio 6. state The detailed definition of the six nodes can be found in the sysfs documentation. HID's execution policy is given to user-space. Signed-off-by: Huan Tang <tanghuan@vivo.com> Signed-off-by: Wenxing Cheng <wenxing.cheng@vivo.com> Link: https://lore.kernel.org/r/20250523064604.800-1-tanghuan@vivo.com Suggested-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Peter Wang <peter.wang@mediatek.com> Reviewed-by: Bean Huo <huobean@gmail.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Yangtao Li <frank.li@vivo.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent c6503be commit ae7795a

4 files changed

Lines changed: 303 additions & 0 deletions

File tree

Documentation/ABI/testing/sysfs-driver-ufs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,3 +1685,86 @@ Description:
16851685
================ ========================================
16861686

16871687
The file is read only.
1688+
1689+
What: /sys/bus/platform/drivers/ufshcd/*/hid/analysis_trigger
1690+
What: /sys/bus/platform/devices/*.ufs/hid/analysis_trigger
1691+
Date: May 2025
1692+
Contact: Huan Tang <tanghuan@vivo.com>
1693+
Description:
1694+
The host can enable or disable HID analysis operation.
1695+
1696+
======= =========================================
1697+
disable disable HID analysis operation
1698+
enable enable HID analysis operation
1699+
======= =========================================
1700+
1701+
The file is write only.
1702+
1703+
What: /sys/bus/platform/drivers/ufshcd/*/hid/defrag_trigger
1704+
What: /sys/bus/platform/devices/*.ufs/hid/defrag_trigger
1705+
Date: May 2025
1706+
Contact: Huan Tang <tanghuan@vivo.com>
1707+
Description:
1708+
The host can enable or disable HID defragmentation operation.
1709+
1710+
======= =========================================
1711+
disable disable HID defragmentation operation
1712+
enable enable HID defragmentation operation
1713+
======= =========================================
1714+
1715+
The attribute is write only.
1716+
1717+
What: /sys/bus/platform/drivers/ufshcd/*/hid/fragmented_size
1718+
What: /sys/bus/platform/devices/*.ufs/hid/fragmented_size
1719+
Date: May 2025
1720+
Contact: Huan Tang <tanghuan@vivo.com>
1721+
Description:
1722+
The total fragmented size in the device is reported through
1723+
this attribute.
1724+
1725+
The attribute is read only.
1726+
1727+
What: /sys/bus/platform/drivers/ufshcd/*/hid/defrag_size
1728+
What: /sys/bus/platform/devices/*.ufs/hid/defrag_size
1729+
Date: May 2025
1730+
Contact: Huan Tang <tanghuan@vivo.com>
1731+
Description:
1732+
The host sets the size to be defragmented by an HID
1733+
defragmentation operation.
1734+
1735+
The attribute is read/write.
1736+
1737+
What: /sys/bus/platform/drivers/ufshcd/*/hid/progress_ratio
1738+
What: /sys/bus/platform/devices/*.ufs/hid/progress_ratio
1739+
Date: May 2025
1740+
Contact: Huan Tang <tanghuan@vivo.com>
1741+
Description:
1742+
Defragmentation progress is reported by this attribute,
1743+
indicates the ratio of the completed defragmentation size
1744+
over the requested defragmentation size.
1745+
1746+
==== ============================================
1747+
1 1%
1748+
...
1749+
100 100%
1750+
==== ============================================
1751+
1752+
The attribute is read only.
1753+
1754+
What: /sys/bus/platform/drivers/ufshcd/*/hid/state
1755+
What: /sys/bus/platform/devices/*.ufs/hid/state
1756+
Date: May 2025
1757+
Contact: Huan Tang <tanghuan@vivo.com>
1758+
Description:
1759+
The HID state is reported by this attribute.
1760+
1761+
==================== ===========================
1762+
idle Idle (analysis required)
1763+
analysis_in_progress Analysis in progress
1764+
defrag_required Defrag required
1765+
defrag_in_progress Defrag in progress
1766+
defrag_completed Defrag completed
1767+
defrag_not_required Defrag is not required
1768+
==================== ===========================
1769+
1770+
The attribute is read only.

drivers/ufs/core/ufs-sysfs.c

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,23 @@ static const char *ufs_wb_resize_status_to_string(enum wb_resize_status status)
8787
}
8888
}
8989

90+
static const char * const ufs_hid_states[] = {
91+
[HID_IDLE] = "idle",
92+
[ANALYSIS_IN_PROGRESS] = "analysis_in_progress",
93+
[DEFRAG_REQUIRED] = "defrag_required",
94+
[DEFRAG_IN_PROGRESS] = "defrag_in_progress",
95+
[DEFRAG_COMPLETED] = "defrag_completed",
96+
[DEFRAG_NOT_REQUIRED] = "defrag_not_required",
97+
};
98+
99+
static const char *ufs_hid_state_to_string(enum ufs_hid_state state)
100+
{
101+
if (state < NUM_UFS_HID_STATES)
102+
return ufs_hid_states[state];
103+
104+
return "unknown";
105+
}
106+
90107
static const char *ufshcd_uic_link_state_to_string(
91108
enum uic_link_state state)
92109
{
@@ -1763,6 +1780,178 @@ static const struct attribute_group ufs_sysfs_attributes_group = {
17631780
.attrs = ufs_sysfs_attributes,
17641781
};
17651782

1783+
static int hid_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
1784+
enum attr_idn idn, u32 *attr_val)
1785+
{
1786+
int ret;
1787+
1788+
down(&hba->host_sem);
1789+
if (!ufshcd_is_user_access_allowed(hba)) {
1790+
up(&hba->host_sem);
1791+
return -EBUSY;
1792+
}
1793+
1794+
ufshcd_rpm_get_sync(hba);
1795+
ret = ufshcd_query_attr(hba, opcode, idn, 0, 0, attr_val);
1796+
ufshcd_rpm_put_sync(hba);
1797+
1798+
up(&hba->host_sem);
1799+
return ret;
1800+
}
1801+
1802+
static ssize_t analysis_trigger_store(struct device *dev,
1803+
struct device_attribute *attr, const char *buf, size_t count)
1804+
{
1805+
struct ufs_hba *hba = dev_get_drvdata(dev);
1806+
int mode;
1807+
int ret;
1808+
1809+
if (sysfs_streq(buf, "enable"))
1810+
mode = HID_ANALYSIS_ENABLE;
1811+
else if (sysfs_streq(buf, "disable"))
1812+
mode = HID_ANALYSIS_AND_DEFRAG_DISABLE;
1813+
else
1814+
return -EINVAL;
1815+
1816+
ret = hid_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
1817+
QUERY_ATTR_IDN_HID_DEFRAG_OPERATION, &mode);
1818+
1819+
return ret < 0 ? ret : count;
1820+
}
1821+
1822+
static DEVICE_ATTR_WO(analysis_trigger);
1823+
1824+
static ssize_t defrag_trigger_store(struct device *dev,
1825+
struct device_attribute *attr, const char *buf, size_t count)
1826+
{
1827+
struct ufs_hba *hba = dev_get_drvdata(dev);
1828+
int mode;
1829+
int ret;
1830+
1831+
if (sysfs_streq(buf, "enable"))
1832+
mode = HID_ANALYSIS_AND_DEFRAG_ENABLE;
1833+
else if (sysfs_streq(buf, "disable"))
1834+
mode = HID_ANALYSIS_AND_DEFRAG_DISABLE;
1835+
else
1836+
return -EINVAL;
1837+
1838+
ret = hid_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
1839+
QUERY_ATTR_IDN_HID_DEFRAG_OPERATION, &mode);
1840+
1841+
return ret < 0 ? ret : count;
1842+
}
1843+
1844+
static DEVICE_ATTR_WO(defrag_trigger);
1845+
1846+
static ssize_t fragmented_size_show(struct device *dev,
1847+
struct device_attribute *attr, char *buf)
1848+
{
1849+
struct ufs_hba *hba = dev_get_drvdata(dev);
1850+
u32 value;
1851+
int ret;
1852+
1853+
ret = hid_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
1854+
QUERY_ATTR_IDN_HID_AVAILABLE_SIZE, &value);
1855+
if (ret)
1856+
return ret;
1857+
1858+
return sysfs_emit(buf, "%u\n", value);
1859+
}
1860+
1861+
static DEVICE_ATTR_RO(fragmented_size);
1862+
1863+
static ssize_t defrag_size_show(struct device *dev,
1864+
struct device_attribute *attr, char *buf)
1865+
{
1866+
struct ufs_hba *hba = dev_get_drvdata(dev);
1867+
u32 value;
1868+
int ret;
1869+
1870+
ret = hid_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
1871+
QUERY_ATTR_IDN_HID_SIZE, &value);
1872+
if (ret)
1873+
return ret;
1874+
1875+
return sysfs_emit(buf, "%u\n", value);
1876+
}
1877+
1878+
static ssize_t defrag_size_store(struct device *dev,
1879+
struct device_attribute *attr, const char *buf, size_t count)
1880+
{
1881+
struct ufs_hba *hba = dev_get_drvdata(dev);
1882+
u32 value;
1883+
int ret;
1884+
1885+
if (kstrtou32(buf, 0, &value))
1886+
return -EINVAL;
1887+
1888+
ret = hid_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
1889+
QUERY_ATTR_IDN_HID_SIZE, &value);
1890+
1891+
return ret < 0 ? ret : count;
1892+
}
1893+
1894+
static DEVICE_ATTR_RW(defrag_size);
1895+
1896+
static ssize_t progress_ratio_show(struct device *dev,
1897+
struct device_attribute *attr, char *buf)
1898+
{
1899+
struct ufs_hba *hba = dev_get_drvdata(dev);
1900+
u32 value;
1901+
int ret;
1902+
1903+
ret = hid_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
1904+
QUERY_ATTR_IDN_HID_PROGRESS_RATIO, &value);
1905+
if (ret)
1906+
return ret;
1907+
1908+
return sysfs_emit(buf, "%u\n", value);
1909+
}
1910+
1911+
static DEVICE_ATTR_RO(progress_ratio);
1912+
1913+
static ssize_t state_show(struct device *dev,
1914+
struct device_attribute *attr, char *buf)
1915+
{
1916+
struct ufs_hba *hba = dev_get_drvdata(dev);
1917+
u32 value;
1918+
int ret;
1919+
1920+
ret = hid_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,
1921+
QUERY_ATTR_IDN_HID_STATE, &value);
1922+
if (ret)
1923+
return ret;
1924+
1925+
return sysfs_emit(buf, "%s\n", ufs_hid_state_to_string(value));
1926+
}
1927+
1928+
static DEVICE_ATTR_RO(state);
1929+
1930+
static struct attribute *ufs_sysfs_hid[] = {
1931+
&dev_attr_analysis_trigger.attr,
1932+
&dev_attr_defrag_trigger.attr,
1933+
&dev_attr_fragmented_size.attr,
1934+
&dev_attr_defrag_size.attr,
1935+
&dev_attr_progress_ratio.attr,
1936+
&dev_attr_state.attr,
1937+
NULL,
1938+
};
1939+
1940+
static umode_t ufs_sysfs_hid_is_visible(struct kobject *kobj,
1941+
struct attribute *attr, int n)
1942+
{
1943+
struct device *dev = container_of(kobj, struct device, kobj);
1944+
struct ufs_hba *hba = dev_get_drvdata(dev);
1945+
1946+
return hba->dev_info.hid_sup ? attr->mode : 0;
1947+
}
1948+
1949+
static const struct attribute_group ufs_sysfs_hid_group = {
1950+
.name = "hid",
1951+
.attrs = ufs_sysfs_hid,
1952+
.is_visible = ufs_sysfs_hid_is_visible,
1953+
};
1954+
17661955
static const struct attribute_group *ufs_sysfs_groups[] = {
17671956
&ufs_sysfs_default_group,
17681957
&ufs_sysfs_capabilities_group,
@@ -1777,6 +1966,7 @@ static const struct attribute_group *ufs_sysfs_groups[] = {
17771966
&ufs_sysfs_string_descriptors_group,
17781967
&ufs_sysfs_flags_group,
17791968
&ufs_sysfs_attributes_group,
1969+
&ufs_sysfs_hid_group,
17801970
NULL,
17811971
};
17821972

drivers/ufs/core/ufshcd.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8414,6 +8414,10 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
84148414

84158415
dev_info->rtt_cap = desc_buf[DEVICE_DESC_PARAM_RTT_CAP];
84168416

8417+
dev_info->hid_sup = get_unaligned_be32(desc_buf +
8418+
DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP) &
8419+
UFS_DEV_HID_SUPPORT;
8420+
84178421
model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
84188422

84198423
err = ufshcd_read_string_desc(hba, model_index,

include/ufs/ufs.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ enum attr_idn {
182182
QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F,
183183
QUERY_ATTR_IDN_TIMESTAMP = 0x30,
184184
QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID = 0x34,
185+
QUERY_ATTR_IDN_HID_DEFRAG_OPERATION = 0x35,
186+
QUERY_ATTR_IDN_HID_AVAILABLE_SIZE = 0x36,
187+
QUERY_ATTR_IDN_HID_SIZE = 0x37,
188+
QUERY_ATTR_IDN_HID_PROGRESS_RATIO = 0x38,
189+
QUERY_ATTR_IDN_HID_STATE = 0x39,
185190
QUERY_ATTR_IDN_WB_BUF_RESIZE_HINT = 0x3C,
186191
QUERY_ATTR_IDN_WB_BUF_RESIZE_EN = 0x3D,
187192
QUERY_ATTR_IDN_WB_BUF_RESIZE_STATUS = 0x3E,
@@ -401,6 +406,7 @@ enum {
401406
UFS_DEV_HPB_SUPPORT = BIT(7),
402407
UFS_DEV_WRITE_BOOSTER_SUP = BIT(8),
403408
UFS_DEV_LVL_EXCEPTION_SUP = BIT(12),
409+
UFS_DEV_HID_SUPPORT = BIT(13),
404410
};
405411
#define UFS_DEV_HPB_SUPPORT_VERSION 0x310
406412

@@ -466,6 +472,24 @@ enum ufs_ref_clk_freq {
466472
REF_CLK_FREQ_INVAL = -1,
467473
};
468474

475+
/* bDefragOperation attribute values */
476+
enum ufs_hid_defrag_operation {
477+
HID_ANALYSIS_AND_DEFRAG_DISABLE = 0,
478+
HID_ANALYSIS_ENABLE = 1,
479+
HID_ANALYSIS_AND_DEFRAG_ENABLE = 2,
480+
};
481+
482+
/* bHIDState attribute values */
483+
enum ufs_hid_state {
484+
HID_IDLE = 0,
485+
ANALYSIS_IN_PROGRESS = 1,
486+
DEFRAG_REQUIRED = 2,
487+
DEFRAG_IN_PROGRESS = 3,
488+
DEFRAG_COMPLETED = 4,
489+
DEFRAG_NOT_REQUIRED = 5,
490+
NUM_UFS_HID_STATES = 6,
491+
};
492+
469493
/* bWriteBoosterBufferResizeEn attribute */
470494
enum wb_resize_en {
471495
WB_RESIZE_EN_IDLE = 0,
@@ -625,6 +649,8 @@ struct ufs_dev_info {
625649
u32 rtc_update_period;
626650

627651
u8 rtt_cap; /* bDeviceRTTCap */
652+
653+
bool hid_sup;
628654
};
629655

630656
/*

0 commit comments

Comments
 (0)