diff --git a/Kbuild b/Kbuild index 1aa6abbc8495..7cc42a030ab4 100644 --- a/Kbuild +++ b/Kbuild @@ -1080,7 +1080,8 @@ ifeq ($(CONFIG_IPA_OFFLOAD), 1) IPA_OBJS := $(IPA_DIR)/dispatcher/src/wlan_ipa_ucfg_api.o \ $(IPA_DIR)/dispatcher/src/wlan_ipa_obj_mgmt_api.o \ $(IPA_DIR)/dispatcher/src/wlan_ipa_tgt_api.o \ - $(IPA_DIR)/core/src/wlan_ipa_main.o + $(IPA_DIR)/core/src/wlan_ipa_main.o \ + $(IPA_DIR)/core/src/wlan_ipa_core.o endif ########## CLD TARGET_IF ####### diff --git a/components/ipa/core/inc/wlan_ipa_core.h b/components/ipa/core/inc/wlan_ipa_core.h new file mode 100644 index 000000000000..d0d281ad92f3 --- /dev/null +++ b/components/ipa/core/inc/wlan_ipa_core.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_IPA_CORE_H_ +#define _WLAN_IPA_CORE_H_ + +#ifdef IPA_OFFLOAD + +#include "wlan_ipa_priv.h" +#include "wlan_ipa_public_struct.h" + +/** + * wlan_ipa_is_enabled() - Is IPA enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPA is enabled, false otherwise + */ +static inline bool wlan_ipa_is_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_ENABLE_MASK); +} + +/** + * wlan_ipa_uc_is_enabled() - Is IPA UC enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPA UC is enabled, false otherwise + */ +static inline bool wlan_ipa_uc_is_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_ENABLE_MASK); +} + +/** + * wlan_ipa_setup - IPA initialize and setup + * @ipa_ctx: IPA priv obj + * @ipa_cfg: IPA config + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_config *ipa_cfg); + +/** + * wlan_ipa_cleanup - IPA cleanup + * @ipa_ctx: IPA priv obj + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx); +#endif /* IPA_OFFLOAD */ +#endif /* _WLAN_IPA_CORE_H_ */ diff --git a/components/ipa/core/inc/wlan_ipa_main.h b/components/ipa/core/inc/wlan_ipa_main.h index c61601a415d0..e82682b7c62b 100644 --- a/components/ipa/core/inc/wlan_ipa_main.h +++ b/components/ipa/core/inc/wlan_ipa_main.h @@ -48,7 +48,7 @@ #define IPA_EXIT() ipa_debug("exit") /** - * wlan_ipa_is_present() - get IPA hw status + * ipa_check_hw_present() - get IPA hw status * * ipa_uc_reg_rdyCB is not directly designed to check * ipa hw status. This is an undocumented function which @@ -57,7 +57,7 @@ * Return: true - ipa hw present * false - ipa hw not present */ -bool wlan_ipa_is_present(void); +bool ipa_check_hw_present(void); /** * wlan_get_pdev_ipa_obj() - private API to get ipa pdev object @@ -77,6 +77,58 @@ ipa_pdev_get_priv_obj(struct wlan_objmgr_pdev *pdev) return pdev_obj; } +/** + * ipa_is_hw_support() - Is IPA HW support? + * + * Return: true if IPA HW is present or false otherwise + */ +bool ipa_is_hw_support(void); + +/** + * ipa_config_mem_alloc() - IPA config allocation + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ipa_config_mem_alloc(void); + +/** + * ipa_config_mem_free() - IPA config mem free + * + * Return: None + */ +void ipa_config_mem_free(void); + +/** + * ipa_config_update() - IPA component config update + * @config: IPA config + * + * Return: None + */ +void ipa_config_update(struct wlan_ipa_config *config); + +/** + * ipa_config_is_enabled() - Is IPA config enabled? + * + * Return: true if IPA is enabled in IPA config + */ +bool ipa_config_is_enabled(void); + +/** + * ipa_obj_setup() - IPA obj initialization and setup + * @ipa_ctx: IPA obj context + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ipa_obj_setup(struct wlan_ipa_priv *ipa_ctx); + +/** + * ipa_obj_cleanup() - IPA obj cleanup + * @ipa_ctx: IPA obj context + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ipa_obj_cleanup(struct wlan_ipa_priv *ipa_ctx); + /** * ipa_send_uc_offload_enable_disable() - wdi enable/disable notify to fw * @pdev: objmgr pdev object @@ -86,5 +138,23 @@ ipa_pdev_get_priv_obj(struct wlan_objmgr_pdev *pdev) */ QDF_STATUS ipa_send_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev, struct ipa_uc_offload_control_params *req); + +/** + * ipa_set_dp_handle() - set dp soc handle + * @psoc: psoc handle + * @dp_soc: dp soc handle + * + * Return: None + */ +void ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, void *dp_soc); + +/** + * ipa_set_txrx_handle() - set dp txrx handle + * @psoc: psoc handle + * @txrx_handle: dp txrx handle + * + * Return: None + */ +void ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, void *txrx_handle); #endif /* IPA_OFFLOAD */ #endif /* end of _WLAN_IPA_MAIN_H_ */ diff --git a/components/ipa/core/src/wlan_ipa_core.c b/components/ipa/core/src/wlan_ipa_core.c new file mode 100644 index 000000000000..a66b0825e506 --- /dev/null +++ b/components/ipa/core/src/wlan_ipa_core.c @@ -0,0 +1,678 @@ +/* + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Include Files */ +#include "wlan_ipa_core.h" +#include "wlan_ipa_main.h" +#include +#include "cdp_txrx_ipa.h" +#include "wal_rx_desc.h" + +static struct wlan_ipa_priv *gp_ipa; + +static struct wlan_ipa_iface_2_client { + qdf_ipa_client_type_t cons_client; + qdf_ipa_client_type_t prod_client; +} wlan_ipa_iface_2_client[WLAN_IPA_MAX_IFACE] = { + { + QDF_IPA_CLIENT_WLAN2_CONS, QDF_IPA_CLIENT_WLAN1_PROD + }, { + QDF_IPA_CLIENT_WLAN3_CONS, QDF_IPA_CLIENT_WLAN1_PROD + }, { + QDF_IPA_CLIENT_WLAN4_CONS, QDF_IPA_CLIENT_WLAN1_PROD + } +}; + +/** + * wlan_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled? + * @ipa_cfg: IPA config + * + * Return: true if STA mode IPA uC offload is enabled, false otherwise + */ +static inline bool wlan_ipa_uc_sta_is_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_STA_ENABLE_MASK); +} + +/** + * wlan_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled? + * @ipa_cfg: IPA config + * + * Return: true if pre-filter is enabled, otherwise false + */ +static inline +bool wlan_ipa_is_pre_filter_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, + WLAN_IPA_PRE_FILTER_ENABLE_MASK); +} + +/** + * wlan_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPv6 is enabled, otherwise false + */ +static inline bool wlan_ipa_is_ipv6_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_IPV6_ENABLE_MASK); +} + +/** + * wlan_ipa_msg_free_fn() - Free an IPA message + * @buff: pointer to the IPA message + * @len: length of the IPA message + * @type: type of IPA message + * + * Return: None + */ +static void wlan_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type) +{ + ipa_debug("msg type:%d, len:%d", type, len); + qdf_mem_free(buff); +} + +/** + * wlan_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback + * @priv_ctxt: IPA context + * + * Will be called by IPA context. + * It's atomic context, then should be scheduled to kworker thread + * + * Return: None + */ +static void wlan_ipa_uc_loaded_uc_cb(void *priv_ctxt) +{ + struct wlan_ipa_priv *ipa_ctx; + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work; + + if (!priv_ctxt) { + ipa_err("Invalid IPA context"); + return; + } + + ipa_ctx = priv_ctxt; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) { + ipa_err("op_msg allocation fails"); + return; + } + + msg->op_code = WLAN_IPA_UC_OPCODE_UC_READY; + + uc_op_work = &ipa_ctx->uc_op_work[msg->op_code]; + + /* When the same uC OPCODE is already pended, just return */ + if (uc_op_work->msg) + goto done; + + uc_op_work->msg = msg; + qdf_sched_work(0, &uc_op_work->work); + /* work handler will free the msg buffer */ + return; + +done: + qdf_mem_free(msg); +} + +/** + * wlan_ipa_uc_send_wdi_control_msg() - Set WDI control message + * @ctrl: WDI control value + * + * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise. + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_ipa_uc_send_wdi_control_msg(bool ctrl) +{ + qdf_ipa_msg_meta_t meta; + qdf_ipa_wlan_msg_t *ipa_msg; + int ret = 0; + + /* WDI enable message to IPA */ + QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg); + ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta)); + if (!ipa_msg) { + ipa_err("msg allocation failed"); + return QDF_STATUS_E_NOMEM; + } + + if (ctrl) + QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_ENABLE); + else + QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_DISABLE); + + ipa_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta)); + ret = qdf_ipa_send_msg(&meta, ipa_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(ipa_msg); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef CONFIG_IPA_WDI_UNIFIED_API + +/* + * TODO: Get WDI version through FW capabilities + */ +#ifdef CONFIG_LITHIUM +static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) +{ + ipa_ctx->wdi_version = IPA_WDI_3; +} +#elif defined(QCA_WIFI_3_0) +static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) +{ + ipa_ctx->wdi_version = IPA_WDI_2; +} +#else +static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) +{ + ipa_ctx->wdi_version = IPA_WDI_1; +} +#endif + +static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_ipa_wdi_init_in_params_t in; + qdf_ipa_wdi_init_out_params_t out; + int ret; + + ipa_ctx->uc_loaded = false; + + QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version; + QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb; + QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = (void *)ipa_ctx; + + ret = qdf_ipa_wdi_init(&in, &out); + if (ret) { + ipa_err("ipa_wdi_init failed with ret=%d", ret); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) { + ipa_info("IPA uC READY"); + ipa_ctx->uc_loaded = true; + ipa_ctx->is_smmu_enabled = + QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out); + ipa_info("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled); + } else { + return QDF_STATUS_E_BUSY; + } + + return QDF_STATUS_SUCCESS; +} + +static inline int wlan_ipa_wdi_cleanup(void) +{ + int ret; + + ret = qdf_ipa_wdi_cleanup(); + if (ret) + ipa_info("ipa_wdi_cleanup failed ret=%d", ret); + return ret; +} + +static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + struct ipa_sys_connect_params *sys, + uint32_t *handle) +{ + return 0; +} + +static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + uint32_t handle) +{ + return 0; +} + +#else /* CONFIG_IPA_WDI_UNIFIED_API */ + +static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) +{ +} + +static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx) +{ + struct ipa_wdi_uc_ready_params uc_ready_param; + + ipa_ctx->uc_loaded = false; + uc_ready_param.priv = (void *)ipa_ctx; + uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb; + if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) { + ipa_info("UC Ready CB register fail"); + return QDF_STATUS_E_FAILURE; + } + + if (true == uc_ready_param.is_uC_ready) { + ipa_info("UC Ready"); + ipa_ctx->uc_loaded = true; + } else { + return QDF_STATUS_E_BUSY; + } + + return QDF_STATUS_SUCCESS; +} + +static inline int wlan_ipa_wdi_cleanup(void) +{ + int ret; + + ret = qdf_ipa_uc_dereg_rdyCB(); + if (ret) + ipa_info("UC Ready CB deregister fail"); + return ret; +} + +static inline int wlan_ipa_wdi_setup_sys_pipe( + struct wlan_ipa_priv *ipa_ctx, + struct ipa_sys_connect_params *sys, uint32_t *handle) +{ + return qdf_ipa_setup_sys_pipe(sys, handle); +} + +static inline int wlan_ipa_wdi_teardown_sys_pipe( + struct wlan_ipa_priv *ipa_ctx, + uint32_t handle) +{ + return qdf_ipa_teardown_sys_pipe(handle); +} + +#endif /* CONFIG_IPA_WDI_UNIFIED_API */ + +/** + * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +static int wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + uint32_t max_desc_cnt; + struct wlan_ipa_tx_desc *tmp_desc; + + max_desc_cnt = ipa_ctx->config->txbuf_count; + + qdf_list_create(&ipa_ctx->tx_desc_list, max_desc_cnt); + + qdf_spin_lock_bh(&ipa_ctx->q_lock); + for (i = 0; i < max_desc_cnt; i++) { + tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc)); + tmp_desc->id = i; + tmp_desc->ipa_tx_desc_ptr = NULL; + qdf_list_insert_back(&ipa_ctx->tx_desc_list, + &tmp_desc->node); + tmp_desc++; + } + + ipa_ctx->stats.num_tx_desc_q_cnt = 0; + ipa_ctx->stats.num_tx_desc_error = 0; + + qdf_spin_unlock_bh(&ipa_ctx->q_lock); + + return QDF_STATUS_SUCCESS; +} + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes + * @ipa_ctx: Global IPA IPA context + * @desc_fifo_sz: Number of descriptors + * + * Return: 0 on success, negative errno on error + */ +static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + int32_t desc_fifo_sz) +{ + int i, ret = 0; + qdf_ipa_sys_connect_params_t *ipa; + + /*setup TX pipes */ + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params; + + ipa->client = wlan_ipa_iface_2_client[i].cons_client; + ipa->desc_fifo_sz = desc_fifo_sz; + ipa->priv = &ipa_ctx->iface_context[i]; + ipa->notify = NULL; + + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + ipa->ipa_ep_cfg.hdr.hdr_len = + WLAN_IPA_UC_WLAN_TX_HDR_LEN; + ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; + ipa->ipa_ep_cfg.hdr.hdr_additional_const_len = + WLAN_IPA_UC_WLAN_8023_HDR_SIZE; + ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + } else { + ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN; + } + ipa->ipa_ep_cfg.mode.mode = IPA_BASIC; + + ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa, + &ipa_ctx->sys_pipe[i].conn_hdl); + if (ret) { + ipa_err("Failed for pipe %d ret: %d", i, ret); + return ret; + } + ipa_ctx->sys_pipe[i].conn_hdl_valid = 1; + } + + return ret; +} +#else +/** + * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes + * @ipa_ctx: Global IPA IPA context + * @desc_fifo_sz: Number of descriptors + * + * Return: 0 on success, negative errno on error + */ +static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + int32_t desc_fifo_sz) +{ + /* + * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2 + * is enabled, where per vdev descriptors are supported in firmware. + */ + return 0; +} +#endif + +/** + * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes + * @ipa_ctx: Global IPA IPA context + * @desc_fifo_sz: Number of descriptors + * + * Return: 0 on success, negative errno on error + */ +static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + int32_t desc_fifo_sz) +{ + int ret = 0; + qdf_ipa_sys_connect_params_t *ipa; + + /* + * Hard code it here, this can be extended if in case + * PROD pipe is also per interface. + * Right now there is no advantage of doing this. + */ + ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params; + + ipa->client = IPA_CLIENT_WLAN1_PROD; + + ipa->desc_fifo_sz = desc_fifo_sz; + ipa->priv = ipa_ctx; + ipa->notify = NULL; + + ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN; + ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1; + ipa->ipa_ep_cfg.mode.mode = IPA_BASIC; + + ret = qdf_ipa_setup_sys_pipe(ipa, + &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl); + if (ret) { + ipa_err("Failed for RX pipe: %d", ret); + return ret; + } + ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1; + + return ret; +} + +/** + * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes + * @ipa_ctx: Global IPA IPA context + * + * Return: 0 on success, negative errno on error + */ +static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx) +{ + int i = WLAN_IPA_MAX_IFACE, ret = 0; + uint32_t desc_fifo_sz; + + /* The maximum number of descriptors that can be provided to a BAM at + * once is one less than the total number of descriptors that the buffer + * can contain. + * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof + * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can + * be provided at once. + * Because of above requirement, one extra descriptor will be added to + * make sure hardware always has one descriptor. + */ + desc_fifo_sz = ipa_ctx->config->desc_size + + SPS_DESC_SIZE; + + ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz); + if (ret) { + ipa_err("Failed for TX pipe: %d", ret); + goto setup_sys_pipe_fail; + } + + if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz); + if (ret) { + ipa_err("Failed for RX pipe: %d", ret); + goto setup_sys_pipe_fail; + } + } + + /* Allocate free Tx desc list */ + ret = wlan_ipa_alloc_tx_desc_list(ipa_ctx); + if (ret) + goto setup_sys_pipe_fail; + + return ret; + +setup_sys_pipe_fail: + + for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) { + if (ipa_ctx->sys_pipe[i].conn_hdl_valid) + qdf_ipa_teardown_sys_pipe( + ipa_ctx->sys_pipe[i].conn_hdl); + qdf_mem_zero(&ipa_ctx->sys_pipe[i], + sizeof(struct wlan_ipa_sys_pipe)); + } + + return ret; +} + +/** + * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes + * @ipa_ctx: Global IPA IPA context + * + * Return: None + */ +static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx) +{ + int ret = 0, i; + struct wlan_ipa_tx_desc *tmp_desc; + qdf_ipa_rx_data_t *ipa_tx_desc; + qdf_list_node_t *node; + + for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) { + if (ipa_ctx->sys_pipe[i].conn_hdl_valid) { + ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx, + ipa_ctx->sys_pipe[i].conn_hdl); + if (ret) + ipa_err("Failed:%d", ret); + + ipa_ctx->sys_pipe[i].conn_hdl_valid = 0; + } + } + + while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) == + QDF_STATUS_SUCCESS) { + tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc, + node); + ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr; + if (ipa_tx_desc) + qdf_ipa_free_skb(ipa_tx_desc); + + qdf_mem_free(tmp_desc); + } +} + +/** + * wlan_ipa_setup() - IPA initialization function + * @ipa_ctx: IPA context + * @ipa_cfg: IPA config + * + * Allocate ipa_ctx resources, ipa pipe resource and register + * wlan interface with IPA module. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_config *ipa_cfg) +{ + int ret, i; + struct wlan_ipa_iface_context *iface_context = NULL; + QDF_STATUS status; + + ipa_debug("enter"); + + gp_ipa = ipa_ctx; + ipa_ctx->num_iface = 0; + ipa_ctx->config = ipa_cfg; + + wlan_ipa_wdi_get_wdi_version(ipa_ctx); + + /* Create the interface context */ + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_context = &ipa_ctx->iface_context[i]; + iface_context->ipa_ctx = ipa_ctx; + iface_context->cons_client = + wlan_ipa_iface_2_client[i].cons_client; + iface_context->prod_client = + wlan_ipa_iface_2_client[i].prod_client; + iface_context->iface_id = i; + iface_context->dev = NULL; + iface_context->device_mode = QDF_MAX_NO_OF_MODE; + iface_context->tl_context = NULL; + qdf_spinlock_create(&iface_context->interface_lock); + } + + qdf_spinlock_create(&ipa_ctx->pm_lock); + qdf_spinlock_create(&ipa_ctx->q_lock); + qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head); + qdf_list_create(&ipa_ctx->pending_event, 1000); + qdf_mutex_create(&ipa_ctx->event_lock); + qdf_mutex_create(&ipa_ctx->ipa_lock); + + for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) + qdf_mem_zero(&ipa_ctx->sys_pipe[i], + sizeof(struct wlan_ipa_sys_pipe)); + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats)); + ipa_ctx->sap_num_connected_sta = 0; + ipa_ctx->ipa_tx_packets_diff = 0; + ipa_ctx->ipa_rx_packets_diff = 0; + ipa_ctx->ipa_p_tx_packets = 0; + ipa_ctx->ipa_p_rx_packets = 0; + ipa_ctx->resource_loading = false; + ipa_ctx->resource_unloading = false; + ipa_ctx->sta_connected = 0; + ipa_ctx->ipa_pipes_down = true; + ipa_ctx->wdi_enabled = false; + /* Setup IPA system pipes */ + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + ret = wlan_ipa_setup_sys_pipe(ipa_ctx); + if (ret) + goto fail_create_sys_pipe; + } + + status = wlan_ipa_wdi_init(ipa_ctx); + if (status == QDF_STATUS_E_BUSY) + status = wlan_ipa_uc_send_wdi_control_msg(false); + if (status != QDF_STATUS_SUCCESS) { + ipa_err("IPA WDI init failed: ret=%d", ret); + goto fail_create_sys_pipe; + } + } else { + ret = wlan_ipa_setup_sys_pipe(ipa_ctx); + if (ret) + goto fail_create_sys_pipe; + } + + qdf_event_create(&ipa_ctx->ipa_resource_comp); + + ipa_debug("exit: success"); + + return QDF_STATUS_SUCCESS; + +fail_create_sys_pipe: + qdf_spinlock_destroy(&ipa_ctx->pm_lock); + gp_ipa = NULL; + ipa_debug("exit: fail"); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_ipa_iface_context *iface_context = NULL; + int i; + + if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) + wlan_ipa_teardown_sys_pipe(ipa_ctx); + + /* Teardown IPA sys_pipe for MCC */ + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) + wlan_ipa_teardown_sys_pipe(ipa_ctx); + + qdf_spinlock_destroy(&ipa_ctx->pm_lock); + qdf_spinlock_destroy(&ipa_ctx->q_lock); + + /* destroy the interface lock */ + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_context = &ipa_ctx->iface_context[i]; + qdf_spinlock_destroy(&iface_context->interface_lock); + } + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + wlan_ipa_wdi_cleanup(); + qdf_mutex_destroy(&ipa_ctx->event_lock); + qdf_mutex_destroy(&ipa_ctx->ipa_lock); + qdf_list_destroy(&ipa_ctx->pending_event); + + } + + gp_ipa = NULL; + + return QDF_STATUS_SUCCESS; +} diff --git a/components/ipa/core/src/wlan_ipa_main.c b/components/ipa/core/src/wlan_ipa_main.c index b30e531c12ba..d0a8ec19eec0 100644 --- a/components/ipa/core/src/wlan_ipa_main.c +++ b/components/ipa/core/src/wlan_ipa_main.c @@ -21,15 +21,77 @@ */ #include "wlan_ipa_main.h" +#include "wlan_ipa_core.h" #include "wlan_ipa_tgt_api.h" -bool wlan_ipa_is_present(void) +static struct wlan_ipa_config *g_ipa_config; +static bool g_ipa_hw_support; + +bool ipa_check_hw_present(void) { /* Check if ipa hw is enabled */ - if (WLAN_IPA_CHECK_HW() != -EPERM) + if (WLAN_IPA_CHECK_HW() != -EPERM) { + g_ipa_hw_support = true; return true; - else + } else { return false; + } +} + +QDF_STATUS ipa_config_mem_alloc(void) +{ + struct wlan_ipa_config *ipa_cfg; + + ipa_cfg = qdf_mem_malloc(sizeof(*ipa_cfg)); + if (!ipa_cfg) { + ipa_err("Failed to allocate memory for ipa config"); + return QDF_STATUS_E_NOMEM; + } + + g_ipa_config = ipa_cfg; + + return QDF_STATUS_SUCCESS; +} + +void ipa_config_mem_free(void) +{ + if (!g_ipa_config) { + ipa_err("IPA config already freed"); + return; + } + + qdf_mem_free(g_ipa_config); + g_ipa_config = NULL; +} + +bool ipa_is_hw_support(void) +{ + return g_ipa_hw_support; +} + +void ipa_config_update(struct wlan_ipa_config *config) +{ + if (!g_ipa_config) { + ipa_err("IPA config already freed"); + return; + } + + qdf_mem_copy(g_ipa_config, config, sizeof(*g_ipa_config)); +} + +bool ipa_config_is_enabled(void) +{ + return wlan_ipa_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); +} + +QDF_STATUS ipa_obj_cleanup(struct wlan_ipa_priv *ipa_ctx) +{ + return wlan_ipa_cleanup(ipa_ctx); } QDF_STATUS ipa_send_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev, @@ -37,3 +99,61 @@ QDF_STATUS ipa_send_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev, { return tgt_ipa_uc_offload_enable_disable(pdev, req); } + +void ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, void *dp_soc) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_ipa_priv *ipa_obj; + + if (!g_ipa_hw_support) { + ipa_info("ipa hw not present"); + return; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_IPA_ID); + + if (!pdev) { + ipa_err("Failed to get pdev handle"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); + return; + } + + ipa_obj->dp_soc = dp_soc; + wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); +} + +void ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, void *txrx_handle) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_ipa_priv *ipa_obj; + + if (!g_ipa_hw_support) { + ipa_info("ipa hw not present"); + return; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_IPA_ID); + + if (!pdev) { + ipa_err("Failed to get pdev handle"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); + return; + } + + ipa_obj->dp_pdev = txrx_handle; + wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); +} diff --git a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h index 7c91e30aaa01..31f7ab3bde55 100644 --- a/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h +++ b/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h @@ -39,6 +39,34 @@ * false - ipa hw not present */ bool ucfg_ipa_is_present(void); + +/** + * ucfg_ipa_update_config() - Update IPA component config + * + * Return: None + */ +void ucfg_ipa_update_config(struct wlan_ipa_config *config); + +/** + * ucfg_ipa_set_dp_handle() - register DP handle + * @psoc: psoc handle + * @dp_soc: data path soc handle + * + * Return: None + */ +void ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_soc); + +/** + * ucfg_ipa_set_txrx_handle() - register pdev txrx handler + * @psoc: psoc handle + * @txrx_handle: data path pdev txrx handle + * + * Return: None + */ +void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle); + #else static inline bool ucfg_ipa_is_present(void) @@ -46,5 +74,22 @@ static inline bool ucfg_ipa_is_present(void) return false; } +static inline void ucfg_ipa_update_config(struct wlan_ipa_config *config) +{ +} + +static inline +QDF_STATUS ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_soc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle) +{ + return QDF_STATUS_SUCCESS; +} #endif /* IPA_OFFLOAD */ #endif /* _WLAN_IPA_UCFG_API_H_ */ diff --git a/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c b/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c index 4697b5acd38f..b57e76cf1d74 100644 --- a/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c +++ b/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c @@ -51,6 +51,7 @@ ipa_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev, if (QDF_IS_STATUS_ERROR(status)) ipa_err("Failed to detatch ipa pdev object"); + ipa_obj_cleanup(ipa_obj); qdf_mem_free(ipa_obj); return status; @@ -72,10 +73,17 @@ ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, ipa_info("ipa pdev created"); + if (!ipa_config_is_enabled()) { + ipa_info("IPA is disabled"); + wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_IPA, + ipa_pdev_obj_destroy_notification, NULL); + return QDF_STATUS_COMP_DISABLED; + } + ipa_obj = qdf_mem_malloc(sizeof(*ipa_obj)); if (!ipa_obj) { ipa_err("Failed to allocate memory for ipa pdev object"); - return QDF_STATUS_E_FAILURE; + return QDF_STATUS_E_NOMEM; } status = wlan_objmgr_pdev_component_obj_attach(pdev, @@ -88,6 +96,16 @@ ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, return status; } + status = ipa_obj_setup(ipa_obj); + if (QDF_IS_STATUS_ERROR(status)) { + ipa_err("Failed to setup ipa component"); + wlan_objmgr_pdev_component_obj_detach(pdev, + WLAN_UMAC_COMP_IPA, + ipa_obj); + qdf_mem_free(ipa_obj); + return status; + } + target_if_ipa_register_tx_ops(ipa_obj->ipa_tx_op); ipa_info("ipa pdev attached"); @@ -101,11 +119,15 @@ QDF_STATUS ipa_init(void) ipa_info("ipa module dispatcher init"); - if (!wlan_ipa_is_present()) { + if (!ipa_check_hw_present()) { ipa_info("ipa hw not present"); return status; } + status = ipa_config_mem_alloc(); + if (QDF_IS_STATUS_ERROR(status)) + return status; + status = wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_IPA, ipa_pdev_obj_create_notification, NULL); @@ -138,7 +160,7 @@ QDF_STATUS ipa_deinit(void) ipa_info("ipa module dispatcher deinit"); - if (!wlan_ipa_is_present()) { + if (!ipa_is_hw_support()) { ipa_info("ipa hw not present"); return status; } @@ -153,5 +175,7 @@ QDF_STATUS ipa_deinit(void) if (QDF_IS_STATUS_ERROR(status)) ipa_err("Failed to unregister pdev create handler"); + ipa_config_mem_free(); + return status; } diff --git a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c index 79b1d71c9690..3f602d72b0ff 100644 --- a/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c +++ b/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c @@ -24,5 +24,22 @@ bool ucfg_ipa_is_present(void) { - return wlan_ipa_is_present(); + return ipa_is_hw_support(); +} + +void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle) +{ + return ipa_set_txrx_handle(psoc, txrx_handle); +} + +void ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_soc) +{ + return ipa_set_dp_handle(psoc, dp_soc); +} + +void ucfg_ipa_update_config(struct wlan_ipa_config *config) +{ + ipa_config_update(config); } diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c index 531331c6c54d..bc70728a4a01 100644 --- a/core/cds/src/cds_api.c +++ b/core/cds/src/cds_api.c @@ -70,6 +70,7 @@ #include "target_type.h" #include "wlan_ocb_ucfg_api.h" #include "qdf_platform.h" +#include "wlan_ipa_ucfg_api.h" #ifdef ENABLE_SMMU_S1_TRANSLATION #include "pld_common.h" diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 8bc79922a64a..3b40e8df0e5a 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -1968,6 +1968,11 @@ void hdd_update_tgt_cfg(void *context, void *param) ret = hdd_update_green_ap_config(hdd_ctx); + ucfg_ipa_set_dp_handle(hdd_ctx->hdd_psoc, + cds_get_context(QDF_MODULE_ID_SOC)); + ucfg_ipa_set_txrx_handle(hdd_ctx->hdd_psoc, + cds_get_context(QDF_MODULE_ID_TXRX)); + if (cds_cfg) { if (hdd_ctx->config->enable_sub_20_channel_width != WLAN_SUB_20_CH_WIDTH_NONE && !cfg->sub_20_support) { @@ -2553,6 +2558,36 @@ hdd_update_cds_ac_specs_params(struct hdd_context *hdd_ctx) } } +#ifdef IPA_OFFLOAD +/** + * hdd_update_ipa_component_config() - update ipa config + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static void hdd_update_ipa_component_config(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg = hdd_ctx->config; + struct wlan_ipa_config ipa_cfg; + + ipa_cfg.ipa_config = cfg->IpaConfig; + ipa_cfg.desc_size = cfg->IpaDescSize; + ipa_cfg.txbuf_count = cfg->IpaUcTxBufCount; + ipa_cfg.bus_bw_high = cfg->busBandwidthHighThreshold; + ipa_cfg.bus_bw_medium = cfg->busBandwidthMediumThreshold; + ipa_cfg.bus_bw_low = cfg->busBandwidthLowThreshold; + ipa_cfg.ipa_bw_high = cfg->IpaHighBandwidthMbps; + ipa_cfg.ipa_bw_medium = cfg->IpaMediumBandwidthMbps; + ipa_cfg.ipa_bw_low = cfg->IpaLowBandwidthMbps; + + ucfg_ipa_update_config(&ipa_cfg); +} +#else +static void hdd_update_ipa_component_config(struct hdd_context *hdd_ctx) +{ +} +#endif + #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH static enum policy_mgr_con_mode wlan_hdd_get_mode_for_non_connected_vdev( struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) @@ -2747,6 +2782,8 @@ int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, goto hif_close; } + hdd_update_ipa_component_config(hdd_ctx); + ret = hdd_update_config(hdd_ctx); if (ret) { hdd_err("Failed to update configuration; errno: %d",