scsi: ufs: core: Support updating device command timeout
authorPeter Wang <peter.wang@mediatek.com>
Sat, 10 May 2025 08:01:01 +0000 (16:01 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 13 May 2025 02:38:41 +0000 (22:38 -0400)
The default device command timeout remains 1.5 seconds, but platform
drivers can override it if needed.

Some UFS device commands may timeout due to being blocked by regular SCSI
write commands. Therefore, the maximum timeout needs to be extended to 30
seconds, matching the SCSI write command timeout. And for error injection
purposes, set the minimum value to 1 ms.

Signed-off-by: Peter Wang <peter.wang@mediatek.com>
Link: https://lore.kernel.org/r/20250510080345.595798-1-peter.wang@mediatek.com
Suggested-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/core/ufshcd.c

index c4aa24612812b9b8be429dcbfeefcba593870eb7..d7ff24b48de3ffeffcc860efef8e47d1f88ff80e 100644 (file)
@@ -63,7 +63,11 @@ enum {
 /* Query request retries */
 #define QUERY_REQ_RETRIES 3
 /* Query request timeout */
-#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */
+enum {
+       QUERY_REQ_TIMEOUT_MIN     = 1,
+       QUERY_REQ_TIMEOUT_DEFAULT = 1500,
+       QUERY_REQ_TIMEOUT_MAX     = 30000
+};
 
 /* Advanced RPMB request timeout */
 #define ADVANCED_RPMB_REQ_TIMEOUT  3000 /* 3 seconds */
@@ -135,6 +139,23 @@ module_param_cb(uic_cmd_timeout, &uic_cmd_timeout_ops, &uic_cmd_timeout, 0644);
 MODULE_PARM_DESC(uic_cmd_timeout,
                 "UFS UIC command timeout in milliseconds. Defaults to 500ms. Supported values range from 500ms to 5 seconds inclusively");
 
+static unsigned int dev_cmd_timeout = QUERY_REQ_TIMEOUT_DEFAULT;
+
+static int dev_cmd_timeout_set(const char *val, const struct kernel_param *kp)
+{
+       return param_set_uint_minmax(val, kp, QUERY_REQ_TIMEOUT_MIN,
+                                    QUERY_REQ_TIMEOUT_MAX);
+}
+
+static const struct kernel_param_ops dev_cmd_timeout_ops = {
+       .set = dev_cmd_timeout_set,
+       .get = param_get_uint,
+};
+
+module_param_cb(dev_cmd_timeout, &dev_cmd_timeout_ops, &dev_cmd_timeout, 0644);
+MODULE_PARM_DESC(dev_cmd_timeout,
+                "UFS Device command timeout in milliseconds. Defaults to 1.5s. Supported values range from 1ms to 30 seconds inclusively");
+
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)                           \
        ({                                                              \
                int _ret;                                               \
@@ -3362,7 +3383,7 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
        struct ufs_query_req *request = NULL;
        struct ufs_query_res *response = NULL;
        int err, selector = 0;
-       int timeout = QUERY_REQ_TIMEOUT;
+       int timeout = dev_cmd_timeout;
 
        BUG_ON(!hba);
 
@@ -3459,7 +3480,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
                goto out_unlock;
        }
 
-       err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+       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, err = %d\n",
@@ -3555,7 +3576,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
                goto out_unlock;
        }
 
-       err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+       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, err = %d\n",
@@ -6017,7 +6038,7 @@ int ufshcd_read_device_lvl_exception_id(struct ufs_hba *hba, u64 *exception_id)
 
        request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
 
-       err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+       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",
@@ -7278,7 +7299,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
         * bound to fail since dev_cmd.query and dev_cmd.type were left empty.
         * read the response directly ignoring all errors.
         */
-       ufshcd_issue_dev_cmd(hba, lrbp, tag, QUERY_REQ_TIMEOUT);
+       ufshcd_issue_dev_cmd(hba, lrbp, tag, dev_cmd_timeout);
 
        /* just copy the upiu response as it is */
        memcpy(rsp_upiu, lrbp->ucd_rsp_ptr, sizeof(*rsp_upiu));
@@ -8716,7 +8737,7 @@ static void ufshcd_set_timestamp_attr(struct ufs_hba *hba)
 
        put_unaligned_be64(ktime_get_real_ns(), &upiu_data->osf3);
 
-       err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT);
+       err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, dev_cmd_timeout);
 
        if (err)
                dev_err(hba->dev, "%s: failed to set timestamp %d\n",