浏览代码

qcacmn: Fix long ping delay after enable RTPM

Issue1: Driver RTPM state is ON/NONE, Kernel state is RESUMING.
cdp_runtime_resume is already complete,
hif_pm_runtime_get return -E_INPROGRESS,
dp_tx_hw_enqueue will set the flush event,
but cdp_runtime_resume is already done,
this flush event will be handled only on next pkt tx.

Issue2: Driver RTPM state: Resuming
hif_pm_runtime_get returns -EBUSY,
dp_tx_hw_enqueue is interrupted by any IRQ,
cdp_runtime_resume is completed,
dp_tx_hw_enqueue will set the flush event,
This flush event will be handled only on next pkt tx.

Fix:
Introduce a link_state_up atomic variable in hif to track the link state
change by pld_cb.
Set atomic variable link_state_up=1 in pmo_core_psoc_bus_runtime_resume
just after pld_cb. pld_cb brings the PCIe bus out of suspend state.
Set atomic variable link_state_up=0 in pmo_core_psoc_bus_runtime_suspend
just before pld_cb. pld_cb puts the PCIe bus into suspend state.

Introduce dp_runtime_get and dp_runtime_put.
dp_runtime_get get refcount with increment of an atomic variable.
dp_runtime_put return refcount with decrement of  this atomic variable.

If hif_pm_runtime_get returns -EBUSY or -EINPROGRESS,
take the dp runtime refcount using dp_runtime_get,
check if the link state is up, write TX ring HP,
return the dp runtime refcount using dp_runtime_put.

cdp_runtime_suspend should reject the suspend, if dp_runtime_get is non
zero.
cdp_runtime_resume should wait until dp_runtime_get becomes zero or time
out, then flush pending tx for runtime suspend.

Change-Id: I5b97d50cba710082f117f3845f7830712b86cda7
CRs-Fixed: 2844888
Jianmin Zhu 4 年之前
父节点
当前提交
6ef2047d56
共有 8 个文件被更改,包括 213 次插入11 次删除
  1. 69 0
      dp/wifi3.0/dp_internal.h
  2. 22 1
      dp/wifi3.0/dp_main.c
  3. 66 10
      dp/wifi3.0/dp_tx.c
  4. 4 0
      dp/wifi3.0/dp_types.h
  5. 31 0
      hif/inc/hif.h
  6. 3 0
      hif/src/hif_main.c
  7. 4 0
      hif/src/hif_main.h
  8. 14 0
      hif/src/hif_runtime_pm.c

+ 69 - 0
dp/wifi3.0/dp_internal.h

@@ -2633,4 +2633,73 @@ void dp_desc_multi_pages_mem_free(struct dp_soc *soc,
 }
 #endif
 
+#ifdef FEATURE_RUNTIME_PM
+/**
+ * dp_runtime_get() - Get dp runtime refcount
+ * @soc: Datapath soc handle
+ *
+ * Get dp runtime refcount by increment of an atomic variable, which can block
+ * dp runtime resume to wait to flush pending tx by runtime suspend.
+ *
+ * Return: Current refcount
+ */
+static inline int32_t dp_runtime_get(struct dp_soc *soc)
+{
+	return qdf_atomic_inc_return(&soc->dp_runtime_refcount);
+}
+
+/**
+ * dp_runtime_put() - Return dp runtime refcount
+ * @soc: Datapath soc handle
+ *
+ * Return dp runtime refcount by decrement of an atomic variable, allow dp
+ * runtime resume finish.
+ *
+ * Return: Current refcount
+ */
+static inline int32_t dp_runtime_put(struct dp_soc *soc)
+{
+	return qdf_atomic_dec_return(&soc->dp_runtime_refcount);
+}
+
+/**
+ * dp_runtime_get_refcount() - Get dp runtime refcount
+ * @soc: Datapath soc handle
+ *
+ * Get dp runtime refcount by returning an atomic variable
+ *
+ * Return: Current refcount
+ */
+static inline int32_t dp_runtime_get_refcount(struct dp_soc *soc)
+{
+	return qdf_atomic_read(&soc->dp_runtime_refcount);
+}
+
+/**
+ * dp_runtime_init() - Init dp runtime refcount when dp soc init
+ * @soc: Datapath soc handle
+ *
+ * Return: QDF_STATUS
+ */
+static inline QDF_STATUS dp_runtime_init(struct dp_soc *soc)
+{
+	return qdf_atomic_init(&soc->dp_runtime_refcount);
+}
+#else
+static inline int32_t dp_runtime_get(struct dp_soc *soc)
+{
+	return 0;
+}
+
+static inline int32_t dp_runtime_put(struct dp_soc *soc)
+{
+	return 0;
+}
+
+static inline QDF_STATUS dp_runtime_init(struct dp_soc *soc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 #endif /* #ifndef _DP_INTERNAL_H_ */

+ 22 - 1
dp/wifi3.0/dp_main.c

@@ -5375,6 +5375,8 @@ dp_soc_attach_target_wifi3(struct cdp_soc_t *cdp_soc)
 
 	DP_STATS_INIT(soc);
 
+	dp_runtime_init(soc);
+
 	/* initialize work queue for stats processing */
 	qdf_create_work(0, &soc->htt_stats.work, htt_t2h_stats_handler, soc);
 
@@ -11422,6 +11424,12 @@ static QDF_STATUS dp_runtime_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 		return QDF_STATUS_E_AGAIN;
 	}
 
