Skip to content

Commit 1fd2e77

Browse files
Bao D. Nguyenmartinkpetersen
authored andcommitted
scsi: ufs: core: Add device level exception support
The ufs device JEDEC specification version 4.1 adds support for the device level exception events. To support this new device level exception feature, expose two new sysfs nodes below to provide the user space access to the device level exception information. /sys/bus/platform/drivers/ufshcd/*/device_lvl_exception_count /sys/bus/platform/drivers/ufshcd/*/device_lvl_exception_id The device_lvl_exception_count sysfs node reports the number of device level exceptions that have occurred since the last time this variable is reset. Writing a value of 0 will reset it. The device_lvl_exception_id reports the exception ID which is the qDeviceLevelExceptionID attribute of the device JEDEC specifications version 4.1 and later. The user space application can query these sysfs nodes to get more information about the device level exception. Signed-off-by: Bao D. Nguyen <[email protected]> Link: https://lore.kernel.org/r/6278d7c125b2f0cf5056f4a647a4b9c1fdd24fc7.1743198325.git.quic_nguyenb@quicinc.com Reviewed-by: Peter Wang <[email protected]> Reviewed-by: Bart Van Assche <[email protected]> Reviewed-by: Arthur Simchaev <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent bdab404 commit 1fd2e77

File tree

6 files changed

+155
-1
lines changed

6 files changed

+155
-1
lines changed

Documentation/ABI/testing/sysfs-driver-ufs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,3 +1604,35 @@ Description:
16041604
prevent the UFS from frequently performing clock gating/ungating.
16051605

16061606
The attribute is read/write.
1607+
1608+
What: /sys/bus/platform/drivers/ufshcd/*/device_lvl_exception_count
1609+
What: /sys/bus/platform/devices/*.ufs/device_lvl_exception_count
1610+
Date: March 2025
1611+
Contact: Bao D. Nguyen <[email protected]>
1612+
Description:
1613+
This attribute is applicable to ufs devices compliant to the
1614+
JEDEC specifications version 4.1 or later. The
1615+
device_lvl_exception_count is a counter indicating the number of
1616+
times the device level exceptions have occurred since the last
1617+
time this variable is reset. Writing a 0 value to this
1618+
attribute will reset the device_lvl_exception_count. If the
1619+
device_lvl_exception_count reads a positive value, the user
1620+
application should read the device_lvl_exception_id attribute to
1621+
know more information about the exception.
1622+
1623+
The attribute is read/write.
1624+
1625+
What: /sys/bus/platform/drivers/ufshcd/*/device_lvl_exception_id
1626+
What: /sys/bus/platform/devices/*.ufs/device_lvl_exception_id
1627+
Date: March 2025
1628+
Contact: Bao D. Nguyen <[email protected]>
1629+
Description:
1630+
Reading the device_lvl_exception_id returns the
1631+
qDeviceLevelExceptionID attribute of the ufs device JEDEC
1632+
specification version 4.1. The definition of the
1633+
qDeviceLevelExceptionID is the ufs device vendor specific
1634+
implementation. Refer to the device manufacturer datasheet for
1635+
more information on the meaning of the qDeviceLevelExceptionID
1636+
attribute value.
1637+
1638+
The attribute is read only.

drivers/ufs/core/ufs-sysfs.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,56 @@ static ssize_t critical_health_show(struct device *dev,
466466
return sysfs_emit(buf, "%d\n", hba->critical_health_count);
467467
}
468468

469+
static ssize_t device_lvl_exception_count_show(struct device *dev,
470+
struct device_attribute *attr,
471+
char *buf)
472+
{
473+
struct ufs_hba *hba = dev_get_drvdata(dev);
474+
475+
if (hba->dev_info.wspecversion < 0x410)
476+
return -EOPNOTSUPP;
477+
478+
return sysfs_emit(buf, "%u\n", atomic_read(&hba->dev_lvl_exception_count));
479+
}
480+
481+
static ssize_t device_lvl_exception_count_store(struct device *dev,
482+
struct device_attribute *attr,
483+
const char *buf, size_t count)
484+
{
485+
struct ufs_hba *hba = dev_get_drvdata(dev);
486+
unsigned int value;
487+
488+
if (kstrtouint(buf, 0, &value))
489+
return -EINVAL;
490+
491+
/* the only supported usecase is to reset the dev_lvl_exception_count */
492+
if (value)
493+
return -EINVAL;
494+
495+
atomic_set(&hba->dev_lvl_exception_count, 0);
496+
497+
return count;
498+
}
499+
500+
static ssize_t device_lvl_exception_id_show(struct device *dev,
501+
struct device_attribute *attr,
502+
char *buf)
503+
{
504+
struct ufs_hba *hba = dev_get_drvdata(dev);
505+
u64 exception_id;
506+
int err;
507+
508+
ufshcd_rpm_get_sync(hba);
509+
err = ufshcd_read_device_lvl_exception_id(hba, &exception_id);
510+
ufshcd_rpm_put_sync(hba);
511+
512+
if (err)
513+
return err;
514+
515+
hba->dev_lvl_exception_id = exception_id;
516+
return sysfs_emit(buf, "%llu\n", exception_id);
517+
}
518+
469519
static DEVICE_ATTR_RW(rpm_lvl);
470520
static DEVICE_ATTR_RO(rpm_target_dev_state);
471521
static DEVICE_ATTR_RO(rpm_target_link_state);
@@ -479,6 +529,8 @@ static DEVICE_ATTR_RW(wb_flush_threshold);
479529
static DEVICE_ATTR_RW(rtc_update_ms);
480530
static DEVICE_ATTR_RW(pm_qos_enable);
481531
static DEVICE_ATTR_RO(critical_health);
532+
static DEVICE_ATTR_RW(device_lvl_exception_count);
533+
static DEVICE_ATTR_RO(device_lvl_exception_id);
482534

