Browse Source

qcacld-3.0: Move IPA WLAN event handler to IPA component

IPA module has been moved to CLD component under the converged
driver model. Move the legacy HDD IPA WLAN event handler to
the IPA component.

Change-Id: Ia53adce7ef29eea747f288fa074f96a84e47925d
CRs-Fixed: 2177925
Sravan Kumar Kairam 7 years ago
parent
commit
5214f65bf9

+ 16 - 0
components/ipa/core/inc/wlan_ipa_core.h

@@ -532,5 +532,21 @@ QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
 }
 #endif
 
+/**
+ * wlan_ipa_wlan_evt() - IPA event handler
+ * @net_dev: Interface net device
+ * @device_mode: Net interface device mode
+ * @sta_id: station id for the event
+ * @session_id: session id for the event
+ * @type: event enum of type ipa_wlan_event
+ * @mac_address: MAC address associated with the event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
+			     uint8_t sta_id, uint8_t session_id,
+			     enum wlan_ipa_wlan_event ipa_event_type,
+			     uint8_t *mac_addr);
+
 #endif /* IPA_OFFLOAD */
 #endif /* _WLAN_IPA_CORE_H_ */

+ 24 - 0
components/ipa/core/inc/wlan_ipa_main.h

@@ -113,6 +113,13 @@ void ipa_config_update(struct wlan_ipa_config *config);
  */
 bool ipa_config_is_enabled(void);
 
+/**
+ * ipa_config_is_uc_enabled() - Is IPA uC config enabled?
+ *
+ * Return: true if IPA uC is enabled in IPA config
+ */
+bool ipa_config_is_uc_enabled(void);
+
 /**
  * ipa_obj_setup() - IPA obj initialization and setup
  * @ipa_ctx: IPA obj context
@@ -326,5 +333,22 @@ QDF_STATUS ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev);
 QDF_STATUS ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev,
 				bool mcc_mode);
 
+/**
+ * ipa_wlan_evt() - IPA event handler
+ * @pdev: pdev obj
+ * @net_dev: Interface net device
+ * @device_mode: Net interface device mode
+ * @sta_id: station id for the event
+ * @session_id: session id for the event
+ * @type: event enum of type ipa_wlan_event
+ * @mac_address: MAC address associated with the event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ipa_wlan_evt(struct wlan_objmgr_pdev *pdev, qdf_netdev_t net_dev,
+			uint8_t device_mode, uint8_t sta_id, uint8_t session_id,
+			enum wlan_ipa_wlan_event ipa_event_type,
+			uint8_t *mac_addr);
+
 #endif /* IPA_OFFLOAD */
 #endif /* end  of _WLAN_IPA_MAIN_H_ */

+ 2 - 1
components/ipa/core/inc/wlan_ipa_priv.h

