summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDov Levenglick <dovl@codeaurora.org>2015-04-29 13:21:44 +0300
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:59:40 -0700
commite9585814da4aa15ba5e5bb5a69f1518ddcfeb646 (patch)
tree6bbc1ac1bdbf499a04e0e07e1ee49afb597fb03d
parentee1ed9411a39cdd9d1f864baf373103322d5ddb6 (diff)
scsi: ufs: recovery from hibern8 exit failure
Perform PHY and controller hard reset to recover from hibern8 exit failure. This requires full initialization of the PHY and the controller before issuing link start-up. Change-Id: I93c5f896d86eb74a1ef490e3e14ae796082888cf Signed-off-by: Dov Levenglick <dovl@codeaurora.org> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c23
-rw-r--r--drivers/scsi/ufs/ufshcd.c8
-rw-r--r--drivers/scsi/ufs/ufshcd.h3
3 files changed, 34 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index c4112e979399..62cb434e6ff3 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -28,6 +28,7 @@
#include "ufshci.h"
#include "ufs-qcom-ice.h"
#include "ufs-qcom-debugfs.h"
+#include <linux/clk/msm-clk.h>
#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \
(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
@@ -634,6 +635,27 @@ out:
return err;
}
+static int ufs_qcom_full_reset(struct ufs_hba *hba)
+{
+ struct ufs_clk_info *clki;
+ int ret = -ENOTSUPP;
+
+ list_for_each_entry(clki, &hba->clk_list_head, list) {
+ if (!strcmp(clki->name, "core_clk")) {
+ ret = clk_reset(clki->clk, CLK_RESET_ASSERT);
+ if (ret)
+ goto out;
+ /* Very small delay, per the documented requirement */
+ usleep_range(1, 2);
+
+ ret = clk_reset(clki->clk, CLK_RESET_DEASSERT);
+ break;
+ }
+ }
+out:
+ return ret;
+}
+
static
int ufs_qcom_crytpo_engine_cfg(struct ufs_hba *hba, unsigned int task_tag)
{
@@ -1777,6 +1799,7 @@ const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
.pwr_change_notify = ufs_qcom_pwr_change_notify,
.suspend = ufs_qcom_suspend,
.resume = ufs_qcom_resume,
+ .full_reset = ufs_qcom_full_reset,
.update_sec_cfg = ufs_qcom_update_sec_cfg,
.dbg_register_dump = ufs_qcom_dump_dbg_regs,
.crypto_engine_cfg = ufs_qcom_crytpo_engine_cfg,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 68e29d752956..c2a19df3f21d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3881,6 +3881,14 @@ static int ufshcd_link_recovery(struct ufs_hba *hba)
ufshcd_set_eh_in_progress(hba);
spin_unlock_irqrestore(hba->host->host_lock, flags);
+ if (hba->vops && hba->vops->full_reset) {
+ ret = hba->vops->full_reset(hba);
+ if (ret)
+ dev_warn(hba->dev,
+ "full reset returned %d, trying to recover the link\n",
+ ret);
+ }
+
ret = ufshcd_host_reset_and_restore(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index f88f160681ee..7a4e606168a4 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -301,6 +301,8 @@ struct ufs_pwr_mode_info {
* to be set.
* @suspend: called during host controller PM callback
* @resume: called during host controller PM callback
+ * @full_reset: called during link recovery for handling variant specific
+ * implementations of resetting the hci
* @update_sec_cfg: called to restore host controller secure configuration
* @dbg_register_dump: used to dump controller debug information
* @crypto_engine_cfg: configure cryptographic engine according to tag parameter
@@ -336,6 +338,7 @@ struct ufs_hba_variant_ops {
struct ufs_pa_layer_attr *);
int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
+ int (*full_reset)(struct ufs_hba *);
int (*update_sec_cfg)(struct ufs_hba *hba, bool restore_sec_cfg);
void (*dbg_register_dump)(struct ufs_hba *hba);
int (*crypto_engine_cfg)(struct ufs_hba *, unsigned int);