]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
scsi: ufs: core: Introduce function ufshcd_query_attr_qword()
authorCan Guo <can.guo@oss.qualcomm.com>
Fri, 24 Apr 2026 15:14:19 +0000 (08:14 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 5 May 2026 07:27:42 +0000 (03:27 -0400)
Introduce a new generic function ufshcd_query_attr_qword() to handle
quad-word (64-bit) UFS attribute operations. This consolidates the
handling of 64-bit attributes which was previously scattered across
multiple specialized functions.

Reviewed-by: Peter Wang <peter.wang@mediatek.com>
Signed-off-by: Can Guo <can.guo@oss.qualcomm.com>
Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Link: https://patch.msgid.link/20260424151420.111675-2-can.guo@oss.qualcomm.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/core/ufs-sysfs.c
drivers/ufs/core/ufshcd-priv.h
drivers/ufs/core/ufshcd.c

index 99af3c73f1af7eaad2757f296389c7b2c7237037..d9dc4cc3452eefcb167a34649dd9ee37a96be3f0 100644 (file)
@@ -594,8 +594,13 @@ static ssize_t device_lvl_exception_id_show(struct device *dev,
        u64 exception_id;
        int err;
 
+       if (hba->dev_info.wspecversion < 0x410)
+               return -EOPNOTSUPP;
+
        ufshcd_rpm_get_sync(hba);
-       err = ufshcd_read_device_lvl_exception_id(hba, &exception_id);
+       err = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_READ_ATTR,
+                                     QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID,
+                                     0, 0, &exception_id);
        ufshcd_rpm_put_sync(hba);
 
        if (err)
@@ -1670,6 +1675,12 @@ static inline bool ufshcd_is_wb_attrs(enum attr_idn idn)
                idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE;
 }
 
+static inline bool ufshcd_is_qword_attr(enum attr_idn idn)
+{
+       return idn == QUERY_ATTR_IDN_TIMESTAMP ||
+              idn == QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID;
+}
+
 static int wb_read_resize_attrs(struct ufs_hba *hba,
                        enum attr_idn idn, u32 *attr_val)
 {
@@ -1736,6 +1747,7 @@ static ssize_t _name##_show(struct device *dev,                           \
        struct device_attribute *attr, char *buf)                       \
 {                                                                      \
        struct ufs_hba *hba = dev_get_drvdata(dev);                     \
+       u64 qword_value;                                                \
        u32 value;                                                      \
        int ret;                                                        \
        u8 index = 0;                                                   \
@@ -1748,14 +1760,24 @@ static ssize_t _name##_show(struct device *dev,                         \
        if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname))                 \
                index = ufshcd_wb_get_query_index(hba);                 \
        ufshcd_rpm_get_sync(hba);                                       \
-       ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,       \
-               QUERY_ATTR_IDN##_uname, index, 0, &value);              \
+       if (ufshcd_is_qword_attr(QUERY_ATTR_IDN##_uname))               \
+               ret = ufshcd_query_attr_qword(hba,                      \
+                       UPIU_QUERY_OPCODE_READ_ATTR,                    \
+                       QUERY_ATTR_IDN##_uname,                         \
+                       index, 0, &qword_value);                        \
+       else                                                            \
+               ret = ufshcd_query_attr(hba,                            \
+                       UPIU_QUERY_OPCODE_READ_ATTR,                    \
+                       QUERY_ATTR_IDN##_uname, index, 0, &value);      \
        ufshcd_rpm_put_sync(hba);                                       \
        if (ret) {                                                      \
                ret = -EINVAL;                                          \
                goto out;                                               \
        }                                                               \
-       ret = sysfs_emit(buf, "0x%08X\n", value);                       \
+       if (ufshcd_is_qword_attr(QUERY_ATTR_IDN##_uname))               \
+               ret = sysfs_emit(buf, "0x%016llX\n", qword_value);      \
+       else                                                            \
+               ret = sysfs_emit(buf, "0x%08X\n", value);               \
 out:                                                                   \
        up(&hba->host_sem);                                             \
        return ret;                                                     \
index 0a72148cb053e30b333d9122afbb46d975b363ef..ed1adeb22ec6220e4a45194427c3a77eab502755 100644 (file)
@@ -60,6 +60,8 @@ int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode,
                            u32 *attr_val);
 int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
                      enum attr_idn idn, u8 index, u8 selector, u32 *attr_val);
+int ufshcd_query_attr_qword(struct ufs_hba *hba, enum query_opcode opcode,
+                           enum attr_idn idn, u8 index, u8 sel, u64 *attr_val);
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
        enum flag_idn idn, u8 index, bool *flag_res);
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
@@ -106,7 +108,6 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
                             enum query_opcode desc_op);
 
 int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable);
-int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id);
 
 int ufshcd_uic_tx_eqtr(struct ufs_hba *hba, int gear);
 void ufshcd_apply_valid_tx_eq_settings(struct ufs_hba *hba);
index 4805e40ed4d78cd4b0c07cda0df6bb0f7e172cb1..c92e0409c7938755377abf46ca6e010219a81bd5 100644 (file)
@@ -3611,6 +3611,67 @@ int ufshcd_query_attr_retry(struct ufs_hba *hba,
        return ret;
 }
 
