qcacld-3.0: Move IPA FW OP event handler to IPA component

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

Change-Id: Idecf12c33a5b4ab80de50626029ff43b5f9336a2
CRs-Fixed: 2177925
diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c
index d0d21db..c9be3aa 100644
--- a/components/ipa/core/src/wlan_ipa_core.c
+++ b/components/ipa/core/src/wlan_ipa_core.c
@@ -1353,6 +1353,240 @@
 	return NULL;
 }
 
+#ifndef QCA_LL_TX_FLOW_CONTROL_V2
+QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx,
+				     bool mcc_mode)
+{
+	qdf_ipa_msg_meta_t meta;
+	qdf_ipa_wlan_msg_t *msg;
+	int ret;
+
+	if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config))
+		return QDF_STATUS_SUCCESS;
+
+	/* Send SCC/MCC Switching event to IPA */
+	QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg);
+	msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta));
+	if (msg == NULL) {
+		ipa_err("msg allocation failed");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	QDF_IPA_MSG_META_MSG_TYPE(&meta) = mcc_mode ?
+			WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC;
+	WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG,
+		    "ipa_send_msg(Evt:%d)",
+		    QDF_IPA_MSG_META_MSG_TYPE(&meta));
+
+	ret = qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn);
+
+	if (ret) {
+		ipa_err("ipa_send_msg(Evt:%d) - fail=%d",
+			QDF_IPA_MSG_META_MSG_TYPE(&meta), ret);
+		qdf_mem_free(msg);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * wlan_ipa_uc_loaded_handler() - Process IPA uC loaded indication
+ * @ipa_ctx: ipa ipa local context
+ *
+ * Will handle IPA UC image loaded indication comes from IPA kernel
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx)
+{
+	struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev;
+	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
+	qdf_device_t qdf_dev = wlan_psoc_get_qdf_dev(psoc);
+	QDF_STATUS status;
+
+	ipa_info("UC READY");
+	if (true == ipa_ctx->uc_loaded) {
+		ipa_info("UC already loaded");
+		return;
+	}
+
+	ipa_ctx->uc_loaded = true;
+
+	/* Connect pipe */
+	status = wlan_ipa_wdi_setup(ipa_ctx, qdf_dev);
+	if (status) {
+		ipa_err("Failure to setup IPA pipes (status=%d)",
+			status);
+		return;
+	}
+
+	cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev);
+}
+
+/**
+ * wlan_ipa_uc_op_cb() - IPA uC operation callback
+ * @op_msg: operation message received from firmware
+ * @usr_ctxt: user context registered with TL (we register the IPA Global
+ *	context)
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
+			      struct wlan_ipa_priv *ipa_ctx)
+{
+	struct op_msg_type *msg = op_msg;
+	struct ipa_uc_fw_stats *uc_fw_stat;
+
+	if (!op_msg) {
+		ipa_err("INVALID ARG");
+		return;
+	}
+
+	if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
+		ipa_err("INVALID OPCODE %d",  msg->op_code);
+		qdf_mem_free(op_msg);
+		return;
+	}
+
+	ipa_debug("OPCODE=%d", msg->op_code);
+
+	if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_RESUME) ||
+	    (msg->op_code == WLAN_IPA_UC_OPCODE_RX_RESUME)) {
+		qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+		ipa_ctx->activated_fw_pipe++;
+		if (ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) {
+			ipa_ctx->resource_loading = false;
+			qdf_event_set(&ipa_ctx->ipa_resource_comp);
+			if (ipa_ctx->wdi_enabled == false) {
+				ipa_ctx->wdi_enabled = true;
+				if (wlan_ipa_uc_send_wdi_control_msg(true) == 0)
+					wlan_ipa_send_mcc_scc_msg(ipa_ctx,
+							ipa_ctx->mcc_mode);
+			}
+			if (ipa_ctx->pending_cons_req)
+				qdf_ipa_rm_notify_completion(
+						QDF_IPA_RM_RESOURCE_GRANTED,
+						QDF_IPA_RM_RESOURCE_WLAN_CONS);
+			ipa_ctx->pending_cons_req = false;
+		}
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	} else if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_SUSPEND) ||
+	    (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND)) {
+		qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+		ipa_ctx->activated_fw_pipe--;
+		if (!ipa_ctx->activated_fw_pipe) {
+			/*
+			 * Async return success from FW
+			 * Disable/suspend all the PIPEs
+			 */
+			ipa_ctx->resource_unloading = false;
+			qdf_event_set(&ipa_ctx->ipa_resource_comp);
+			wlan_ipa_uc_disable_pipes(ipa_ctx);
+			if (wlan_ipa_is_rm_enabled(ipa_ctx->config))
+				qdf_ipa_rm_release_resource(
+					QDF_IPA_RM_RESOURCE_WLAN_PROD);
+			ipa_ctx->pending_cons_req = false;
+		}
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	} else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
+		(ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_DEBUG)) {
+		uc_fw_stat = (struct ipa_uc_fw_stats *)
+			((uint8_t *)op_msg + sizeof(struct op_msg_type));
+
+		/* WLAN FW WDI stats */
+		wlan_ipa_print_fw_wdi_stats(ipa_ctx, uc_fw_stat);
+	} else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) &&
+		(ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_BW_CAL)) {
+		/* STATs from FW */
+		uc_fw_stat = (struct ipa_uc_fw_stats *)
+			((uint8_t *)op_msg + sizeof(struct op_msg_type));
+		qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+		ipa_ctx->ipa_tx_packets_diff = BW_GET_DIFF(
+			uc_fw_stat->tx_pkts_completed,
+			ipa_ctx->ipa_p_tx_packets);
+		ipa_ctx->ipa_rx_packets_diff = BW_GET_DIFF(
+			(uc_fw_stat->rx_num_ind_drop_no_space +
+			uc_fw_stat->rx_num_ind_drop_no_buf +
+			uc_fw_stat->rx_num_pkts_indicated),
+			ipa_ctx->ipa_p_rx_packets);
+
+		ipa_ctx->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed;
+		ipa_ctx->ipa_p_rx_packets =
+			(uc_fw_stat->rx_num_ind_drop_no_space +
+			uc_fw_stat->rx_num_ind_drop_no_buf +
+			uc_fw_stat->rx_num_pkts_indicated);
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	} else if (msg->op_code == WLAN_IPA_UC_OPCODE_UC_READY) {
+		qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+		wlan_ipa_uc_loaded_handler(ipa_ctx);
+		qdf_mutex_release(&ipa_ctx->ipa_lock);
+	} else if (wlan_ipa_uc_op_metering(ipa_ctx, op_msg)) {
+		ipa_err("Invalid message: op_code=%d, reason=%d",
+			msg->op_code, ipa_ctx->stat_req_reason);
+	}
+
+	qdf_mem_free(op_msg);
+}
+
+/**
+ * wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
+ * @work: uC OP work
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_fw_op_event_handler(void *data)
+{
+	struct op_msg_type *msg;
+	struct uc_op_work_struct *uc_op_work =
+				(struct uc_op_work_struct *)data;
+	struct wlan_ipa_priv *ipa_ctx = gp_ipa;
+
+	msg = uc_op_work->msg;
+	uc_op_work->msg = NULL;
+	ipa_debug("posted msg %d", msg->op_code);
+
+	wlan_ipa_uc_op_cb(msg, ipa_ctx);
+}
+
+/**
+ * wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
+ * @op_msg: operation message received from firmware
+ * @ipa_ctx: Global IPA context
+ *
+ * Return: None
+ */
+static void wlan_ipa_uc_op_event_handler(uint8_t *op_msg, void *ctx)
+{
+	struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)ctx;
+	struct op_msg_type *msg;
+	struct uc_op_work_struct *uc_op_work;
+
+	if (!ipa_ctx)
+		goto end;
+
+	msg = (struct op_msg_type *)op_msg;
+
+	if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) {
+		ipa_err("Invalid OP Code (%d)", msg->op_code);
+		goto end;
+	}
+
+	uc_op_work = &ipa_ctx->uc_op_work[msg->op_code];
+	if (uc_op_work->msg) {
+		/* When the same uC OPCODE is already pended, just return */
+		goto end;
+	}
+
+	uc_op_work->msg = msg;
+	qdf_sched_work(0, &uc_op_work->work);
+	return;
+
+end:
+	qdf_mem_free(op_msg);
+}
+
 QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx,
 			       qdf_device_t osdev)
 {
@@ -1397,14 +1631,40 @@
 		wlan_ipa_init_metering(ipa_ctx);
 	}
 
