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

Commit f8f1e10c 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: I6b50e32a12c0279d12e82b278af9b2c2da82ff54
Signed-off-by: default avatarVijay Viswanath <vviswana@codeaurora.org>
parent e1420870
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -1273,7 +1273,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.
@@ -1522,6 +1523,7 @@ out:
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;

@@ -1531,6 +1533,10 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba)
	INIT_DELAYED_WORK(&gating->gate_work, ufshcd_gate_work);
	INIT_WORK(&gating->ungate_work, ufshcd_ungate_work);

	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;

	/*
@@ -1607,6 +1613,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
	device_remove_file(hba->dev, &hba->clk_gating.enable_attr);
	cancel_work_sync(&hba->clk_gating.ungate_work);
	cancel_delayed_work_sync(&hba->clk_gating.gate_work);
	destroy_workqueue(hba->clk_gating.ungating_workq);
}

/**
+1 −0
Original line number Diff line number Diff line
@@ -421,6 +421,7 @@ struct ufs_clk_gating {
	struct device_attribute enable_attr;
	bool is_enabled;
	int active_reqs;
	struct workqueue_struct *ungating_workq;
};

/* Hibern8 state  */