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

Commit a3efc800 authored by Subash Abhinov Kasiviswanathan's avatar Subash Abhinov Kasiviswanathan Committed by Gerrit - the friendly Code Review server
Browse files

soc: qcom: wda: Disable powersave work on deinitialization



A delayed powersave work may not be cancelled if it re-arms itself.
This could lead to invalid memory access after the work is destroyed.
This change prevents the powersave work from re-queueing during
deinitialization process.

Change-Id: Ib5257c05e10e2e12c64ec28043ad0664574ccf97
Acked-by: default avatarWeiyi Chen <weiyic@qti.qualcomm.com>
Signed-off-by: default avatarSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>
parent db92782e
Loading
Loading
Loading
Loading
+19 −15
Original line number Diff line number Diff line
@@ -737,6 +737,7 @@ EXPORT_SYMBOL(qmi_rmnet_qos_exit);
#ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE
static struct workqueue_struct  *rmnet_ps_wq;
static struct rmnet_powersave_work *rmnet_work;
static bool rmnet_work_quit;
static LIST_HEAD(ps_list);

struct rmnet_powersave_work {
@@ -819,9 +820,10 @@ EXPORT_SYMBOL(qmi_rmnet_set_powersave_mode);

static void qmi_rmnet_work_restart(void *port)
{
	if (!rmnet_ps_wq || !rmnet_work)
		return;
	rcu_read_lock();
	if (!rmnet_work_quit)
		queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, NO_DELAY);
	rcu_read_unlock();
}

static void qmi_rmnet_check_stats(struct work_struct *work)
@@ -848,13 +850,9 @@ static void qmi_rmnet_check_stats(struct work_struct *work)
		qmi->ps_ignore_grant = false;

		/* Register to get QMI DFC and DL marker */
		if (qmi_rmnet_set_powersave_mode(real_work->port, 0) < 0) {
			/* If this failed need to retry quickly */
			queue_delayed_work(rmnet_ps_wq,
					   &real_work->work, HZ / 50);
			return;
		if (qmi_rmnet_set_powersave_mode(real_work->port, 0) < 0)
			goto end;

		}
		qmi->ps_enabled = false;

		/* Do a query when coming out of powersave */
@@ -884,11 +882,9 @@ static void qmi_rmnet_check_stats(struct work_struct *work)
			goto end;

		/* Deregister to suppress QMI DFC and DL marker */
		if (qmi_rmnet_set_powersave_mode(real_work->port, 1) < 0) {
			queue_delayed_work(rmnet_ps_wq,
					   &real_work->work, PS_INTERVAL);
			return;
		}
		if (qmi_rmnet_set_powersave_mode(real_work->port, 1) < 0)
			goto end;

		qmi->ps_enabled = true;

		/* Ignore grant after going into powersave */
@@ -906,7 +902,10 @@ static void qmi_rmnet_check_stats(struct work_struct *work)
		return;
	}
end:
	rcu_read_lock();
	if (!rmnet_work_quit)
		queue_delayed_work(rmnet_ps_wq, &real_work->work, PS_INTERVAL);
	rcu_read_unlock();
}

static void qmi_rmnet_work_set_active(void *port, int status)
@@ -942,6 +941,7 @@ void qmi_rmnet_work_init(void *port)
	rmnet_get_packets(rmnet_work->port, &rmnet_work->old_rx_pkts,
			  &rmnet_work->old_tx_pkts);

	rmnet_work_quit = false;
	qmi_rmnet_work_set_active(rmnet_work->port, 1);
	queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, PS_INTERVAL);
}
@@ -964,6 +964,10 @@ void qmi_rmnet_work_exit(void *port)
{
	if (!rmnet_ps_wq || !rmnet_work)
		return;

	rmnet_work_quit = true;
	synchronize_rcu();

	cancel_delayed_work_sync(&rmnet_work->work);
	destroy_workqueue(rmnet_ps_wq);
	qmi_rmnet_work_set_active(port, 0);