+	cdp_ipa_register_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev,
+			       wlan_ipa_uc_op_event_handler, (void *)ipa_ctx);
+
+	for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
+		qdf_create_work(0, &ipa_ctx->uc_op_work[i].work,
+				wlan_ipa_uc_fw_op_event_handler,
+				&ipa_ctx->uc_op_work[i]);
+		ipa_ctx->uc_op_work[i].msg = NULL;
+	}
+
 fail_return:
 	ipa_debug("exit: status=%d", status);
 	return status;
 }
 
+/**
+ * wlan_ipa_cleanup_pending_event() - Cleanup IPA pending event list
+ * @ipa_ctx: pointer to IPA IPA struct
+ *
+ * Return: none
+ */
+static void wlan_ipa_cleanup_pending_event(struct wlan_ipa_priv *ipa_ctx)
+{
+	struct wlan_ipa_uc_pending_event *pending_event = NULL;
+
+	while (qdf_list_remove_front(&ipa_ctx->pending_event,
+		(qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS)
+		qdf_mem_free(pending_event);
+}
+
 QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	int i;
 
 	ipa_debug("enter");
 
@@ -1423,6 +1683,16 @@
 				status);
 	}
 
+	qdf_mutex_acquire(&ipa_ctx->ipa_lock);
+	wlan_ipa_cleanup_pending_event(ipa_ctx);
+	qdf_mutex_release(&ipa_ctx->ipa_lock);
+
+	for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) {
+		qdf_cancel_work(&ipa_ctx->uc_op_work[i].work);
+		qdf_mem_free(ipa_ctx->uc_op_work[i].msg);
+		ipa_ctx->uc_op_work[i].msg = NULL;
+	}
+
 	ipa_debug("exit: ret=%d", status);
 	return status;
 }