483535
static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
484536
&dev_attr_rpm_lvl.attr,
@@ -494,6 +546,8 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = {
494546
&dev_attr_rtc_update_ms.attr,
495547
&dev_attr_pm_qos_enable.attr,
496548
&dev_attr_critical_health.attr,
549+
&dev_attr_device_lvl_exception_count.attr,
550+
&dev_attr_device_lvl_exception_id.attr,
497551
NULL
498552
};
499553

drivers/ufs/core/ufshcd-priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
9494
enum query_opcode desc_op);
9595

9696
int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable);
97+
int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id);
9798

9899
/* Wrapper functions for safely calling variant operations */
99100
static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)

drivers/ufs/core/ufshcd.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5998,6 +5998,42 @@ static void ufshcd_bkops_exception_event_handler(struct ufs_hba *hba)
59985998
__func__, err);
59995999
}
60006000

6001+
int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id)
6002+
{
6003+
struct utp_upiu_query_v4_0 *upiu_resp;
6004+
struct ufs_query_req *request = NULL;
6005+
struct ufs_query_res *response = NULL;
6006+
int err;
6007+
6008+
if (hba->dev_info.wspecversion < 0x410)
6009+
return -EOPNOTSUPP;
6010+
6011+
ufshcd_hold(hba);
6012+
mutex_lock(&hba->dev_cmd.lock);
6013+
6014+
ufshcd_init_query(hba, &request, &response,
6015+
UPIU_QUERY_OPCODE_READ_ATTR,
6016+
QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID, 0, 0);
6017+
6018+
request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
6019+
6020+
err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
6021+
6022+
if (err) {
6023+
dev_err(hba->dev, "%s: failed to read device level exception %d\n",
6024+
__func__, err);
6025+
goto out;
6026+
}
6027+
6028+
upiu_resp = (struct utp_upiu_query_v4_0 *)response;
6029+
*exception_id = get_unaligned_be64(&upiu_resp->osf3);
6030+
out:
6031+
mutex_unlock(&hba->dev_cmd.lock);
6032+
ufshcd_release(hba);
6033+
6034+
return err;
6035+
}
6036+
60016037
static int __ufshcd_wb_toggle(struct ufs_hba *hba, bool set, enum flag_idn idn)
60026038
{
60036039
u8 index;
@@ -6223,6 +6259,11 @@ static void ufshcd_exception_event_handler(struct work_struct *work)
62236259
sysfs_notify(&hba->dev->kobj, NULL, "critical_health");
62246260
}
62256261