+	if (dp_runtime_get_refcount(soc)) {
+		dp_init_info("refcount: %d", dp_runtime_get_refcount(soc));
+
+		return QDF_STATUS_E_AGAIN;
+	}
+
 	if (soc->intr_mode == DP_INTR_POLL)
 		qdf_timer_stop(&soc->int_timer);
 
@@ -11449,9 +11457,12 @@ void dp_flush_ring_hptp(struct dp_soc *soc, hal_ring_handle_t hal_srng)
 		hal_srng_access_end(soc->hal_soc, hal_srng);
 
 		hal_srng_set_flush_last_ts(hal_srng);
+		dp_debug("flushed");
 	}
 }
 
+#define DP_FLUSH_WAIT_CNT 10
+#define DP_RUNTIME_SUSPEND_WAIT_MS 10
 /**
  * dp_runtime_resume() - ensure DP is ready to runtime resume
  * @soc_hdl: Datapath soc handle
@@ -11464,11 +11475,21 @@ void dp_flush_ring_hptp(struct dp_soc *soc, hal_ring_handle_t hal_srng)
 static QDF_STATUS dp_runtime_resume(struct cdp_soc_t *soc_hdl, uint8_t pdev_id)
 {
 	struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl);
-	int i;
+	int i, suspend_wait = 0;
 
 	if (soc->intr_mode == DP_INTR_POLL)
 		qdf_timer_mod(&soc->int_timer, DP_INTR_POLL_TIMER_MS);
 
+	/*
+	 * Wait until dp runtime refcount becomes zero or time out, then flush
+	 * pending tx for runtime suspend.
+	 */
+	while (dp_runtime_get_refcount(soc) &&
+	       suspend_wait < DP_FLUSH_WAIT_CNT) {
+		qdf_sleep(DP_RUNTIME_SUSPEND_WAIT_MS);
+		suspend_wait++;
+	}
+
 	for (i = 0; i < MAX_TCL_DATA_RINGS; i++) {
 		dp_flush_ring_hptp(soc, soc->tcl_data_ring[i].hal_srng);
 	}

+ 66 - 10
dp/wifi3.0/dp_tx.c

