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

Commit db0785db authored by Vijay Viswanath's avatar Vijay Viswanath
Browse files

scsi: ufs: Add clock ungating to a separate workqueue



UFS driver can receive a request during memory reclaim by kswapd.
So when ufs driver puts the ungate work in queue, and if there are no
idle workers, kthreadd is invoked to create a new kworker. Since
kswapd task holds a mutex which kthreadd also needs, this can cause
a deadlock situation. So ungate work must be done in a separate
work queue with WQ__RECLAIM flag enabled.Such a workqueue will have
a rescue thread which will be called when the above deadlock
condition is possible.

Change-Id: I91c5bff812be403addc98fbb8c620e67cf28f5d9
Signed-off-by: default avatarVijay Viswanath <vviswana@codeaurora.org>
parent 55e8426a
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -1344,7 +1344,8 @@ start:
		hba->clk_gating.state = REQ_CLKS_ON;
		trace_ufshcd_clk_gating(dev_name(hba->dev),
			hba->clk_gating.state);
		schedule_work(&hba->clk_gating.ungate_work);
		queue_work(hba->clk_gating.ungating_workq,
				&hba->clk_gating.ungate_work);
		/*
		 * fall through to check if we should wait for this
		 * work to be done or not.
@@ -1617,6 +1618,7 @@ static enum hrtimer_restart ufshcd_clkgate_hrtimer_handler(
static void ufshcd_init_clk_gating(struct ufs_hba *hba)
{
	struct ufs_clk_gating *gating = &hba->clk_gating;
	char wq_name[sizeof("ufs_clk_ungating_00")];

	hba->clk_gating.state = CLKS_ON;

@@ -1645,6 +1647,10 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
	hrtimer_init(&gating->gate_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	gating->gate_hrtimer.function = ufshcd_clkgate_hrtimer_handler;

	snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_ungating_%d",
			hba->host->host_no);
	hba->clk_gating.ungating_workq = create_singlethread_workqueue(wq_name);

	gating->is_enabled = true;

	gating->delay_ms_pwr_save = UFSHCD_CLK_GATING_DELAY_MS_PWR_SAVE;
@@ -1707,6 +1713,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
	device_remove_file(hba->dev, &hba->clk_gating.enable_attr);
	ufshcd_cancel_gate_work(hba);
	cancel_work_sync(&hba->clk_gating.ungate_work);
	destroy_workqueue(hba->clk_gating.ungating_workq);
}

static void ufshcd_set_auto_hibern8_timer(struct ufs_hba *hba, u32 delay)
+1 −0
Original line number Diff line number Diff line
@@ -431,6 +431,7 @@ struct ufs_clk_gating {
	struct device_attribute enable_attr;
	bool is_enabled;
	int active_reqs;
	struct workqueue_struct *ungating_workq;
};

/* Hibern8 state  */