diff --git a/ipa/core/inc/wlan_ipa_core.h b/ipa/core/inc/wlan_ipa_core.h index e0369fa3e9..c7583d6943 100644 --- a/ipa/core/inc/wlan_ipa_core.h +++ b/ipa/core/inc/wlan_ipa_core.h @@ -513,5 +513,24 @@ QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx); */ QDF_STATUS wlan_ipa_resume(struct wlan_ipa_priv *ipa_ctx); +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * wlan_ipa_send_mcc_scc_msg() - Send IPA WLAN_SWITCH_TO_MCC/SCC message + * @ipa_ctx: IPA context + * @mcc_mode: 0=MCC/1=SCC + * + * Return: QDF STATUS + */ +QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx, + bool mcc_mode); +#else +static inline +QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx, + bool mcc_mode) +{ + return QDF_STATUS_SUCCESS; +} +#endif + #endif /* IPA_OFFLOAD */ #endif /* _WLAN_IPA_CORE_H_ */ diff --git a/ipa/core/inc/wlan_ipa_main.h b/ipa/core/inc/wlan_ipa_main.h index 068b9da777..d804b75a5a 100644 --- a/ipa/core/inc/wlan_ipa_main.h +++ b/ipa/core/inc/wlan_ipa_main.h @@ -316,5 +316,15 @@ QDF_STATUS ipa_uc_ol_init(struct wlan_objmgr_pdev *pdev, */ QDF_STATUS ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev); +/** + * ipa_send_mcc_scc_msg() - Send IPA WLAN_SWITCH_TO_MCC/SCC message + * @pdev: pdev obj + * @mcc_mode: 0=MCC/1=SCC + * + * Return: QDF STATUS + */ +QDF_STATUS ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode); + #endif /* IPA_OFFLOAD */ #endif /* end of _WLAN_IPA_MAIN_H_ */ diff --git a/ipa/core/src/wlan_ipa_core.c b/ipa/core/src/wlan_ipa_core.c index d0d21dbf38..c9be3aaac7 100644 --- a/ipa/core/src/wlan_ipa_core.c +++ b/ipa/core/src/wlan_ipa_core.c @@ -1353,6 +1353,240 @@ struct wlan_ipa_iface_context 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 @@ QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx, 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 @@ QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx) 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; } diff --git a/ipa/core/src/wlan_ipa_main.c b/ipa/core/src/wlan_ipa_main.c index d109ffba57..fdfaa2d68c 100644 --- a/ipa/core/src/wlan_ipa_main.c +++ b/ipa/core/src/wlan_ipa_main.c @@ -484,3 +484,22 @@ QDF_STATUS ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev) return wlan_ipa_uc_ol_deinit(ipa_obj); } + +QDF_STATUS ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode) +{ + 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_send_mcc_scc_msg(ipa_obj, mcc_mode); +} diff --git a/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h b/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h index b30dcb5059..80869844ee 100644 --- a/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h +++ b/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h @@ -228,6 +228,15 @@ QDF_STATUS ucfg_ipa_uc_ol_init(struct wlan_objmgr_pdev *pdev, */ QDF_STATUS ucfg_ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev); +/** + * ucfg_ipa_send_mcc_scc_msg() - Send IPA WLAN_SWITCH_TO_MCC/SCC message + * @mcc_mode: 0=MCC/1=SCC + * + * Return: QDF STATUS + */ +QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode); + #else static inline bool ucfg_ipa_is_present(void) @@ -351,5 +360,12 @@ QDF_STATUS ucfg_ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev) { return QDF_STATUS_SUCCESS; } + +static inline +QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode) +{ + return QDF_STATUS_SUCCESS; +} #endif /* IPA_OFFLOAD */ #endif /* _WLAN_IPA_UCFG_API_H_ */ diff --git a/ipa/dispatcher/src/wlan_ipa_ucfg_api.c b/ipa/dispatcher/src/wlan_ipa_ucfg_api.c index 2b8ce8a7ea..61c66bb971 100644 --- a/ipa/dispatcher/src/wlan_ipa_ucfg_api.c +++ b/ipa/dispatcher/src/wlan_ipa_ucfg_api.c @@ -138,3 +138,9 @@ QDF_STATUS ucfg_ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev) { return ipa_uc_ol_deinit(pdev); } + +QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode) +{ + return ipa_send_mcc_scc_msg(pdev, mcc_mode); +}