@@ -443,7 +443,7 @@ struct ipa_uc_fw_stats {
  */
 struct wlan_ipa_uc_pending_event {
 	qdf_list_node_t node;
-	qdf_ipa_wlan_event_t type;
+	qdf_ipa_wlan_event type;
 	qdf_netdev_t net_dev;
 	uint8_t device_mode;
 	uint8_t sta_id;
@@ -559,6 +559,7 @@ typedef int (*wlan_ipa_send_to_nw)(qdf_nbuf_t skb, qdf_netdev_t dev);
 
 /* IPA private context structure definition */
 struct wlan_ipa_priv {
+	struct wlan_objmgr_pdev *pdev;
 	struct wlan_ipa_sys_pipe sys_pipe[WLAN_IPA_MAX_SYSBAM_PIPE];
 	struct wlan_ipa_iface_context iface_context[WLAN_IPA_MAX_IFACE];
 	uint8_t num_iface;

+ 893 - 2
components/ipa/core/src/wlan_ipa_core.c

@@ -925,6 +925,887 @@ end:
 	return QDF_STATUS_SUCCESS;
 }
 
+/**
+ * wlan_ipa_uc_find_add_assoc_sta() - Find associated station
+ * @ipa_ctx: Global IPA IPA context
+ * @sta_add: Should station be added
+ * @sta_id: ID of the station being queried
+ *
+ * Return: true if the station was found
+ */
+static bool wlan_ipa_uc_find_add_assoc_sta(struct wlan_ipa_priv *ipa_ctx,
+					   bool sta_add, uint8_t sta_id,
+					   uint8_t *mac_addr)
+{
+	bool sta_found = false;
+	uint8_t idx;
+
+	for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
+		if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
+		    (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
+			sta_found = true;
+			break;
+		}
+	}
+	if (sta_add && sta_found) {
+		ipa_err("STA ID %d already exist, cannot add", sta_id);
+		return sta_found;
+	}
+	if (sta_add) {
+		for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
+			if (!ipa_ctx->assoc_stas_map[idx].is_reserved) {
+				ipa_ctx->assoc_stas_map[idx].is_reserved = true;
+				ipa_ctx->assoc_stas_map[idx].sta_id = sta_id;
+				qdf_mem_copy(&ipa_ctx->assoc_stas_map[idx].
+					     mac_addr, mac_addr,
+					     QDF_NET_ETH_LEN);
+				return sta_found;
+			}
+		}
+	}
+	if (!sta_add && !sta_found) {
+		ipa_err("STA ID %d does not exist, cannot delete", sta_id);
+		return sta_found;
+	}
+	if (!sta_add) {
+		for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) {
+			if ((ipa_ctx->assoc_stas_map[idx].is_reserved) &&
+			    (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) {
+				ipa_ctx->assoc_stas_map[idx].is_reserved =
+					false;
+				ipa_ctx->assoc_stas_map[idx].sta_id = 0xFF;
+				qdf_mem_set(&ipa_ctx->assoc_stas_map[idx].
+					    mac_addr, 0, QDF_NET_ETH_LEN);
+				return sta_found;
+			}
+		}
+	}
+
+	return sta_found;
+}
+
+/**
+ * wlan_ipa_get_ifaceid() - Get IPA context interface ID
+ * @ipa_ctx: IPA context
+ * @session_id: Session ID
+ *
+ * Return: None
+ */
+static int wlan_ipa_get_ifaceid(struct wlan_ipa_priv *ipa_ctx,
+				uint8_t session_id)
+{
+	struct wlan_ipa_iface_context *iface_ctx;
+	int i;
+
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+		iface_ctx = &ipa_ctx->iface_context[i];
+		if (iface_ctx->session_id == session_id)
+			break;
+	}
+
+	return i;
+}
+
+/**
+ * wlan_ipa_cleanup_iface() - Cleanup IPA on a given interface
+ * @iface_context: interface-specific IPA context
+ *
+ * Return: None
+ */
+static void wlan_ipa_cleanup_iface(struct wlan_ipa_iface_context *iface_context)
+{
+	struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx;
+
+	ipa_debug("enter");
+
+	if (!iface_context->tl_context)
+		return;
+
+	cdp_ipa_cleanup_iface(ipa_ctx->dp_soc,
+			      iface_context->dev->name,
+			      wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
+
+	qdf_spin_lock_bh(&iface_context->interface_lock);
+	iface_context->tl_context = NULL;
+	iface_context->dev = NULL;
+	iface_context->device_mode = QDF_MAX_NO_OF_MODE;
+	iface_context->session_id = WLAN_IPA_MAX_SESSION;
+	iface_context->sta_id = WLAN_IPA_MAX_STA_COUNT;
+	qdf_spin_unlock_bh(&iface_context->interface_lock);
+	iface_context->ifa_address = 0;
+	if (!iface_context->ipa_ctx->num_iface) {
+		ipa_err("NUM INTF 0, Invalid");
+		QDF_ASSERT(0);
+	}
+	iface_context->ipa_ctx->num_iface--;
+	ipa_debug("exit: num_iface=%d", iface_context->ipa_ctx->num_iface);
+}
+
+/**
+ * wlan_ipa_setup_iface() - Setup IPA on a given interface
+ * @ipa_ctx: IPA IPA global context
+ * @net_dev: Interface net device
+ * @device_mode: Net interface device mode
+ * @adapter: Interface upon which IPA is being setup
+ * @sta_id: Station ID of the API instance
+ * @session_id: Station ID of the API instance
+ *
+ * Return: QDF STATUS
+ */
+static QDF_STATUS wlan_ipa_setup_iface(struct wlan_ipa_priv *ipa_ctx,
+				       qdf_netdev_t net_dev,
+				       uint8_t device_mode, uint8_t sta_id,
+				       uint8_t session_id)
+{
+	struct wlan_ipa_iface_context *iface_context = NULL;
+	void *tl_context = NULL;
+	int i;
+	QDF_STATUS status;
+
+	/* Lower layer may send multiple START_BSS_EVENT in DFS mode or during
+	 * channel change indication. Since these indications are sent by lower
+	 * layer as SAP updates and IPA doesn't have to do anything for these
+	 * updates so ignoring!
+	 */
+	if (device_mode == QDF_SAP_MODE) {
+		for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+			iface_context = &(ipa_ctx->iface_context[i]);
+			if (iface_context->dev == net_dev)
+				return QDF_STATUS_SUCCESS;
+		}
+	}
+
+	for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+		if (ipa_ctx->iface_context[i].tl_context == NULL) {
+			iface_context = &(ipa_ctx->iface_context[i]);
+			break;
+		}
+	}
+
+	if (iface_context == NULL) {
+		ipa_err("All the IPA interfaces are in use");
+		status = QDF_STATUS_E_NOMEM;
+		goto end;
+	}
+
+	iface_context->sta_id = sta_id;
+	tl_context = (void *)cdp_peer_get_vdev_by_sta_id(ipa_ctx->dp_soc,
+							 ipa_ctx->dp_pdev,
+							 sta_id);
+	if (tl_context == NULL) {
+		ipa_err("Not able to get TL context sta_id: %d", sta_id);
+		status = QDF_STATUS_E_INVAL;
+		goto end;
+	}
+
+	iface_context->tl_context = tl_context;
+	iface_context->dev = net_dev;
+	iface_context->device_mode = device_mode;
+	iface_context->session_id = session_id;
+
+	status = cdp_ipa_setup_iface(ipa_ctx->dp_soc, net_dev->name,
+				     net_dev->dev_addr,
+				     iface_context->prod_client,
+				     iface_context->cons_client,
+				     session_id,
+				     wlan_ipa_is_ipv6_enabled(ipa_ctx->config));
+	if (status != QDF_STATUS_SUCCESS)
+		goto end;
+
+	ipa_ctx->num_iface++;
+
+	ipa_debug("exit: num_iface=%d", ipa_ctx->num_iface);
+
+	return status;
+
+end:
+	if (iface_context)
+		wlan_ipa_cleanup_iface(iface_context);
+
+	return status;
+}
+
+/**
+ * wlan_ipa_uc_handle_first_con() - Handle first uC IPA connection
+ * @ipa_ctx: IPA context
+ *
+ * Return: QDF STATUS
+ */
+static QDF_STATUS wlan_ipa_uc_handle_first_con(struct wlan_ipa_priv *ipa_ctx)
+{
+	ipa_debug("enter");
+
+	ipa_ctx->activated_fw_pipe = 0;
+	ipa_ctx->resource_loading = true;
+
+	/* If RM feature enabled
+	 * Request PROD Resource first
+	 * PROD resource may return sync or async manners
+	 */
+	if (wlan_ipa_is_rm_enabled(ipa_ctx->config)) {
+		if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) {
+			/* RM PROD request sync return
+			 * enable pipe immediately
+			 */
+			if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
+				ipa_err("IPA WDI Pipe activation failed");
+				ipa_ctx->resource_loading = false;
+				return QDF_STATUS_E_BUSY;
+			}
+		} else {
+			ipa_err("IPA WDI Pipe activation deferred");
+		}
+	} else {
+		/* RM Disabled
+		 * Just enabled all the PIPEs
+		 */
+		if (wlan_ipa_uc_enable_pipes(ipa_ctx)) {
+			ipa_err("IPA WDI Pipe activation failed");
+			ipa_ctx->resource_loading = false;
+			return QDF_STATUS_E_BUSY;
+		}
+		ipa_ctx->resource_loading = false;
+	}
+
+	ipa_debug("exit");
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wlan_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection
+ * @ipa_ctx: IPA context
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_handle_last_discon(struct wlan_ipa_priv *ipa_ctx)
+{
+	ipa_debug("enter");
+
+	ipa_ctx->resource_unloading = true;
+	qdf_event_reset(&ipa_ctx->ipa_resource_comp);
+	ipa_info("Disable FW RX PIPE");
+	cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, false);
+	ipa_info("Disable FW TX PIPE");
+	cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, true);
+
+	ipa_debug("exit: IPA WDI Pipes deactivated");
+}
+
+/**
+ * wlan_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw
+ * @ipa_ctx: global IPA context
+ * @offload_type: MCC or SCC
+ * @session_id: Session Id
+ * @enable: TX offload enable or disable
+ *
+ * Return: none
+ */
+static void wlan_ipa_uc_offload_enable_disable(struct wlan_ipa_priv *ipa_ctx,
+					       uint32_t offload_type,
+					       uint8_t session_id,
+					       bool enable)
+{
+
+	struct ipa_uc_offload_control_params req = {0};
+
+	if (session_id >= WLAN_IPA_MAX_SESSION) {
+		ipa_err("invalid session id: %d", session_id);
+		return;
+	}
+
+	if (enable == ipa_ctx->vdev_offload_enabled[session_id]) {
+		/*
+		 * This shouldn't happen :
+		 * IPA offload status is already set as desired
+		 */
+		QDF_ASSERT(0);
+		ipa_warn("IPA offload status is already set");
+		ipa_warn("offload_type=%d, vdev_id=%d, enable=%d",
+			 offload_type, session_id, enable);
+		return;
+	}
+
+	ipa_info("offload_type=%d, session_id=%d, enable=%d",
+		 offload_type, session_id, enable);
+
+	req.offload_type = offload_type;
+	req.vdev_id = session_id;
+	req.enable = enable;
+
+	if (QDF_STATUS_SUCCESS !=
+	    ipa_send_uc_offload_enable_disable(ipa_ctx->pdev, &req)) {
+		ipa_err("Fail to enable IPA offload");
+		ipa_err("offload type=%d, vdev_id=%d, enable=%d",
+			offload_type, session_id, enable);
+	} else {
+		ipa_ctx->vdev_offload_enabled[session_id] = enable;
+	}
+}
+
+/**
+ * __wlan_ipa_wlan_evt() - IPA event handler
+ * @net_dev: Interface net device
+ * @device_mode: Net interface device mode
+ * @sta_id: station id for the event
+ * @session_id: session id for the event
+ * @type: event enum of type ipa_wlan_event
+ * @mac_address: MAC address associated with the event
+ *
+ * This function is meant to be called from within wlan_ipa_ctx.c
+ *
+ * Return: QDF STATUS
+ */
+static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
+				      uint8_t sta_id, uint8_t session_id,
+				      qdf_ipa_wlan_event type,
+				      uint8_t *mac_addr)
+{
+	struct wlan_ipa_priv *ipa_ctx = gp_ipa;
+	struct wlan_ipa_iface_context *iface_ctx = NULL;
+	qdf_ipa_msg_meta_t meta;
+	qdf_ipa_wlan_msg_t *msg;
+	qdf_ipa_wlan_msg_ex_t *msg_ex = NULL;
+	int i;
+	QDF_STATUS status;
+
+	ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d",
+		  net_dev->name, type, mac_addr, sta_id);
+
+	if (type >= QDF_IPA_WLAN_EVENT_MAX)
+		return QDF_STATUS_E_INVAL;
+
+	if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
+	    !wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
+	    (device_mode != QDF_SAP_MODE)) {
+		return QDF_STATUS_SUCCESS;
+	}
+
+	/*
+	 * During IPA UC resource loading/unloading new events can be issued.
+	 */
+	if (wlan_ipa_uc_is_enabled(ipa_ctx->config) &&
+	    (ipa_ctx->resource_loading || ipa_ctx->resource_unloading)) {
+		unsigned int pending_event_count;
+		struct wlan_ipa_uc_pending_event *pending_event = NULL;
+
+		ipa_info("Event:%d IPA resource %s inprogress", type,
+			 ipa_ctx->resource_loading ?
+			 "load" : "unload");
+
+		/* Wait until completion of the long/unloading */
+		status = qdf_wait_for_event_completion(
+				&ipa_ctx->ipa_resource_comp,
+				msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME));
+		if (status != QDF_STATUS_SUCCESS) {
+			/*
+			 * If timed out, store the events separately and
+			 * handle them later.
+			 */
+			ipa_info("IPA resource %s timed out",
+				  ipa_ctx->resource_loading ?
+				  "load" : "unload");
+
+			qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+
+			pending_event_count =
+				qdf_list_size(&ipa_ctx->pending_event);
+			if (pending_event_count >=
+			    WLAN_IPA_MAX_PENDING_EVENT_COUNT) {
+				ipa_info("Reached max pending evt count");
+				qdf_list_remove_front(
+					&ipa_ctx->pending_event,
+					(qdf_list_node_t **)&pending_event);
+			} else {
+				pending_event =
+					(struct wlan_ipa_uc_pending_event *)
+					qdf_mem_malloc(sizeof(
+					struct wlan_ipa_uc_pending_event));
+			}
+
+			if (!pending_event) {
+				ipa_err("Pending event memory alloc fail");
+				qdf_mutex_release(&ipa_ctx->ipa_lock);
+				return QDF_STATUS_E_NOMEM;
+			}
+
+			pending_event->net_dev = net_dev;
+			pending_event->device_mode = device_mode;
+			pending_event->sta_id = sta_id;
+			pending_event->session_id = session_id;
+			pending_event->type = type;
+			pending_event->is_loading = ipa_ctx->resource_loading;
+			qdf_mem_copy(pending_event->mac_addr,
+				     mac_addr, QDF_MAC_ADDR_SIZE);
+			qdf_list_insert_back(&ipa_ctx->pending_event,
+					     &pending_event->node);
+
+			qdf_mutex_release(&ipa_ctx->ipa_lock);
+
+			return QDF_STATUS_SUCCESS;
+		}
+		ipa_info("IPA resource %s completed",
+			 ipa_ctx->resource_loading ?
+			 "load" : "unload");
+	}
+
+	ipa_ctx->stats.event[type]++;
+
+	QDF_IPA_SET_META_MSG_TYPE(&meta, type);
+	switch (type) {
+	case QDF_IPA_STA_CONNECT:
+		qdf_mutex_acquire(&ipa_ctx->event_lock);
+
+		/* STA already connected and without disconnect, connect again
+		 * This is Roaming scenario
+		 */
+		if (ipa_ctx->sta_connected) {
+			iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
+			if (iface_ctx)
+				wlan_ipa_cleanup_iface(iface_ctx);
+		}
+
+		status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
+					   sta_id, session_id);
+		if (status != QDF_STATUS_SUCCESS) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			goto end;
+		}
+
+		if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
+		    (ipa_ctx->sap_num_connected_sta > 0) &&
+		    !ipa_ctx->sta_connected) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			wlan_ipa_uc_offload_enable_disable(ipa_ctx,
+				SIR_STA_RX_DATA_OFFLOAD, session_id,
+				true);
+			qdf_mutex_acquire(&ipa_ctx->event_lock);
+		}
+
+		ipa_ctx->vdev_to_iface[session_id] =
+				wlan_ipa_get_ifaceid(ipa_ctx, session_id);
+
+		ipa_ctx->sta_connected = 1;
+
+		qdf_mutex_release(&ipa_ctx->event_lock);
+
+		ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
+		break;
+
+	case QDF_IPA_AP_CONNECT:
+		qdf_mutex_acquire(&ipa_ctx->event_lock);
+
+		/* For DFS channel we get two start_bss event (before and after
+		 * CAC). Also when ACS range includes both DFS and non DFS
+		 * channels, we could possibly change channel many times due to
+		 * RADAR detection and chosen channel may not be a DFS channels.
+		 * So dont return error here. Just discard the event.
+		 */
+		if (wlan_ipa_get_iface(ipa_ctx, QDF_SAP_MODE)) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			return 0;
+		}
+
+		status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode,
+					   sta_id, session_id);
+		if (status != QDF_STATUS_SUCCESS) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			ipa_err("%s: Evt: %d, Interface setup failed",
+				msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
+			goto end;
+		}
+
+		if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			wlan_ipa_uc_offload_enable_disable(ipa_ctx,
+				SIR_AP_RX_DATA_OFFLOAD, session_id, true);
+			qdf_mutex_acquire(&ipa_ctx->event_lock);
+		}
+
+		ipa_ctx->vdev_to_iface[session_id] =
+				wlan_ipa_get_ifaceid(ipa_ctx, session_id);
+		qdf_mutex_release(&ipa_ctx->event_lock);
+		break;
+
+	case QDF_IPA_STA_DISCONNECT:
+		qdf_mutex_acquire(&ipa_ctx->event_lock);
+
+		if (!ipa_ctx->sta_connected) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			ipa_err("%s: Evt: %d, STA already disconnected",
+				msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta));
+			return QDF_STATUS_E_INVAL;
+		}
+
+		ipa_ctx->sta_connected = 0;
+
+		if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
+			ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
+				  msg_ex->name);
+		} else {
+			/* Disable IPA UC TX PIPE when STA disconnected */
+			if ((ipa_ctx->num_iface == 1) &&
+			    (ipa_ctx->activated_fw_pipe ==
+			     WLAN_IPA_UC_NUM_WDI_PIPE) &&
+			    !ipa_ctx->ipa_pipes_down)
+				wlan_ipa_uc_handle_last_discon(ipa_ctx);
+		}
+
+		if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
+		    (ipa_ctx->sap_num_connected_sta > 0)) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			wlan_ipa_uc_offload_enable_disable(ipa_ctx,
+				SIR_STA_RX_DATA_OFFLOAD, session_id, false);
+			qdf_mutex_acquire(&ipa_ctx->event_lock);
+			ipa_ctx->vdev_to_iface[session_id] =
+				WLAN_IPA_MAX_SESSION;
+		}
+
+		for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+			iface_ctx = &ipa_ctx->iface_context[i];
+
+			if (iface_ctx->dev == net_dev)
+				break;
+		}
+		if (i < WLAN_IPA_MAX_IFACE)
+			wlan_ipa_cleanup_iface(iface_ctx);
+
+		qdf_mutex_release(&ipa_ctx->event_lock);
+
+		ipa_debug("sta_connected=%d", ipa_ctx->sta_connected);
+		break;
+
+	case QDF_IPA_AP_DISCONNECT:
+		qdf_mutex_acquire(&ipa_ctx->event_lock);
+
+		if ((ipa_ctx->num_iface == 1) &&
+		    (ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) &&
+		    !ipa_ctx->ipa_pipes_down) {
+			if (cds_is_driver_unloading()) {
+				/*
+				 * We disable WDI pipes directly here since
+				 * IPA_OPCODE_TX/RX_SUSPEND message will not be
+				 * processed when unloading WLAN driver is in
+				 * progress
+				 */
+				wlan_ipa_uc_disable_pipes(ipa_ctx);
+			} else {
+				/*
+				 * This shouldn't happen :
+				 * No interface left but WDI pipes are still
+				 * active - force close WDI pipes
+				 */
+				ipa_err("No interface left but WDI pipes are still active");
+				wlan_ipa_uc_handle_last_discon(ipa_ctx);
+			}
+		}
+
+		if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			wlan_ipa_uc_offload_enable_disable(ipa_ctx,
+				SIR_AP_RX_DATA_OFFLOAD, session_id, false);
+			qdf_mutex_acquire(&ipa_ctx->event_lock);
+			ipa_ctx->vdev_to_iface[session_id] =
+				WLAN_IPA_MAX_SESSION;
+		}
+
+		for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) {
+			iface_ctx = &ipa_ctx->iface_context[i];
+
+			if (iface_ctx->dev == net_dev)
+				break;
+		}
+		if (i < WLAN_IPA_MAX_IFACE)
+			wlan_ipa_cleanup_iface(iface_ctx);
+
+		qdf_mutex_release(&ipa_ctx->event_lock);
+		break;
+
+	case QDF_IPA_CLIENT_CONNECT_EX:
+		if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
+			ipa_debug("%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED",
+				  net_dev->name, type);
+			return QDF_STATUS_SUCCESS;
+		}
+
+		qdf_mutex_acquire(&ipa_ctx->event_lock);
+		if (wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, true, sta_id,
+						   mac_addr)) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			ipa_err("%s: STA ID %d found", net_dev->name, sta_id);
+			return QDF_STATUS_SUCCESS;
+		}
+
+		/* Enable IPA UC Data PIPEs when first STA connected */
+		if (ipa_ctx->sap_num_connected_sta == 0 &&
+				ipa_ctx->uc_loaded == true) {
+			if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
+			    ipa_ctx->sta_connected) {
+				qdf_mutex_release(&ipa_ctx->event_lock);
+				wlan_ipa_uc_offload_enable_disable(ipa_ctx,
+							SIR_STA_RX_DATA_OFFLOAD,
+							session_id, true);
+				qdf_mutex_acquire(&ipa_ctx->event_lock);
+			}
+
+			status = wlan_ipa_uc_handle_first_con(ipa_ctx);
+			if (status != QDF_STATUS_SUCCESS) {
+				ipa_info("%s: handle 1st con fail",
+					 net_dev->name);
+
+				if (wlan_ipa_uc_sta_is_enabled(
+					ipa_ctx->config) &&
+				    ipa_ctx->sta_connected) {
+					qdf_mutex_release(&ipa_ctx->event_lock);
+					wlan_ipa_uc_offload_enable_disable(
+							ipa_ctx,
+							SIR_STA_RX_DATA_OFFLOAD,
+							session_id, false);
+				} else {
+					qdf_mutex_release(&ipa_ctx->event_lock);
+				}
+
+				return status;
+			}
+		}
+
+		ipa_ctx->sap_num_connected_sta++;
+
+		qdf_mutex_release(&ipa_ctx->event_lock);
+
+		QDF_IPA_SET_META_MSG_TYPE(&meta, type);
+		QDF_IPA_MSG_META_MSG_LEN(&meta) =
+			(sizeof(qdf_ipa_wlan_msg_ex_t) +
+				sizeof(qdf_ipa_wlan_hdr_attrib_val_t));
+		msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
+
+		if (msg_ex == NULL) {
+			ipa_err("msg_ex allocation failed");
+			return QDF_STATUS_E_NOMEM;
+		}
+		strlcpy(msg_ex->name, net_dev->name,
+			IPA_RESOURCE_NAME_MAX);
+		msg_ex->num_of_attribs = 1;
+		msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR;
+		if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
+			msg_ex->attribs[0].offset =
+				WLAN_IPA_UC_WLAN_HDR_DES_MAC_OFFSET;
+		} else {
+			msg_ex->attribs[0].offset =
+				WLAN_IPA_WLAN_HDR_DES_MAC_OFFSET;
+		}
+		memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr,
+		       IPA_MAC_ADDR_SIZE);
+
+		if (qdf_ipa_send_msg(&meta, msg_ex, wlan_ipa_msg_free_fn)) {
+			ipa_info("%s: Evt: %d send ipa msg fail",
+				 net_dev->name, type);
+			qdf_mem_free(msg_ex);
+			return QDF_STATUS_E_FAILURE;
+		}
+		ipa_ctx->stats.num_send_msg++;
+
+		ipa_info("sap_num_connected_sta=%d",
+			  ipa_ctx->sap_num_connected_sta);
+
+		return QDF_STATUS_SUCCESS;
+
+	case WLAN_CLIENT_DISCONNECT:
+		if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) {
+			ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED",
+				  msg_ex->name);
+			return QDF_STATUS_SUCCESS;
+		}
+
+		qdf_mutex_acquire(&ipa_ctx->event_lock);
+		if (!ipa_ctx->sap_num_connected_sta) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			ipa_err("%s: Evt: %d, Client already disconnected",
+				 msg_ex->name,
+				 QDF_IPA_MSG_META_MSG_TYPE(&meta));
+
+			return QDF_STATUS_SUCCESS;
+		}
+		if (!wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, false,
+						    sta_id, mac_addr)) {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+			ipa_err("%s: STA ID %d NOT found, not valid",
+				 msg_ex->name, sta_id);
+
+			return QDF_STATUS_SUCCESS;
+		}
+		ipa_ctx->sap_num_connected_sta--;
+
+		/* Disable IPA UC TX PIPE when last STA disconnected */
+		if (!ipa_ctx->sap_num_connected_sta &&
+				ipa_ctx->uc_loaded == true) {
+			if ((false == ipa_ctx->resource_unloading)
+			    && (WLAN_IPA_UC_NUM_WDI_PIPE ==
+				ipa_ctx->activated_fw_pipe) &&
+				!ipa_ctx->ipa_pipes_down) {
+				wlan_ipa_uc_handle_last_discon(ipa_ctx);
+			}
+
+			if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) &&
+			    ipa_ctx->sta_connected) {
+				qdf_mutex_release(&ipa_ctx->event_lock);
+				wlan_ipa_uc_offload_enable_disable(ipa_ctx,
+							SIR_STA_RX_DATA_OFFLOAD,
+							session_id, false);
+			} else {
+				qdf_mutex_release(&ipa_ctx->event_lock);
+			}
+		} else {
+			qdf_mutex_release(&ipa_ctx->event_lock);
+		}
+
+		ipa_info("sap_num_connected_sta=%d",
+			 ipa_ctx->sap_num_connected_sta);
+		break;
+
+	default:
+		return QDF_STATUS_SUCCESS;
+	}
+
+	QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t);
+	msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
+	if (!msg) {
+		ipa_err("msg allocation failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	QDF_IPA_SET_META_MSG_TYPE(&meta, type);
+	strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name,
+		IPA_RESOURCE_NAME_MAX);
+	qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN);
+
+	ipa_debug("%s: Evt: %d", QDF_IPA_WLAN_MSG_NAME(msg),
+		  QDF_IPA_MSG_META_MSG_TYPE(&meta));
+
+	if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) {
+
+		ipa_err("%s: Evt: %d fail",
+			QDF_IPA_WLAN_MSG_NAME(msg),
+			QDF_IPA_MSG_META_MSG_TYPE(&meta));
+		qdf_mem_free(msg);
+
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ipa_ctx->stats.num_send_msg++;
+
+end:
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * wlan_host_to_ipa_wlan_event() - convert wlan_ipa_wlan_event to ipa_wlan_event
+ * @wlan_ipa_event_type: IPA IPA WLAN event to be converted to an ipa_wlan_event
+ *
+ * Return: qdf_ipa_wlan_event representing the wlan_ipa_wlan_event
+ */
+static qdf_ipa_wlan_event
+wlan_host_to_ipa_wlan_event(enum wlan_ipa_wlan_event wlan_ipa_event_type)
+{
+	qdf_ipa_wlan_event_t ipa_event;
+
+	switch (wlan_ipa_event_type) {
+	case WLAN_IPA_CLIENT_CONNECT:
+		ipa_event = QDF_IPA_CLIENT_CONNECT;
+		break;
+	case WLAN_IPA_CLIENT_DISCONNECT:
+		ipa_event = QDF_IPA_CLIENT_DISCONNECT;
+		break;
+	case WLAN_IPA_AP_CONNECT:
+		ipa_event = QDF_IPA_AP_CONNECT;
+		break;
+	case WLAN_IPA_AP_DISCONNECT:
+		ipa_event = QDF_IPA_AP_DISCONNECT;
+		break;
+	case WLAN_IPA_STA_CONNECT:
+		ipa_event = QDF_IPA_STA_CONNECT;
+		break;
+	case WLAN_IPA_STA_DISCONNECT:
+		ipa_event = QDF_IPA_STA_DISCONNECT;
+		break;
+	case WLAN_IPA_CLIENT_CONNECT_EX:
+		ipa_event = QDF_IPA_CLIENT_CONNECT_EX;
+		break;
+	case WLAN_IPA_WLAN_EVENT_MAX:
+	default:
+		ipa_event =  QDF_IPA_WLAN_EVENT_MAX;
+		break;
+	}
+
+	return ipa_event;
+}
+
+/**
+ * wlan_ipa_wlan_evt() - SSR wrapper for __wlan_ipa_wlan_evt
+ * @net_dev: Interface net device
+ * @device_mode: Net interface device mode
+ * @sta_id: station id for the event
+ * @session_id: session id for the event
+ * @ipa_event_type: event enum of type wlan_ipa_wlan_event
+ * @mac_address: MAC address associated with the event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode,
+		      uint8_t sta_id, uint8_t session_id,
+		      enum wlan_ipa_wlan_event ipa_event_type,
+		      uint8_t *mac_addr)
+{
+	qdf_ipa_wlan_event type = wlan_host_to_ipa_wlan_event(ipa_event_type);
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	/* Data path offload only support for STA and SAP mode */
+	if ((device_mode == QDF_STA_MODE) ||
+	    (device_mode == QDF_SAP_MODE))
+		status  = __wlan_ipa_wlan_evt(net_dev, device_mode, sta_id,
+					      session_id, type, mac_addr);
+
+	return status;
+}
+
+/**
+ * wlan_ipa_uc_proc_pending_event() - Process IPA uC pending events
+ * @ipa_ctx: Global IPA IPA context
+ * @is_loading: Indicate if invoked during loading
+ *
+ * Return: None
+ */
+static void
+wlan_ipa_uc_proc_pending_event(struct wlan_ipa_priv *ipa_ctx, bool is_loading)
+{
+	unsigned int pending_event_count;
+	struct wlan_ipa_uc_pending_event *pending_event = NULL;
+
+	pending_event_count = qdf_list_size(&ipa_ctx->pending_event);
+	ipa_debug("Pending Event Count %d",  pending_event_count);
+	if (!pending_event_count) {
+		ipa_debug("No Pending Event");
+		return;
+	}
+
+	qdf_list_remove_front(&ipa_ctx->pending_event,
+			(qdf_list_node_t **)&pending_event);
+	while (pending_event != NULL) {
+		if (pending_event->is_loading == is_loading) {
+			__wlan_ipa_wlan_evt(pending_event->net_dev,
+					   pending_event->device_mode,
+					   pending_event->sta_id,
+					   pending_event->session_id,
+					   pending_event->type,
+					   pending_event->mac_addr);
+		}
+		qdf_mem_free(pending_event);
+		pending_event = NULL;
+		qdf_list_remove_front(&ipa_ctx->pending_event,
+				      (qdf_list_node_t **)&pending_event);
+	}
+}
+
 /**
  * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list
  * @ipa_ctx: IPA context
@@ -1372,8 +2253,10 @@ QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
 		return QDF_STATUS_E_NOMEM;
 	}
 
-	QDF_IPA_MSG_META_MSG_TYPE(&meta) = mcc_mode ?
-			WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
+	if (mcc_mode)
+		QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_MCC);
+	else
+		QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_SCC);
 	WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
 		    "ipa_send_msg(Evt:%d)",
 		    QDF_IPA_MSG_META_MSG_TYPE(&meta));
@@ -1423,6 +2306,12 @@ static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx)
 	}
 
 	cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
+
+	/* If already any STA connected, enable IPA/FW PIPEs */
+	if (ipa_ctx->sap_num_connected_sta) {
+		ipa_debug("Client already connected, enable IPA/FW PIPEs");
+		wlan_ipa_uc_handle_first_con(ipa_ctx);
+	}
 }
 
 /**
@@ -1465,6 +2354,7 @@ static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
 					wlan_ipa_send_mcc_scc_msg(ipa_ctx,
 							ipa_ctx->mcc_mode);
 			}
+			wlan_ipa_uc_proc_pending_event(ipa_ctx, true);
 			if (ipa_ctx->pending_cons_req)
 				qdf_ipa_rm_notify_completion(
 						QDF_IPA_RM_RESOURCE_GRANTED,
@@ -1487,6 +2377,7 @@ static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
 			if (wlan_ipa_is_rm_enabled(ipa_ctx->config))
 				qdf_ipa_rm_release_resource(
 					QDF_IPA_RM_RESOURCE_WLAN_PROD);
+			wlan_ipa_uc_proc_pending_event(ipa_ctx, false);
 			ipa_ctx->pending_cons_req = false;
 		}
 		qdf_mutex_release(&ipa_ctx->ipa_lock);

+ 27 - 0
components/ipa/core/src/wlan_ipa_main.c

@@ -84,6 +84,11 @@ bool ipa_config_is_enabled(void)
 	return wlan_ipa_is_enabled(g_ipa_config);
 }
 
+bool ipa_config_is_uc_enabled(void)
+{
+	return wlan_ipa_uc_is_enabled(g_ipa_config);
+}
+
 QDF_STATUS ipa_obj_setup(struct wlan_ipa_priv *ipa_ctx)
 {
 	return wlan_ipa_setup(ipa_ctx, g_ipa_config);
@@ -503,3 +508,25 @@ QDF_STATUS ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev,
 
 	return wlan_ipa_send_mcc_scc_msg(ipa_obj, mcc_mode);
 }
+
+QDF_STATUS ipa_wlan_evt(struct wlan_objmgr_pdev *pdev, qdf_netdev_t net_dev,
+			uint8_t device_mode, uint8_t sta_id, uint8_t session_id,
+			enum wlan_ipa_wlan_event ipa_event_type,
+			uint8_t *mac_addr)
+{
+	struct wlan_ipa_priv *ipa_obj;
+
+	if (!g_ipa_hw_support) {
+		ipa_info("ipa hw not present");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ipa_obj = ipa_pdev_get_priv_obj(pdev);
+	if (!ipa_obj) {
+		ipa_err("IPA object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return wlan_ipa_wlan_evt(net_dev, device_mode, sta_id, session_id,
+				 ipa_event_type, mac_addr);
+}

+ 55 - 0
components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h

@@ -40,6 +40,22 @@
  */
 bool ucfg_ipa_is_present(void);
 
