[COMMON] scsi: ufs: asynchronous link establishment on UFS resume
authorhgchu <hg.chu@samsung.com>
Fri, 12 Jan 2018 06:35:04 +0000 (15:35 +0900)
committerJaeHun Jung <jh0801.jung@samsung.com>
Tue, 8 May 2018 08:20:36 +0000 (17:20 +0900)
Change-Id: I62f0259277959fa90590f5823adbe3bc7fbc2ccd
Signed-off-by: hgchu <hg.chu@samsung.com>
drivers/scsi/ufs/Kconfig
drivers/scsi/ufs/ufshcd.c

index 42afe905acff28b243e075b62aec8574c7850f68..5b174f8feb9143ec1c23e155db1ba2917ae142d4 100644 (file)
@@ -87,6 +87,18 @@ config SCSI_UFS_DWC_TC_PLATFORM
 
          If unsure, say N.
 
+config SCSI_UFS_ASYNC_RELINK
+       tristate "Asynchronous link establishment on UFS device resume"
+       depends on SCSI_UFSHCD && SCSI_UFSHCD_PLATFORM
+       ---help---
+         This feature is to support concurrency of UFS resume and the others.
+         In UFS re-link, system wake-up may task a long time when UFS resume
+         time is increased for device latency or etc.
+
+         If you want to enable this feature, say Y or M here.
+
+         If unsure, say N.
+
 config SCSI_UFS_QCOM
        tristate "QCOM specific hooks to UFS controller platform driver"
        depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
index 317eae63c98c506eedc5a3d0ad567803ab5d1075..5a6d7f76e4052048d4561efd7e8c2ea55737da58 100644 (file)
@@ -6003,7 +6003,7 @@ out:
  */
 static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
 {
-       int err;
+       int err = 0;
        unsigned long flags;
 
        /* Reset the host controller */
@@ -6017,12 +6017,20 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
        ufshcd_scale_clks(hba, true);
 
        /* Establish the link again and restore the device */
-       err = ufshcd_probe_hba(hba);
+#ifdef CONFIG_SCSI_UFS_ASYNC_RELINK
+       if (hba->pm_op_in_progress)
+               async_schedule(ufshcd_async_scan, hba);
+       else
+#endif
+       {
+               err = ufshcd_probe_hba(hba);
 
                if (!err && (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)) {
                        dev_err(hba->dev, "%s: failed\n", __func__);
                        err = -EIO;
                }
+       }
+
        spin_lock_irqsave(hba->host->host_lock, flags);
        ufshcd_clear_eh_in_progress(hba);
        spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -6685,7 +6693,8 @@ retry:
         * If we are in error handling context or in power management callbacks
         * context, no need to scan the host
         */
-       if (!ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress) {
+       if (!ufshcd_eh_in_progress(hba) && !hba->pm_op_in_progress
+                       && !hba->async_resume) {
                bool flag;
 
                /* clear any previous UFS device information */
@@ -6777,8 +6786,30 @@ out:
 static void ufshcd_async_scan(void *data, async_cookie_t cookie)
 {
        struct ufs_hba *hba = (struct ufs_hba *)data;
+       int err = 0;
 
-       ufshcd_probe_hba(hba);
+       if (hba->async_resume) {
+               scsi_block_requests(hba->host);
+               err = ufshcd_probe_hba(hba);
+               if (err)
+                       goto err;
+
+               if (!ufshcd_is_ufs_dev_active(hba)) {
+                       scsi_unblock_requests(hba->host);
+                       ufshcd_set_dev_pwr_mode(hba, UFS_ACTIVE_PWR_MODE);
+                       scsi_block_requests(hba->host);
+               }
+
+               /*
+                * If BKOPs operations are urgently needed at this moment then
+                * keep auto-bkops enabled or else disable it.
+                */
+               ufshcd_urgent_bkops(hba);
+err:
+               scsi_unblock_requests(hba->host);
+       } else {
+               ufshcd_probe_hba(hba);
+       }
 }
 
 static enum blk_eh_timer_return ufshcd_eh_timed_out(struct scsi_cmnd *scmd)