Browse Source

qcacld-3.0: ipa hw pipe force shutdown

qcacld-2.0 to qcacld-3.0 propagation

When the driver is in SoftAP mode when it is unloaded,
and if many clients are connected,
sometimes not all clients can gracefully disconnect.
In this case the IPA HW pipes are not cleaned up properly,
and subsequent pipe setup will usually fail.
To avoid a bad pipe configuration, before unloading driver,
check the pipe status and if the pipes are not closed properly,
shutdown the pipes forcefully.

Change-Id: Icc0543567423cc4b625140280be13ef733d7d67d
CRs-fixed: 886229
Leo Chang 9 years ago
parent
commit
e3e4944153
3 changed files with 59 additions and 9 deletions
  1. 7 6
      core/hdd/inc/wlan_hdd_ipa.h
  2. 50 3
      core/hdd/src/wlan_hdd_ipa.c
  3. 2 0
      core/hdd/src/wlan_hdd_main.c

+ 7 - 6
core/hdd/inc/wlan_hdd_ipa.h

@@ -56,6 +56,9 @@ void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason);
 bool hdd_ipa_is_enabled(hdd_context_t *pHddCtx);
 bool hdd_ipa_uc_is_enabled(hdd_context_t *pHddCtx);
 int hdd_ipa_send_mcc_scc_msg(hdd_context_t *pHddCtx, bool mcc_mode);
+int hdd_ipa_uc_ssr_reinit(void);
+int hdd_ipa_uc_ssr_deinit(void);
+void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx);
 #else
 static inline CDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
 {
@@ -131,12 +134,6 @@ static inline bool hdd_ipa_uc_is_enabled(hdd_context_t *pHddCtx)
 {
 	return false;
 }
-#endif /* IPA_OFFLOAD */
-
-#ifdef IPA_UC_OFFLOAD
-int hdd_ipa_uc_ssr_reinit(void);
-int hdd_ipa_uc_ssr_deinit(void);
-#else
 static inline int hdd_ipa_uc_ssr_reinit(void)
 {
 	return false;
@@ -146,6 +143,10 @@ static inline int hdd_ipa_uc_ssr_deinit(void)
 {
 	return false;
 }
+static inline void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
+{
+	return;
+}
 #endif
 
 #endif /* #ifndef HDD_IPA_H__ */

+ 50 - 3
core/hdd/src/wlan_hdd_ipa.c

@@ -397,6 +397,7 @@ struct hdd_ipa_priv {
 	struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT];
 	cdf_list_t pending_event;
 	cdf_mutex_t event_lock;
+	bool ipa_pipes_down;
 	uint32_t ipa_tx_packets_diff;
 	uint32_t ipa_rx_packets_diff;
 	uint32_t ipa_p_tx_packets;
@@ -1005,7 +1006,7 @@ static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa)
 		return result;
 	}
 	ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, true, false);
-
+	hdd_ipa->ipa_pipes_down = false;
 	return 0;
 }
 
@@ -1019,6 +1020,8 @@ static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa)
 {
 	int result;
 
+	hdd_ipa->ipa_pipes_down = true;
+
 	HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__);
 	result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle);
 	if (result) {
@@ -1754,7 +1757,37 @@ static CDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
 	return CDF_STATUS_SUCCESS;
 }
 
-#ifdef IPA_UC_OFFLOAD
+/**
+ * hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe
+ * @hdd_ctx: hdd main context
+ *
+ * Force shutdown IPA pipe
+ * Independent of FW pipe status, IPA pipe shutdonw progress
+ * in case, any STA does not leave properly, IPA HW pipe should cleaned up
+ * independent from FW pipe status
+ *
+ * Return: NONE
+ */
+void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx)
+{
+	struct hdd_ipa_priv *hdd_ipa;
+
+	if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa)
+		return;
+
+	hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa;
+	if (false == hdd_ipa->ipa_pipes_down) {
+		HDD_IPA_LOG(CDF_TRACE_LEVEL_ERROR,
+				"IPA pipes are not down yet, force shutdown");
+		hdd_ipa_uc_disable_pipes(hdd_ipa);
+	} else {
+		HDD_IPA_LOG(CDF_TRACE_LEVEL_INFO,
+				"IPA pipes are down, do nothing");
+	}
+
+	return;
+}
+
 /**
  * hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR
  *
@@ -1763,6 +1796,7 @@ static CDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx)
  *
  * Return: 0 - Success
  */
+#ifdef IPA_UC_OFFLOAD
 int hdd_ipa_uc_ssr_deinit(void)
 {
 	struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
@@ -1798,6 +1832,13 @@ int hdd_ipa_uc_ssr_deinit(void)
 	 */
 	return 0;
 }
+#else
+int hdd_ipa_uc_ssr_deinit(void)
+{
+	return 0;
+}
+#endif
+
 
 /**
  * hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR
@@ -1807,6 +1848,7 @@ int hdd_ipa_uc_ssr_deinit(void)
  *
  * Return: 0 - Success
  */
+#ifdef IPA_UC_OFFLOAD
 int hdd_ipa_uc_ssr_reinit(void)
 {
 	struct hdd_ipa_priv *hdd_ipa = ghdd_ipa;
@@ -1821,6 +1863,11 @@ int hdd_ipa_uc_ssr_reinit(void)
 	 */
 	return 0;
 }
+#else
+int hdd_ipa_uc_ssr_reinit(void)
+{
+	return 0;
+}
 #endif
 
 /**
@@ -3813,7 +3860,7 @@ CDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx)
 		hdd_ipa->resource_loading = false;
 		hdd_ipa->resource_unloading = false;
 		hdd_ipa->sta_connected = 0;
-
+		hdd_ipa->ipa_pipes_down = true;
 		/* Setup IPA sys_pipe for MCC */
 		if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) {
 			ret = hdd_ipa_setup_sys_pipe(hdd_ipa);

+ 2 - 0
core/hdd/src/wlan_hdd_main.c

@@ -5672,6 +5672,8 @@ static void hdd_driver_exit(void)
 		hddLog(CDF_TRACE_LEVEL_FATAL,
 		       FL("module exit called before probe"));
 	} else {
+		/* Check IPA HW Pipe shutdown */
+		hdd_ipa_uc_force_pipe_shutdown(hdd_ctx);
 #ifdef QCA_PKT_PROTO_TRACE
 		cds_pkt_proto_trace_close();
 #endif /* QCA_PKT_PROTO_TRACE */