scsi: ufs: Change fDeviceInit busy wait
authorKiwoong Kim <kwmad.kim@samsung.com>
Mon, 10 Aug 2020 10:02:27 +0000 (19:02 +0900)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 21 Aug 2020 01:53:42 +0000 (21:53 -0400)
Currently, the UFS driver busy waits for fDeviceInit to be cleared. Provide
an upper bound and sleep between attempts instead of busy waiting.

Link: https://lore.kernel.org/r/1597053747-75171-1-git-send-email-kwmad.kim@samsung.com
Tested-by: Kiwoong Kim <kwmad.kim@samsung.com>
Reviewed-by: Avri Altman <avri.altman@wdc.com>
Signed-off-by: Kiwoong Kim <kwmad.kim@samsung.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/ufs/ufshcd.c

index 2b55c2e..66e837c 100644 (file)
@@ -74,6 +74,9 @@
 /* Default value of wait time before gating device ref clock */
 #define UFSHCD_REF_CLK_GATING_WAIT_US 0xFF /* microsecs */
 
+/* Polling time to wait for fDeviceInit */
+#define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */
+
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)                           \
        ({                                                              \
                int _ret;                                               \
@@ -4175,9 +4178,9 @@ EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode);
  */
 static int ufshcd_complete_dev_init(struct ufs_hba *hba)
 {
-       int i;
        int err;
        bool flag_res = true;
+       ktime_t timeout;
 
        err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
                QUERY_FLAG_IDN_FDEVICEINIT, 0, NULL);
@@ -4188,20 +4191,26 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba)
                goto out;
        }
 
-       /* poll for max. 1000 iterations for fDeviceInit flag to clear */
-       for (i = 0; i < 1000 && !err && flag_res; i++)
-               err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG,
-                       QUERY_FLAG_IDN_FDEVICEINIT, 0, &flag_res);
+       /* Poll fDeviceInit flag to be cleared */
+       timeout = ktime_add_ms(ktime_get(), FDEVICEINIT_COMPL_TIMEOUT);
+       do {
+               err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,
+                                       QUERY_FLAG_IDN_FDEVICEINIT, 0, &flag_res);
+               if (!flag_res)
+                       break;
+               usleep_range(5000, 10000);
+       } while (ktime_before(ktime_get(), timeout));
 
-       if (err)
+       if (err) {
                dev_err(hba->dev,
-                       "%s reading fDeviceInit flag failed with error %d\n",
-                       __func__, err);
-       else if (flag_res)
+                               "%s reading fDeviceInit flag failed with error %d\n",
+                               __func__, err);
+       } else if (flag_res) {
                dev_err(hba->dev,
-                       "%s fDeviceInit was not cleared by the device\n",
-                       __func__);
-
+                               "%s fDeviceInit was not cleared by the device\n",
+                               __func__);
+               err = -EBUSY;
+       }
 out:
        return err;
 }