@@ -1295,8 +1295,73 @@ dp_tx_ring_access_end(struct dp_soc *soc, hal_ring_handle_t hal_ring_hdl,
 {
 	dp_tx_hal_ring_access_end(soc, hal_ring_hdl);
 }
+#endif
 
+#ifdef FEATURE_RUNTIME_PM
+/**
+ * dp_tx_ring_access_end_wrapper() - Wrapper for ring access end
+ * @soc: Datapath soc handle
+ * @hal_ring_hdl: HAL ring handle
+ * @coalesce: Coalesce the current write or not
+ *
+ * Wrapper for HAL ring access end for data transmission for
+ * FEATURE_RUNTIME_PM
+ *
+ * Returns: none
+ */
+static inline void
+dp_tx_ring_access_end_wrapper(struct dp_soc *soc,
+			      hal_ring_handle_t hal_ring_hdl,
+			      int coalesce)
+{
+	int ret;
+
+	ret = hif_pm_runtime_get(soc->hif_handle,
+				 RTPM_ID_DW_TX_HW_ENQUEUE, true);
+	switch (ret) {
+	case 0:
+		dp_tx_ring_access_end(soc, hal_ring_hdl, coalesce);
+		hif_pm_runtime_put(soc->hif_handle,
+				   RTPM_ID_DW_TX_HW_ENQUEUE);
+		break;
+	/*
+	 * If hif_pm_runtime_get returns -EBUSY or -EINPROGRESS,
+	 * take the dp runtime refcount using dp_runtime_get,
+	 * check link state,if up, write TX ring HP, else just set flush event.
+	 * In dp_runtime_resume, wait until dp runtime refcount becomes
+	 * zero or time out, then flush pending tx.
+	 */
+	case -EBUSY:
+	case -EINPROGRESS:
+		dp_runtime_get(soc);
+		if (hif_pm_get_link_state(soc->hif_handle) ==
+		    HIF_PM_LINK_STATE_UP) {
+			dp_tx_ring_access_end(soc, hal_ring_hdl, coalesce);
+		} else {
+			dp_tx_hal_ring_access_end_reap(soc, hal_ring_hdl);
+			hal_srng_set_event(hal_ring_hdl, HAL_SRNG_FLUSH_EVENT);
+			hal_srng_inc_flush_cnt(hal_ring_hdl);
+		}
+		dp_runtime_put(soc);
+		break;
+	default:
+		dp_runtime_get(soc);
+		dp_tx_hal_ring_access_end_reap(soc, hal_ring_hdl);
+		hal_srng_set_event(hal_ring_hdl, HAL_SRNG_FLUSH_EVENT);
+		hal_srng_inc_flush_cnt(hal_ring_hdl);
+		dp_runtime_put(soc);
+	}
+}
+#else
+static inline void
+dp_tx_ring_access_end_wrapper(struct dp_soc *soc,
+			      hal_ring_handle_t hal_ring_hdl,
+			      int coalesce)
+{
+	dp_tx_ring_access_end(soc, hal_ring_hdl, coalesce);
+}
 #endif
+
 /**
  * dp_tx_hw_enqueue() - Enqueue to TCL HW for transmit
  * @soc: DP Soc Handle
@@ -1432,16 +1497,7 @@ dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev,
 	status = QDF_STATUS_SUCCESS;
 
 ring_access_fail:
-	if (hif_pm_runtime_get(soc->hif_handle,
-			       RTPM_ID_DW_TX_HW_ENQUEUE, true) == 0) {
-		dp_tx_ring_access_end(soc, hal_ring_hdl, coalesce);
-		hif_pm_runtime_put(soc->hif_handle,
-				   RTPM_ID_DW_TX_HW_ENQUEUE);
-	} else {
-		dp_tx_hal_ring_access_end_reap(soc, hal_ring_hdl);
-		hal_srng_set_event(hal_ring_hdl, HAL_SRNG_FLUSH_EVENT);
-		hal_srng_inc_flush_cnt(hal_ring_hdl);
-	}
+	dp_tx_ring_access_end_wrapper(soc, hal_ring_hdl, coalesce);
 
 	return status;
 }

+ 4 - 0
dp/wifi3.0/dp_types.h

@@ -1719,6 +1719,10 @@ struct dp_soc {
 #ifdef WLAN_DP_FEATURE_SW_LATENCY_MGR
 	struct dp_swlm swlm;
 #endif
+#ifdef FEATURE_RUNTIME_PM
+	/* Dp runtime refcount */
+	qdf_atomic_t dp_runtime_refcount;
+#endif
 };
 
 #ifdef IPA_OFFLOAD

+ 31 - 0
hif/inc/hif.h

@@ -1022,8 +1022,19 @@ static inline char *rtpm_string_from_dbgid(wlan_rtpm_dbgid id)
 	return (char *)strings[id];
 }
 
+/**
+ * enum hif_pm_link_state - hif link state
+ * HIF_PM_LINK_STATE_DOWN: hif link state is down
+ * HIF_PM_LINK_STATE_UP: hif link state is up
+ */
+enum hif_pm_link_state {
+	HIF_PM_LINK_STATE_DOWN,
+	HIF_PM_LINK_STATE_UP
+};
+
 #ifdef FEATURE_RUNTIME_PM
 struct hif_pm_runtime_lock;
