diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/ufs/ufs-qcom.c | 45 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.c | 22 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 9 |
3 files changed, 63 insertions, 13 deletions
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index bfa82ca64499..a3bcfb42ca6a 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -996,7 +996,7 @@ static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) } } -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +static int __ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) { int err = 0; @@ -1027,7 +1027,7 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) vote = ufs_qcom_get_bus_vote(host, mode); if (vote >= 0) - err = ufs_qcom_set_bus_vote(host, vote); + err = __ufs_qcom_set_bus_vote(host, vote); else err = vote; @@ -1038,6 +1038,35 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) return err; } +static int ufs_qcom_set_bus_vote(struct ufs_hba *hba, bool on) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int vote, err; + + /* + * In case ufs_qcom_init() is not yet done, simply ignore. + * This ufs_qcom_set_bus_vote() shall be called from + * ufs_qcom_init() after init is done. + */ + if (!host) + return 0; + + if (on) { + vote = host->bus_vote.saved_vote; + if (vote == host->bus_vote.min_bw_vote) + ufs_qcom_update_bus_bw_vote(host); + } else { + vote = host->bus_vote.min_bw_vote; + } + + err = __ufs_qcom_set_bus_vote(host, vote); + if (err) + dev_err(hba->dev, "%s: set bus vote failed %d\n", + __func__, err); + + return err; +} + static ssize_t show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, char *buf) @@ -1403,7 +1432,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, { struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err; - int vote = 0; /* * In case ufs_qcom_init() is not yet done, simply ignore. @@ -1428,9 +1456,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, /* enable the device ref clock for HS mode*/ if (ufshcd_is_hs_mode(&hba->pwr_info)) ufs_qcom_dev_ref_clk_ctrl(host, true); - vote = host->bus_vote.saved_vote; - if (vote == host->bus_vote.min_bw_vote) - ufs_qcom_update_bus_bw_vote(host); err = ufs_qcom_ice_resume(host); if (err) @@ -1449,14 +1474,8 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, /* disable device ref_clk */ ufs_qcom_dev_ref_clk_ctrl(host, false); } - vote = host->bus_vote.min_bw_vote; } - err = ufs_qcom_set_bus_vote(host, vote); - if (err) - dev_err(hba->dev, "%s: set bus vote failed %d\n", - __func__, err); - out: return err; } @@ -2011,6 +2030,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); + ufs_qcom_set_bus_vote(hba, true); ufs_qcom_setup_clocks(hba, true, false); if (hba->dev->id < MAX_UFS_QCOM_HOSTS) @@ -2521,6 +2541,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .full_reset = ufs_qcom_full_reset, .update_sec_cfg = ufs_qcom_update_sec_cfg, .get_scale_down_gear = ufs_qcom_get_scale_down_gear, + .set_bus_vote = ufs_qcom_set_bus_vote, .dbg_register_dump = ufs_qcom_dump_dbg_regs, #ifdef CONFIG_DEBUG_FS .add_debugfs = ufs_qcom_dbg_add_debugfs, diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index ce779d760c69..a49b3c7bc4ef 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -7555,6 +7555,13 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on, if (!head || list_empty(head)) goto out; + /* call vendor specific bus vote before enabling the clocks */ + if (on) { + ret = ufshcd_vops_set_bus_vote(hba, on); + if (ret) + return ret; + } + /* * vendor specific setup_clocks ops may depend on clocks managed by * this standard driver hence call the vendor specific setup_clocks @@ -7593,11 +7600,24 @@ static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on, * this standard driver hence call the vendor specific setup_clocks * after enabling the clocks managed here. */ - if (on) + if (on) { ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context); + if (ret) + goto out; + } + + /* + * call vendor specific bus vote to remove the vote after + * disabling the clocks. + */ + if (!on) + ret = ufshcd_vops_set_bus_vote(hba, on); out: if (ret) { + if (on) + /* Can't do much if this fails */ + (void) ufshcd_vops_set_bus_vote(hba, false); list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled) clk_disable_unprepare(clki->clk); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 552d50081e3f..b79bebb58dcd 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -309,6 +309,7 @@ struct ufs_pwr_mode_info { * @update_sec_cfg: called to restore host controller secure configuration * @get_scale_down_gear: called to get the minimum supported gear to * scale down + * @set_bus_vote: called to vote for the required bus bandwidth * @add_debugfs: used to add debugfs entries * @remove_debugfs: used to remove debugfs entries */ @@ -335,6 +336,7 @@ struct ufs_hba_variant_ops { void (*dbg_register_dump)(struct ufs_hba *hba); int (*update_sec_cfg)(struct ufs_hba *hba, bool restore_sec_cfg); u32 (*get_scale_down_gear)(struct ufs_hba *); + int (*set_bus_vote)(struct ufs_hba *, bool); #ifdef CONFIG_DEBUG_FS void (*add_debugfs)(struct ufs_hba *hba, struct dentry *root); void (*remove_debugfs)(struct ufs_hba *hba); @@ -1259,6 +1261,13 @@ static inline u32 ufshcd_vops_get_scale_down_gear(struct ufs_hba *hba) return UFS_HS_G1; } +static inline int ufshcd_vops_set_bus_vote(struct ufs_hba *hba, bool on) +{ + if (hba->var && hba->var->vops && hba->var->vops->set_bus_vote) + return hba->var->vops->set_bus_vote(hba, on); + return 0; +} + #ifdef CONFIG_DEBUG_FS static inline void ufshcd_vops_add_debugfs(struct ufs_hba *hba, struct dentry *root) |