6262+
if (status & hba->ee_drv_mask & MASK_EE_DEV_LVL_EXCEPTION) {
6263+
atomic_inc(&hba->dev_lvl_exception_count);
6264+
sysfs_notify(&hba->dev->kobj, NULL, "device_lvl_exception_count");
6265+
}
6266+
62266267
ufs_debugfs_exception_event(hba, status);
62276268
}
62286269

@@ -8122,6 +8163,22 @@ static void ufshcd_temp_notif_probe(struct ufs_hba *hba, const u8 *desc_buf)
81228163
}
81238164
}
81248165

8166+
static void ufshcd_device_lvl_exception_probe(struct ufs_hba *hba, u8 *desc_buf)
8167+
{
8168+
u32 ext_ufs_feature;
8169+
8170+
if (hba->dev_info.wspecversion < 0x410)
8171+
return;
8172+
8173+
ext_ufs_feature = get_unaligned_be32(desc_buf +
8174+
DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP);
8175+
if (!(ext_ufs_feature & UFS_DEV_LVL_EXCEPTION_SUP))
8176+
return;
8177+
8178+
atomic_set(&hba->dev_lvl_exception_count, 0);
8179+
ufshcd_enable_ee(hba, MASK_EE_DEV_LVL_EXCEPTION);
8180+
}
8181+
81258182
static void ufshcd_set_rtt(struct ufs_hba *hba)
81268183
{
81278184
struct ufs_dev_info *dev_info = &hba->dev_info;
@@ -8322,6 +8379,8 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
83228379

83238380
ufs_init_rtc(hba, desc_buf);
83248381

8382+
ufshcd_device_lvl_exception_probe(hba, desc_buf);
8383+
83258384
/*
83268385
* ufshcd_read_string_desc returns size of the string
83278386
* reset the error value

include/ufs/ufs.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ enum attr_idn {
180180
QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D,
181181
QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E,
182182
QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE = 0x1F,
183-
QUERY_ATTR_IDN_TIMESTAMP = 0x30
183+
QUERY_ATTR_IDN_TIMESTAMP = 0x30,
184+
QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID = 0x34,
184185
};
185186

186187
/* Descriptor idn for Query requests */
@@ -390,6 +391,7 @@ enum {
390391
UFS_DEV_EXT_TEMP_NOTIF = BIT(6),
391392
UFS_DEV_HPB_SUPPORT = BIT(7),
392393
UFS_DEV_WRITE_BOOSTER_SUP = BIT(8),
394+
UFS_DEV_LVL_EXCEPTION_SUP = BIT(12),
393395
};
394396
#define UFS_DEV_HPB_SUPPORT_VERSION 0x310
395397

@@ -419,6 +421,7 @@ enum {
419421
MASK_EE_TOO_LOW_TEMP = BIT(4),
420422
MASK_EE_WRITEBOOSTER_EVENT = BIT(5),
421423
MASK_EE_PERFORMANCE_THROTTLING = BIT(6),
424+
MASK_EE_DEV_LVL_EXCEPTION = BIT(7),
422425
MASK_EE_HEALTH_CRITICAL = BIT(9),
423426
};
424427
#define MASK_EE_URGENT_TEMP (MASK_EE_TOO_HIGH_TEMP | MASK_EE_TOO_LOW_TEMP)

include/ufs/ufshcd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,9 @@ enum ufshcd_mcq_opr {
968968
* @pm_qos_req: PM QoS request handle
969969
* @pm_qos_enabled: flag to check if pm qos is enabled
970970
* @critical_health_count: count of critical health exceptions
971+
* @dev_lvl_exception_count: count of device level exceptions since last reset
972+
* @dev_lvl_exception_id: vendor specific information about the
973+
* device level exception event.
971974
*/
972975
struct ufs_hba {
973976
void __iomem *mmio_base;
@@ -1138,6 +1141,8 @@ struct ufs_hba {
11381141
bool pm_qos_enabled;
11391142

11401143
int critical_health_count;
1144+
atomic_t dev_lvl_exception_count;
1145+
u64 dev_lvl_exception_id;
11411146
};
11421147

11431148
/**

0 commit comments

Comments
 (0)