+/**
+ * ucfg_ipa_is_enabled() - get IPA enable status
+ *
+ * Return: true - ipa is enabled
+ *         false - ipa is not enabled
+ */
+bool ucfg_ipa_is_enabled(void);
+
+/**
+ * ucfg_ipa_uc_is_enabled() - get IPA uC enable status
+ *
+ * Return: true - ipa uC is enabled
+ *         false - ipa uC is not enabled
+ */
+bool ucfg_ipa_uc_is_enabled(void);
+
 /**
  * ucfg_ipa_update_config() - Update IPA component config
  *
@@ -237,6 +253,24 @@ QDF_STATUS ucfg_ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev);
 QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev,
 				     bool mcc_mode);
 
+/**
+ * ucfg_ipa_wlan_evt() - IPA event handler
+ * @pdev: pdev obj
+ * @net_dev: Interface net device
+ * @device_mode: Net interface device mode
+ * @sta_id: station id for the event
+ * @session_id: session id for the event
+ * @type: event enum of type ipa_wlan_event
+ * @mac_address: MAC address associated with the event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_ipa_wlan_evt(struct wlan_objmgr_pdev *pdev,
+			     qdf_netdev_t net_dev, uint8_t device_mode,
+			     uint8_t sta_id, uint8_t session_id,
+			     enum wlan_ipa_wlan_event ipa_event_type,
+			     uint8_t *mac_addr);
+
 #else
 
 static inline bool ucfg_ipa_is_present(void)
@@ -248,6 +282,16 @@ static inline void ucfg_ipa_update_config(struct wlan_ipa_config *config)
 {
 }
 
+static inline bool ucfg_ipa_is_enabled(void)
+{
+	return false;
+}
+
+static inline bool ucfg_ipa_uc_is_enabled(void)
+{
+	return false;
+}
+
 static inline
 QDF_STATUS ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc,
 				     void *dp_soc)
@@ -367,5 +411,16 @@ QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev,
 {
 	return QDF_STATUS_SUCCESS;
 }
+
+static inline
+QDF_STATUS ucfg_ipa_wlan_evt(struct wlan_objmgr_pdev *pdev,
+			     qdf_netdev_t net_dev, uint8_t device_mode,
+			     uint8_t sta_id, uint8_t session_id,
+			     enum wlan_ipa_wlan_event ipa_event_type,
+			     uint8_t *mac_addr)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 #endif /* IPA_OFFLOAD */
 #endif /* _WLAN_IPA_UCFG_API_H_ */