+/**
+ * ufshcd_query_attr_qword - Function of sending query requests for quad-word attributes
+ * @hba: per-adapter instance
+ * @opcode: attribute opcode
+ * @idn: attribute idn to access
+ * @index: index field
+ * @sel: selector field
+ * @attr_val: the attribute value after the query request completes
+ *
+ * Return: 0 for success, non-zero in case of failure.
+ */
+int ufshcd_query_attr_qword(struct ufs_hba *hba, enum query_opcode opcode,
+                           enum attr_idn idn, u8 index, u8 sel, u64 *attr_val)
+{
+       struct utp_upiu_query_v4_0 *upiu_req;
+       struct utp_upiu_query_v4_0 *upiu_resp;
+       struct ufs_query_req *request = NULL;
+       struct ufs_query_res *response = NULL;
+       int err;
+
+       if (!attr_val) {
+               dev_err(hba->dev, "%s: attribute value required for opcode 0x%x\n",
+                       __func__, opcode);
+               return -EINVAL;
+       }
+
+       ufshcd_dev_man_lock(hba);
+
+       ufshcd_init_query(hba, &request, &response, opcode, idn, index, sel);
+
+       switch (opcode) {
+       case UPIU_QUERY_OPCODE_WRITE_ATTR:
+               request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+               upiu_req = (struct utp_upiu_query_v4_0 *)&request->upiu_req;
+               put_unaligned_be64(*attr_val, &upiu_req->osf3);
+               break;
+       case UPIU_QUERY_OPCODE_READ_ATTR:
+               request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+               break;
+       default:
+               dev_err(hba->dev, "%s: Expected query attr opcode but got = 0x%.2x\n",
+                       __func__, opcode);
+               err = -EINVAL;
+               goto out_unlock;
+       }
+
+       err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout);
+       if (err) {
+               dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, selector %d, err = %d\n",
+                       __func__, opcode, idn, index, sel, err);
+               goto out_unlock;
+       }
+
+       upiu_resp = (struct utp_upiu_query_v4_0 *)response;
+       *attr_val = get_unaligned_be64(&upiu_resp->osf3);
+
+out_unlock:
+       ufshcd_dev_man_unlock(hba);
+       return err;
+}
+
 /*
  * Return: 0 upon success; > 0 in case the UFS device reported an OCS error;
  * < 0 if another error occurred.
@@ -6224,46 +6285,6 @@ out:
                                __func__, err);
 }
 
-/*
- * Return: 0 upon success; > 0 in case the UFS device reported an OCS error;
- * < 0 if another error occurred.
- */
-int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id)
-{
-       struct utp_upiu_query_v4_0 *upiu_resp;
-       struct ufs_query_req *request = NULL;
-       struct ufs_query_res *response = NULL;
-       int err;
-
-       if (hba->dev_info.wspecversion < 0x410)
-               return -EOPNOTSUPP;
-
-       ufshcd_hold(hba);
-       mutex_lock(&hba->dev_cmd.lock);
-
-       ufshcd_init_query(hba, &request, &response,
-                         UPIU_QUERY_OPCODE_READ_ATTR,
-                         QUERY_ATTR_IDN_DEV_LVL_EXCEPTION_ID, 0, 0);
-
-       request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
-
-       err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout);
-
-       if (err) {
-               dev_err(hba->dev, "%s: failed to read device level exception %d\n",
-                       __func__, err);
-               goto out;
-       }
-
-       upiu_resp = (struct utp_upiu_query_v4_0 *)response;
-       *exception_id = get_unaligned_be64(&upiu_resp->osf3);
-out:
-       mutex_unlock(&hba->dev_cmd.lock);
-       ufshcd_release(hba);
-
-       return err;
-}
-
 static int __ufshcd_wb_toggle(struct ufs_hba *hba, bool set, enum flag_idn idn)
 {
        u8 index;
@@ -9113,35 +9134,20 @@ out:
 
 static void ufshcd_set_timestamp_attr(struct ufs_hba *hba)
 {
-       int err;
-       struct ufs_query_req *request = NULL;
-       struct ufs_query_res *response = NULL;
        struct ufs_dev_info *dev_info = &hba->dev_info;
-       struct utp_upiu_query_v4_0 *upiu_data;
+       u64 ts_ns;
+       int err;
 
        if (dev_info->wspecversion < 0x400 ||
            hba->dev_quirks & UFS_DEVICE_QUIRK_NO_TIMESTAMP_SUPPORT)
                return;
 
-       ufshcd_dev_man_lock(hba);
-
-       ufshcd_init_query(hba, &request, &response,
-                         UPIU_QUERY_OPCODE_WRITE_ATTR,
-                         QUERY_ATTR_IDN_TIMESTAMP, 0, 0);
-
-       request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
-
-       upiu_data = (struct utp_upiu_query_v4_0 *)&request->upiu_req;
-
-       put_unaligned_be64(ktime_get_real_ns(), &upiu_data->osf3);
-
-       err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout);
-
+       ts_ns = ktime_get_real_ns();
+       err = ufshcd_query_attr_qword(hba, UPIU_QUERY_OPCODE_WRITE_ATTR,
+                                     QUERY_ATTR_IDN_TIMESTAMP, 0, 0, &ts_ns);
        if (err)
                dev_err(hba->dev, "%s: failed to set timestamp %d\n",
                        __func__, err);
-
-       ufshcd_dev_man_unlock(hba);
 }
 
 /**