Переглянути джерело

qcacld-3.0: Fix IPA pipe unloading timeout during driver restart

Host driver drops incoming HDD IPA events during unloading prcess,
when IPA pipe unloading timeout occurs, and IPA offload state could
be mismatch between host driver and FW.
Fix by setting unloading complete before IPA pipe disable and putting
events into pending event queue for unloading timeout case as well.

Change-Id: If44caa07f328bf3ac2d2fc02aafb796176114678
CRs-Fixed: 2152490
Yun Park 7 роки тому
батько
коміт
a4bb37c234
2 змінених файлів з 56 додано та 69 видалено
  1. 1 13
      core/hdd/src/wlan_hdd_cfg80211.c
  2. 55 56
      core/hdd/src/wlan_hdd_ipa.c

+ 1 - 13
core/hdd/src/wlan_hdd_cfg80211.c

@@ -18550,14 +18550,7 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
 						adapter->sta_info[i].
 							sta_mac.bytes,
 						QDF_MAC_ADDR_SIZE);
-					if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
-						hdd_ipa_wlan_evt(adapter,
-							adapter->
-								 sta_info[i].
-								 sta_id,
-							HDD_IPA_CLIENT_DISCONNECT,
-							mac);
-					}
+
 					hdd_debug("Delete STA with MAC::"
 						  MAC_ADDRESS_STR,
 					       MAC_ADDR_ARRAY(mac));
@@ -18598,11 +18591,6 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
 				return -ENOENT;
 			}
 
-			if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
-				hdd_ipa_wlan_evt(adapter, staId,
-					HDD_IPA_CLIENT_DISCONNECT, mac);
-			}
-
 			if (adapter->sta_info[staId].is_deauth_in_progress ==
 			    true) {
 				hdd_debug("Skip DEL STA as deauth is in progress::"

+ 55 - 56
core/hdd/src/wlan_hdd_ipa.c

@@ -309,6 +309,7 @@ struct ipa_uc_pending_event {
 	qdf_ipa_wlan_event_t type;
 	uint8_t sta_id;
 	uint8_t mac_addr[QDF_MAC_ADDR_SIZE];
+	bool is_loading;
 };
 
 /**
@@ -550,7 +551,8 @@ static void hdd_ipa_wdi_meter_notifier_cb(void);
 static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type);
 
 static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context);
-static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa);
+static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa,
+					  bool is_loading);
 
 #if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \
 	defined(IPA_CLIENT_IS_MHI_CONS))
@@ -2692,7 +2694,7 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
 					hdd_ipa_send_mcc_scc_msg(hdd_ctx,
 							 hdd_ctx->mcc_mode);
 			}
-			hdd_ipa_uc_proc_pending_event(hdd_ipa);
+			hdd_ipa_uc_proc_pending_event(hdd_ipa, true);
 			if (hdd_ipa->pending_cons_req)
 				ipa_rm_notify_completion(
 						IPA_RM_RESOURCE_GRANTED,
@@ -2709,13 +2711,13 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt)
 			 * Async return success from FW
 			 * Disable/suspend all the PIPEs
 			 */
+			hdd_ipa->resource_unloading = false;
+			complete(&hdd_ipa->ipa_resource_comp);
 			hdd_ipa_uc_disable_pipes(hdd_ipa);
 			if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx))
 				ipa_rm_release_resource(
 					IPA_RM_RESOURCE_WLAN_PROD);
-			hdd_ipa->resource_unloading = false;
-			complete(&hdd_ipa->ipa_resource_comp);
-			hdd_ipa_uc_proc_pending_event(hdd_ipa);
+			hdd_ipa_uc_proc_pending_event(hdd_ipa, false);
 			hdd_ipa->pending_cons_req = false;
 		}
 		qdf_mutex_release(&hdd_ipa->ipa_lock);
@@ -3121,6 +3123,12 @@ QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
 		status = QDF_STATUS_E_FAILURE;
 		goto fail_return;
 	}
+
+	for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+		hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
+		hdd_ipa->vdev_offload_enabled[i] = false;
+	}
+
 	if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) {
 		HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL,
 			"IPA UC resource alloc fail");
@@ -3153,7 +3161,7 @@ QDF_STATUS hdd_ipa_uc_ol_init(struct hdd_context *hdd_ctx)
 
 	for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
 		hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
-					hdd_ipa_uc_fw_op_event_handler);
+				hdd_ipa_uc_fw_op_event_handler);
 		hdd_ipa->uc_op_work[i].msg = NULL;
 	}
 
@@ -3209,7 +3217,9 @@ int hdd_ipa_uc_ol_deinit(struct hdd_context *hdd_ctx)
 		}
 	}
 
+	qdf_mutex_acquire(&hdd_ipa->ipa_lock);
 	hdd_ipa_cleanup_pending_event(hdd_ipa);
+	qdf_mutex_release(&hdd_ipa->ipa_lock);
 
 	HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "exit: ret=%d", ret);
 	return ret;
@@ -3471,6 +3481,7 @@ static int __hdd_ipa_uc_ssr_deinit(void)
 			hdd_ipa_cleanup_iface(iface_context);
 	}
 	hdd_ipa->num_iface = 0;