+ 3 - 1
components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c

@@ -96,6 +96,8 @@ ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
 		return status;
 	}
 
+	ipa_obj->pdev = pdev;
+
 	status = ipa_obj_setup(ipa_obj);
 	if (QDF_IS_STATUS_ERROR(status)) {
 		ipa_err("Failed to setup ipa component");
@@ -106,7 +108,7 @@ ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev,
 		return status;
 	}
 
-	target_if_ipa_register_tx_ops(ipa_obj->ipa_tx_op);
+	target_if_ipa_register_tx_ops(&ipa_obj->ipa_tx_op);
 
 	ipa_info("ipa pdev attached");
 

+ 20 - 0
components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c

@@ -27,6 +27,16 @@ bool ucfg_ipa_is_present(void)
 	return ipa_is_hw_support();
 }
 
+bool ucfg_ipa_is_enabled(void)
+{
+	return ipa_config_is_enabled();
+}
+
+bool ucfg_ipa_uc_is_enabled(void)
+{
+	return ipa_config_is_uc_enabled();
+}
+
 void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc,
 				    void *txrx_handle)
 {
@@ -144,3 +154,13 @@ QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev,
 {
 	return ipa_send_mcc_scc_msg(pdev, mcc_mode);
 }
+
+QDF_STATUS ucfg_ipa_wlan_evt(struct wlan_objmgr_pdev *pdev,
+			     qdf_netdev_t net_dev, uint8_t device_mode,
+			     uint8_t sta_id, uint8_t session_id,
+			     enum wlan_ipa_wlan_event ipa_event_type,
+			     uint8_t *mac_addr)
+{
+	return ipa_wlan_evt(pdev, net_dev, device_mode, sta_id, session_id,
+			    ipa_event_type, mac_addr);
+}

+ 1 - 1
components/target_if/ipa/inc/target_if_ipa.h

@@ -34,7 +34,7 @@
  *
  * Return: None
  */
-void target_if_ipa_register_tx_ops(ipa_uc_offload_control_req ipa_tx_op);
+void target_if_ipa_register_tx_ops(ipa_uc_offload_control_req *ipa_tx_op);
 
 #endif /* IPA_OFFLOAD */
 #endif /* _TARGET_IF_IPA_H_ */

+ 2 - 7
components/target_if/ipa/src/target_if_ipa.c

@@ -44,12 +44,7 @@ target_if_ipa_uc_offload_control_req(struct wlan_objmgr_psoc *psoc,
 						   req);
 }
 
