Jelajahi Sumber

qcacmn: Move delayed-reg-work active_work_cnt decrement

Currently, we decrement active_work_cnt in a while loop in delayed
register worker and later on make a "allow_l1" call to enable L1ss.
The bus suspend routine depends on the value of active_work_cnt to
determine if any register writes are pending. In case there are, bus
suspend is rejected.
As a result its possible that when bus suspend happens, the
delayed worker while processing the last remaining enqueued
write,  makes the active_work_cnt to 0. This will allow the bus suspend
routine to continue to disable the bus, even before the
delayed-reg-worker has called allow_l1 and run to completion. This may
lead to a NOC error while calling "allow_l1" API from
delayed-reg-worker.

Hence, move the decrement of active_work_cnt to the very end in
hal_reg_write_work function.

Change-Id: Iec602f97c953df1c6a018310fd02ab458547ce3a
CRs-fixed: 2813733
Mohit Khanna 4 tahun lalu
induk
melakukan
a939d20dbf
2 mengubah file dengan 16 tambahan dan 5 penghapusan
  1. 0 2
      dp/wifi3.0/dp_main.c
  2. 16 3
      hal/wifi3.0/hal_srng.c

+ 0 - 2
dp/wifi3.0/dp_main.c

@@ -11526,8 +11526,6 @@ static QDF_STATUS dp_bus_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 		dp_service_mon_rings(soc, DP_MON_REAP_BUDGET);
 	}
 
-	hal_flush_reg_write_work(soc->hal_soc);
-
 	return QDF_STATUS_SUCCESS;
 }
 

+ 16 - 3
hal/wifi3.0/hal_srng.c

@@ -547,6 +547,7 @@ static void hal_reg_write_work(void *arg)
 	uint64_t delta_us;
 	uint8_t ring_id;
 	uint32_t *addr;
+	uint32_t num_processed = 0;
 
 	q_elem = &hal->reg_write_queue[(hal->read_idx)];
 	q_elem->work_scheduled_time = qdf_get_log_timestamp();
@@ -584,20 +585,30 @@ static void hal_reg_write_work(void *arg)
 		hal_verbose_debug("read_idx %u srng 0x%x, addr 0x%pK dequeue_val %u sched delay %llu us",
 				  hal->read_idx, ring_id, addr, write_val, delta_us);
 
-		qdf_atomic_dec(&hal->active_work_cnt);
+		num_processed++;
 		hal->read_idx = (hal->read_idx + 1) &
 					(HAL_REG_WRITE_QUEUE_LEN - 1);
 		q_elem = &hal->reg_write_queue[(hal->read_idx)];
 	}
 
 	hif_allow_link_low_power_states(hal->hif_handle);
+	/*
+	 * Decrement active_work_cnt by the number of elements dequeued after
+	 * hif_allow_link_low_power_states.
+	 * This makes sure that hif_try_complete_tasks will wait till we make
+	 * the bus access in hif_allow_link_low_power_states. This will avoid
+	 * race condition between delayed register worker and bus suspend
+	 * (system suspend or runtime suspend).
+	 *
+	 * The following decrement should be done at the end!
+	 */
+	qdf_atomic_sub(num_processed, &hal->active_work_cnt);
 }
 
 static void __hal_flush_reg_write_work(struct hal_soc *hal)
 {
 	qdf_cancel_work(&hal->reg_write_work);
-	qdf_flush_work(&hal->reg_write_work);
-	qdf_flush_workqueue(0, hal->reg_write_wq);
+
 }
 
 void hal_flush_reg_write_work(hal_soc_handle_t hal_handle)
@@ -738,6 +749,8 @@ static QDF_STATUS hal_delayed_reg_write_init(struct hal_soc *hal)
 static void hal_delayed_reg_write_deinit(struct hal_soc *hal)
 {
 	__hal_flush_reg_write_work(hal);
+
+	qdf_flush_workqueue(0, hal->reg_write_wq);
 	qdf_destroy_workqueue(0, hal->reg_write_wq);
 	qdf_mem_free(hal->reg_write_queue);
 }