diff options
author | Dov Levenglick <dovl@codeaurora.org> | 2015-04-29 13:21:44 +0300 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 10:59:40 -0700 |
commit | e9585814da4aa15ba5e5bb5a69f1518ddcfeb646 (patch) | |
tree | 6bbc1ac1bdbf499a04e0e07e1ee49afb597fb03d /drivers/scsi/ufs | |
parent | ee1ed9411a39cdd9d1f864baf373103322d5ddb6 (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>
Diffstat (limited to 'drivers/scsi/ufs')
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.c | 23 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 8 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 3 |
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); |