-void target_if_ipa_register_tx_ops(ipa_uc_offload_control_req ipa_tx_op)
+void target_if_ipa_register_tx_ops(ipa_uc_offload_control_req *ipa_tx_op)
 {
-	if (!ipa_tx_op) {
-		target_if_err("ipa_tx_op is null");
-		return;
-	}
-
-	ipa_tx_op = target_if_ipa_uc_offload_control_req;
+	*ipa_tx_op = target_if_ipa_uc_offload_control_req;
 }

+ 15 - 8
core/hdd/src/wlan_hdd_assoc.c

@@ -67,6 +67,7 @@
 #include "wlan_hdd_tsf.h"
 #include "wlan_utility.h"
 #include "wlan_p2p_ucfg_api.h"
+#include "wlan_ipa_ucfg_api.h"
 
 /* These are needed to recognize WPA and RSN suite types */
 #define HDD_WPA_OUI_SIZE 4
@@ -1617,10 +1618,13 @@ static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter,
 				     WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER,
 				     WLAN_CONTROL_PATH);
 
-	if (hdd_ipa_is_enabled(hdd_ctx))
-		hdd_ipa_wlan_evt(adapter, sta_ctx->conn_info.staId[0],
-				HDD_IPA_STA_DISCONNECT,
-				sta_ctx->conn_info.bssId.bytes);
+	if (ucfg_ipa_is_enabled())
+		ucfg_ipa_wlan_evt(hdd_ctx->hdd_pdev, adapter->dev,
+				  adapter->device_mode,
+				  sta_ctx->conn_info.staId[0],
+				  adapter->session_id,
+				  WLAN_IPA_STA_DISCONNECT,
+				  sta_ctx->conn_info.bssId.bytes);
 
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
 	wlan_hdd_auto_shutdown_enable(hdd_ctx, true);
