diff --git a/drivers/scsi/ufs/debugfs.c b/drivers/scsi/ufs/debugfs.c index 50e23d08407f..6b00aab43a99 100644 --- a/drivers/scsi/ufs/debugfs.c +++ b/drivers/scsi/ufs/debugfs.c @@ -462,7 +462,7 @@ static int ufsdbg_host_regs_show(struct seq_file *file, void *data) ufsdbg_pr_buf_to_std(file, hba->mmio_base, UFSHCI_REG_SPACE_SIZE, "host regs"); pm_runtime_put_sync(hba->dev); - ufshcd_release(hba); + ufshcd_release(hba, false); return 0; } diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 51b9a1c4af1c..67351200c939 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1148,7 +1148,7 @@ out: } /* host lock must be held before calling this variant */ -static void __ufshcd_release(struct ufs_hba *hba) +static void __ufshcd_release(struct ufs_hba *hba, bool no_sched) { if (!ufshcd_is_clkgating_allowed(hba)) return; @@ -1159,7 +1159,7 @@ static void __ufshcd_release(struct ufs_hba *hba) || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL || hba->lrb_in_use || hba->outstanding_tasks || hba->active_uic_cmd || hba->uic_async_done - || ufshcd_eh_in_progress(hba)) + || ufshcd_eh_in_progress(hba) || no_sched) return; hba->clk_gating.state = REQ_CLKS_OFF; @@ -1170,12 +1170,12 @@ static void __ufshcd_release(struct ufs_hba *hba) msecs_to_jiffies(hba->clk_gating.delay_ms)); } -void ufshcd_release(struct ufs_hba *hba) +void ufshcd_release(struct ufs_hba *hba, bool no_sched) { unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); - __ufshcd_release(hba); + __ufshcd_release(hba, no_sched); spin_unlock_irqrestore(hba->host->host_lock, flags); } EXPORT_SYMBOL_GPL(ufshcd_release); @@ -1226,7 +1226,7 @@ static ssize_t ufshcd_clkgate_enable_store(struct device *dev, goto out; if (value) { - ufshcd_release(hba); + ufshcd_release(hba, false); } else { spin_lock_irqsave(hba->host->host_lock, flags); hba->clk_gating.active_reqs++; @@ -1353,7 +1353,7 @@ out: } /* host lock must be held before calling this variant */ -static void __ufshcd_hibern8_release(struct ufs_hba *hba) +static void __ufshcd_hibern8_release(struct ufs_hba *hba, bool no_sched) { unsigned long delay_in_jiffies; @@ -1368,7 +1368,7 @@ static void __ufshcd_hibern8_release(struct ufs_hba *hba) || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL || hba->lrb_in_use || hba->outstanding_tasks || hba->active_uic_cmd || hba->uic_async_done - || ufshcd_eh_in_progress(hba)) + || ufshcd_eh_in_progress(hba) || no_sched) return; hba->hibern8_on_idle.state = REQ_HIBERN8_ENTER; @@ -1391,12 +1391,12 @@ static void __ufshcd_hibern8_release(struct ufs_hba *hba) delay_in_jiffies); } -void ufshcd_hibern8_release(struct ufs_hba *hba) +void ufshcd_hibern8_release(struct ufs_hba *hba, bool no_sched) { unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); - __ufshcd_hibern8_release(hba); + __ufshcd_hibern8_release(hba, no_sched); spin_unlock_irqrestore(hba->host->host_lock, flags); } @@ -1477,7 +1477,7 @@ static void ufshcd_hibern8_exit_work(struct work_struct *work) if (ufshcd_is_link_hibern8(hba)) { ufshcd_hold(hba, false); ret = ufshcd_uic_hibern8_exit(hba); - ufshcd_release(hba); + ufshcd_release(hba, false); if (!ret) { spin_lock_irqsave(hba->host->host_lock, flags); ufshcd_set_link_active(hba); @@ -1662,24 +1662,24 @@ static int ufshcd_pm_qos_hold(struct ufs_hba *hba, bool async) } /* Host lock is assumed to be held by caller */ -static void __ufshcd_pm_qos_release(struct ufs_hba *hba) +static void __ufshcd_pm_qos_release(struct ufs_hba *hba, bool no_sched) { if (!hba->pm_qos.cpu_dma_latency_us) return; - if (--hba->pm_qos.active_reqs) + if (--hba->pm_qos.active_reqs || no_sched) return; hba->pm_qos.state = PM_QOS_REQ_UNVOTE; schedule_work(&hba->pm_qos.unvote_work); } -static void ufshcd_pm_qos_release(struct ufs_hba *hba) +static void ufshcd_pm_qos_release(struct ufs_hba *hba, bool no_sched) { unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); - __ufshcd_pm_qos_release(hba); + __ufshcd_pm_qos_release(hba, no_sched); spin_unlock_irqrestore(hba->host->host_lock, flags); } @@ -1785,9 +1785,9 @@ static void ufshcd_hold_all(struct ufs_hba *hba) static void ufshcd_release_all(struct ufs_hba *hba) { - ufshcd_hibern8_release(hba); - ufshcd_pm_qos_release(hba); - ufshcd_release(hba); + ufshcd_hibern8_release(hba, false); + ufshcd_pm_qos_release(hba, false); + ufshcd_release(hba, false); } /* Must be called with host lock acquired */ @@ -2412,7 +2412,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (err) { err = SCSI_MLQUEUE_HOST_BUSY; clear_bit_unlock(tag, &hba->lrb_in_use); - ufshcd_release(hba); + ufshcd_release(hba, true); goto out; } @@ -2420,8 +2420,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (err) { clear_bit_unlock(tag, &hba->lrb_in_use); err = SCSI_MLQUEUE_HOST_BUSY; - ufshcd_pm_qos_release(hba); - ufshcd_release(hba); + ufshcd_pm_qos_release(hba, true); + ufshcd_release(hba, true); goto out; } WARN_ON(hba->hibern8_on_idle.state != HIBERN8_EXITED); @@ -4707,9 +4707,9 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, clear_bit_unlock(index, &hba->lrb_in_use); /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); - __ufshcd_release(hba); - __ufshcd_pm_qos_release(hba); - __ufshcd_hibern8_release(hba); + __ufshcd_release(hba, false); + __ufshcd_pm_qos_release(hba, false); + __ufshcd_hibern8_release(hba, false); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE) { if (hba->dev_cmd.complete) { ufshcd_cond_add_cmd_trace(hba, index, @@ -8076,7 +8076,7 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev, } hba->clk_scaling.is_allowed = value; - ufshcd_release(hba); + ufshcd_release(hba, false); pm_runtime_put_sync(hba->dev); out: return count; diff --git a/include/linux/scsi/ufs/ufshcd.h b/include/linux/scsi/ufs/ufshcd.h index fd3ba04771c8..c29027ea9ee7 100644 --- a/include/linux/scsi/ufs/ufshcd.h +++ b/include/linux/scsi/ufs/ufshcd.h @@ -972,7 +972,7 @@ int ufshcd_query_descriptor(struct ufs_hba *hba, enum query_opcode opcode, enum desc_idn idn, u8 index, u8 selector, u8 *desc_buf, int *buf_len); int ufshcd_hold(struct ufs_hba *hba, bool async); -void ufshcd_release(struct ufs_hba *hba); +void ufshcd_release(struct ufs_hba *hba, bool no_sched); int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us); int ufshcd_change_power_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *pwr_mode);