+
 	/* After SSR, wlan driver reloads FW again. But we need to protect
 	 * IPA submodule during SSR transient state. So deinit basic IPA
 	 * UC host side to be in sync with reloaded FW during SSR
@@ -3546,10 +3557,6 @@ static int __hdd_ipa_uc_ssr_reinit(struct hdd_context *hdd_ctx)
 		iface_context->iface_id = i;
 		iface_context->adapter = NULL;
 	}
-	for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
-		hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
-		hdd_ipa->vdev_offload_enabled[i] = false;
-	}
 
 	if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) {
 		hdd_ipa->resource_loading = false;
@@ -5369,42 +5376,42 @@ static int __hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
 				    hdd_ipa->resource_loading ?
 				    "load" : "unload");
 
-			if (hdd_ipa->resource_loading) {
-				qdf_mutex_acquire(&hdd_ipa->ipa_lock);
-
-				pending_event_count =
-					qdf_list_size(&hdd_ipa->pending_event);
-				if (pending_event_count >=
-				    HDD_IPA_MAX_PENDING_EVENT_COUNT) {
-					hdd_debug(
-					    "Reached max pending event count");
-					qdf_list_remove_front(
-					    &hdd_ipa->pending_event,
-					    (qdf_list_node_t **)&pending_event);
-				} else {
-					pending_event =
-						(struct ipa_uc_pending_event *)
-						qdf_mem_malloc(sizeof(
+			qdf_mutex_acquire(&hdd_ipa->ipa_lock);
+
+			pending_event_count =
+				qdf_list_size(&hdd_ipa->pending_event);
+			if (pending_event_count >=
+					HDD_IPA_MAX_PENDING_EVENT_COUNT) {
+				hdd_debug("Reached max pending event count");
+				qdf_list_remove_front(
+					&hdd_ipa->pending_event,
+					(qdf_list_node_t **)&pending_event);
+			} else {
+				pending_event =
+					(struct ipa_uc_pending_event *)
+					qdf_mem_malloc(sizeof(
 						struct ipa_uc_pending_event));
-				}
+			}
 
-				if (!pending_event) {
-					HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
+			if (!pending_event) {
+				HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR,
 					    "Pending event memory alloc fail");
-					qdf_mutex_release(&hdd_ipa->ipa_lock);
-					return -ENOMEM;
-				}
-
-				pending_event->adapter = adapter;
-				pending_event->sta_id = sta_id;
-				pending_event->type = type;
-				qdf_mem_copy(pending_event->mac_addr,
-					     mac_addr, QDF_MAC_ADDR_SIZE);
-				qdf_list_insert_back(&hdd_ipa->pending_event,
-						     &pending_event->node);
-
 				qdf_mutex_release(&hdd_ipa->ipa_lock);
+				return -ENOMEM;
 			}
+
+			pending_event->adapter = adapter;
+			pending_event->sta_id = sta_id;
+			pending_event->type = type;
+			pending_event->is_loading =
+				hdd_ipa->resource_loading;
+			qdf_mem_copy(pending_event->mac_addr,
+					mac_addr, QDF_MAC_ADDR_SIZE);
+			qdf_list_insert_back(&hdd_ipa->pending_event,
+					&pending_event->node);
+
+			qdf_mutex_release(&hdd_ipa->ipa_lock);
+
 			return 0;
 		}
 		HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO,
@@ -5796,11 +5803,12 @@ int hdd_ipa_wlan_evt(struct hdd_adapter *adapter, uint8_t sta_id,
 /**
  * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events
  * @hdd_ipa: Global HDD IPA context
+ * @is_loading: Indicate if invoked during loading
  *
  * Return: None
  */
 static void
-hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
+hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa, bool is_loading)
 {
 	unsigned int pending_event_count;
 	struct ipa_uc_pending_event *pending_event = NULL;
@@ -5817,10 +5825,11 @@ hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa)
 	qdf_list_remove_front(&hdd_ipa->pending_event,
 			(qdf_list_node_t **)&pending_event);
 	while (pending_event != NULL) {
-		__hdd_ipa_wlan_evt(pending_event->adapter,
-			pending_event->sta_id,
-			pending_event->type,
-			pending_event->mac_addr);
+	       if (pending_event->is_loading == is_loading)
+		       __hdd_ipa_wlan_evt(pending_event->adapter,
+				       pending_event->sta_id,
+				       pending_event->type,
+				       pending_event->mac_addr);
 		qdf_mem_free(pending_event);
 		pending_event = NULL;
 		qdf_list_remove_front(&hdd_ipa->pending_event,
@@ -5899,10 +5908,6 @@ static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
 		iface_context->adapter = NULL;
 		qdf_spinlock_create(&iface_context->interface_lock);
 	}
-	for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
-		hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX;
-		hdd_ipa->vdev_offload_enabled[i] = false;
-	}
 
 	INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush);
 	qdf_spinlock_create(&hdd_ipa->pm_lock);
@@ -5941,12 +5946,6 @@ static QDF_STATUS __hdd_ipa_init(struct hdd_context *hdd_ctx)
 		}
 		if (hdd_ipa_uc_register_uc_ready(hdd_ipa))
 			goto fail_create_sys_pipe;
-
-		for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) {
-			hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work,
-						hdd_ipa_uc_fw_op_event_handler);
-			hdd_ipa->uc_op_work[i].msg = NULL;
-		}
 	} else {
 		ret = hdd_ipa_setup_sys_pipe(hdd_ipa);
 		if (ret)