@@ -2735,10 +2739,13 @@ hdd_association_completion_handler(struct hdd_adapter *adapter,
 		else
 			hdd_err("Wrong Staid: %d", roam_info->staId);
 
-		if (hdd_ipa_is_enabled(hdd_ctx))
-			hdd_ipa_wlan_evt(adapter, roam_info->staId,
-					 HDD_IPA_STA_CONNECT,
-					 roam_info->bssid.bytes);
+		if (ucfg_ipa_is_enabled())
+			ucfg_ipa_wlan_evt(hdd_ctx->hdd_pdev, adapter->dev,
+					  adapter->device_mode,
+					  roam_info->staId,
+					  adapter->session_id,
+					  WLAN_IPA_STA_CONNECT,
+					  roam_info->bssid.bytes);
 
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
 		wlan_hdd_auto_shutdown_enable(hdd_ctx, false);

+ 18 - 10
core/hdd/src/wlan_hdd_hostapd.c

@@ -1768,10 +1768,12 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 			}
 		}
 
-		if (hdd_ipa_is_enabled(hdd_ctx)) {
-			status = hdd_ipa_wlan_evt(adapter,
+		if (ucfg_ipa_is_enabled()) {
+			status = ucfg_ipa_wlan_evt(hdd_ctx->hdd_pdev,
+					adapter->dev, adapter->device_mode,
 					ap_ctx->broadcast_sta_id,
-					HDD_IPA_AP_CONNECT,
+					adapter->session_id,
+					WLAN_IPA_AP_CONNECT,
 					adapter->dev->dev_addr);
 			if (status) {
 				hdd_err("WLAN_AP_CONNECT event failed!!");
@@ -1913,10 +1915,12 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 
 		/* Invalidate the channel info. */
 		ap_ctx->operating_channel = 0;
-		if (hdd_ipa_is_enabled(hdd_ctx)) {
-			status = hdd_ipa_wlan_evt(adapter,
+		if (ucfg_ipa_is_enabled()) {
+			status = ucfg_ipa_wlan_evt(hdd_ctx->hdd_pdev,
+					adapter->dev, adapter->device_mode,
 					ap_ctx->broadcast_sta_id,
-					HDD_IPA_AP_DISCONNECT,
+					adapter->session_id,
+					WLAN_IPA_AP_DISCONNECT,
 					adapter->dev->dev_addr);
 			if (status) {
 				hdd_err("WLAN_AP_DISCONNECT event failed!!");
@@ -2168,10 +2172,14 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 
 		adapter->sta_info[staId].ecsa_capable = event->ecsa_capable;
 
-		if (hdd_ipa_is_enabled(hdd_ctx)) {
-			status = hdd_ipa_wlan_evt(adapter,
-					event->staId, HDD_IPA_CLIENT_CONNECT_EX,
-					event->staMac.bytes);
+		if (ucfg_ipa_is_enabled()) {
+			status = ucfg_ipa_wlan_evt(hdd_ctx->hdd_pdev,
+						   adapter->dev,
+						   adapter->device_mode,
+						   event->staId,
+						   adapter->session_id,
+						   WLAN_IPA_CLIENT_CONNECT_EX,
+						   event->staMac.bytes);
 			if (status) {
 				hdd_err("WLAN_CLIENT_CONNECT_EX event failed");
 				goto stopbss;

+ 1 - 1
core/hdd/src/wlan_hdd_main.c

@@ -8996,7 +8996,7 @@ static int hdd_update_cds_config(struct hdd_context *hdd_ctx)
 			hdd_ctx->config->reorderOffloadSupport;
 
 	/* IPA micro controller data path offload resource config item */
-	cds_cfg->uc_offload_enabled = hdd_ipa_uc_is_enabled(hdd_ctx);
+	cds_cfg->uc_offload_enabled = ucfg_ipa_uc_is_enabled();
 	if (!is_power_of_2(hdd_ctx->config->IpaUcTxBufCount)) {
 		/* IpaUcTxBufCount should be power of 2 */
 		hdd_debug("Round down IpaUcTxBufCount %d to nearest power of 2",

+ 9 - 7
core/hdd/src/wlan_hdd_softap_tx_rx.c

@@ -48,8 +48,8 @@
 #include <cdp_txrx_misc.h>
 #include <wlan_hdd_object_manager.h>
 #include "wlan_p2p_ucfg_api.h"
-#include <wlan_hdd_ipa.h>
 #include <wlan_hdd_regulatory.h>
+#include "wlan_ipa_ucfg_api.h"
 
 /* Preprocessor definitions and constants */
 #undef QCA_HDD_SAP_DUMP_SK_BUFF
@@ -864,12 +864,14 @@ QDF_STATUS hdd_softap_deregister_sta(struct hdd_adapter *adapter,
 			adapter->sta_info[staId].sta_mac.bytes);
 
 	if (adapter->sta_info[staId].in_use) {
-		if (hdd_ipa_uc_is_enabled(hdd_ctx)) {
-			hdd_ipa_wlan_evt(adapter,
-					 adapter->sta_info[staId].sta_id,
-					 HDD_IPA_CLIENT_DISCONNECT,
-					 adapter->sta_info[staId].sta_mac.
-					 bytes);
+		if (ucfg_ipa_is_enabled()) {
+			ucfg_ipa_wlan_evt(hdd_ctx->hdd_pdev, adapter->dev,
+					  adapter->device_mode,
+					  adapter->sta_info[staId].sta_id,
+					  adapter->session_id,
+					  WLAN_IPA_CLIENT_DISCONNECT,
+					  adapter->sta_info[staId].sta_mac.
+					  bytes);
 		}
 		spin_lock_bh(&adapter->sta_info_lock);
 		qdf_mem_zero(&adapter->sta_info[staId],