Loading drivers/scsi/ufs/ufshcd.c +35 −4 Original line number Diff line number Diff line Loading @@ -381,6 +381,8 @@ static int ufshcd_disable_clocks(struct ufs_hba *hba, bool is_gating_context); static int ufshcd_disable_clocks_skip_ref_clk(struct ufs_hba *hba, bool is_gating_context); static void ufshcd_hold_all(struct ufs_hba *hba); static void ufshcd_release_all(struct ufs_hba *hba); static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); static inline void ufshcd_save_tstamp_of_last_dme_cmd(struct ufs_hba *hba); Loading Loading @@ -2055,6 +2057,22 @@ static void ufshcd_hibern8_enter_work(struct work_struct *work) return; } static void __ufshcd_set_auto_hibern8_timer(struct ufs_hba *hba, unsigned long delay_ms) { pm_runtime_get_sync(hba->dev); ufshcd_hold_all(hba); ufshcd_scsi_block_requests(hba); down_write(&hba->lock); /* wait for all the outstanding requests to finish */ ufshcd_wait_for_doorbell_clr(hba, U64_MAX); ufshcd_set_auto_hibern8_timer(hba, delay_ms); up_write(&hba->lock); ufshcd_scsi_unblock_requests(hba); ufshcd_release_all(hba); pm_runtime_put_sync(hba->dev); } static void ufshcd_hibern8_exit_work(struct work_struct *work) { int ret; Loading Loading @@ -2106,18 +2124,31 @@ static ssize_t ufshcd_hibern8_on_idle_delay_store(struct device *dev, { struct ufs_hba *hba = dev_get_drvdata(dev); unsigned long flags, value; bool change = true; if (kstrtoul(buf, 0, &value)) return -EINVAL; spin_lock_irqsave(hba->host->host_lock, flags); if (hba->hibern8_on_idle.delay_ms == value) change = false; if (value >= hba->clk_gating.delay_ms_pwr_save || value >= hba->clk_gating.delay_ms_perf) { dev_err(hba->dev, "hibern8_on_idle_delay (%lu) can not be >= to clkgate_delay_ms_pwr_save (%lu) and clkgate_delay_ms_perf (%lu)\n", value, hba->clk_gating.delay_ms_pwr_save, hba->clk_gating.delay_ms_perf); spin_unlock_irqrestore(hba->host->host_lock, flags); return -EINVAL; } hba->hibern8_on_idle.delay_ms = value; spin_unlock_irqrestore(hba->host->host_lock, flags); /* Update auto hibern8 timer value if supported */ if (ufshcd_is_auto_hibern8_supported(hba) && if (change && ufshcd_is_auto_hibern8_supported(hba) && hba->hibern8_on_idle.is_enabled) ufshcd_set_auto_hibern8_timer(hba, __ufshcd_set_auto_hibern8_timer(hba, hba->hibern8_on_idle.delay_ms); return count; Loading Loading @@ -2148,7 +2179,7 @@ static ssize_t ufshcd_hibern8_on_idle_enable_store(struct device *dev, /* Update auto hibern8 timer value if supported */ if (ufshcd_is_auto_hibern8_supported(hba)) { ufshcd_set_auto_hibern8_timer(hba, __ufshcd_set_auto_hibern8_timer(hba, value ? hba->hibern8_on_idle.delay_ms : value); goto update; } Loading Loading
drivers/scsi/ufs/ufshcd.c +35 −4 Original line number Diff line number Diff line Loading @@ -381,6 +381,8 @@ static int ufshcd_disable_clocks(struct ufs_hba *hba, bool is_gating_context); static int ufshcd_disable_clocks_skip_ref_clk(struct ufs_hba *hba, bool is_gating_context); static void ufshcd_hold_all(struct ufs_hba *hba); static void ufshcd_release_all(struct ufs_hba *hba); static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); static inline void ufshcd_save_tstamp_of_last_dme_cmd(struct ufs_hba *hba); Loading Loading @@ -2055,6 +2057,22 @@ static void ufshcd_hibern8_enter_work(struct work_struct *work) return; } static void __ufshcd_set_auto_hibern8_timer(struct ufs_hba *hba, unsigned long delay_ms) { pm_runtime_get_sync(hba->dev); ufshcd_hold_all(hba); ufshcd_scsi_block_requests(hba); down_write(&hba->lock); /* wait for all the outstanding requests to finish */ ufshcd_wait_for_doorbell_clr(hba, U64_MAX); ufshcd_set_auto_hibern8_timer(hba, delay_ms); up_write(&hba->lock); ufshcd_scsi_unblock_requests(hba); ufshcd_release_all(hba); pm_runtime_put_sync(hba->dev); } static void ufshcd_hibern8_exit_work(struct work_struct *work) { int ret; Loading Loading @@ -2106,18 +2124,31 @@ static ssize_t ufshcd_hibern8_on_idle_delay_store(struct device *dev, { struct ufs_hba *hba = dev_get_drvdata(dev); unsigned long flags, value; bool change = true; if (kstrtoul(buf, 0, &value)) return -EINVAL; spin_lock_irqsave(hba->host->host_lock, flags); if (hba->hibern8_on_idle.delay_ms == value) change = false; if (value >= hba->clk_gating.delay_ms_pwr_save || value >= hba->clk_gating.delay_ms_perf) { dev_err(hba->dev, "hibern8_on_idle_delay (%lu) can not be >= to clkgate_delay_ms_pwr_save (%lu) and clkgate_delay_ms_perf (%lu)\n", value, hba->clk_gating.delay_ms_pwr_save, hba->clk_gating.delay_ms_perf); spin_unlock_irqrestore(hba->host->host_lock, flags); return -EINVAL; } hba->hibern8_on_idle.delay_ms = value; spin_unlock_irqrestore(hba->host->host_lock, flags); /* Update auto hibern8 timer value if supported */ if (ufshcd_is_auto_hibern8_supported(hba) && if (change && ufshcd_is_auto_hibern8_supported(hba) && hba->hibern8_on_idle.is_enabled) ufshcd_set_auto_hibern8_timer(hba, __ufshcd_set_auto_hibern8_timer(hba, hba->hibern8_on_idle.delay_ms); return count; Loading Loading @@ -2148,7 +2179,7 @@ static ssize_t ufshcd_hibern8_on_idle_enable_store(struct device *dev, /* Update auto hibern8 timer value if supported */ if (ufshcd_is_auto_hibern8_supported(hba)) { ufshcd_set_auto_hibern8_timer(hba, __ufshcd_set_auto_hibern8_timer(hba, value ? hba->hibern8_on_idle.delay_ms : value); goto update; } Loading