Răsfoiți Sursa

qcacmn: Wait for all the txrx tasks completion after rings drain

After draining txrx rings there is possibility of reg work
getting triggered to update rings write pointer, this
might cause the reg work to execute later after suspend
complete and cause allow suspend and prevent suspend count
to go out of sync. So make sure all the txrx dependent
tasks are complete after drain.

Change-Id: I30b0696cef4499cc1e92b4556488b58037520184
CRs-Fixed: 3717885
Karthik Kantamneni 1 an în urmă
părinte
comite
7e541922fe
6 a modificat fișierele cu 54 adăugiri și 10 ștergeri
  1. 6 4
      dp/inc/cdp_txrx_cmn.h
  2. 1 1
      dp/inc/cdp_txrx_ops.h
  3. 4 3
      dp/wifi3.0/dp_rings.h
  4. 10 1
      dp/wifi3.0/dp_rings_main.c
  5. 9 1
      hif/inc/hif.h
  6. 24 0
      hif/src/hif_main.c

+ 6 - 4
dp/inc/cdp_txrx_cmn.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-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
@@ -3025,19 +3025,21 @@ cdp_wds_ext_set_bit(ol_txrx_soc_handle soc, uint8_t *mac)
  * cdp_drain_txrx() - drain TX/RX SRNGs
  * @soc: opaque soc handle
  * @rx_only: drain only RX rings
+ *
+ * Return: QDF_STATUS
  */
-static inline void
+static inline QDF_STATUS
 cdp_drain_txrx(ol_txrx_soc_handle soc, uint8_t rx_only)
 {
 	if (!soc || !soc->ops) {
 		dp_cdp_debug("Invalid Instance");
 		QDF_BUG(0);
-		return;
+		return QDF_STATUS_E_FAULT;
 	}
 
 	if (!soc->ops->cmn_drv_ops ||
 	    !soc->ops->cmn_drv_ops->txrx_drain)
-		return;
+		return QDF_STATUS_E_FAULT;
 
 	return soc->ops->cmn_drv_ops->txrx_drain(soc, rx_only);
 }

+ 1 - 1
dp/inc/cdp_txrx_ops.h

