Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a51b7f60 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "scsi: ufs: fix deadlock between clock scaling and shutdown"

parents a532239b 3b284d45
Loading
Loading
Loading
Loading
+33 −10
Original line number Diff line number Diff line
@@ -8904,6 +8904,35 @@ static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba)
	ufshcd_add_spm_lvl_sysfs_nodes(hba);
}

static void ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
{
	bool suspend = false;
	unsigned long flags;

	spin_lock_irqsave(hba->host->host_lock, flags);
	if (hba->clk_scaling.is_allowed) {
		hba->clk_scaling.is_allowed = false;
		suspend = true;
	}
	spin_unlock_irqrestore(hba->host->host_lock, flags);

	/**
	 * Scaling may be scheduled before, hence make sure it
	 * doesn't race with shutdown
	 */
	if (ufshcd_is_clkscaling_supported(hba)) {
		device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
		cancel_work_sync(&hba->clk_scaling.suspend_work);
		cancel_work_sync(&hba->clk_scaling.resume_work);
		if (suspend)
			ufshcd_suspend_clkscaling(hba);
	}

	/* Unregister so that devfreq_monitor can't race with shutdown */
	if (hba->devfreq)
		devfreq_remove_device(hba->devfreq);
}

/**
 * ufshcd_shutdown - shutdown routine
 * @hba: per adapter instance
@@ -8921,16 +8950,14 @@ int ufshcd_shutdown(struct ufs_hba *hba)

	pm_runtime_get_sync(hba->dev);
	ufshcd_hold_all(hba);
	ufshcd_mark_shutdown_ongoing(hba);
	ufshcd_shutdown_clkscaling(hba);
	/**
	 * (1) Set state to shutting down
	 * (2) Acquire the lock to stop any more requests
	 * (3) Suspend clock scaling
	 * (4) Wait for all issued requests to complete
	 * (1) Acquire the lock to stop any more requests
	 * (2) Wait for all issued requests to complete
	 */
	ufshcd_mark_shutdown_ongoing(hba);
	ufshcd_get_write_lock(hba);
	ufshcd_scsi_block_requests(hba);
	ufshcd_suspend_clkscaling(hba);
	ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX);
	if (ret)
		dev_err(hba->dev, "%s: waiting for DB clear: failed: %d\n",
@@ -9373,10 +9400,6 @@ static void ufshcd_clk_scaling_resume_work(struct work_struct *work)
					   clk_scaling.resume_work);
	unsigned long irq_flags;

	/* Let's not resume scaling if shutdown is ongoing */
	if (ufshcd_is_shutdown_ongoing(hba))
		return;

	spin_lock_irqsave(hba->host->host_lock, irq_flags);
	if (!hba->clk_scaling.is_suspended) {
		spin_unlock_irqrestore(hba->host->host_lock, irq_flags);