Explorar el Código

qcacmn: Fix out of sync OOM work counter

Currently OOM work counter is incremented when schedule_work
is called and counter is decremented when work is scheduled.
But there is possibility of OOM schedule_work is getting called
from tasklet context and worker thread context and resulting
only one time work execution but active work counter being
incremented twice. This scenario may result in OOM work going
out of sync and preventing suspend usecase.

Avoid this by incrementing the OOM active work count only when
work is getting added to global work queue and corresponding count
will be decremented when work handler gets executed.

Change-Id: Ie02d5b9c821327337a1b822c81c51878af522832
CRs-Fixed: 3787873
Karthik Kantamneni hace 1 año
padre
commit
332fc3b9eb
Se han modificado 5 ficheros con 22 adiciones y 18 borrados
  1. 3 1
      hif/src/ce/ce_main.c
  2. 4 3
      hif/src/hif_main.c
  3. 7 6
      qdf/inc/qdf_defer.h
  4. 5 5
      qdf/linux/src/i_qdf_defer.h
  5. 3 3
      qdf/linux/src/qdf_defer.c

+ 3 - 1
hif/src/ce/ce_main.c

@@ -3865,7 +3865,9 @@ static void hif_post_recv_buffers_failure(struct HIF_CE_pipe_info *pipe_info,
 	    (ce_srng_based(scn) &&
 	     bufs_needed_tmp == CE_state->dest_ring->nentries - 2)) {
 		qdf_atomic_inc(&scn->active_oom_work_cnt);
-		qdf_sched_work(scn->qdf_dev, &CE_state->oom_allocation_work);
+		if (!qdf_sched_work(scn->qdf_dev,
+				    &CE_state->oom_allocation_work))
+			qdf_atomic_dec(&scn->active_oom_work_cnt);
 	}
 
 }

+ 4 - 3
hif/src/hif_main.c

@@ -1437,11 +1437,12 @@ QDF_STATUS hif_try_complete_tasks(struct hif_softc *scn)
 			 * There is chance of OOM thread getting scheduled
 			 * continuously or execution get delayed during low
 			 * memory state. So avoid panic and prevent suspend
-			 * only if OOM thread is unable to complete pending
+			 * if OOM thread is unable to complete pending
 			 * work.
 			 */
-			if ((!tasklet) && (!grp_tasklet) && (!work) && oom_work)
-				hif_err("OOM thread is still pending cannot complete the work");
+			if (oom_work)
+				hif_err("OOM thread is still pending %d tasklets %d grp tasklets %d work %d",
+					oom_work, tasklet, grp_tasklet, work);
 			else
 				QDF_DEBUG_PANIC("Complete tasks takes more than %u ms: tasklets %d grp tasklets %d work %d oom_work %d",
 						HIF_TASK_DRAIN_WAIT_CNT * 10,

+ 7 - 6
qdf/inc/qdf_defer.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -166,9 +166,9 @@ QDF_STATUS qdf_create_work(qdf_handle_t hdl, qdf_work_t  *work,
  * @hdl: OS handle
  * @work: pointer to work
  *
- * Return: none
+ * Return: false if work was already on a queue, true otherwise
  */
-void qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work);
+bool qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work);
 
 /**
  * qdf_queue_work - Queue the work/task
@@ -379,11 +379,12 @@ static inline void qdf_destroy_workqueue(qdf_handle_t hdl,
  * qdf_sched_work - Schedule a deferred task on non-interrupt context
  * @hdl: OS handle
  * @work: pointer to work
- * Return: none
+ *
+ * Return: false if work was already on a queue, true otherwise
  */
-static inline void qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work)
+static inline bool qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work)
 {
-	__qdf_sched_work(work);
+	return __qdf_sched_work(work);
 }
 
 /**

+ 5 - 5
qdf/linux/src/i_qdf_defer.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -116,12 +116,12 @@ __qdf_queue_work(__qdf_workqueue_t *wqueue, __qdf_work_t *work)
 /**
  * __qdf_sched_work - Schedule a deferred task on non-interrupt context
  * @work: pointer to work
- * Return: none
+ *
+ * Return: false if work was already on a global queue, true otherwise
  */
-static inline QDF_STATUS __qdf_sched_work(__qdf_work_t *work)
+static inline bool __qdf_sched_work(__qdf_work_t *work)
 {
-	schedule_work(&work->work);
-	return QDF_STATUS_SUCCESS;
+	return schedule_work(&work->work);
 }
 
 /**

+ 3 - 3
qdf/linux/src/qdf_defer.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2014-2019,2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -138,9 +138,9 @@ QDF_STATUS qdf_create_work(qdf_handle_t hdl, qdf_work_t  *work,
 
 qdf_export_symbol(qdf_create_work);
 
-void qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work)
+bool qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work)
 {
-	__qdf_sched_work(work);
+	return __qdf_sched_work(work);
 }
 
 qdf_export_symbol(qdf_sched_work);