+
 void hif_fastpath_resume(struct hif_opaque_softc *hif_ctx);
 int hif_pm_runtime_get_sync(struct hif_opaque_softc *hif_ctx,
 			    wlan_rtpm_dbgid rtpm_dbgid);
@@ -1058,6 +1069,22 @@ void hif_pm_runtime_mark_dp_rx_busy(struct hif_opaque_softc *hif_ctx);
 int hif_pm_runtime_is_dp_rx_busy(struct hif_opaque_softc *hif_ctx);
 qdf_time_t hif_pm_runtime_get_dp_rx_busy_mark(struct hif_opaque_softc *hif_ctx);
 int hif_pm_runtime_sync_resume(struct hif_opaque_softc *hif_ctx);
+
+/**
+ * hif_pm_set_link_state() - set link state during RTPM
+ * @hif_sc: HIF Context
+ *
+ * Return: None
+ */
+void hif_pm_set_link_state(struct hif_opaque_softc *hif_handle, uint8_t val);
+
+/**
+ * hif_is_link_state_up() - Is link state up
+ * @hif_sc: HIF Context
+ *
+ * Return: 1 link is up, 0 link is down
+ */
+uint8_t hif_pm_get_link_state(struct hif_opaque_softc *hif_handle);
 #else
 struct hif_pm_runtime_lock {
 	const char *name;
@@ -1132,6 +1159,10 @@ hif_pm_runtime_get_dp_rx_busy_mark(struct hif_opaque_softc *hif_ctx)
 { return 0; }
 static inline int hif_pm_runtime_sync_resume(struct hif_opaque_softc *hif_ctx)
 { return 0; }
+static inline
+void hif_pm_set_link_state(struct hif_opaque_softc *hif_handle, uint8_t val)
+{}
+
 #endif
 
 void hif_enable_power_management(struct hif_opaque_softc *hif_ctx,

+ 3 - 0
hif/src/hif_main.c

@@ -669,6 +669,7 @@ struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx,
 		     sizeof(struct hif_driver_state_callbacks));
 	scn->bus_type  = bus_type;
 
+	hif_pm_set_link_state(GET_HIF_OPAQUE_HDL(scn), HIF_PM_LINK_STATE_DOWN);
 	hif_get_cfg_from_psoc(scn, psoc);
 
 	hif_set_event_hist_mask(GET_HIF_OPAQUE_HDL(scn));
@@ -896,6 +897,7 @@ QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev,
 		return status;
 	}
 
+	hif_pm_set_link_state(GET_HIF_OPAQUE_HDL(scn), HIF_PM_LINK_STATE_UP);
 	status = hif_hal_attach(scn);
 	if (status != QDF_STATUS_SUCCESS) {
 		hif_err("hal attach failed");
@@ -949,6 +951,7 @@ void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type)
 
 	hif_hal_detach(scn);
 
+	hif_pm_set_link_state(hif_ctx, HIF_PM_LINK_STATE_DOWN);
 	hif_disable_bus(scn);
 
 	hif_wlan_disable(scn);

+ 4 - 0
hif/src/hif_main.h

@@ -265,6 +265,10 @@ struct hif_softc {
 	/* Flag to indicate whether bus is suspended */
 	bool bus_suspended;
 	bool pktlog_init;
+#ifdef FEATURE_RUNTIME_PM
+	/* Variable to track the link state change in RTPM */
+	qdf_atomic_t pm_link_state;
+#endif
 };
 
 static inline

+ 14 - 0
hif/src/hif_runtime_pm.c

@@ -1775,4 +1775,18 @@ qdf_time_t hif_pm_runtime_get_dp_rx_busy_mark(struct hif_opaque_softc *hif_ctx)
 	rpm_ctx = hif_bus_get_rpm_ctx(scn);
 	return rpm_ctx->dp_last_busy_timestamp;
 }
+
+void hif_pm_set_link_state(struct hif_opaque_softc *hif_handle, uint8_t val)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_handle);
+
+	qdf_atomic_set(&scn->pm_link_state, val);
+}
+
+uint8_t hif_pm_get_link_state(struct hif_opaque_softc *hif_handle)
+{
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_handle);
+
+	return qdf_atomic_read(&scn->pm_link_state);
+}
 #endif /* FEATURE_RUNTIME_PM */