From b4f591d8aa3f341bdafa99e9e5c669a10acb9f5c Mon Sep 17 00:00:00 2001 From: Yun Park Date: Wed, 29 Mar 2017 15:51:01 -0700 Subject: [PATCH] qcacld-3.0: Enable WLAN host data path support for IPA WDI3.0 Change to support WLAN Napier host autonomy data path architecture. Change-Id: I80e8f609587d0df85d2da9fb0f41cb49e02a9d2f CRs-Fixed: 2033368 --- Kbuild | 11 + core/dp/htt/htt_t2h.c | 72 ++- core/dp/ol/inc/ol_cfg.h | 4 +- core/dp/txrx/ol_tx.c | 3 +- core/dp/txrx/ol_txrx.c | 171 +----- core/dp/txrx/ol_txrx_ipa.c | 936 +++++++++++++++++++++++++++++++ core/dp/txrx/ol_txrx_ipa.h | 132 +++++ core/dp/txrx/ol_txrx_types.h | 13 +- core/hdd/inc/wlan_hdd_ipa.h | 2 +- core/hdd/src/wlan_hdd_ipa.c | 1028 +++++----------------------------- core/wma/src/wma_main.c | 169 ++++-- 11 files changed, 1416 insertions(+), 1125 deletions(-) create mode 100644 core/dp/txrx/ol_txrx_ipa.c create mode 100644 core/dp/txrx/ol_txrx_ipa.h diff --git a/Kbuild b/Kbuild index c70b0832cf7e..a8eb85bd858f 100644 --- a/Kbuild +++ b/Kbuild @@ -9,6 +9,7 @@ endif ifeq ($(CONFIG_CNSS_QCA6290), y) CONFIG_LITHIUM := y CONFIG_WLAN_FEATURE_11AX := y + CONFIG_IPA := n endif ifeq ($(CONFIG_CLD_HL_SDIO_CORE), y) @@ -1061,6 +1062,10 @@ ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) TXRX_OBJS += $(TXRX_DIR)/ol_txrx_flow_control.o endif +ifeq ($(CONFIG_IPA_OFFLOAD), 1) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_ipa.o +endif + ifeq ($(CONFIG_LITHIUM), y) ############ DP 3.0 ############ DP_INC := -I$(WLAN_COMMON_ROOT)/dp/inc \ @@ -1085,6 +1090,10 @@ DP_OBJS += $(DP_SRC)/dp_tx_flow_control.o endif endif +ifeq ($(CONFIG_IPA_OFFLOAD), 1) +DP_OBJS += $(DP_SRC)/dp_ipa.o +endif + ############ CFG ############ WCFG_DIR := wlan_cfg WCFG_INC := -I$(WLAN_COMMON_INC)/$(WCFG_DIR) @@ -1998,9 +2007,11 @@ CDEFINES += -DFEATURE_GREEN_AP endif #Stats & Quota Metering feature +ifeq ($(CONFIG_IPA),y) ifeq ($(CONFIG_QCACLD_FEATURE_METERING),y) CDEFINES += -DFEATURE_METERING endif +endif #Enable RX Full re-order OL feature only "LL and NON-MDM9630 platform" ifneq ($(CONFIG_ARCH_MDM9630), y) diff --git a/core/dp/htt/htt_t2h.c b/core/dp/htt/htt_t2h.c index 5fe1bc2322ca..c3d51abe5523 100644 --- a/core/dp/htt/htt_t2h.c +++ b/core/dp/htt/htt_t2h.c @@ -151,6 +151,50 @@ static uint8_t *htt_t2h_mac_addr_deswizzle(uint8_t *tgt_mac_addr, #endif } +/** + * htt_ipa_op_response() - invoke an event handler from FW + * @pdev: Handle (pointer) to HTT pdev. + * @msg_word: htt msg + * + * Return: None + */ +#ifdef IPA_OFFLOAD +static void htt_ipa_op_response(struct htt_pdev_t *pdev, uint32_t *msg_word) +{ + uint8_t op_code; + uint16_t len; + uint8_t *op_msg_buffer; + uint8_t *msg_start_ptr; + + htc_pm_runtime_put(pdev->htc_pdev); + msg_start_ptr = (uint8_t *) msg_word; + op_code = + HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(*msg_word); + msg_word++; + len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*msg_word); + + op_msg_buffer = + qdf_mem_malloc(sizeof + (struct htt_wdi_ipa_op_response_t) + + len); + if (!op_msg_buffer) { + qdf_print("OPCODE messsage buffer alloc fail"); + return; + } + qdf_mem_copy(op_msg_buffer, + msg_start_ptr, + sizeof(struct htt_wdi_ipa_op_response_t) + + len); + cdp_ipa_op_response(cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_pdev *)pdev->txrx_pdev, + op_msg_buffer); +} +#else +static void htt_ipa_op_response(struct htt_pdev_t *pdev, uint32_t *msg_word) +{ +} +#endif + /* Target to host Msg/event handler for low priority messages*/ static void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, bool free_msg_buf) @@ -426,33 +470,7 @@ static void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, case HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE: { - uint8_t op_code; - uint16_t len; - uint8_t *op_msg_buffer; - uint8_t *msg_start_ptr; - - htc_pm_runtime_put(pdev->htc_pdev); - msg_start_ptr = (uint8_t *) msg_word; - op_code = - HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(*msg_word); - msg_word++; - len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*msg_word); - - op_msg_buffer = - qdf_mem_malloc(sizeof - (struct htt_wdi_ipa_op_response_t) + - len); - if (!op_msg_buffer) { - qdf_print("OPCODE messsage buffer alloc fail"); - break; - } - qdf_mem_copy(op_msg_buffer, - msg_start_ptr, - sizeof(struct htt_wdi_ipa_op_response_t) + - len); - cdp_ipa_op_response(cds_get_context(QDF_MODULE_ID_SOC), - (struct cdp_pdev *)pdev->txrx_pdev, - op_msg_buffer); + htt_ipa_op_response(pdev, msg_word); break; } diff --git a/core/dp/ol/inc/ol_cfg.h b/core/dp/ol/inc/ol_cfg.h index 3fe4762c9293..40123a48e4fd 100644 --- a/core/dp/ol/inc/ol_cfg.h +++ b/core/dp/ol/inc/ol_cfg.h @@ -572,7 +572,7 @@ unsigned int ol_cfg_ipa_uc_rx_ind_ring_size(struct cdp_cfg *cfg_pdev); */ unsigned int ol_cfg_ipa_uc_tx_partition_base(struct cdp_cfg *cfg_pdev); void ol_cfg_set_ipa_uc_tx_partition_base(struct cdp_cfg *cfg_pdev, - uint32_t value); + uint32_t value); #else static inline unsigned int ol_cfg_ipa_uc_offload_enabled( struct cdp_cfg *cfg_pdev) @@ -605,7 +605,7 @@ static inline unsigned int ol_cfg_ipa_uc_tx_partition_base( } static inline void ol_cfg_set_ipa_uc_tx_partition_base( - struct cdp_cfg *cfg_pdev, uint32_t value) + void *cfg_pdev, uint32_t value) { } #endif /* IPA_OFFLOAD */ diff --git a/core/dp/txrx/ol_tx.c b/core/dp/txrx/ol_tx.c index 0ed5376d173c..7a18c28d5161 100644 --- a/core/dp/txrx/ol_tx.c +++ b/core/dp/txrx/ol_tx.c @@ -286,8 +286,7 @@ qdf_nbuf_t ol_tx_data(void *data_vdev, qdf_nbuf_t skb) } #ifdef IPA_OFFLOAD -qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_vdev *vdev, - qdf_nbuf_t skb) +qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_vdev *vdev, qdf_nbuf_t skb) { struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); qdf_nbuf_t ret; diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index a80d57c0a251..663cccb1ac3d 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -86,6 +86,8 @@ #include #include #include +#include + #ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID ol_txrx_peer_handle ol_txrx_peer_find_by_local_id(struct cdp_pdev *pdev, @@ -4519,159 +4521,7 @@ ol_txrx_ll_set_tx_pause_q_depth(uint8_t vdev_id, int pause_q_depth) } #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ -#ifdef IPA_OFFLOAD /** - * ol_txrx_ipa_uc_get_resource() - Client request resource information - * @pdev: handle to the HTT instance - * @ce_sr_base_paddr: copy engine source ring base physical address - * @ce_sr_ring_size: copy engine source ring size - * @ce_reg_paddr: copy engine register physical address - * @tx_comp_ring_base_paddr: tx comp ring base physical address - * @tx_comp_ring_size: tx comp ring size - * @tx_num_alloc_buffer: number of allocated tx buffer - * @rx_rdy_ring_base_paddr: rx ready ring base physical address - * @rx_rdy_ring_size: rx ready ring size - * @rx_proc_done_idx_paddr: rx process done index physical address - * @rx_proc_done_idx_vaddr: rx process done index virtual address - * @rx2_rdy_ring_base_paddr: rx done ring base physical address - * @rx2_rdy_ring_size: rx done ring size - * @rx2_proc_done_idx_paddr: rx done index physical address - * @rx2_proc_done_idx_vaddr: rx done index virtual address - * - * OL client will reuqest IPA UC related resource information - * Resource information will be distributted to IPA module - * All of the required resources should be pre-allocated - * - * Return: none - */ -static void -ol_txrx_ipa_uc_get_resource(struct cdp_pdev *ppdev, - struct ol_txrx_ipa_resources *ipa_res) -{ - struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - - htt_ipa_uc_get_resource(pdev->htt_pdev, - &ipa_res->ce_sr_base_paddr, - &ipa_res->ce_sr_ring_size, - &ipa_res->ce_reg_paddr, - &ipa_res->tx_comp_ring_base_paddr, - &ipa_res->tx_comp_ring_size, - &ipa_res->tx_num_alloc_buffer, - &ipa_res->rx_rdy_ring_base_paddr, - &ipa_res->rx_rdy_ring_size, - &ipa_res->rx_proc_done_idx_paddr, - &ipa_res->rx_proc_done_idx_vaddr, - &ipa_res->rx2_rdy_ring_base_paddr, - &ipa_res->rx2_rdy_ring_size, - &ipa_res->rx2_proc_done_idx_paddr, - &ipa_res->rx2_proc_done_idx_vaddr); -} - -/** - * ol_txrx_ipa_uc_set_doorbell_paddr() - Client set IPA UC doorbell register - * @pdev: handle to the HTT instance - * @ipa_uc_tx_doorbell_paddr: tx comp doorbell physical address - * @ipa_uc_rx_doorbell_paddr: rx ready doorbell physical address - * - * IPA UC let know doorbell register physical address - * WLAN firmware will use this physical address to notify IPA UC - * - * Return: none - */ -static void -ol_txrx_ipa_uc_set_doorbell_paddr(struct cdp_pdev *ppdev, - qdf_dma_addr_t ipa_tx_uc_doorbell_paddr, - qdf_dma_addr_t ipa_rx_uc_doorbell_paddr) -{ - struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - htt_ipa_uc_set_doorbell_paddr(pdev->htt_pdev, - ipa_tx_uc_doorbell_paddr, - ipa_rx_uc_doorbell_paddr); -} - -/** - * ol_txrx_ipa_uc_set_active() - Client notify IPA UC data path active or not - * @pdev: handle to the HTT instance - * @ipa_uc_tx_doorbell_paddr: tx comp doorbell physical address - * @ipa_uc_rx_doorbell_paddr: rx ready doorbell physical address - * - * IPA UC let know doorbell register physical address - * WLAN firmware will use this physical address to notify IPA UC - * - * Return: none - */ -static void -ol_txrx_ipa_uc_set_active(struct cdp_pdev *ppdev, bool uc_active, bool is_tx) -{ - struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - htt_h2t_ipa_uc_set_active(pdev->htt_pdev, uc_active, is_tx); -} - -/** - * ol_txrx_ipa_uc_op_response() - Handle OP command response from firmware - * @pdev: handle to the HTT instance - * @op_msg: op response message from firmware - * - * Return: none - */ -static void ol_txrx_ipa_uc_op_response(struct cdp_pdev *ppdev, uint8_t *op_msg) -{ - struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - if (pdev->ipa_uc_op_cb) { - pdev->ipa_uc_op_cb(op_msg, pdev->osif_dev); - } else { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: IPA callback function is not registered", __func__); - qdf_mem_free(op_msg); - return; - } -} - -/** - * ol_txrx_ipa_uc_register_op_cb() - Register OP handler function - * @pdev: handle to the HTT instance - * @op_cb: handler function pointer - * @osif_dev: register client context - * - * Return: none - */ -static void -ol_txrx_ipa_uc_register_op_cb(struct cdp_pdev *ppdev, - ipa_uc_op_cb_type op_cb, void *osif_dev) -{ - struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - pdev->ipa_uc_op_cb = op_cb; - pdev->osif_dev = osif_dev; -} - -/** - * ol_txrx_ipa_uc_get_stat() - Get firmware wdi status - * @pdev: handle to the HTT instance - * - * Return: none - */ -static void ol_txrx_ipa_uc_get_stat(struct cdp_pdev *ppdev) -{ - struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - htt_h2t_ipa_uc_get_stats(pdev->htt_pdev); -} - -static void ol_txrx_ipa_uc_get_share_stats(struct cdp_pdev *ppdev, - uint8_t reset_stats) -{ - struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - htt_h2t_ipa_uc_get_share_stats(pdev->htt_pdev, reset_stats); -} - -static void ol_txrx_ipa_uc_set_quota(struct cdp_pdev *ppdev, - uint64_t quota_bytes) -{ - struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; - htt_h2t_ipa_uc_set_quota(pdev->htt_pdev, quota_bytes); -} -#endif /* IPA_UC_OFFLOAD */ - -/* * ol_txrx_display_stats() - Display OL TXRX display stats * @value: Module id for which stats needs to be displayed * @@ -5566,8 +5416,8 @@ static struct cdp_lflowctl_ops ol_ops_l_flowctl = { #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ }; -static struct cdp_ipa_ops ol_ops_ipa = { #ifdef IPA_OFFLOAD +static struct cdp_ipa_ops ol_ops_ipa = { .ipa_get_resource = ol_txrx_ipa_uc_get_resource, .ipa_set_doorbell_paddr = ol_txrx_ipa_uc_set_doorbell_paddr, .ipa_set_active = ol_txrx_ipa_uc_set_active, @@ -5576,10 +5426,21 @@ static struct cdp_ipa_ops ol_ops_ipa = { .ipa_get_stat = ol_txrx_ipa_uc_get_stat, .ipa_tx_data_frame = ol_tx_send_ipa_data_frame, .ipa_set_uc_tx_partition_base = ol_cfg_set_ipa_uc_tx_partition_base, + .ipa_enable_autonomy = ol_txrx_ipa_enable_autonomy, + .ipa_disable_autonomy = ol_txrx_ipa_disable_autonomy, + .ipa_setup = ol_txrx_ipa_setup, + .ipa_cleanup = ol_txrx_ipa_cleanup, + .ipa_setup_iface = ol_txrx_ipa_setup_iface, + .ipa_cleanup_iface = ol_txrx_ipa_cleanup_iface, + .ipa_enable_pipes = ol_txrx_ipa_enable_pipes, + .ipa_disable_pipes = ol_txrx_ipa_disable_pipes, + .ipa_set_perf_level = ol_txrx_ipa_set_perf_level, +#ifdef FEATURE_METERING .ipa_uc_get_share_stats = ol_txrx_ipa_uc_get_share_stats, .ipa_uc_set_quota = ol_txrx_ipa_uc_set_quota -#endif /* IPA_OFFLOAD */ +#endif }; +#endif static struct cdp_bus_ops ol_ops_bus = { .bus_suspend = ol_txrx_bus_suspend, @@ -5696,7 +5557,9 @@ static struct cdp_ops ol_txrx_ops = { .cfg_ops = &ol_ops_cfg, .flowctl_ops = &ol_ops_flowctl, .l_flowctl_ops = &ol_ops_l_flowctl, +#ifdef IPA_OFFLOAD .ipa_ops = &ol_ops_ipa, +#endif .bus_ops = &ol_ops_bus, .ocb_ops = &ol_ops_ocb, .peer_ops = &ol_ops_peer, diff --git a/core/dp/txrx/ol_txrx_ipa.c b/core/dp/txrx/ol_txrx_ipa.c new file mode 100644 index 000000000000..dbbd10439076 --- /dev/null +++ b/core/dp/txrx/ol_txrx_ipa.c @@ -0,0 +1,936 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/*=== includes ===*/ +/* header files for OS primitives */ +#include /* uint32_t, etc. */ +#include /* qdf_mem_malloc,free */ +#include /* qdf_device_t, qdf_print */ +#include /* qdf_spinlock */ +#include /* qdf_atomic_read */ + +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +/* Required for WLAN_FEATURE_FASTPATH */ +#include +#endif +/* header files for utilities */ +#include /* TAILQ */ + +/* header files for configuration API */ +#include /* ol_cfg_is_high_latency */ +#include + +/* header files for HTT API */ +#include +#include + +/* header files for our own APIs */ +#include +#include +#include +#include +#include +#include +/* header files for our internal definitions */ +#include /* TXRX_ASSERT, etc. */ +#include /* WDI events */ +#include /* ol_tx_ll */ +#include /* ol_rx_deliver */ +#include /* ol_txrx_peer_find_attach, etc. */ +#include /* ol_rx_pn_check, etc. */ +#include /* ol_rx_fwd_check, etc. */ +#include /* OL_RX_REORDER_TIMEOUT_INIT, etc. */ +#include +#include /* ol_tx_discard_target_frms */ +#include /* ol_tx_desc_frame_free */ +#include +#include /* ol_tx_sched_attach, etc. */ +#include +#include +#include +#include +#include +#include +#include "wma.h" +#include "hif.h" +#include +#ifndef REMOVE_PKT_LOG +#include "pktlog_ac.h" +#endif +#include "epping_main.h" +#include + +#ifdef IPA_OFFLOAD +#include + +/* For Tx pipes, use Ethernet-II Header format */ +struct ol_txrx_ipa_uc_tx_hdr ipa_uc_tx_hdr = { + { + 0x0000, + 0x00000000, + 0x00000000 + }, + { + 0x00000000 + }, + { + {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc}, + {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff}, + 0x0008 + } +}; + +/** + * ol_txrx_ipa_uc_get_resource() - Client request resource information + * @pdev: handle to the HTT instance + * + * OL client will reuqest IPA UC related resource information + * Resource information will be distributted to IPA module + * All of the required resources should be pre-allocated + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_uc_get_resource(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + + htt_ipa_uc_get_resource(pdev->htt_pdev, + &ipa_res->ce_sr_base_paddr, + &ipa_res->ce_sr_ring_size, + &ipa_res->ce_reg_paddr, + &ipa_res->tx_comp_ring_base_paddr, + &ipa_res->tx_comp_ring_size, + &ipa_res->tx_num_alloc_buffer, + &ipa_res->rx_rdy_ring_base_paddr, + &ipa_res->rx_rdy_ring_size, + &ipa_res->rx_proc_done_idx_paddr, + &ipa_res->rx_proc_done_idx_vaddr, + &ipa_res->rx2_rdy_ring_base_paddr, + &ipa_res->rx2_rdy_ring_size, + &ipa_res->rx2_proc_done_idx_paddr, + &ipa_res->rx2_proc_done_idx_vaddr); + + if ((0 == ipa_res->ce_sr_base_paddr) || + (0 == ipa_res->tx_comp_ring_base_paddr) || + (0 == ipa_res->rx_rdy_ring_base_paddr) +#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3) + || (0 == ipa_res->rx2_rdy_ring_base_paddr) +#endif + ) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_uc_set_doorbell_paddr() - Client set IPA UC doorbell register + * @pdev: handle to the HTT instance + * + * IPA UC let know doorbell register physical address + * WLAN firmware will use this physical address to notify IPA UC + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_uc_set_doorbell_paddr(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + int ret; + + ret = htt_ipa_uc_set_doorbell_paddr(pdev->htt_pdev, + ipa_res->tx_comp_doorbell_paddr, + ipa_res->rx_ready_doorbell_paddr); + + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "htt_ipa_uc_set_doorbell_paddr fail: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_uc_set_active() - Client notify IPA UC data path active or not + * @pdev: handle to the HTT instance + * @uc_active: WDI UC path enable or not + * @is_tx: TX path or RX path + * + * IPA UC let know doorbell register physical address + * WLAN firmware will use this physical address to notify IPA UC + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_uc_set_active(struct cdp_pdev *ppdev, bool uc_active, + bool is_tx) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + int ret; + + ret = htt_h2t_ipa_uc_set_active(pdev->htt_pdev, uc_active, is_tx); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "htt_h2t_ipa_uc_set_active fail: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_uc_op_response() - Handle OP command response from firmware + * @pdev: handle to the device instance + * @op_msg: op response message from firmware + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_op_response(struct cdp_pdev *ppdev, uint8_t *op_msg) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + + if (pdev->ipa_uc_op_cb) { + pdev->ipa_uc_op_cb(op_msg, pdev->usr_ctxt); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: IPA callback function is not registered", __func__); + qdf_mem_free(op_msg); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_uc_register_op_cb() - Register OP handler function + * @pdev: handle to the device instance + * @op_cb: handler function pointer + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_register_op_cb(struct cdp_pdev *ppdev, + ipa_uc_op_cb_type op_cb, void *usr_ctxt) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + + pdev->ipa_uc_op_cb = op_cb; + pdev->usr_ctxt = usr_ctxt; + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_uc_get_stat() - Get firmware wdi status + * @pdev: handle to the HTT instance + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_get_stat(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + int ret; + + ret = htt_h2t_ipa_uc_get_stats(pdev->htt_pdev); + + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "htt_h2t_ipa_uc_get_stats fail: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_enable_autonomy() - Enable autonomy RX path + * @pdev: handle to the device instance + * + * Set all RX packet route to IPA + * Return: none + */ +QDF_STATUS ol_txrx_ipa_enable_autonomy(struct cdp_pdev *ppdev) +{ + /* TBD */ + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_disable_autonomy() - Disable autonomy RX path + * @pdev: handle to the device instance + * + * Disable RX packet route to host + * Return: none + */ +QDF_STATUS ol_txrx_ipa_disable_autonomy(struct cdp_pdev *ppdev) +{ + /* TBD */ + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_setup() - Setup and connect IPA pipes + * @pdev: handle to the device instance + * @ipa_i2w_cb: IPA to WLAN callback + * @ipa_w2i_cb: WLAN to IPA callback + * @ipa_wdi_meter_notifier_cb: IPA WDI metering callback + * @ipa_desc_size: IPA descriptor size + * @ipa_priv: handle to the HTT instance + * @is_rm_enabled: Is IPA RM enabled or not + * @p_tx_pipe_handle: pointer to Tx pipe handle + * @p_rx_pipe_handle: pointer to Rx pipe handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *ppdev, void *ipa_i2w_cb, + void *ipa_w2i_cb, void *ipa_wdi_meter_notifier_cb, + uint32_t ipa_desc_size, void *ipa_priv, + bool is_rm_enabled, uint32_t *p_tx_pipe_handle, + uint32_t *p_rx_pipe_handle) + +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + struct ipa_wdi_in_params pipe_in; + struct ipa_wdi_out_params pipe_out; + int ret; + + qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params)); + qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params)); + + /* TX PIPE */ + pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len = + OL_TXRX_IPA_UC_WLAN_8023_HDR_SIZE; + pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; + pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS; + pipe_in.sys.desc_fifo_sz = ipa_desc_size; + pipe_in.sys.priv = ipa_priv; + pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + pipe_in.sys.notify = ipa_i2w_cb; + if (!is_rm_enabled) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: IPA RM DISABLED, IPA AWAKE", __func__); + pipe_in.sys.keep_ipa_awake = true; + } + + pipe_in.u.dl.comp_ring_base_pa = ipa_res->tx_comp_ring_base_paddr; + pipe_in.u.dl.comp_ring_size = ipa_res->tx_comp_ring_size * + sizeof(qdf_dma_addr_t); + pipe_in.u.dl.ce_ring_base_pa = ipa_res->ce_sr_base_paddr; + pipe_in.u.dl.ce_door_bell_pa = ipa_res->ce_reg_paddr; + pipe_in.u.dl.ce_ring_size = ipa_res->ce_sr_ring_size; + pipe_in.u.dl.num_tx_buffers = ipa_res->tx_num_alloc_buffer; + + /* Connect WDI IPA PIPE */ + ret = ipa_connect_wdi_pipe(&pipe_in, &pipe_out); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_connect_wdi_pipe: Tx pipe setup failed: ret=%d", ret); + return QDF_STATUS_E_FAILURE; + } + + /* Micro Controller Doorbell register */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s CONS DB pipe out 0x%x TX PIPE Handle 0x%x", + __func__, (unsigned int)pipe_out.uc_door_bell_pa, + pipe_out.clnt_hdl); + ipa_res->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa; + /* WLAN TX PIPE Handle */ + ipa_res->tx_pipe_handle = pipe_out.clnt_hdl; + *p_tx_pipe_handle = pipe_out.clnt_hdl; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "TX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x, %s %d, %sNB %d, %s 0x%x", + "comp_ring_base_pa", + (unsigned int)pipe_in.u.dl.comp_ring_base_pa, + "comp_ring_size", + pipe_in.u.dl.comp_ring_size, + "ce_ring_base_pa", + (unsigned int)pipe_in.u.dl.ce_ring_base_pa, + "ce_door_bell_pa", + (unsigned int)pipe_in.u.dl.ce_door_bell_pa, + "ce_ring_size", + pipe_in.u.dl.ce_ring_size, + "num_tx_buffers", + pipe_in.u.dl.num_tx_buffers, + "tx_comp_doorbell_paddr", + (unsigned int)ipa_res->tx_comp_doorbell_paddr); + + /* RX PIPE */ + pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = OL_TXRX_IPA_UC_WLAN_RX_HDR_LEN; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1; + pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; + pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD; + pipe_in.sys.desc_fifo_sz = ipa_desc_size + sizeof(struct sps_iovec); + pipe_in.sys.notify = ipa_w2i_cb; + if (!is_rm_enabled) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: IPA RM DISABLED, IPA AWAKE", __func__); + pipe_in.sys.keep_ipa_awake = true; + } + + pipe_in.u.ul.rdy_ring_base_pa = ipa_res->rx_rdy_ring_base_paddr; + pipe_in.u.ul.rdy_ring_size = ipa_res->rx_rdy_ring_size; + pipe_in.u.ul.rdy_ring_rp_pa = ipa_res->rx_proc_done_idx_paddr; + OL_TXRX_IPA_WDI2_SET(pipe_in, ipa_res); + +#ifdef FEATURE_METERING + pipe_in.wdi_notify = ipa_wdi_meter_notifier_cb; +#endif + + ret = ipa_connect_wdi_pipe(&pipe_in, &pipe_out); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_connect_wdi_pipe: Rx pipe setup failed: ret=%d", ret); + return QDF_STATUS_E_FAILURE; + } + ipa_res->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; + ipa_res->rx_pipe_handle = pipe_out.clnt_hdl; + *p_rx_pipe_handle = pipe_out.clnt_hdl; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "RX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x", + "rdy_ring_base_pa", + (unsigned int)pipe_in.u.ul.rdy_ring_base_pa, + "rdy_ring_size", + pipe_in.u.ul.rdy_ring_size, + "rdy_ring_rp_pa", + (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa, + "rx_ready_doorbell_paddr", + (unsigned int)ipa_res->rx_ready_doorbell_paddr); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_cleanup() - Disconnect IPA pipes + * @tx_pipe_handle: Tx pipe handle + * @rx_pipe_handle: Rx pipe handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_cleanup(uint32_t tx_pipe_handle, uint32_t rx_pipe_handle) +{ + int ret; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disconnect TX PIPE tx_pipe_handle=0x%x", + __func__, tx_pipe_handle); + ret = ipa_disconnect_wdi_pipe(tx_pipe_handle); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_disconnect_wdi_pipe: Tx pipe cleanup failed: ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disconnect RX PIPE rx_pipe_handle=0x%x", + __func__, rx_pipe_handle); + ret = ipa_disconnect_wdi_pipe(rx_pipe_handle); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_disconnect_wdi_pipe: Rx pipe cleanup failed: ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_remove_ipa_header() - Remove a specific header from IPA + * @name: Name of the header to be removed + * + * Return: QDF_STATUS + */ +static QDF_STATUS ol_txrx_ipa_remove_header(char *name) +{ + struct ipa_ioc_get_hdr hdrlookup; + int ret = 0, len; + struct ipa_ioc_del_hdr *ipa_hdr; + + qdf_mem_zero(&hdrlookup, sizeof(hdrlookup)); + strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name)); + ret = ipa_get_hdr(&hdrlookup); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "Hdr deleted already %s, %d", name, ret); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", + hdrlookup.hdl); + len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1; + ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len); + if (ipa_hdr == NULL) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_hdr allocation failed"); + return QDF_STATUS_E_FAILURE; + } + ipa_hdr->num_hdls = 1; + ipa_hdr->commit = 0; + ipa_hdr->hdl[0].hdl = hdrlookup.hdl; + ipa_hdr->hdl[0].status = -1; + ret = ipa_del_hdr(ipa_hdr); + if (ret != 0) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Delete header failed: %d", ret); + qdf_mem_free(ipa_hdr); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_free(ipa_hdr); + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_add_header_info() - Add IPA header for a given interface + * @ifname: Interface name + * @mac_addr: Interface MAC address + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: 0 on success, negativer errno value on error + */ +static int ol_txrx_ipa_add_header_info(char *ifname, uint8_t *mac_addr, + uint8_t session_id, bool is_ipv6_enabled) +{ + struct ipa_ioc_add_hdr *ipa_hdr = NULL; + int ret = -EINVAL; + struct ol_txrx_ipa_uc_tx_hdr *uc_tx_hdr = NULL; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "Add Partial hdr: %s, %pM", ifname, mac_addr); + + /* dynamically allocate the memory to add the hdrs */ + ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr) + + sizeof(struct ipa_hdr_add)); + if (!ipa_hdr) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: ipa_hdr allocation failed", ifname); + ret = -ENOMEM; + goto end; + } + + ipa_hdr->commit = 0; + ipa_hdr->num_hdrs = 1; + + uc_tx_hdr = (struct ol_txrx_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; + memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN); + memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN); + uc_tx_hdr->ipa_hd.vdev_id = session_id; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "ifname=%s, vdev_id=%d", + ifname, uc_tx_hdr->ipa_hd.vdev_id); + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV4_NAME_EXT); + ipa_hdr->hdr[0].hdr_len = OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN; + ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II; + ipa_hdr->hdr[0].is_partial = 1; + ipa_hdr->hdr[0].hdr_hdl = 0; + ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; + ipa_hdr->hdr[0].eth2_ofst = OL_TXRX_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + + ret = ipa_add_hdr(ipa_hdr); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s IPv4 add hdr failed: %d", ifname, ret); + goto end; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: IPv4 hdr_hdl: 0x%x", + ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); + + if (is_ipv6_enabled) { + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV6_NAME_EXT); + + uc_tx_hdr = (struct ol_txrx_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; + uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6); + + ret = ipa_add_hdr(ipa_hdr); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: IPv6 add hdr failed: %d", ifname, ret); + goto clean_ipv4_hdr; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: IPv6 hdr_hdl: 0x%x", + ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); + } + + qdf_mem_free(ipa_hdr); + + return ret; + +clean_ipv4_hdr: + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV4_NAME_EXT); + ol_txrx_ipa_remove_header(ipa_hdr->hdr[0].name); +end: + if (ipa_hdr) + qdf_mem_free(ipa_hdr); + + return ret; +} + +/** + * ol_txrx_ipa_register_interface() - register IPA interface + * @ifname: Interface name + * @prod_client: IPA prod client type + * @cons_client: IPA cons client type + * @session_id: Session ID + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: 0 on success, negative errno on error + */ +static int ol_txrx_ipa_register_interface(char *ifname, + enum ipa_client_type prod_client, + enum ipa_client_type cons_client, + uint8_t session_id, + bool is_ipv6_enabled) +{ + struct ipa_tx_intf tx_intf; + struct ipa_rx_intf rx_intf; + struct ipa_ioc_tx_intf_prop *tx_prop = NULL; + struct ipa_ioc_rx_intf_prop *rx_prop = NULL; + + char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX]; + char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX]; + + int num_prop = 1; + int ret = 0; + + if (is_ipv6_enabled) + num_prop++; + + /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */ + tx_prop = + qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop); + if (!tx_prop) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "tx_prop allocation failed"); + goto register_interface_fail; + } + + /* Allocate RX properties, 1 each for IPv4 & IPv6 */ + rx_prop = + qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop); + if (!rx_prop) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "rx_prop allocation failed"); + goto register_interface_fail; + } + + qdf_mem_zero(&tx_intf, sizeof(tx_intf)); + qdf_mem_zero(&rx_intf, sizeof(rx_intf)); + + snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV4_NAME_EXT); + snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV6_NAME_EXT); + + rx_prop[IPA_IP_v4].ip = IPA_IP_v4; + rx_prop[IPA_IP_v4].src_pipe = prod_client; + rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; + + /* + * Interface ID is 3rd byte in the CLD header. Add the meta data and + * mask to identify the interface in IPA hardware + */ + rx_prop[IPA_IP_v4].attrib.meta_data = + htonl(session_id << 16); + rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); + + rx_intf.num_props++; + if (is_ipv6_enabled) { + rx_prop[IPA_IP_v6].ip = IPA_IP_v6; + rx_prop[IPA_IP_v6].src_pipe = prod_client; + rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[IPA_IP_v6].attrib.attrib_mask = IPA_FLT_META_DATA; + rx_prop[IPA_IP_v6].attrib.meta_data = + htonl(session_id << 16); + rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); + + rx_intf.num_props++; + } + + tx_prop[IPA_IP_v4].ip = IPA_IP_v4; + tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS; + tx_prop[IPA_IP_v4].alt_dst_pipe = cons_client; + strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name, + IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + + if (is_ipv6_enabled) { + tx_prop[IPA_IP_v6].ip = IPA_IP_v6; + tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS; + tx_prop[IPA_IP_v6].alt_dst_pipe = cons_client; + strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name, + IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + } + + tx_intf.prop = tx_prop; + rx_intf.prop = rx_prop; + + /* Call the ipa api to register interface */ + ret = ipa_register_intf(ifname, &tx_intf, &rx_intf); + +register_interface_fail: + qdf_mem_free(tx_prop); + qdf_mem_free(rx_prop); + return ret; +} + +/** + * ol_txrx_ipa_setup_iface() - Setup IPA header and register interface + * @ifname: Interface name + * @mac_addr: Interface MAC address + * @prod_client: IPA prod client type + * @cons_client: IPA cons client type + * @session_id: Session ID + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_setup_iface(char *ifname, uint8_t *mac_addr, + enum ipa_client_type prod_client, + enum ipa_client_type cons_client, + uint8_t session_id, bool is_ipv6_enabled) +{ + int ret; + + ret = ol_txrx_ipa_add_header_info(ifname, mac_addr, session_id, + is_ipv6_enabled); + if (ret) + return QDF_STATUS_E_FAILURE; + + /* Configure the TX and RX pipes filter rules */ + ret = ol_txrx_ipa_register_interface(ifname, prod_client, cons_client, + session_id, is_ipv6_enabled); + if (ret) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_cleanup_iface() - Cleanup IPA header and deregister interface + * @ifname: Interface name + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_cleanup_iface(char *ifname, bool is_ipv6_enabled) +{ + char name_ipa[IPA_RESOURCE_NAME_MAX]; + int ret; + + /* Remove the headers */ + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV4_NAME_EXT); + ol_txrx_ipa_remove_header(name_ipa); + + if (is_ipv6_enabled) { + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV6_NAME_EXT); + ol_txrx_ipa_remove_header(name_ipa); + } + /* unregister the interface with IPA */ + ret = ipa_deregister_intf(ifname); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: ipa_deregister_intf fail: %d", + ifname, ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + + /** + * ol_txrx_ipa_uc_enable_pipes() - Enable and resume traffic on Tx/Rx pipes + * @pdev: handle to the device instance + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + int result; + + /* ACTIVATE TX PIPE */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Enable TX PIPE(tx_pipe_handle=%d)", + __func__, ipa_res->tx_pipe_handle); + result = ipa_enable_wdi_pipe(ipa_res->tx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Enable TX PIPE fail, code %d", + __func__, result); + return QDF_STATUS_E_FAILURE; + } + result = ipa_resume_wdi_pipe(ipa_res->tx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Resume TX PIPE fail, code %d", + __func__, result); + return QDF_STATUS_E_FAILURE; + } + ol_txrx_ipa_uc_set_active((struct cdp_pdev *)pdev, true, true); + + /* ACTIVATE RX PIPE */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Enable RX PIPE(rx_pipe_handle=%d)", + __func__, ipa_res->rx_pipe_handle); + result = ipa_enable_wdi_pipe(ipa_res->rx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Enable RX PIPE fail, code %d", + __func__, result); + return QDF_STATUS_E_FAILURE; + } + result = ipa_resume_wdi_pipe(ipa_res->rx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Resume RX PIPE fail, code %d", + __func__, result); + return QDF_STATUS_E_FAILURE; + } + ol_txrx_ipa_uc_set_active((struct cdp_pdev *)pdev, true, false); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_uc_disable_pipes() – Suspend traffic and disable Tx/Rx pipes + * @pdev: handle to the device instance + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + int result; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disable RX PIPE", __func__); + result = ipa_suspend_wdi_pipe(ipa_res->rx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Suspend RX PIPE fail, code %d", + __func__, result); + return QDF_STATUS_E_FAILURE; + } + + result = ipa_disable_wdi_pipe(ipa_res->rx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Disable RX PIPE fail, code %d", + __func__, result); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disable TX PIPE", __func__); + result = ipa_suspend_wdi_pipe(ipa_res->tx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Suspend TX PIPE fail, code %d", + __func__, result); + return QDF_STATUS_E_FAILURE; + } + result = ipa_disable_wdi_pipe(ipa_res->tx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Disable TX PIPE fail, code %d", + __func__, result); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_set_perf_level() - Set IPA clock bandwidth based on data rates + * @client: Client type + * @max_supported_bw_mbps: Maximum bandwidth needed (in Mbps) + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_set_perf_level(int client, + uint32_t max_supported_bw_mbps) +{ + struct ipa_rm_perf_profile profile; + int result; + + profile.max_supported_bandwidth_mbps = max_supported_bw_mbps; + result = ipa_rm_set_perf_profile(client, &profile); + + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Set perf profile failed, code %d", result); + + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_METERING +QDF_STATUS ol_txrx_ipa_uc_get_share_stats(struct cdp_pdev *ppdev, + uint8_t reset_stats) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + int result; + + result = htt_h2t_ipa_uc_get_share_stats(pdev->htt_pdev, reset_stats); + + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Get IPA sharing stats failed, code %d", result); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_uc_set_quota(struct cdp_pdev *ppdev, + uint64_t quota_bytes) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + int result; + + result = htt_h2t_ipa_uc_set_quota(pdev->htt_pdev, quota_bytes); + + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Set IPA quota failed, code %d", result); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif +#endif /* IPA_UC_OFFLOAD */ diff --git a/core/dp/txrx/ol_txrx_ipa.h b/core/dp/txrx/ol_txrx_ipa.h new file mode 100644 index 000000000000..d2e0ced144b9 --- /dev/null +++ b/core/dp/txrx/ol_txrx_ipa.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _OL_TXRX_IPA_H_ +#define _OL_TXRX_IPA_H_ + +#ifdef IPA_OFFLOAD + +#include /* ol_txrx_vdev_t, etc. */ +#include + +/** + * struct frag_header - fragment header type registered to IPA hardware + * @length: fragment length + * @reserved1: Reserved not used + * @reserved2: Reserved not used + * + */ +struct frag_header { + uint16_t length; + uint32_t reserved1; + uint32_t reserved2; +} __packed; + +/** + * struct ipa_header - ipa header type registered to IPA hardware + * @vdev_id: vdev id + * @reserved: Reserved not used + * + */ +struct ipa_header { + uint32_t + vdev_id:8, /* vdev_id field is LSB of IPA DESC */ + reserved:24; +} __packed; + +/** + * struct ol_txrx_ipa_uc_tx_hdr - full tx header registered to IPA hardware + * @frag_hd: fragment header + * @ipa_hd: ipa header + * @eth: ether II header + * + */ +struct ol_txrx_ipa_uc_tx_hdr { + struct frag_header frag_hd; + struct ipa_header ipa_hd; + struct ethhdr eth; +} __packed; + +/** + * struct ol_txrx_ipa_uc_rx_hdr - full rx header registered to IPA hardware + * @eth: ether II header + * + */ +struct ol_txrx_ipa_uc_rx_hdr { + struct ethhdr eth; +} __packed; + +#define OL_TXRX_IPA_UC_WLAN_8023_HDR_SIZE 14 + +#define OL_TXRX_IPA_IPV4_NAME_EXT "_ipv4" +#define OL_TXRX_IPA_IPV6_NAME_EXT "_ipv6" + +#define OL_TXRX_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header) +#define OL_TXRX_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header) +#define OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct ol_txrx_ipa_uc_tx_hdr) +#define OL_TXRX_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct ol_txrx_ipa_uc_rx_hdr) +#define OL_TXRX_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \ + (OL_TXRX_IPA_WLAN_FRAG_HEADER + OL_TXRX_IPA_WLAN_IPA_HEADER) + +#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3) +#define OL_TXRX_IPA_WDI2_SET(pipe_in, ipa_res) \ + do { \ + pipe_in.u.ul.rdy_ring_rp_va = \ + ipa_res->rx_proc_done_idx_vaddr; \ + pipe_in.u.ul.rdy_comp_ring_base_pa = \ + ipa_res->rx2_rdy_ring_base_paddr;\ + pipe_in.u.ul.rdy_comp_ring_size = \ + ipa_res->rx2_rdy_ring_size; \ + pipe_in.u.ul.rdy_comp_ring_wp_pa = \ + ipa_res->rx2_proc_done_idx_paddr; \ + pipe_in.u.ul.rdy_comp_ring_wp_va = \ + ipa_res->rx2_proc_done_idx_vaddr; \ + } while (0) +#else +/* Do nothing */ +#define OL_TXRX_IPA_WDI2_SET(pipe_in, ipa_res) +#endif /* IPA3 */ + +QDF_STATUS ol_txrx_ipa_uc_get_resource(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_uc_set_doorbell_paddr(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_uc_set_active(struct cdp_pdev *pdev, bool uc_active, + bool is_tx); +QDF_STATUS ol_txrx_ipa_uc_op_response(struct cdp_pdev *pdev, uint8_t *op_msg); +QDF_STATUS ol_txrx_ipa_uc_register_op_cb(struct cdp_pdev *pdev, + ipa_uc_op_cb_type op_cb, void *usr_ctxt); +QDF_STATUS ol_txrx_ipa_uc_get_stat(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_enable_autonomy(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_disable_autonomy(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *pdev, void *ipa_i2w_cb, + void *ipa_w2i_cb, void *ipa_wdi_meter_notifier_cb, + uint32_t ipa_desc_size, void *ipa_priv, bool is_rm_enabled, + uint32_t *tx_pipe_handle, uint32_t *rx_pipe_handle); +QDF_STATUS ol_txrx_ipa_cleanup(uint32_t tx_pipe_handle, + uint32_t rx_pipe_handle); +QDF_STATUS ol_txrx_ipa_setup_iface(char *ifname, uint8_t *mac_addr, + enum ipa_client_type prod_client, + enum ipa_client_type cons_client, + uint8_t session_id, bool is_ipv6_enabled); +QDF_STATUS ol_txrx_ipa_cleanup_iface(char *ifname, bool is_ipv6_enabled); +QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_set_perf_level(int client, + uint32_t max_supported_bw_mbps); +#ifdef FEATURE_METERING +QDF_STATUS ol_txrx_ipa_uc_get_share_stats(struct cdp_pdev *pdev, + uint8_t reset_stats); +QDF_STATUS ol_txrx_ipa_uc_set_quota(struct cdp_pdev *pdev, + uint64_t quota_bytes); +#endif +#endif +#endif /* _OL_TXRX_IPA_H_*/ diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index 9ad311d13625..c85598776d01 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -406,7 +406,7 @@ enum throttle_phase { #define THROTTLE_TX_THRESHOLD (100) -typedef void (*ipa_uc_op_cb_type)(uint8_t *op_msg, void *osif_ctxt); +typedef void (*ipa_uc_op_cb_type)(uint8_t *op_msg, void *usr_ctxt); struct ol_tx_queue_group_t { qdf_atomic_t credit; @@ -918,11 +918,6 @@ struct ol_txrx_pdev_t { bool is_paused; } tx_throttle; -#ifdef IPA_OFFLOAD - ipa_uc_op_cb_type ipa_uc_op_cb; - void *osif_dev; -#endif /* IPA_UC_OFFLOAD */ - #if defined(FEATURE_TSO) struct { uint16_t pool_size; @@ -979,6 +974,12 @@ struct ol_txrx_pdev_t { } lro_info; struct ol_txrx_peer_t *self_peer; qdf_work_t peer_unmap_timer_work; + +#ifdef IPA_OFFLOAD + ipa_uc_op_cb_type ipa_uc_op_cb; + void *usr_ctxt; + struct ol_txrx_ipa_resources ipa_resource; +#endif /* IPA_UC_OFFLOAD */ }; struct ol_txrx_vdev_t { diff --git a/core/hdd/inc/wlan_hdd_ipa.h b/core/hdd/inc/wlan_hdd_ipa.h index 929810b18fe0..34954c52fb4e 100644 --- a/core/hdd/inc/wlan_hdd_ipa.h +++ b/core/hdd/inc/wlan_hdd_ipa.h @@ -269,7 +269,7 @@ static inline void hdd_ipa_set_tx_flow_info(void) * * Return: 0 on success, negativer errno on error */ -static int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx) +static inline int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx) { return 0; } diff --git a/core/hdd/src/wlan_hdd_ipa.c b/core/hdd/src/wlan_hdd_ipa.c index b47776677135..545d2048733c 100644 --- a/core/hdd/src/wlan_hdd_ipa.c +++ b/core/hdd/src/wlan_hdd_ipa.c @@ -35,7 +35,7 @@ #ifdef IPA_OFFLOAD /* Include Files */ -#include +#include #include #include @@ -58,16 +58,11 @@ #include "wal_rx_desc.h" #include "cdp_txrx_ipa.h" -#include #include "wlan_policy_mgr_api.h" -#define HDD_IPA_DESC_BUFFER_RATIO 4 -#define HDD_IPA_IPV4_NAME_EXT "_ipv4" -#define HDD_IPA_IPV6_NAME_EXT "_ipv6" - #define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000 #define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14 -/* WDI TX and RX PIPE */ + #define HDD_IPA_UC_NUM_WDI_PIPE 2 #define HDD_IPA_UC_MAX_PENDING_EVENT 33 @@ -79,6 +74,7 @@ #define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0 #define HDD_IPA_MAX_IFACE 3 #define HDD_IPA_MAX_SYSBAM_PIPE 4 + #define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE #define HDD_IPA_ENABLE_MASK BIT(0) #define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1) @@ -221,10 +217,6 @@ struct hdd_ipa_pm_tx_cb { struct ipa_rx_data *ipa_tx_desc; }; -struct hdd_ipa_uc_rx_hdr { - struct ethhdr eth; -} __packed; - struct hdd_ipa_sys_pipe { uint32_t conn_hdl; uint8_t conn_hdl_valid; @@ -438,8 +430,6 @@ struct hdd_ipa_priv { struct delayed_work wake_lock_work; bool wake_lock_released; - enum ipa_client_type prod_client; - atomic_t tx_ref_cnt; qdf_nbuf_queue_t pm_queue_head; struct work_struct pm_work; @@ -493,10 +483,7 @@ struct hdd_ipa_priv { qdf_mc_timer_t rt_debug_fill_timer; qdf_mutex_t rt_debug_lock; qdf_mutex_t ipa_lock; - struct ol_txrx_ipa_resources ipa_resource; - /* IPA UC doorbell registers paddr */ - qdf_dma_addr_t tx_comp_doorbell_paddr; - qdf_dma_addr_t rx_ready_doorbell_paddr; + uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX]; bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX]; #ifdef FEATURE_METERING @@ -515,7 +502,6 @@ struct hdd_ipa_priv { #define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr) #define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr) #define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr) -#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr) #define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \ (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER) @@ -550,24 +536,9 @@ struct hdd_ipa_priv { #define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1) #if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3) -#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \ -do { \ - pipe_in.u.ul.rdy_ring_rp_va = \ - ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \ - pipe_in.u.ul.rdy_comp_ring_base_pa = \ - ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\ - pipe_in.u.ul.rdy_comp_ring_size = \ - ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \ - pipe_in.u.ul.rdy_comp_ring_wp_pa = \ - ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \ - pipe_in.u.ul.rdy_comp_ring_wp_va = \ - ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \ -} while (0) - #define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL) #else /* Do nothing */ -#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) #define HDD_IPA_CHECK_HW() 0 #endif /* IPA3 */ @@ -587,39 +558,6 @@ static struct hdd_ipa_adapter_2_client { }, }; -/* For Tx pipes, use Ethernet-II Header format */ -struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = { - { - 0x0000, - 0x00000000, - 0x00000000 - }, - { - 0x00000000 - }, - { - {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc}, - {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff}, - 0x0008 - } -}; - -/* For Tx pipes, use 802.3 Header format */ -static struct hdd_ipa_tx_hdr ipa_tx_hdr = { - { - {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, - {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, - 0x00 /* length can be zero */ - }, - { - /* LLC SNAP header 8 bytes */ - 0xaa, 0xaa, - {0x03, 0x00, 0x00, 0x00}, - 0x0008 /* type value(2 bytes) ,filled by wlan */ - /* 0x0800 - IPV4, 0x86dd - IPV6 */ - } -}; - #ifdef FEATURE_METERING #define IPA_UC_SHARING_STATES_WAIT_TIME 500 #define IPA_UC_SET_QUOTA_WAIT_TIME 500 @@ -632,6 +570,12 @@ static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data); static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data); +#ifdef FEATURE_METERING +static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, + void *data); +#else +static void hdd_ipa_wdi_meter_notifier_cb(void); +#endif static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type); static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context); @@ -639,28 +583,6 @@ static void hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa); #if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \ defined(IPA_CLIENT_IS_MHI_CONS)) -/** - * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address - * @db_paddr: Doorbell physical address should be given bu IPA - * @client: IPA client type - * - * Query doorbell physical address from IPA - * IPA will give physical address for TX COMP and RX READY - * - * Return: None - */ -static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr, - enum ipa_client_type client) -{ - struct ipa_wdi_db_params dbpa; - - dbpa.client = client; - ipa_uc_wdi_get_dbpa(&dbpa); - *db_paddr = dbpa.uc_door_bell_pa; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s PROD DB get dbpa 0x%x", - __func__, (unsigned int)dbpa.uc_door_bell_pa); -} - /** * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback * @priv_ctxt: hdd ipa local context @@ -780,12 +702,6 @@ static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa) return ret; } #else -static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr, - enum ipa_client_type client) -{ - /* Do nothing */ -} - static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa) { hdd_ipa->uc_loaded = true; @@ -921,8 +837,7 @@ static void hdd_ipa_uc_rt_debug_host_fill(void *ctext) return; if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s: IPA UC is not enabled", __func__); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled"); return; } @@ -967,8 +882,7 @@ static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx) hdd_ipa = hdd_ctx->hdd_ipa; if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s: IPA UC is not enabled", __func__); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "IPA UC is not enabled"); return; } @@ -1035,7 +949,8 @@ static void hdd_ipa_uc_rt_debug_handler(void *ctext) hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { - hdd_debug("IPA RT debug is not enabled"); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "IPA RT debug is not enabled"); return; } @@ -1069,8 +984,7 @@ static void hdd_ipa_uc_rt_debug_handler(void *ctext) static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb) { if (!ghdd_ipa) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: invalid hdd context", __func__); + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "invalid hdd context"); return; } @@ -1097,7 +1011,8 @@ static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx) qdf_mutex_destroy(&hdd_ipa->rt_debug_lock); if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { - hdd_debug("IPA RT debug is not enabled"); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "IPA RT debug is not enabled"); return; } @@ -1144,7 +1059,8 @@ static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx) /* Reatime debug enable on feature enable */ if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { - hdd_debug("IPA RT debug is not enabled"); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "IPA RT debug is not enabled"); return; } @@ -1182,7 +1098,6 @@ static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa) "wake_lock: %p\n" "wake_lock_work: %p\n" "wake_lock_released: %d\n" - "prod_client: %d\n" "tx_ref_cnt: %d\n" "pm_queue_head----\n" "\thead: %p\n" @@ -1199,7 +1114,6 @@ static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa) &hdd_ipa->wake_lock, &hdd_ipa->wake_lock_work, hdd_ipa->wake_lock_released, - hdd_ipa->prod_client, hdd_ipa->tx_ref_cnt.counter, hdd_ipa->pm_queue_head.head, hdd_ipa->pm_queue_head.tail, @@ -1896,8 +1810,7 @@ static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa, } if (sta_add && sta_found) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: STA ID %d already exist, cannot add", - __func__, sta_id); + "STA ID %d already exist, cannot add", sta_id); return sta_found; } if (sta_add) { @@ -1911,8 +1824,7 @@ static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa, } if (!sta_add && !sta_found) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: STA ID %d does not exist, cannot delete", - __func__, sta_id); + "STA ID %d does not exist, cannot delete", sta_id); return sta_found; } if (!sta_add) { @@ -1938,53 +1850,20 @@ static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa, static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa) { int result; - p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context; void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); - /* ACTIVATE TX PIPE */ - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s: Enable TX PIPE(tx_pipe_handle=%d)", - __func__, hdd_ipa->tx_pipe_handle); - result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle); + result = cdp_ipa_enable_pipes(soc, (struct cdp_pdev *)pdev); if (result) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Enable TX PIPE fail, code %d", - __func__, result); + "Enable PIPE fail, code %d", result); return result; } - result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Resume TX PIPE fail, code %d", - __func__, result); - return result; - } - cdp_ipa_set_active(soc, - (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx, - true, true); - /* ACTIVATE RX PIPE */ - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s: Enable RX PIPE(rx_pipe_handle=%d)", - __func__, hdd_ipa->rx_pipe_handle); - result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Enable RX PIPE fail, code %d", - __func__, result); - return result; - } - result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Resume RX PIPE fail, code %d", - __func__, result); - return result; - } - cdp_ipa_set_active(soc, - (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx, - true, false); hdd_ipa->ipa_pipes_down = false; + + cdp_ipa_enable_autonomy(soc, (struct cdp_pdev *)pdev); + return 0; } @@ -1996,39 +1875,18 @@ static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa) */ static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa) { + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); int result; hdd_ipa->ipa_pipes_down = true; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable RX PIPE", __func__); - result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Suspend RX PIPE fail, code %d", - __func__, result); - return result; - } - result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Disable RX PIPE fail, code %d", - __func__, result); - return result; - } + cdp_ipa_disable_autonomy(soc, (struct cdp_pdev *)pdev); - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable TX PIPE", __func__); - result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle); + result = cdp_ipa_disable_pipes(soc, (struct cdp_pdev *)pdev); if (result) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Suspend TX PIPE fail, code %d", - __func__, result); - return result; - } - result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle); - if (result) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Disable TX PIPE fail, code %d", - __func__, result); + "Disable WDI PIPE fail, code %d", result); return result; } @@ -2043,22 +1901,22 @@ static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa) */ static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa) { + hdd_context_t *hdd_ctx = hdd_ipa->hdd_ctx; + hdd_ipa->activated_fw_pipe = 0; hdd_ipa->resource_loading = true; /* If RM feature enabled * Request PROD Resource first - * PROD resource may return sync or async manners - */ - if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) { + * PROD resource may return sync or async manners */ + if (hdd_ipa_is_rm_enabled(hdd_ctx)) { if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) { /* RM PROD request sync return * enable pipe immediately */ if (hdd_ipa_uc_enable_pipes(hdd_ipa)) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: IPA WDI Pipe activation failed", - __func__); + "IPA WDI Pipe activation failed"); hdd_ipa->resource_loading = false; return -EBUSY; } @@ -2069,8 +1927,7 @@ static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa) */ if (hdd_ipa_uc_enable_pipes(hdd_ipa)) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: IPA WDI Pipe activation failed", - __func__); + "IPA WDI Pipe activation failed"); hdd_ipa->resource_loading = false; return -EBUSY; } @@ -2078,7 +1935,7 @@ static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa) } HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s: IPA WDI Pipes activated successfully", __func__); + "IPA WDI Pipes activated successfully"); return 0; } @@ -2090,24 +1947,20 @@ static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa) */ static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa) { - p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context; void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); - if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) { + if (!pdev) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL"); QDF_ASSERT(0); return; } hdd_ipa->resource_unloading = true; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW RX PIPE", __func__); - cdp_ipa_set_active(soc, - (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx, - false, false); - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: Disable FW TX PIPE", __func__); - cdp_ipa_set_active(soc, - (struct cdp_pdev *)cds_ctx->pdev_txrx_ctx, - false, true); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW RX PIPE"); + cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, false); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Disable FW TX PIPE"); + cdp_ipa_set_active(soc, (struct cdp_pdev *)pdev, false, true); } /** @@ -2124,15 +1977,16 @@ hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event) { struct hdd_ipa_priv *hdd_ipa = context; QDF_STATUS status = QDF_STATUS_SUCCESS; + hdd_context_t *hdd_ctx = hdd_ipa->hdd_ctx; /* * When SSR is going on or driver is unloading, just return. */ - status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + status = wlan_hdd_validate_context(hdd_ctx); if (status) return; - if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + if (!hdd_ipa_is_rm_enabled(hdd_ctx)) return; HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s, event code %d", @@ -2141,7 +1995,6 @@ hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event) switch (event) { case IPA_RM_RESOURCE_GRANTED: /* Differed RM Granted */ - hdd_ipa_uc_enable_pipes(hdd_ipa); qdf_mutex_acquire(&hdd_ipa->ipa_lock); if ((false == hdd_ipa->resource_unloading) && (!hdd_ipa->activated_fw_pipe)) { @@ -2192,46 +2045,51 @@ static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work) /** * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication - * @ipa_ctxt: hdd ipa local context + * @hdd_ipa: hdd ipa local context * * Will handle IPA UC image loaded indication comes from IPA kernel * * Return: None */ -static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt) +static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *hdd_ipa) { - struct ipa_wdi_out_params pipe_out; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + hdd_context_t *hdd_ctx; + QDF_STATUS status; HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__); - if (true == ipa_ctxt->uc_loaded) { + if (true == hdd_ipa->uc_loaded) { HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s : UC already loaded", __func__); return; } - ipa_ctxt->uc_loaded = true; - /* Connect pipe */ - ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out); - ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; - ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa; - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s : TX PIPE Handle %d, DBPA 0x%llx", - __func__, ipa_ctxt->tx_pipe_handle, - (unsigned long long) pipe_out.uc_door_bell_pa); + hdd_ctx = hdd_ipa->hdd_ctx; + hdd_ipa->uc_loaded = true; - ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out); - ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; - ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s : RX PIPE Handle %d, DBPA 0x%llx", - __func__, ipa_ctxt->rx_pipe_handle, - (unsigned long long) pipe_out.uc_door_bell_pa); + /* Connect pipe */ + status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev, + hdd_ipa_i2w_cb, hdd_ipa_w2i_cb, + hdd_ipa_wdi_meter_notifier_cb, + hdd_ctx->config->IpaDescSize, + hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx), + &hdd_ipa->tx_pipe_handle, + &hdd_ipa->rx_pipe_handle); + if (status) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Failure to setup IPA pipes (status=%d)", + status); + return; + } + + cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev); /* If already any STA connected, enable IPA/FW PIPEs */ - if (ipa_ctxt->sap_num_connected_sta) { + if (hdd_ipa->sap_num_connected_sta) { HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Client already connected, enable IPA/FW PIPEs"); - hdd_ipa_uc_handle_first_con(ipa_ctxt); + hdd_ipa_uc_handle_first_con(hdd_ipa); } } @@ -2411,39 +2269,12 @@ static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) qdf_mutex_release(&hdd_ipa->ipa_lock); } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) && (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) { - struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource; /* STATs from host */ - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, - "==== IPA_UC WLAN_HOST CE ====\n" - "CE RING BASE: 0x%llx\n" - "CE RING SIZE: %d\n" - "CE REG ADDR : 0x%llx", - (unsigned long long)res->ce_sr_base_paddr, - res->ce_sr_ring_size, - (unsigned long long)res->ce_reg_paddr); - QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, - "==== IPA_UC WLAN_HOST TX ====\n" - "COMP RING BASE: 0x%llx\n" - "COMP RING SIZE: %d\n" - "NUM ALLOC BUF: %d\n" - "COMP RING DBELL : 0x%llx", - (unsigned long long)res->tx_comp_ring_base_paddr, - res->tx_comp_ring_size, - res->tx_num_alloc_buffer, - (unsigned long long)hdd_ipa->tx_comp_doorbell_paddr); QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, "==== IPA_UC WLAN_HOST RX ====\n" - "IND RING BASE: 0x%llx\n" - "IND RING SIZE: %d\n" - "IND RING DBELL : 0x%llx\n" - "PROC DONE IND ADDR : 0x%llx\n" "NUM EXCP PKT : %llu\n" "NUM TX FWD OK : %llu\n" "NUM TX FWD ERR : %llu", - (unsigned long long)res->rx_rdy_ring_base_paddr, - res->rx_rdy_ring_size, - (unsigned long long)hdd_ipa->rx_ready_doorbell_paddr, - (unsigned long long)res->rx_proc_done_idx_paddr, hdd_ipa->stats.num_rx_excep, hdd_ipa->stats.num_tx_fwd_ok, hdd_ipa->stats.num_tx_fwd_err); @@ -2658,7 +2489,7 @@ static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter, if (enable == hdd_ipa->vdev_offload_enabled[session_id]) { /* IPA offload status is already set as desired */ HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: (offload_type=%d, vdev_id=%d, enable=%d)", + "%s (offload_type=%d, vdev_id=%d, enable=%d)", "IPA offload status is already set", offload_type, session_id, enable); return; @@ -2687,8 +2518,8 @@ static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter, sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter), adapter->sessionId, &ipa_offload_enable_disable)) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)", - __func__, + "%s (offload_type=%d, vdev_id=%d, enable=%d)", + "Failure to enable IPA offload", ipa_offload_enable_disable.offload_type, ipa_offload_enable_disable.vdev_id, ipa_offload_enable_disable.enable); @@ -2750,8 +2581,8 @@ static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx) goto end; if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)", - __func__, msg->op_code); + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid OP Code (%d)", + msg->op_code); goto end; } @@ -2906,7 +2737,7 @@ static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler. * IPA calls to get WLAN stats or set quota limit. * @priv: pointer to private data registered with IPA (we register a - *» pointer to the global IPA context) + * pointer to the global IPA context) * @evt: the IPA event which triggered the callback * @data: data associated with the event * @@ -2920,17 +2751,17 @@ static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, cds_ssr_unprotect(__func__); } -static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt, - struct ipa_wdi_in_params *pipe_in) +static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt) { - pipe_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb; - init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp); init_completion(&ipa_ctxt->ipa_uc_set_quota_comp); } #else -static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt, - struct ipa_wdi_in_params *pipe_in) +static void hdd_ipa_wdi_meter_notifier_cb(void) +{ +} + +static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt) { } #endif @@ -2947,13 +2778,11 @@ static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt, */ QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) { - struct ipa_wdi_in_params pipe_in; - struct ipa_wdi_out_params pipe_out; - struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; void *soc = cds_get_context(QDF_MODULE_ID_SOC); struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); - int ret; - QDF_STATUS stat = QDF_STATUS_SUCCESS; + uint8_t i; + QDF_STATUS status = QDF_STATUS_SUCCESS; if (!hdd_ipa_uc_is_enabled(hdd_ctx)) return QDF_STATUS_SUCCESS; @@ -2965,179 +2794,46 @@ QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) */ if (!pdev || !soc) { HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "DP context is NULL"); - stat = QDF_STATUS_E_FAILURE; + status = QDF_STATUS_E_FAILURE; goto fail_return; } - - cdp_ipa_get_resource(soc, (void *)pdev, &ipa_ctxt->ipa_resource); - if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) || - (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) || - (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) || - (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) { + if (cdp_ipa_get_resource(soc, (struct cdp_pdev *)pdev)) { HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "IPA UC resource alloc fail"); return QDF_STATUS_E_FAILURE; } - qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params)); - qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params)); - qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params)); - qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params)); - /* TX PIPE */ - pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len = - HDD_IPA_UC_WLAN_8023_HDR_SIZE; - pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; - pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS; - pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize; - pipe_in.sys.priv = hdd_ctx->hdd_ipa; - pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true; - pipe_in.sys.notify = hdd_ipa_i2w_cb; - if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s: IPA RM DISABLED, IPA AWAKE", __func__); - pipe_in.sys.keep_ipa_awake = true; - } - - pipe_in.u.dl.comp_ring_base_pa = - ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr; - /* IPA requires total byte counts of Tx comp ring */ - pipe_in.u.dl.comp_ring_size = - ipa_ctxt->ipa_resource.tx_comp_ring_size * - sizeof(target_paddr_t); - pipe_in.u.dl.ce_ring_base_pa = - ipa_ctxt->ipa_resource.ce_sr_base_paddr; - pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr; - pipe_in.u.dl.ce_ring_size = - ipa_ctxt->ipa_resource.ce_sr_ring_size; - pipe_in.u.dl.num_tx_buffers = - ipa_ctxt->ipa_resource.tx_num_alloc_buffer; - - qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in, - sizeof(struct ipa_wdi_in_params)); - hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr, - IPA_CLIENT_WLAN1_CONS); - - if (true == ipa_ctxt->uc_loaded) { - /* Connect WDI IPA PIPE */ - ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out); - if (ret) { + if (true == hdd_ipa->uc_loaded) { + status = cdp_ipa_setup(soc, (struct cdp_pdev *)pdev, + hdd_ipa_i2w_cb, hdd_ipa_w2i_cb, + hdd_ipa_wdi_meter_notifier_cb, + hdd_ctx->config->IpaDescSize, + hdd_ipa, hdd_ipa_is_rm_enabled(hdd_ctx), + &hdd_ipa->tx_pipe_handle, + &hdd_ipa->rx_pipe_handle); + if (status) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "ipa_connect_wdi_pipe falied for Tx: ret=%d", - ret); - stat = QDF_STATUS_E_FAILURE; - goto fail_return; + "Failure to setup IPA pipes (status=%d)", + status); + return QDF_STATUS_E_FAILURE; } - /* Micro Controller Doorbell register */ - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "CONS DB pipe out 0x%x TX PIPE Handle 0x%x", - (unsigned int)pipe_out.uc_door_bell_pa, - ipa_ctxt->tx_pipe_handle); - ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa; - - /* WLAN TX PIPE Handle */ - ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "TX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x, %s %d, %s %d, %s 0x%x", - "comp_ring_base_pa", - (unsigned int)pipe_in.u.dl.comp_ring_base_pa, - "comp_ring_size", - pipe_in.u.dl.comp_ring_size, - "ce_ring_base_pa", - (unsigned int)pipe_in.u.dl.ce_ring_base_pa, - "ce_door_bell_pa", - (unsigned int)pipe_in.u.dl.ce_door_bell_pa, - "ce_ring_size", - pipe_in.u.dl.ce_ring_size, - "num_tx_buffers", - pipe_in.u.dl.num_tx_buffers, - "tx_comp_doorbell_paddr", - (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr); + cdp_ipa_set_doorbell_paddr(soc, (struct cdp_pdev *)pdev); + hdd_ipa_init_metering(hdd_ipa); } - /* RX PIPE */ - pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0; - pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1; - pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; - pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD; - pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize + - sizeof(struct sps_iovec); - pipe_in.sys.notify = hdd_ipa_w2i_cb; - if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: IPA RM DISABLED, IPA AWAKE", __func__); - pipe_in.sys.keep_ipa_awake = true; - } - - pipe_in.u.ul.rdy_ring_base_pa = - ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr; - pipe_in.u.ul.rdy_ring_size = - ipa_ctxt->ipa_resource.rx_rdy_ring_size; - pipe_in.u.ul.rdy_ring_rp_pa = - ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr; - HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt); - - hdd_ipa_init_metering(ipa_ctxt, &pipe_in); - - qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in, - sizeof(struct ipa_wdi_in_params)); - hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr, - IPA_CLIENT_WLAN1_PROD); - - if (true == ipa_ctxt->uc_loaded) { - ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out); - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "ipa_connect_wdi_pipe failed for Rx: ret=%d", - ret); - stat = QDF_STATUS_E_FAILURE; - ret = ipa_disconnect_wdi_pipe(ipa_ctxt->tx_pipe_handle); - if (ret) - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "disconnect failed for TX: ret=%d", - ret); - goto fail_return; - } - ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; - ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "PROD DB pipe out 0x%x TX PIPE Handle 0x%x", - (unsigned int)pipe_out.uc_door_bell_pa, - ipa_ctxt->tx_pipe_handle); - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "RX: %s 0x%x, %s %d, %s 0x%x, %s 0x%x", - "rdy_ring_base_pa", - (unsigned int)pipe_in.u.ul.rdy_ring_base_pa, - "rdy_ring_size", - pipe_in.u.ul.rdy_ring_size, - "rdy_ring_rp_pa", - (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa, - "rx_ready_doorbell_paddr", - (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr); - } - - cdp_ipa_set_doorbell_paddr(soc, (void *)pdev, - ipa_ctxt->tx_comp_doorbell_paddr, - ipa_ctxt->rx_ready_doorbell_paddr); - - cdp_ipa_register_op_cb(soc, (void *)pdev, + cdp_ipa_register_op_cb(soc, (struct cdp_pdev *)pdev, hdd_ipa_uc_op_event_handler, (void *)hdd_ctx); - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, - "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x", - pdev->ipa_uc_op_cb, - (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr, - (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr); + for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) { + hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work, + hdd_ipa_uc_fw_op_event_handler); + hdd_ipa->uc_op_work[i].msg = NULL; + } fail_return: EXIT(); - return stat; + return status; } /** @@ -3150,6 +2846,7 @@ int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx) { struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; int ret = 0; + QDF_STATUS status; if (!hdd_ipa_uc_is_enabled(hdd_ctx)) return ret; @@ -3158,14 +2855,15 @@ int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx) hdd_ipa_uc_disable_pipes(hdd_ipa); if (true == hdd_ipa->uc_loaded) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "%s: Disconnect TX PIPE tx_pipe_handle=0x%x", - __func__, hdd_ipa->tx_pipe_handle); - ret = ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle); - HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, - "%s: Disconnect RX PIPE rx_pipe_handle=0x%x", - __func__, hdd_ipa->rx_pipe_handle); - ret = ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle); + status = cdp_ipa_cleanup(cds_get_context(QDF_MODULE_ID_SOC), + hdd_ipa->tx_pipe_handle, + hdd_ipa->rx_pipe_handle); + if (status) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Failure to cleanup IPA pipes (status=%d)", + status); + return -EFAULT; + } } return ret; @@ -3192,11 +2890,11 @@ static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx) hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; if (false == hdd_ipa->ipa_pipes_down) { HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "IPA pipes are not down yet, force shutdown"); + "IPA pipes are not down yet, force shutdown"); hdd_ipa_uc_disable_pipes(hdd_ipa); } else { HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "IPA pipes are down, do nothing"); + "IPA pipes are down, do nothing"); } } @@ -3526,93 +3224,6 @@ int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx) return ret; } -/** - * __hdd_ipa_tx_packet_ipa() - send packet to IPA - * @hdd_ctx: Global HDD context - * @skb: skb sent to IPA - * @session_id: send packet instance session id - * - * Send TX packet which generated by system to IPA. - * This routine only will be used for function verification - * - * Return: NULL packet sent to IPA properly - * NULL invalid packet drop - * skb packet not sent to IPA. legacy data path should handle - */ -static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx, - struct sk_buff *skb, uint8_t session_id) -{ - struct ipa_header *ipa_header; - struct frag_header *frag_header; - struct hdd_ipa_priv *hdd_ipa; - - if (wlan_hdd_validate_context(hdd_ctx)) - return skb; - - hdd_ipa = hdd_ctx->hdd_ipa; - - if (!hdd_ipa_uc_is_enabled(hdd_ctx)) - return skb; - - if (!hdd_ipa) - return skb; - - if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe) - return skb; - - if (skb_headroom(skb) < - (sizeof(struct ipa_header) + sizeof(struct frag_header))) - return skb; - - ipa_header = (struct ipa_header *) skb_push(skb, - sizeof(struct ipa_header)); - if (!ipa_header) { - /* No headroom, legacy */ - return skb; - } - memset(ipa_header, 0, sizeof(*ipa_header)); - ipa_header->vdev_id = 0; - - frag_header = (struct frag_header *) skb_push(skb, - sizeof(struct frag_header)); - if (!frag_header) { - /* No headroom, drop */ - kfree_skb(skb); - return NULL; - } - memset(frag_header, 0, sizeof(*frag_header)); - frag_header->length = skb->len - sizeof(struct frag_header) - - sizeof(struct ipa_header); - - ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL); - return NULL; -} - -/** - * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa - * @hdd_ctx: Global HDD context - * @skb: skb sent to IPA - * @session_id: send packet instance session id - * - * Send TX packet which generated by system to IPA. - * This routine only will be used for function verification - * - * Return: NULL packet sent to IPA properly - * NULL invalid packet drop - * skb packet not sent to IPA. legacy data path should handle - */ -struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx, - struct sk_buff *skb, uint8_t session_id) -{ - struct sk_buff *ret; - - cds_ssr_protect(__func__); - ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id); - cds_ssr_unprotect(__func__); - - return ret; -} - /** * hdd_ipa_wake_lock_timer_func() - Wake lock work handler * @work: scheduled work @@ -3837,14 +3448,12 @@ static int hdd_ipa_rm_cons_request(void) if (ghdd_ipa->resource_loading) { HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, - "%s: IPA resource loading in progress", - __func__); + "IPA resource loading in progress"); ghdd_ipa->pending_cons_req = true; ret = -EINPROGRESS; } else if (ghdd_ipa->resource_unloading) { HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, - "%s: IPA resource unloading in progress", - __func__); + "IPA resource unloading in progress"); ghdd_ipa->pending_cons_req = true; ret = -EPERM; } @@ -3866,6 +3475,7 @@ static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, uint32_t next_cons_bw, next_prod_bw; struct hdd_ipa_priv *hdd_ipa; struct ipa_rm_perf_profile profile; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); int ret; if (wlan_hdd_validate_context(hdd_ctx)) @@ -3905,9 +3515,8 @@ static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, if (hdd_ipa->curr_cons_bw != next_cons_bw) { hdd_debug("Requesting CONS perf curr: %d, next: %d", hdd_ipa->curr_cons_bw, next_cons_bw); - profile.max_supported_bandwidth_mbps = next_cons_bw; - ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS, - &profile); + ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_CONS, + next_cons_bw); if (ret) { hdd_err("RM CONS set perf profile failed: %d", ret); @@ -3920,9 +3529,8 @@ static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, if (hdd_ipa->curr_prod_bw != next_prod_bw) { hdd_debug("Requesting PROD perf curr: %d, next: %d", hdd_ipa->curr_prod_bw, next_prod_bw); - profile.max_supported_bandwidth_mbps = next_prod_bw; - ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD, - &profile); + ret = cdp_ipa_set_perf_level(soc, IPA_RM_RESOURCE_WLAN_PROD, + next_prod_bw); if (ret) { hdd_err("RM PROD set perf profile failed: %d", ret); return ret; @@ -4926,11 +4534,9 @@ static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa) * PROD pipe is also per interface. * Right now there is no advantage of doing this. */ - hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD; - ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params; - ipa->client = hdd_ipa->prod_client; + ipa->client = IPA_CLIENT_WLAN1_PROD; ipa->desc_fifo_sz = desc_fifo_sz; ipa->priv = hdd_ipa; @@ -4986,9 +4592,8 @@ static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa) for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) { if (hdd_ipa->sys_pipe[i].conn_hdl_valid) { - ret = - ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i]. - conn_hdl); + ret = ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i]. + conn_hdl); if (ret) HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d", ret); @@ -5016,348 +4621,6 @@ static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa) } } -/** - * hdd_ipa_register_interface() - register IPA interface - * @hdd_ipa: Global IPA context - * @iface_context: Per-interface IPA context - * - * Return: 0 on success, negative errno on error - */ -static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa, - struct hdd_ipa_iface_context - *iface_context) -{ - struct ipa_tx_intf tx_intf; - struct ipa_rx_intf rx_intf; - struct ipa_ioc_tx_intf_prop *tx_prop = NULL; - struct ipa_ioc_rx_intf_prop *rx_prop = NULL; - char *ifname = iface_context->adapter->dev->name; - - char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX]; - char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX]; - - int num_prop = 1; - int ret = 0; - - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) - num_prop++; - - /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */ - tx_prop = - qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop); - if (!tx_prop) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed"); - goto register_interface_fail; - } - - /* Allocate RX properties, 1 each for IPv4 & IPv6 */ - rx_prop = - qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop); - if (!rx_prop) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed"); - goto register_interface_fail; - } - - qdf_mem_zero(&tx_intf, sizeof(tx_intf)); - qdf_mem_zero(&rx_intf, sizeof(rx_intf)); - - snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV4_NAME_EXT); - snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV6_NAME_EXT); - - rx_prop[IPA_IP_v4].ip = IPA_IP_v4; - rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client; - rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; - - /* - * Interface ID is 3rd byte in the CLD header. Add the meta data and - * mask to identify the interface in IPA hardware - */ - rx_prop[IPA_IP_v4].attrib.meta_data = - htonl(iface_context->adapter->sessionId << 16); - rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); - - rx_intf.num_props++; - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { - rx_prop[IPA_IP_v6].ip = IPA_IP_v6; - rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client; - rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; - rx_prop[IPA_IP_v4].attrib.meta_data = - htonl(iface_context->adapter->sessionId << 16); - rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); - - rx_intf.num_props++; - } - - tx_prop[IPA_IP_v4].ip = IPA_IP_v4; - tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS; - tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client; - strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name, - IPA_RESOURCE_NAME_MAX); - tx_intf.num_props++; - - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { - tx_prop[IPA_IP_v6].ip = IPA_IP_v6; - tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; - tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS; - tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client; - strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name, - IPA_RESOURCE_NAME_MAX); - tx_intf.num_props++; - } - - tx_intf.prop = tx_prop; - rx_intf.prop = rx_prop; - - /* Call the ipa api to register interface */ - ret = ipa_register_intf(ifname, &tx_intf, &rx_intf); - - /* Register IPA Tx desc free callback */ - qdf_nbuf_reg_free_cb(hdd_ipa_nbuf_cb); - -register_interface_fail: - qdf_mem_free(tx_prop); - qdf_mem_free(rx_prop); - return ret; -} - -/** - * hdd_remove_ipa_header() - Remove a specific header from IPA - * @name: Name of the header to be removed - * - * Return: None - */ -static void hdd_ipa_remove_header(char *name) -{ - struct ipa_ioc_get_hdr hdrlookup; - int ret = 0, len; - struct ipa_ioc_del_hdr *ipa_hdr; - - qdf_mem_zero(&hdrlookup, sizeof(hdrlookup)); - strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name)); - ret = ipa_get_hdr(&hdrlookup); - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Hdr deleted already %s, %d", - name, ret); - return; - } - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", hdrlookup.hdl); - len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1; - ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len); - if (ipa_hdr == NULL) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed"); - return; - } - ipa_hdr->num_hdls = 1; - ipa_hdr->commit = 0; - ipa_hdr->hdl[0].hdl = hdrlookup.hdl; - ipa_hdr->hdl[0].status = -1; - ret = ipa_del_hdr(ipa_hdr); - if (ret != 0) - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d", - ret); - - qdf_mem_free(ipa_hdr); -} - -/** - * wlan_ipa_add_hdr() - Add IPA Tx header - * @ipa_hdr: pointer to IPA header addition parameters - * - * Call IPA API to add IPA Tx header descriptor - * and dump Tx header struct - * - * Return: 0 for success, non-zero for failure - */ -static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr) -{ - int ret; - - hdd_debug("==== IPA Tx Header ====\n" - "name: %s\n" - "hdr_len: %d\n" - "type: %d\n" - "is_partial: %d\n" - "hdr_hdl: 0x%x\n" - "status: %d\n" - "is_eth2_ofst_valid: %d\n" - "eth2_ofst: %d\n", - ipa_hdr->hdr[0].name, - ipa_hdr->hdr[0].hdr_len, - ipa_hdr->hdr[0].type, - ipa_hdr->hdr[0].is_partial, - ipa_hdr->hdr[0].hdr_hdl, - ipa_hdr->hdr[0].status, - ipa_hdr->hdr[0].is_eth2_ofst_valid, - ipa_hdr->hdr[0].eth2_ofst); - - HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, "hdr:", - ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); - - ret = ipa_add_hdr(ipa_hdr); - return ret; -} - -/** - * hdd_ipa_add_header_info() - Add IPA header for a given interface - * @hdd_ipa: Global HDD IPA context - * @iface_context: Interface-specific HDD IPA context - * @mac_addr: Interface MAC address - * - * Return: 0 on success, negativer errno value on error - */ -static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa, - struct hdd_ipa_iface_context *iface_context, - uint8_t *mac_addr) -{ - hdd_adapter_t *adapter = iface_context->adapter; - char *ifname; - struct ipa_ioc_add_hdr *ipa_hdr = NULL; - int ret = -EINVAL; - struct hdd_ipa_tx_hdr *tx_hdr = NULL; - struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL; - - ifname = adapter->dev->name; - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Add Partial hdr: %s, %pM", - ifname, mac_addr); - - /* dynamically allocate the memory to add the hdrs */ - ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr) - + sizeof(struct ipa_hdr_add)); - if (!ipa_hdr) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: ipa_hdr allocation failed", ifname); - ret = -ENOMEM; - goto end; - } - - ipa_hdr->commit = 0; - ipa_hdr->num_hdrs = 1; - - if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { - uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; - memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); - memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN); - uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId; - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "ifname=%s, vdev_id=%d", - ifname, uc_tx_hdr->ipa_hd.vdev_id); - snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV4_NAME_EXT); - ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; - ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II; - ipa_hdr->hdr[0].is_partial = 1; - ipa_hdr->hdr[0].hdr_hdl = 0; - ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; - ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; - - ret = wlan_ipa_add_hdr(ipa_hdr); - } else { - tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; - - /* Set the Source MAC */ - memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN); - memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN); - - snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV4_NAME_EXT); - ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN; - ipa_hdr->hdr[0].is_partial = 1; - ipa_hdr->hdr[0].hdr_hdl = 0; - ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; - ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET; - - /* Set the type to IPV4 in the header */ - tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP); - - ret = ipa_add_hdr(ipa_hdr); - } - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d", - ifname, ret); - goto end; - } - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv4 hdr_hdl: 0x%x", - ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); - - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { - snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV6_NAME_EXT); - - if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { - uc_tx_hdr = - (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; - uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6); - ret = wlan_ipa_add_hdr(ipa_hdr); - } else { - /* Set the type to IPV6 in the header */ - tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; - tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6); - ret = ipa_add_hdr(ipa_hdr); - } - - if (ret) { - HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, - "%s: IPv6 add hdr failed: %d", ifname, ret); - goto clean_ipv4_hdr; - } - - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "%s: IPv6 hdr_hdl: 0x%x", - ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); - } - - qdf_mem_free(ipa_hdr); - - return ret; - -clean_ipv4_hdr: - snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", - ifname, HDD_IPA_IPV4_NAME_EXT); - hdd_ipa_remove_header(ipa_hdr->hdr[0].name); -end: - if (ipa_hdr) - qdf_mem_free(ipa_hdr); - - return ret; -} - -/** - * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter - * @adapter: Adapter upon which IPA was previously configured - * - * Return: None - */ -static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter) -{ - struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; - int ret; - char name_ipa[IPA_RESOURCE_NAME_MAX]; - - /* Remove the headers */ - snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", - adapter->dev->name, HDD_IPA_IPV4_NAME_EXT); - hdd_ipa_remove_header(name_ipa); - - if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { - snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", - adapter->dev->name, HDD_IPA_IPV6_NAME_EXT); - hdd_ipa_remove_header(name_ipa); - } - /* unregister the interface with IPA */ - ret = ipa_deregister_intf(adapter->dev->name); - if (ret) - HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, - "%s: ipa_deregister_intf fail: %d", - adapter->dev->name, ret); -} - /** * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface * @iface_context: interface-specific IPA context @@ -5369,7 +4632,9 @@ static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context) if (iface_context == NULL) return; - hdd_ipa_clean_hdr(iface_context->adapter); + cdp_ipa_cleanup_iface(cds_get_context(QDF_MODULE_ID_SOC), + iface_context->adapter->dev->name, + hdd_ipa_is_ipv6_enabled(iface_context->hdd_ipa->hdd_ctx)); qdf_spin_lock_bh(&iface_context->interface_lock); iface_context->adapter->ipa_context = NULL; @@ -5436,23 +4701,18 @@ static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa, iface_context->tl_context = tl_context; - ret = hdd_ipa_add_header_info(hdd_ipa, iface_context, - adapter->dev->dev_addr); - + ret = cdp_ipa_setup_iface(cds_get_context(QDF_MODULE_ID_SOC), + adapter->dev->name, adapter->dev->dev_addr, + iface_context->prod_client, + iface_context->cons_client, + adapter->sessionId, + hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)); if (ret) goto end; - /* Configure the TX and RX pipes filter rules */ - ret = hdd_ipa_register_interface(hdd_ipa, iface_context); - if (ret) - goto cleanup_header; - hdd_ipa->num_iface++; return ret; -cleanup_header: - - hdd_ipa_clean_hdr(adapter); end: if (iface_context) hdd_ipa_cleanup_iface(iface_context); diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 39d829bea344..f9f9f3993770 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -605,6 +605,99 @@ int wma_cli_set_command(int vdev_id, int param_id, int sval, int vpdev) } +/** + * wma_ipa_get_stat() - get IPA data path stats from FW + * + * Return: 0 on success, errno on failure + */ +#ifdef IPA_OFFLOAD +static int wma_ipa_get_stat(void) +{ + struct cdp_pdev *pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc stat"); + return -EINVAL; + } + cdp_ipa_get_stat(cds_get_context(QDF_MODULE_ID_SOC), pdev); + + return 0; +} +#else +static int wma_ipa_get_stat(void) +{ + return 0; +} +#endif + +/** + * wma_ipa_uc_get_share_stats() - get Tx/Rx byte stats from FW + * @privcmd: private command + * + * Return: 0 on success, errno on failure + */ +#if defined(IPA_OFFLOAD) && defined(FEATURE_METERING) +static int wma_ipa_uc_get_share_stats(wma_cli_set_cmd_t *privcmd) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_pdev *pdev; + uint8_t reset_stats = privcmd->param_value; + + WMA_LOGD("%s: reset_stats=%d", + "WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID", + reset_stats); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc get share stats"); + return -EINVAL; + } + cdp_ipa_uc_get_share_stats(soc, pdev, reset_stats); + + return 0; +} +#else +static int wma_ipa_uc_get_share_stats(wma_cli_set_cmd_t *privcmd) +{ + return 0; +} +#endif + +/** + * wma_ipa_uc_set_quota() - set quota limit to FW + * @privcmd: private command + * + * Return: 0 on success, errno on failure + */ +#if defined(IPA_OFFLOAD) && defined(FEATURE_METERING) +static int wma_ipa_uc_set_quota(wma_cli_set_cmd_t *privcmd) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_pdev *pdev; + uint64_t quota_bytes = privcmd->param_sec_value; + + quota_bytes <<= 32; + quota_bytes |= privcmd->param_value; + + WMA_LOGD("%s: quota_bytes=%llu", + "WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID", + quota_bytes); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc set quota"); + return -EINVAL; + } + cdp_ipa_uc_set_quota(soc, pdev, quota_bytes); + + return 0; +} +#else +static int wma_ipa_uc_set_quota(wma_cli_set_cmd_t *privcmd) +{ + return 0; +} +#endif + /** * wma_set_priv_cfg() - set private config parameters * @wma_handle: wma handle @@ -751,54 +844,20 @@ static int32_t wma_set_priv_cfg(tp_wma_handle wma_handle, case WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID: { - void *soc = cds_get_context(QDF_MODULE_ID_SOC); - struct cdp_pdev *pdev; - - pdev = cds_get_context(QDF_MODULE_ID_TXRX); - if (!pdev) { - WMA_LOGE("pdev NULL for uc stat"); - return -EINVAL; - } - cdp_ipa_get_stat(soc, pdev); + wma_ipa_get_stat(); } break; case WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID: { - void *soc = cds_get_context(QDF_MODULE_ID_SOC); - struct cdp_pdev *pdev; - uint8_t reset_stats = privcmd->param_value; - - WMA_LOGE("%s: reset_stats=%d", - "WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID", - reset_stats); - pdev = cds_get_context(QDF_MODULE_ID_TXRX); - if (!pdev) { - WMA_LOGE("pdev NULL for uc stat"); - return -EINVAL; - } - cdp_ipa_uc_get_share_stats(soc, pdev, reset_stats); + wma_ipa_uc_get_share_stats(privcmd); } break; case WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID: { - void *soc = cds_get_context(QDF_MODULE_ID_SOC); - struct cdp_pdev *pdev; - uint64_t quota_bytes = privcmd->param_sec_value; + wma_ipa_uc_set_quota(privcmd); - quota_bytes <<= 32; - quota_bytes |= privcmd->param_value; - - WMA_LOGE("%s: quota_bytes=%llu", - "WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID", - quota_bytes); - pdev = cds_get_context(QDF_MODULE_ID_TXRX); - if (!pdev) { - WMA_LOGE("pdev NULL for uc stat"); - return -EINVAL; - } - cdp_ipa_uc_set_quota(soc, pdev, quota_bytes); } break; @@ -3826,6 +3885,28 @@ static void wma_alloc_host_mem(tp_wma_handle wma_handle, uint32_t req_id, wma_handle->num_mem_chunks = idx; } +/** + * wma_set_tx_partition_base() - set TX MSDU ID partition base for IPA + * @value: TX MSDU ID partition base + * + * Return: none + */ +#ifdef IPA_OFFLOAD +static void wma_set_tx_partition_base(uint32_t value) +{ + cdp_ipa_set_uc_tx_partition_base( + cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_cfg *)cds_get_context(QDF_MODULE_ID_CFG), + value); + WMA_LOGD("%s: TX_MSDU_ID_PARTITION=%d", __func__, + value); +} +#else +static void wma_set_tx_partition_base(uint32_t value) +{ +} +#endif + /** * wma_update_target_services() - update target services from wma handle * @wh: wma handle @@ -3920,19 +4001,9 @@ static inline void wma_update_target_services(tp_wma_handle wh, if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT)) { - cdp_ipa_set_uc_tx_partition_base( - cds_get_context(QDF_MODULE_ID_SOC), - (struct cdp_cfg *)cds_get_context(QDF_MODULE_ID_CFG), - HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN); - WMA_LOGD("%s: TX_MSDU_ID_NEW_PARTITION=%d", __func__, - HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN); + wma_set_tx_partition_base(HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN); } else { - cdp_ipa_set_uc_tx_partition_base( - cds_get_context(QDF_MODULE_ID_SOC), - (struct cdp_cfg *)cds_get_context(QDF_MODULE_ID_CFG), - HTT_TX_IPA_MSDU_ID_SPACE_BEGIN); - WMA_LOGD("%s: TX_MSDU_ID_OLD_PARTITION=%d", __func__, - HTT_TX_IPA_MSDU_ID_SPACE_BEGIN); + wma_set_tx_partition_base(HTT_TX_IPA_MSDU_ID_SPACE_BEGIN); } wma_he_update_tgt_services(wh, cfg);