scsi: ufs: core: Add support for reinitializing the UFS device
authorManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Thu, 22 Dec 2022 14:09:57 +0000 (19:39 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 12 Jan 2023 02:49:34 +0000 (21:49 -0500)
Some platforms like Qcom, requires the UFS device to be reinitialized after
switching to maximum gear speed. So add support for that in UFS core by
introducing a new quirk (UFSHCD_CAP_REINIT_AFTER_MAX_GEAR_SWITCH) and doing
the reinitialization, if the quirk is enabled by the controller driver.

Suggested-by: Can Guo <quic_cang@quicinc.com>
Tested-by: Andrew Halaney <ahalaney@redhat.com> # Qdrive3/sa8540p-ride
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/ufs/core/ufshcd.c
include/ufs/ufshcd.h

index 99ca5b0..0514669 100644 (file)
@@ -8231,27 +8231,18 @@ out:
        return ret;
 }
 
-/**
- * ufshcd_probe_hba - probe hba to detect device and initialize it
- * @hba: per-adapter instance
- * @init_dev_params: whether or not to call ufshcd_device_params_init().
- *
- * Execute link-startup and verify device initialization
- */
-static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
+static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params)
 {
        int ret;
-       unsigned long flags;
-       ktime_t start = ktime_get();
 
        hba->ufshcd_state = UFSHCD_STATE_RESET;
 
        ret = ufshcd_link_startup(hba);
        if (ret)
-               goto out;
+               return ret;
 
        if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION)
-               goto out;
+               return ret;
 
        /* Debug counters initialization */
        ufshcd_clear_dbg_ufs_stats(hba);
@@ -8262,12 +8253,12 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
        /* Verify device initialization by sending NOP OUT UPIU */
        ret = ufshcd_verify_dev_init(hba);
        if (ret)
-               goto out;
+               return ret;
 
        /* Initiate UFS initialization, and waiting until completion */
        ret = ufshcd_complete_dev_init(hba);
        if (ret)
-               goto out;
+               return ret;
 
        /*
         * Initialize UFS device parameters used by driver, these
@@ -8276,7 +8267,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
        if (init_dev_params) {
                ret = ufshcd_device_params_init(hba);
                if (ret)
-                       goto out;
+                       return ret;
        }
 
        ufshcd_tune_unipro_params(hba);
@@ -8297,11 +8288,51 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
                if (ret) {
                        dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
                                        __func__, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * ufshcd_probe_hba - probe hba to detect device and initialize it
+ * @hba: per-adapter instance
+ * @init_dev_params: whether or not to call ufshcd_device_params_init().
+ *
+ * Execute link-startup and verify device initialization
+ */
+static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
+{
+       ktime_t start = ktime_get();
+       unsigned long flags;
+       int ret;
+
+       ret = ufshcd_device_init(hba, init_dev_params);
+       if (ret)
+               goto out;
+
+       if (hba->quirks & UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH) {
+               /* Reset the device and controller before doing reinit */
+               ufshcd_device_reset(hba);
+               ufshcd_hba_stop(hba);
+               ufshcd_vops_reinit_notify(hba);
+               ret = ufshcd_hba_enable(hba);
+               if (ret) {
+                       dev_err(hba->dev, "Host controller enable failed\n");
+                       ufshcd_print_evt_hist(hba);
+                       ufshcd_print_host_state(hba);
                        goto out;
                }
-               ufshcd_print_pwr_info(hba);
+
+               /* Reinit the device */
+               ret = ufshcd_device_init(hba, init_dev_params);
+               if (ret)
+                       goto out;
        }
 
+       ufshcd_print_pwr_info(hba);
+
        /*
         * bActiveICCLevel is volatile for UFS device (as per latest v2.1 spec)
         * and for removable UFS card as well, hence always set the parameter.
index 97f007d..ff13892 100644 (file)
@@ -596,6 +596,12 @@ enum ufshcd_quirks {
         * auto-hibernate capability but it's FASTAUTO only.
         */
        UFSHCD_QUIRK_HIBERN_FASTAUTO                    = 1 << 18,
+
+       /*
+        * This quirk needs to be enabled if the host controller needs
+        * to reinit the device after switching to maximum gear.
+        */
+       UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH       = 1 << 19,
 };
 
 enum ufshcd_caps {