@@ -717,7 +717,7 @@ struct cdp_cmn_ops {
 	QDF_STATUS (*set_wds_ext_peer_bit)(ol_txrx_soc_handle soc,
 					   uint8_t *mac);
 #endif /* QCA_SUPPORT_WDS_EXTENDED */
-	void (*txrx_drain)(ol_txrx_soc_handle soc, uint8_t rx_only);
+	QDF_STATUS (*txrx_drain)(ol_txrx_soc_handle soc, uint8_t rx_only);
 	int (*get_free_desc_poolsize)(struct cdp_soc_t *soc);
 #ifdef WLAN_SYSFS_DP_STATS
 	QDF_STATUS (*txrx_sysfs_fill_stats)(ol_txrx_soc_handle soc,

+ 4 - 3
dp/wifi3.0/dp_rings.h

@@ -570,7 +570,7 @@ dp_dump_wbm_idle_hptp(struct dp_soc *soc, struct dp_pdev *pdev);
 bool dp_display_srng_info(struct cdp_soc_t *soc_hdl);
 
 #if defined(DP_POWER_SAVE) || defined(FEATURE_RUNTIME_PM)
-void dp_drain_txrx(struct cdp_soc_t *soc_handle, uint8_t rx_only);
+QDF_STATUS dp_drain_txrx(struct cdp_soc_t *soc_handle, uint8_t rx_only);
 
 /*
  * dp_update_ring_hptp() - update dp rings hptp
@@ -818,9 +818,10 @@ static inline bool dp_display_srng_info(struct cdp_soc_t *soc_hdl)
 }
 
 #if defined(DP_POWER_SAVE) || defined(FEATURE_RUNTIME_PM)
-static inline void dp_drain_txrx(struct cdp_soc_t *soc_handle,
-				 uint8_t rx_only)
+static inline QDF_STATUS dp_drain_txrx(struct cdp_soc_t *soc_handle,
+				       uint8_t rx_only)
 {
+	return QDF_STATUS_SUCCESS;
 }
 #endif
 #endif /* WLAN_SOFTUMAC_SUPPORT */

+ 10 - 1
dp/wifi3.0/dp_rings_main.c

@@ -2957,7 +2957,7 @@ QDF_STATUS dp_set_vdev_pcp_tid_map_wifi3(struct cdp_soc_t *soc_hdl,
 }
 
 #if defined(FEATURE_RUNTIME_PM) || defined(DP_POWER_SAVE)
-void dp_drain_txrx(struct cdp_soc_t *soc_handle, uint8_t rx_only)
+QDF_STATUS dp_drain_txrx(struct cdp_soc_t *soc_handle, uint8_t rx_only)
 {
 	struct dp_soc *soc = (struct dp_soc *)soc_handle;
 	uint32_t cur_tx_limit, cur_rx_limit;
@@ -2965,6 +2965,7 @@ void dp_drain_txrx(struct cdp_soc_t *soc_handle, uint8_t rx_only)
 	uint32_t val;
 	int i;
 	int cpu = dp_srng_get_cpu();
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
 
 	cur_tx_limit = soc->wlan_cfg_ctx->tx_comp_loop_pkt_limit;
 	cur_rx_limit = soc->wlan_cfg_ctx->rx_reap_loop_pkt_limit;
@@ -2985,11 +2986,19 @@ void dp_drain_txrx(struct cdp_soc_t *soc_handle, uint8_t rx_only)
 
 	dp_update_soft_irq_limits(soc, cur_tx_limit, cur_rx_limit);
 
+	status = hif_try_complete_dp_tasks(soc->hif_handle);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("Failed to complete DP tasks");
+		return status;
+	}
+
 	/* Do a dummy read at offset 0; this will ensure all
 	 * pendings writes(HP/TP) are flushed before read returns.
 	 */
 	val = HAL_REG_READ((struct hal_soc *)soc->hal_soc, 0);
 	dp_debug("Register value at offset 0: %u", val);
+
+	return status;
 }
 #endif
 

+ 9 - 1
hif/inc/hif.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-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
@@ -2380,6 +2380,14 @@ hif_softc_to_hif_opaque_softc(struct hif_softc *hif_handle)
 	return (struct hif_opaque_softc *)hif_handle;
 }
 
+/**
+ * hif_try_complete_dp_tasks() - Try to complete all DP related tasks
+ * @hif_ctx: opaque softc handle
+ *
+ * Return: QDF_STATUS of operation
+ */
+QDF_STATUS hif_try_complete_dp_tasks(struct hif_opaque_softc *hif_ctx);
+
 #if defined(HIF_IPCI) && defined(FEATURE_HAL_DELAYED_REG_WRITE)
 QDF_STATUS hif_try_prevent_ep_vote_access(struct hif_opaque_softc *hif_ctx);
 void hif_set_ep_intermediate_vote_access(struct hif_opaque_softc *hif_ctx);

+ 24 - 0
hif/src/hif_main.c

@@ -1457,6 +1457,30 @@ QDF_STATUS hif_try_complete_tasks(struct hif_softc *scn)
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS hif_try_complete_dp_tasks(struct hif_opaque_softc *hif_ctx)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+	uint32_t task_drain_wait_cnt = 0;
+	int grp_tasklet = 0, work = 0;
+
+	while ((grp_tasklet = hif_get_num_active_grp_tasklets(scn)) ||
+	       (work = hif_get_num_pending_work(scn))) {
+		if (++task_drain_wait_cnt > HIF_TASK_DRAIN_WAIT_CNT) {
+			hif_err("pending grp tasklets %d work %d",
+				grp_tasklet, work);
+			QDF_DEBUG_PANIC("Complete tasks takes more than %u ms: grp tasklets %d work %d",
+					HIF_TASK_DRAIN_WAIT_CNT * 10,
+					grp_tasklet, work);
+			return QDF_STATUS_E_FAULT;
+		}
+		hif_info("waiting for grp tasklets %d work %d",
+			 grp_tasklet, work);
+		msleep(10);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 #ifdef HIF_HAL_REG_ACCESS_SUPPORT
 void hif_reg_window_write(struct hif_softc *scn, uint32_t offset,
 			  uint32_t value)