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

Commit 74995369 authored by Isaac J. Manjarres's avatar Isaac J. Manjarres
Browse files

soc: qcom: service-notifier: Use ordered workqueue for PDR



Currently, a global multi-threaded workqueue is used for
handling acks sent to the root PD for a subsystem during PDR.

Since the new EARLY_PD_DOWN indication does not require an ack,
the remote PD can continue with the PD teardown sequence,
and send a PD_DOWN indication, before we have handled the
EARLY_DOWN indication. Since the workqueue is multi-threaded,
the worker threads handling both of these indications can race
against each other, resulting in non-deterministic behavior with
respect to the order in which the EARLY_PD_DOWN and PD_DOWN
indications are processed.

Use an ordered workqueue to ensure that indications are
processed in the order in which they arrive, and migrate
from using a global workqueue for handling acks, to
per-service workqueues, to maintain parallelism between PDRs
for two distinct PDs.

Change-Id: I4e95524a927bbccc079eaf6481a254fda808b85c
Signed-off-by: default avatarIsaac J. Manjarres <isaacm@codeaurora.org>
parent 8b16ad0e
Loading
Loading
Loading
Loading
+10 −13
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ struct qmi_client_info {
	struct work_struct new_server;
	struct work_struct del_server;
	struct workqueue_struct *svc_event_wq;
	struct workqueue_struct *ind_ack_wq;
	struct qmi_handle clnt_handle;
	struct notifier_block notifier;
	void *ssr_handle;
@@ -107,7 +108,6 @@ struct qmi_client_info {
static LIST_HEAD(qmi_client_list);
static DEFINE_MUTEX(qmi_list_lock);
static DEFINE_MUTEX(notif_add_lock);
static struct workqueue_struct *pdr_wq;

static struct service_notif_info *_find_service_info(const char *service_path)
{
@@ -228,7 +228,7 @@ static void root_service_service_ind_cb(struct qmi_handle *qmi,
	snprintf(qmi_data->ind_msg.service_path,
		ARRAY_SIZE(qmi_data->ind_msg.service_path), "%s",
		ind_msg.service_name);
	queue_work(pdr_wq, &qmi_data->ind_ack);
	queue_work(qmi_data->ind_ack_wq, &qmi_data->ind_ack);
}

static int send_notif_listener_msg_req(struct service_notif_info *service_notif,
@@ -506,6 +506,12 @@ static void *add_service_notif(const char *service_path, int instance_id,
		rc = -ENOMEM;
		goto exit;
	}
	qmi_data->ind_ack_wq = alloc_ordered_workqueue("%s_pdr_wq", WQ_HIGHPRI,
						       subsys);
	if (!qmi_data->ind_ack_wq) {
		rc = -ENOMEM;
		goto exit;
	}

	INIT_WORK(&qmi_data->ind_ack, send_ind_ack);
	INIT_WORK(&qmi_data->new_server, new_server_work);
@@ -554,6 +560,8 @@ static void *add_service_notif(const char *service_path, int instance_id,

	return service_notif;
exit:
	if (qmi_data->ind_ack_wq)
		destroy_workqueue(qmi_data->ind_ack_wq);
	if (qmi_data->svc_event_wq)
		destroy_workqueue(qmi_data->svc_event_wq);
	kfree(qmi_data);
@@ -708,14 +716,3 @@ int service_notif_unregister_notifier(void *service_notif_handle,
				&service_notif->service_notif_rcvr_list, nb);
}
EXPORT_SYMBOL(service_notif_unregister_notifier);

static int __init service_notif_init(void)
{

	pdr_wq = alloc_workqueue("pdr_wq", WQ_CPU_INTENSIVE | WQ_UNBOUND |
				 WQ_HIGHPRI, 0);
	BUG_ON(!pdr_wq);

	return 0;
}
arch_initcall(service_notif_init);