diff --git a/ipa/core/inc/wlan_ipa_core.h b/ipa/core/inc/wlan_ipa_core.h index 6182898b38..a6ca4db8a4 100644 --- a/ipa/core/inc/wlan_ipa_core.h +++ b/ipa/core/inc/wlan_ipa_core.h @@ -80,6 +80,19 @@ bool wlan_ipa_is_clk_scaling_enabled(struct wlan_ipa_config *ipa_cfg) WLAN_IPA_RM_ENABLE_MASK); } +/** + * wlan_ipa_is_rt_debugging_enabled() - Is IPA RT debugging enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPA RT debugging is enabled, false otherwise + */ +static inline +bool wlan_ipa_is_rt_debugging_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, + WLAN_IPA_REAL_TIME_DEBUGGING); +} + /** * wlan_ipa_setup - IPA initialize and setup * @ipa_ctx: IPA priv obj @@ -132,6 +145,16 @@ QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx); QDF_STATUS wlan_ipa_set_perf_level(struct wlan_ipa_priv *ipa_ctx, uint64_t tx_packets, uint64_t rx_packets); +/** + * wlan_ipa_get_iface() - Get IPA interface + * @ipa_ctx: IPA context + * @mode: Interface device mode + * + * Return: IPA interface address + */ +struct wlan_ipa_iface_context +*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode); + #ifndef CONFIG_IPA_WDI_UNIFIED_API /** * wlan_ipa_wdi_rm_request_resource() - IPA WDI request resource @@ -234,5 +257,139 @@ static inline QDF_STATUS wlan_ipa_wdi_rm_try_release(struct wlan_ipa_priv #endif /* CONFIG_IPA_WDI_UNIFIED_API */ +#ifdef FEATURE_METERING + +/** + * wlan_ipa_uc_op_metering() - IPA uC operation for stats and quota limit + * @ipa_ctx: IPA context + * @op_msg: operation message received from firmware + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx, + struct op_msg_type *op_msg); + +/** + * wlan_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) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt, + void *data); +#else + +static inline +QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx, + struct op_msg_type *op_msg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void wlan_ipa_wdi_meter_notifier_cb(void) +{ +} +#endif /* FEATURE_METERING */ + +/** + * wlan_ipa_uc_stat() - Print IPA uC stats + * @ipa_ctx: IPA context + * + * Return: None + */ +void wlan_ipa_uc_stat(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_info() - Print IPA uC resource and session information + * @ipa_ctx: IPA context + * + * Return: None + */ +void wlan_ipa_uc_info(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_print_fw_wdi_stats() - Print FW IPA WDI stats + * @ipa_ctx: IPA context + * + * Return: None + */ +void wlan_ipa_print_fw_wdi_stats(struct wlan_ipa_priv *ipa_ctx, + struct ipa_uc_fw_stats *uc_fw_stat); + +/** + * wlan_ipa_uc_stat_request() - Get IPA stats from IPA + * @ipa_ctx: IPA context + * @reason: STAT REQ Reason + * + * Return: None + */ +void wlan_ipa_uc_stat_request(struct wlan_ipa_priv *ipa_ctx, uint8_t reason); + +/** + * wlan_ipa_uc_stat_query() - Query the IPA stats + * @ipa_ctx: IPA context + * @ipa_tx_diff: tx packet count diff from previous tx packet count + * @ipa_rx_diff: rx packet count diff from previous rx packet count + * + * Return: None + */ +void wlan_ipa_uc_stat_query(struct wlan_ipa_priv *ipa_ctx, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff); + +/** + * wlan_ipa_dump_info() - dump IPA IPA struct + * @ipa_ctx: IPA context + * + * Dump entire struct ipa_ctx + * + * Return: none + */ +void wlan_ipa_dump_info(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_rt_debug_host_dump - dump rt debug buffer + * @ipa_ctx: IPA context + * + * If rt debug enabled, dump debug buffer contents based on requirement + * + * Return: none + */ +void wlan_ipa_uc_rt_debug_host_dump(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_rt_debug_destructor() - called by data packet free + * @nbuff: packet pinter + * + * when free data packet, will be invoked by wlan client and will increase + * free counter + * + * Return: none + */ +void wlan_ipa_uc_rt_debug_destructor(qdf_nbuf_t nbuff); + +/** + * wlan_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging + * @ipa_ctx: IPA context + * + * free all rt debugging resources + * + * Return: none + */ +void wlan_ipa_uc_rt_debug_deinit(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_rt_debug_init() - initialize resources to handle rt debugging + * @ipa_ctx: IPA context + * + * alloc and initialize all rt debugging resources + * + * Return: none + */ +void wlan_ipa_uc_rt_debug_init(struct wlan_ipa_priv *ipa_ctx); + #endif /* IPA_OFFLOAD */ #endif /* _WLAN_IPA_CORE_H_ */ diff --git a/ipa/core/inc/wlan_ipa_main.h b/ipa/core/inc/wlan_ipa_main.h index fa5330da12..b8e5aa5b17 100644 --- a/ipa/core/inc/wlan_ipa_main.h +++ b/ipa/core/inc/wlan_ipa_main.h @@ -167,5 +167,59 @@ void ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, void *txrx_handle); */ QDF_STATUS ipa_rm_set_perf_level(struct wlan_objmgr_pdev *pdev, uint64_t tx_packets, uint64_t rx_packets); + +/** + * ipa_uc_info() - Print IPA uC resource and session information + * @pdev: pdev obj + * + * Return: None + */ +void ipa_uc_info(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_uc_stat() - Print IPA uC stats + * @pdev: pdev obj + * + * Return: None + */ +void ipa_uc_stat(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_uc_rt_debug_host_dump() - IPA rt debug host dump + * @pdev: pdev obj + * + * Return: None + */ +void ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_dump_info() - Dump IPA context information + * @pdev: pdev obj + * + * Return: None + */ +void ipa_dump_info(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_uc_stat_request() - Get IPA stats from IPA. + * @pdev: pdev obj + * @reason: STAT REQ Reason + * + * Return: None + */ +void ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, + uint8_t reason); + +/** + * ipa_uc_stat_query() - Query the IPA stats + * @pdev: pdev obj + * @ipa_tx_diff: tx packet count diff from previous tx packet count + * @ipa_rx_diff: rx packet count diff from previous rx packet count + * + * Return: None + */ +void ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff); + #endif /* IPA_OFFLOAD */ #endif /* end of _WLAN_IPA_MAIN_H_ */ diff --git a/ipa/core/inc/wlan_ipa_priv.h b/ipa/core/inc/wlan_ipa_priv.h index 8f5d737351..0220a5a67b 100644 --- a/ipa/core/inc/wlan_ipa_priv.h +++ b/ipa/core/inc/wlan_ipa_priv.h @@ -302,7 +302,7 @@ struct wlan_ipa_iface_context { qdf_ipa_client_type_t prod_client; uint8_t iface_id; /* This iface ID */ - qdf_device_t dev; + qdf_netdev_t dev; enum tQDF_ADAPTER_MODE device_mode; uint8_t sta_id; /* This iface station ID */ uint8_t session_id; @@ -682,6 +682,11 @@ struct wlan_ipa_priv { #define IPA_RESOURCE_COMP_WAIT_TIME 100 +#ifdef FEATURE_METERING +#define IPA_UC_SHARING_STATES_WAIT_TIME 500 +#define IPA_UC_SET_QUOTA_WAIT_TIME 500 +#endif + /** * wlan_ipa_wlan_event_to_str() - convert IPA WLAN event to string * @event: IPA WLAN event to be converted to a string diff --git a/ipa/core/src/wlan_ipa_core.c b/ipa/core/src/wlan_ipa_core.c index 340eecdf74..78544bcfd4 100644 --- a/ipa/core/src/wlan_ipa_core.c +++ b/ipa/core/src/wlan_ipa_core.c @@ -180,6 +180,11 @@ static QDF_STATUS wlan_ipa_uc_send_wdi_control_msg(bool ctrl) return QDF_STATUS_SUCCESS; } +struct wlan_ipa_priv *wlan_ipa_get_obj_context(void) +{ + return gp_ipa; +} + #ifdef CONFIG_IPA_WDI_UNIFIED_API /* @@ -202,6 +207,33 @@ static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) } #endif +#ifdef FEATURE_METERING +/** + * wlan_ipa_wdi_init_metering() - IPA WDI metering init + * @ipa_ctx: IPA context + * @in: IPA WDI in param + * + * Return: QDF_STATUS + */ +static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt, + qdf_ipa_wdi_init_in_params_t *in) +{ + QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(in) = + wlan_ipa_wdi_meter_notifier_cb; +} +#else +static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt, + qdf_ipa_wdi_init_in_params_t *in) +{ +} +#endif + +/** + * wlan_ipa_wdi_init() - IPA WDI init + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx) { qdf_ipa_wdi_init_in_params_t in; @@ -212,7 +244,8 @@ static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx) QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version; QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb; - QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = (void *)ipa_ctx; + QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = ipa_ctx; + wlan_ipa_wdi_init_metering(ipa_ctx, &in); ret = qdf_ipa_wdi_init(&in, &out); if (ret) { @@ -761,3 +794,19 @@ QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx) return QDF_STATUS_SUCCESS; } + +struct wlan_ipa_iface_context +*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode) +{ + struct wlan_ipa_iface_context *iface_ctx = NULL; + int i; + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + + if (iface_ctx->device_mode == mode) + return iface_ctx; + } + + return NULL; +} diff --git a/ipa/core/src/wlan_ipa_main.c b/ipa/core/src/wlan_ipa_main.c index 64d6149e36..8baed7fcfa 100644 --- a/ipa/core/src/wlan_ipa_main.c +++ b/ipa/core/src/wlan_ipa_main.c @@ -176,3 +176,112 @@ QDF_STATUS ipa_rm_set_perf_level(struct wlan_objmgr_pdev *pdev, return wlan_ipa_set_perf_level(ipa_obj, tx_packets, rx_packets); } + +void ipa_uc_info(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!g_ipa_hw_support) { + ipa_info("ipa hw not present"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_info(ipa_obj); +} + +void ipa_uc_stat(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!g_ipa_hw_support) { + ipa_info("ipa hw not present"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_stat(ipa_obj); +} + +void ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!g_ipa_hw_support) { + ipa_info("ipa hw not present"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_rt_debug_host_dump(ipa_obj); +} + +void ipa_dump_info(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!g_ipa_hw_support) { + ipa_info("ipa hw not present"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_dump_info(ipa_obj); +} + +void ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, uint8_t reason) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!g_ipa_hw_support) { + ipa_info("ipa hw not present"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_stat_request(ipa_obj, reason); +} + +void ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!g_ipa_hw_support) { + ipa_info("ipa hw not present"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_stat_query(ipa_obj, ipa_tx_diff, ipa_rx_diff); +} diff --git a/ipa/core/src/wlan_ipa_stats.c b/ipa/core/src/wlan_ipa_stats.c new file mode 100644 index 0000000000..05fddd77ff --- /dev/null +++ b/ipa/core/src/wlan_ipa_stats.c @@ -0,0 +1,961 @@ +/* + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Include Files */ +#include "wlan_ipa_main.h" +#include "wlan_ipa_core.h" +#include "cdp_txrx_ipa.h" + +/** + * wlan_ipa_uc_rt_debug_host_fill - fill rt debug buffer + * @ctext: pointer to ipa context. + * + * If rt debug enabled, periodically called, and fill debug buffer + * + * Return: none + */ +static void wlan_ipa_uc_rt_debug_host_fill(void *ctext) +{ + struct wlan_ipa_priv *ipa_ctx = ctext; + struct uc_rt_debug_info *dump_info = NULL; + + if (!ipa_ctx) + return; + + qdf_mutex_acquire(&ipa_ctx->rt_debug_lock); + dump_info = &ipa_ctx->rt_bug_buffer[ + ipa_ctx->rt_buf_fill_index % WLAN_IPA_UC_RT_DEBUG_BUF_COUNT]; + + dump_info->time = (uint64_t)qdf_mc_timer_get_system_time(); + dump_info->ipa_excep_count = ipa_ctx->stats.num_rx_excep; + dump_info->rx_drop_count = ipa_ctx->ipa_rx_internal_drop_count; + dump_info->net_sent_count = ipa_ctx->ipa_rx_net_send_count; + dump_info->tx_fwd_count = ipa_ctx->ipa_tx_forward; + dump_info->tx_fwd_ok_count = ipa_ctx->stats.num_tx_fwd_ok; + dump_info->rx_discard_count = ipa_ctx->ipa_rx_discard; + dump_info->rx_destructor_call = ipa_ctx->ipa_rx_destructor_count; + ipa_ctx->rt_buf_fill_index++; + qdf_mutex_release(&ipa_ctx->rt_debug_lock); + + qdf_mc_timer_start(&ipa_ctx->rt_debug_fill_timer, + WLAN_IPA_UC_RT_DEBUG_FILL_INTERVAL); +} + +void wlan_ipa_uc_rt_debug_host_dump(struct wlan_ipa_priv *ipa_ctx) +{ + unsigned int dump_count; + unsigned int dump_index; + struct uc_rt_debug_info *dump_info = NULL; + + if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) { + ipa_debug("IPA RT debug is not enabled"); + return; + } + + ipa_info("========= WLAN-IPA DEBUG BUF DUMP ==========\n"); + ipa_info(" TM : EXEP : DROP : NETS : FWOK" + ": TXFD : DSTR : DSCD\n"); + + qdf_mutex_acquire(&ipa_ctx->rt_debug_lock); + for (dump_count = 0; + dump_count < WLAN_IPA_UC_RT_DEBUG_BUF_COUNT; + dump_count++) { + dump_index = (ipa_ctx->rt_buf_fill_index + dump_count) % + WLAN_IPA_UC_RT_DEBUG_BUF_COUNT; + dump_info = &ipa_ctx->rt_bug_buffer[dump_index]; + ipa_info("%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n", + dump_info->time, dump_info->ipa_excep_count, + dump_info->rx_drop_count, dump_info->net_sent_count, + dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count, + dump_info->rx_destructor_call, + dump_info->rx_discard_count); + } + qdf_mutex_release(&ipa_ctx->rt_debug_lock); +} + +/** + * wlan_ipa_uc_rt_debug_handler - periodic memory health monitor handler + * @ctext: pointer to ipa context. + * + * periodically called by timer expire + * will try to alloc dummy memory and detect out of memory condition + * if out of memory detected, dump wlan-ipa stats + * + * Return: none + */ +static void wlan_ipa_uc_rt_debug_handler(void *ctext) +{ + struct wlan_ipa_priv *ipa_ctx = ctext; + void *dummy_ptr = NULL; + + if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) { + ipa_debug("IPA RT debug is not enabled"); + return; + } + + /* Allocate dummy buffer periodically and free immediately. this will + * proactively detect OOM and if allocation fails dump ipa stats + */ + dummy_ptr = qdf_mem_malloc(WLAN_IPA_UC_DEBUG_DUMMY_MEM_SIZE); + if (!dummy_ptr) { + wlan_ipa_uc_rt_debug_host_dump(ipa_ctx); + wlan_ipa_uc_stat_request(ipa_ctx, + WLAN_IPA_UC_STAT_REASON_DEBUG); + } else { + qdf_mem_free(dummy_ptr); + } + + qdf_mc_timer_start(&ipa_ctx->rt_debug_timer, + WLAN_IPA_UC_RT_DEBUG_PERIOD); +} + +void wlan_ipa_uc_rt_debug_destructor(qdf_nbuf_t nbuff) +{ + struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context(); + + if (!ipa_ctx) { + ipa_err("invalid ipa context"); + return; + } + + ipa_ctx->ipa_rx_destructor_count++; +} + +void wlan_ipa_uc_rt_debug_deinit(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_mutex_destroy(&ipa_ctx->rt_debug_lock); + + if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) { + ipa_debug("IPA RT debug is not enabled"); + return; + } + + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&ipa_ctx->rt_debug_fill_timer)) { + qdf_mc_timer_stop(&ipa_ctx->rt_debug_fill_timer); + } + qdf_mc_timer_destroy(&ipa_ctx->rt_debug_fill_timer); + + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&ipa_ctx->rt_debug_timer)) { + qdf_mc_timer_stop(&ipa_ctx->rt_debug_timer); + } + qdf_mc_timer_destroy(&ipa_ctx->rt_debug_timer); +} + +void wlan_ipa_uc_rt_debug_init(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_mutex_create(&ipa_ctx->rt_debug_lock); + ipa_ctx->rt_buf_fill_index = 0; + qdf_mem_zero(ipa_ctx->rt_bug_buffer, + sizeof(struct uc_rt_debug_info) * + WLAN_IPA_UC_RT_DEBUG_BUF_COUNT); + ipa_ctx->ipa_tx_forward = 0; + ipa_ctx->ipa_rx_discard = 0; + ipa_ctx->ipa_rx_net_send_count = 0; + ipa_ctx->ipa_rx_internal_drop_count = 0; + ipa_ctx->ipa_rx_destructor_count = 0; + + /* Reatime debug enable on feature enable */ + if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) { + ipa_debug("IPA RT debug is not enabled"); + return; + } + + qdf_mc_timer_init(&ipa_ctx->rt_debug_fill_timer, QDF_TIMER_TYPE_SW, + wlan_ipa_uc_rt_debug_host_fill, (void *)ipa_ctx); + qdf_mc_timer_start(&ipa_ctx->rt_debug_fill_timer, + WLAN_IPA_UC_RT_DEBUG_FILL_INTERVAL); + + qdf_mc_timer_init(&ipa_ctx->rt_debug_timer, QDF_TIMER_TYPE_SW, + wlan_ipa_uc_rt_debug_handler, (void *)ipa_ctx); + qdf_mc_timer_start(&ipa_ctx->rt_debug_timer, + WLAN_IPA_UC_RT_DEBUG_PERIOD); + +} + +/** + * wlan_ipa_dump_ipa_ctx() - dump entries in IPA IPA struct + * @ipa_ctx: IPA context + * + * Dump entries in struct ipa_ctx + * + * Return: none + */ +static void wlan_ipa_dump_ipa_ctx(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + + /* IPA IPA */ + ipa_info("\n==== IPA IPA ====\n" + "num_iface: %d\n" + "rm_state: %d\n" + "rm_lock: %pK\n" + "uc_rm_work: %pK\n" + "uc_op_work: %pK\n" + "wake_lock: %pK\n" + "wake_lock_work: %pK\n" + "wake_lock_released: %d\n" + "tx_ref_cnt: %d\n" + "pm_queue_head----\n" + "\thead: %pK\n" + "\ttail: %pK\n" + "\tqlen: %d\n" + "pm_work: %pK\n" + "pm_lock: %pK\n" + "suspended: %d\n", + ipa_ctx->num_iface, + ipa_ctx->rm_state, + &ipa_ctx->rm_lock, + &ipa_ctx->uc_rm_work, + &ipa_ctx->uc_op_work, + &ipa_ctx->wake_lock, + &ipa_ctx->wake_lock_work, + ipa_ctx->wake_lock_released, + ipa_ctx->tx_ref_cnt.counter, + ipa_ctx->pm_queue_head.head, + ipa_ctx->pm_queue_head.tail, + ipa_ctx->pm_queue_head.qlen, + &ipa_ctx->pm_work, + &ipa_ctx->pm_lock, + ipa_ctx->suspended); + + ipa_info("\nq_lock: %pK\n" + "pend_desc_head----\n" + "\tnext: %pK\n" + "\tprev: %pK\n" + "stats: %pK\n" + "curr_prod_bw: %d\n" + "curr_cons_bw: %d\n" + "activated_fw_pipe: %d\n" + "sap_num_connected_sta: %d\n" + "sta_connected: %d\n", + &ipa_ctx->q_lock, + ipa_ctx->pend_desc_head.next, + ipa_ctx->pend_desc_head.prev, + &ipa_ctx->stats, + ipa_ctx->curr_prod_bw, + ipa_ctx->curr_cons_bw, + ipa_ctx->activated_fw_pipe, + ipa_ctx->sap_num_connected_sta, + (unsigned int)ipa_ctx->sta_connected); + + ipa_info("\ntx_pipe_handle: 0x%x\n" + "rx_pipe_handle: 0x%x\n" + "resource_loading: %d\n" + "resource_unloading: %d\n" + "pending_cons_req: %d\n" + "pending_event----\n" + "\tanchor.next: %pK\n" + "\tanchor.prev: %pK\n" + "\tcount: %d\n" + "\tmax_size: %d\n" + "event_lock: %pK\n" + "ipa_tx_packets_diff: %d\n" + "ipa_rx_packets_diff: %d\n" + "ipa_p_tx_packets: %d\n" + "ipa_p_rx_packets: %d\n" + "stat_req_reason: %d\n", + ipa_ctx->tx_pipe_handle, + ipa_ctx->rx_pipe_handle, + ipa_ctx->resource_loading, + ipa_ctx->resource_unloading, + ipa_ctx->pending_cons_req, + ipa_ctx->pending_event.anchor.next, + ipa_ctx->pending_event.anchor.prev, + ipa_ctx->pending_event.count, + ipa_ctx->pending_event.max_size, + &ipa_ctx->event_lock, + ipa_ctx->ipa_tx_packets_diff, + ipa_ctx->ipa_rx_packets_diff, + ipa_ctx->ipa_p_tx_packets, + ipa_ctx->ipa_p_rx_packets, + ipa_ctx->stat_req_reason); + + ipa_info("\ncons_pipe_in----\n" + "\tsys: %pK\n" + "\tdl.comp_ring_base_pa: 0x%x\n" + "\tdl.comp_ring_size: %d\n" + "\tdl.ce_ring_base_pa: 0x%x\n" + "\tdl.ce_door_bell_pa: 0x%x\n" + "\tdl.ce_ring_size: %d\n" + "\tdl.num_tx_buffers: %d\n" + "prod_pipe_in----\n" + "\tsys: %pK\n" + "\tul.rdy_ring_base_pa: 0x%x\n" + "\tul.rdy_ring_size: %d\n" + "\tul.rdy_ring_rp_pa: 0x%x\n" + "uc_loaded: %d\n" + "wdi_enabled: %d\n" + "rt_debug_fill_timer: %pK\n" + "rt_debug_lock: %pK\n" + "ipa_lock: %pK\n", + &ipa_ctx->cons_pipe_in.sys, + (unsigned int)ipa_ctx->cons_pipe_in.u.dl.comp_ring_base_pa, + ipa_ctx->cons_pipe_in.u.dl.comp_ring_size, + (unsigned int)ipa_ctx->cons_pipe_in.u.dl.ce_ring_base_pa, + (unsigned int)ipa_ctx->cons_pipe_in.u.dl.ce_door_bell_pa, + ipa_ctx->cons_pipe_in.u.dl.ce_ring_size, + ipa_ctx->cons_pipe_in.u.dl.num_tx_buffers, + &ipa_ctx->prod_pipe_in.sys, + (unsigned int)ipa_ctx->prod_pipe_in.u.ul.rdy_ring_base_pa, + ipa_ctx->prod_pipe_in.u.ul.rdy_ring_size, + (unsigned int)ipa_ctx->prod_pipe_in.u.ul.rdy_ring_rp_pa, + ipa_ctx->uc_loaded, + ipa_ctx->wdi_enabled, + &ipa_ctx->rt_debug_fill_timer, + &ipa_ctx->rt_debug_lock, + &ipa_ctx->ipa_lock); + + ipa_info("\nvdev_to_iface----"); + for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) + ipa_info("\n\t[%d]=%d", i, ipa_ctx->vdev_to_iface[i]); + + QDF_TRACE(QDF_MODULE_ID_IPA, QDF_TRACE_LEVEL_INFO, + "\nvdev_offload_enabled----"); + for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) + ipa_info("\n\t[%d]=%d", i, ipa_ctx->vdev_offload_enabled[i]); + + QDF_TRACE(QDF_MODULE_ID_IPA, QDF_TRACE_LEVEL_INFO, + "\nassoc_stas_map ----"); + for (i = 0; i < WLAN_IPA_MAX_STA_COUNT; i++) { + ipa_info("\n\t[%d]: is_reserved=%d, sta_id=%d", i, + ipa_ctx->assoc_stas_map[i].is_reserved, + ipa_ctx->assoc_stas_map[i].sta_id); + } +} + +/** + * wlan_ipa_dump_sys_pipe() - dump IPA IPA SYS Pipe struct + * @ipa_ctx: IPA IPA struct + * + * Dump entire struct wlan_ipa_sys_pipe + * + * Return: none + */ +static void wlan_ipa_dump_sys_pipe(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + + /* IPA SYS Pipes */ + ipa_info("==== IPA SYS Pipes ===="); + + for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) { + struct wlan_ipa_sys_pipe *sys_pipe; + qdf_ipa_sys_connect_params_t *ipa_sys_params; + + sys_pipe = &ipa_ctx->sys_pipe[i]; + ipa_sys_params = &sys_pipe->ipa_sys_params; + + ipa_info("\nsys_pipe[%d]----\n" + "\tconn_hdl: 0x%x\n" + "\tconn_hdl_valid: %d\n" + "\tnat_en: %d\n" + "\thdr_len %d\n" + "\thdr_additional_const_len: %d\n" + "\thdr_ofst_pkt_size_valid: %d\n" + "\thdr_ofst_pkt_size: %d\n" + "\thdr_little_endian: %d\n" + "\tmode: %d\n" + "\tclient: %d\n" + "\tdesc_fifo_sz: %d\n" + "\tpriv: %pK\n" + "\tnotify: %pK\n" + "\tskip_ep_cfg: %d\n" + "\tkeep_ipa_awake: %d\n", + i, + sys_pipe->conn_hdl, + sys_pipe->conn_hdl_valid, + QDF_IPA_SYS_PARAMS_NAT_EN(ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_LEN(ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_ADDITIONAL_CONST_LEN( + ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE_VALID( + ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE(ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_LITTLE_ENDIAN(ipa_sys_params), + QDF_IPA_SYS_PARAMS_MODE(ipa_sys_params), + QDF_IPA_SYS_PARAMS_CLIENT(ipa_sys_params), + QDF_IPA_SYS_PARAMS_DESC_FIFO_SZ(ipa_sys_params), + QDF_IPA_SYS_PARAMS_PRIV(ipa_sys_params), + QDF_IPA_SYS_PARAMS_NOTIFY(ipa_sys_params), + QDF_IPA_SYS_PARAMS_SKIP_EP_CFG(ipa_sys_params), + QDF_IPA_SYS_PARAMS_KEEP_IPA_AWAKE(ipa_sys_params)); + } +} + +/** + * wlan_ipa_dump_iface_context() - dump IPA IPA Interface Context struct + * @ipa_ctx: IPA IPA struct + * + * Dump entire struct wlan_ipa_iface_context + * + * Return: none + */ +static void wlan_ipa_dump_iface_context(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + + /* IPA Interface Contexts */ + ipa_info("\n==== IPA Interface Contexts ====\n"); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + struct wlan_ipa_iface_context *iface_context; + + iface_context = &ipa_ctx->iface_context[i]; + + ipa_info("\niface_context[%d]----\n" + "\tipa_ctx: %pK\n" + "\ttl_context: %pK\n" + "\tcons_client: %d\n" + "\tprod_client: %d\n" + "\tiface_id: %d\n" + "\tsta_id: %d\n" + "\tinterface_lock: %pK\n" + "\tifa_address: 0x%x\n", + i, + iface_context->ipa_ctx, + iface_context->tl_context, + iface_context->cons_client, + iface_context->prod_client, + iface_context->iface_id, + iface_context->sta_id, + &iface_context->interface_lock, + iface_context->ifa_address); + } +} + +void wlan_ipa_dump_info(struct wlan_ipa_priv *ipa_ctx) +{ + wlan_ipa_dump_ipa_ctx(ipa_ctx); + wlan_ipa_dump_sys_pipe(ipa_ctx); + wlan_ipa_dump_iface_context(ipa_ctx); +} + +void wlan_ipa_uc_stat_query(struct wlan_ipa_priv *ipa_ctx, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + *ipa_tx_diff = 0; + *ipa_rx_diff = 0; + + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if ((ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) && + (false == ipa_ctx->resource_loading)) { + *ipa_tx_diff = ipa_ctx->ipa_tx_packets_diff; + *ipa_rx_diff = ipa_ctx->ipa_rx_packets_diff; + } + qdf_mutex_release(&ipa_ctx->ipa_lock); +} + +void wlan_ipa_uc_stat_request(struct wlan_ipa_priv *ipa_ctx, uint8_t reason) +{ + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if ((ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) && + (false == ipa_ctx->resource_loading)) { + ipa_ctx->stat_req_reason = reason; + cdp_ipa_get_stat(ipa_ctx->dp_soc, ipa_ctx->dp_pdev); + qdf_mutex_release(&ipa_ctx->ipa_lock); + } else { + qdf_mutex_release(&ipa_ctx->ipa_lock); + } +} + +/** + * wlan_ipa_print_session_info - Print IPA session info + * @ipa_ctx: IPA context + * + * Return: None + */ +static void wlan_ipa_print_session_info(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_ipa_uc_pending_event *event = NULL, *next = NULL; + struct wlan_ipa_iface_context *iface_context = NULL; + int i; + + ipa_info("\n==== IPA SESSION INFO ====\n" + "NUM IFACE: %d\n" + "RM STATE: %d\n" + "ACTIVATED FW PIPE: %d\n" + "SAP NUM STAs: %d\n" + "STA CONNECTED: %d\n" + "CONCURRENT MODE: %s\n" + "RSC LOADING: %d\n" + "RSC UNLOADING: %d\n" + "PENDING CONS REQ: %d\n" + "IPA PIPES DOWN: %d\n" + "IPA UC LOADED: %d\n" + "IPA WDI ENABLED: %d\n" + "NUM SEND MSG: %d\n" + "NUM FREE MSG: %d\n", + ipa_ctx->num_iface, + ipa_ctx->rm_state, + ipa_ctx->activated_fw_pipe, + ipa_ctx->sap_num_connected_sta, + ipa_ctx->sta_connected, + (ipa_ctx->mcc_mode ? "MCC" : "SCC"), + ipa_ctx->resource_loading, + ipa_ctx->resource_unloading, + ipa_ctx->pending_cons_req, + ipa_ctx->ipa_pipes_down, + ipa_ctx->uc_loaded, + ipa_ctx->wdi_enabled, + (unsigned int)ipa_ctx->stats.num_send_msg, + (unsigned int)ipa_ctx->stats.num_free_msg); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_context = &ipa_ctx->iface_context[i]; + + if (!iface_context->tl_context) + continue; + + ipa_info("\nIFACE[%d]: sta_id:%d, mode:%d, offload:%d", + i, iface_context->sta_id, + iface_context->device_mode, + ipa_ctx->vdev_offload_enabled[iface_context-> + session_id]); + } + + for (i = 0; i < IPA_WLAN_EVENT_MAX; i++) + ipa_info("\nEVENT[%d]=%d", + i, ipa_ctx->stats.event[i]); + + i = 0; + qdf_list_peek_front(&ipa_ctx->pending_event, + (qdf_list_node_t **)&event); + while (event != NULL) { + ipa_info("PENDING EVENT[%d]: EVT:%s, sta_id:%d, MAC:%pM", + i, wlan_ipa_wlan_event_to_str(event->type), + event->sta_id, event->mac_addr); + + qdf_list_peek_next(&ipa_ctx->pending_event, + (qdf_list_node_t *)event, + (qdf_list_node_t **)&next); + event = next; + next = NULL; + i++; + } +} + +/** + * wlan_ipa_print_txrx_stats - Print IPA IPA TX/RX stats + * @ipa_ctx: IPA context + * + * Return: None + */ +static void wlan_ipa_print_txrx_stats(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + struct wlan_ipa_iface_context *iface_context = NULL; + + ipa_info("\n==== IPA IPA TX/RX STATS ====\n" + "NUM RM GRANT: %llu\n" + "NUM RM RELEASE: %llu\n" + "NUM RM GRANT IMM: %llu\n" + "NUM CONS PERF REQ: %llu\n" + "NUM PROD PERF REQ: %llu\n" + "NUM RX DROP: %llu\n" + "NUM EXCP PKT: %llu\n" + "NUM TX FWD OK: %llu\n" + "NUM TX FWD ERR: %llu\n" + "NUM TX DESC Q CNT: %llu\n" + "NUM TX DESC ERROR: %llu\n" + "NUM TX COMP CNT: %llu\n" + "NUM TX QUEUED: %llu\n" + "NUM TX DEQUEUED: %llu\n" + "NUM MAX PM QUEUE: %llu\n" + "TX REF CNT: %d\n" + "SUSPENDED: %d\n" + "PEND DESC HEAD: %pK\n" + "TX DESC LIST: %pK\n", + ipa_ctx->stats.num_rm_grant, + ipa_ctx->stats.num_rm_release, + ipa_ctx->stats.num_rm_grant_imm, + ipa_ctx->stats.num_cons_perf_req, + ipa_ctx->stats.num_prod_perf_req, + ipa_ctx->stats.num_rx_drop, + ipa_ctx->stats.num_rx_excep, + ipa_ctx->stats.num_tx_fwd_ok, + ipa_ctx->stats.num_tx_fwd_err, + ipa_ctx->stats.num_tx_desc_q_cnt, + ipa_ctx->stats.num_tx_desc_error, + ipa_ctx->stats.num_tx_comp_cnt, + ipa_ctx->stats.num_tx_queued, + ipa_ctx->stats.num_tx_dequeued, + ipa_ctx->stats.num_max_pm_queue, + ipa_ctx->tx_ref_cnt.counter, + ipa_ctx->suspended, + &ipa_ctx->pend_desc_head, + &ipa_ctx->tx_desc_list); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + + iface_context = &ipa_ctx->iface_context[i]; + if (!iface_context->tl_context) + continue; + + ipa_info("IFACE[%d]: TX:%llu, TX DROP:%llu, TX ERR:%llu," + " TX CAC DROP:%llu, RX IPA EXCEP:%llu", + i, iface_context->stats.num_tx, + iface_context->stats.num_tx_drop, + iface_context->stats.num_tx_err, + iface_context->stats.num_tx_cac_drop, + iface_context->stats.num_rx_ipa_excep); + } +} + +void wlan_ipa_print_fw_wdi_stats(struct wlan_ipa_priv *ipa_ctx, + struct ipa_uc_fw_stats *uc_fw_stat) +{ + ipa_info("\n==== WLAN FW WDI TX STATS ====\n" + "COMP RING BASE: 0x%x\n" + "COMP RING SIZE: %d\n" + "COMP RING DBELL : 0x%x\n" + "COMP RING DBELL IND VAL : %d\n" + "COMP RING DBELL CACHED VAL : %d\n" + "PKTS ENQ : %d\n" + "PKTS COMP : %d\n" + "IS SUSPEND : %d\n", + uc_fw_stat->tx_comp_ring_base, + uc_fw_stat->tx_comp_ring_size, + uc_fw_stat->tx_comp_ring_dbell_addr, + uc_fw_stat->tx_comp_ring_dbell_ind_val, + uc_fw_stat->tx_comp_ring_dbell_cached_val, + uc_fw_stat->tx_pkts_enqueued, + uc_fw_stat->tx_pkts_completed, + uc_fw_stat->tx_is_suspend); + + ipa_info("\n==== WLAN FW WDI RX STATS ====\n" + "IND RING BASE: 0x%x\n" + "IND RING SIZE: %d\n" + "IND RING DBELL : 0x%x\n" + "IND RING DBELL IND VAL : %d\n" + "IND RING DBELL CACHED VAL : %d\n" + "RDY IND ADDR : 0x%x\n" + "RDY IND CACHE VAL : %d\n" + "RFIL IND : %d\n" + "NUM PKT INDICAT : %d\n" + "BUF REFIL : %d\n" + "NUM DROP NO SPC : %d\n" + "NUM DROP NO BUF : %d\n" + "IS SUSPND : %d\n", + uc_fw_stat->rx_ind_ring_base, + uc_fw_stat->rx_ind_ring_size, + uc_fw_stat->rx_ind_ring_dbell_addr, + uc_fw_stat->rx_ind_ring_dbell_ind_val, + uc_fw_stat->rx_ind_ring_dbell_ind_cached_val, + uc_fw_stat->rx_ind_ring_rdidx_addr, + uc_fw_stat->rx_ind_ring_rd_idx_cached_val, + uc_fw_stat->rx_refill_idx, + uc_fw_stat->rx_num_pkts_indicated, + uc_fw_stat->rx_buf_refilled, + uc_fw_stat->rx_num_ind_drop_no_space, + uc_fw_stat->rx_num_ind_drop_no_buf, + uc_fw_stat->rx_is_suspend); +} + +/** + * wlan_ipa_print_ipa_wdi_stats - Print IPA WDI stats + * @ipa_ctx: IPA context + * + * Return: None + */ +static void wlan_ipa_print_ipa_wdi_stats(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_ipa_hw_stats_wdi_info_data_t ipa_stat; + + qdf_ipa_get_wdi_stats(&ipa_stat); + + ipa_info("\n==== IPA WDI TX STATS ====\n" + "NUM PROCD : %d\n" + "CE DBELL : 0x%x\n" + "NUM DBELL FIRED : %d\n" + "COMP RNG FULL : %d\n" + "COMP RNG EMPT : %d\n" + "COMP RNG USE HGH : %d\n" + "COMP RNG USE LOW : %d\n" + "BAM FIFO FULL : %d\n" + "BAM FIFO EMPT : %d\n" + "BAM FIFO USE HGH : %d\n" + "BAM FIFO USE LOW : %d\n" + "NUM DBELL : %d\n" + "NUM UNEXP DBELL : %d\n" + "NUM BAM INT HDL : 0x%x\n" + "NUM QMB INT HDL : 0x%x\n", + ipa_stat.tx_ch_stats.num_pkts_processed, + ipa_stat.tx_ch_stats.copy_engine_doorbell_value, + ipa_stat.tx_ch_stats.num_db_fired, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow, + ipa_stat.tx_ch_stats.bam_stats.bamFifoFull, + ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty, + ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh, + ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow, + ipa_stat.tx_ch_stats.num_db, + ipa_stat.tx_ch_stats.num_unexpected_db, + ipa_stat.tx_ch_stats.num_bam_int_handled, + ipa_stat.tx_ch_stats.num_qmb_int_handled); + + ipa_info("\n==== IPA WDI RX STATS ====\n" + "MAX OST PKT : %d\n" + "NUM PKT PRCSD : %d\n" + "RNG RP : 0x%x\n" + "IND RNG FULL : %d\n" + "IND RNG EMPT : %d\n" + "IND RNG USE HGH : %d\n" + "IND RNG USE LOW : %d\n" + "BAM FIFO FULL : %d\n" + "BAM FIFO EMPT : %d\n" + "BAM FIFO USE HGH : %d\n" + "BAM FIFO USE LOW : %d\n" + "NUM DB : %d\n" + "NUM UNEXP DB : %d\n" + "NUM BAM INT HNDL : 0x%x\n", + ipa_stat.rx_ch_stats.max_outstanding_pkts, + ipa_stat.rx_ch_stats.num_pkts_processed, + ipa_stat.rx_ch_stats.rx_ring_rp_value, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow, + ipa_stat.rx_ch_stats.bam_stats.bamFifoFull, + ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty, + ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh, + ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow, + ipa_stat.rx_ch_stats.num_db, + ipa_stat.rx_ch_stats.num_unexpected_db, + ipa_stat.rx_ch_stats.num_bam_int_handled); +} + +void wlan_ipa_uc_info(struct wlan_ipa_priv *ipa_ctx) +{ + wlan_ipa_print_session_info(ipa_ctx); +} + +void wlan_ipa_uc_stat(struct wlan_ipa_priv *ipa_ctx) +{ + /* IPA IPA TX/RX stats */ + wlan_ipa_print_txrx_stats(ipa_ctx); + /* IPA WDI stats */ + wlan_ipa_print_ipa_wdi_stats(ipa_ctx); + /* WLAN FW WDI stats */ + wlan_ipa_uc_stat_request(ipa_ctx, WLAN_IPA_UC_STAT_REASON_DEBUG); +} + +#ifdef FEATURE_METERING +/** + * wlan_ipa_uc_sharing_stats_request() - Get IPA stats from IPA. + * @ipa_ctx: IPA context + * @reset_stats: reset stat countis after response + * + * Return: None + */ +static void wlan_ipa_uc_sharing_stats_request(struct wlan_ipa_priv *ipa_ctx, + uint8_t reset_stats) +{ + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if (false == ipa_ctx->resource_loading) { + qdf_mutex_release(&ipa_ctx->ipa_lock); + cdp_ipa_uc_get_share_stats(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, + reset_stats); + } else { + qdf_mutex_release(&ipa_ctx->ipa_lock); + } +} + +/** + * wlan_ipa_uc_set_quota() - Set quota limit bytes from IPA. + * @ipa_ctx: IPA context + * @set_quota: when 1, FW starts quota monitoring + * @quota_bytes: quota limit in bytes + * + * Return: None + */ +static void wlan_ipa_uc_set_quota(struct wlan_ipa_priv *ipa_ctx, + uint8_t set_quota, + uint64_t quota_bytes) +{ + ipa_info("SET_QUOTA: set_quota=%d, quota_bytes=%llu", + set_quota, quota_bytes); + + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if (false == ipa_ctx->resource_loading) { + qdf_mutex_release(&ipa_ctx->ipa_lock); + } else { + cdp_ipa_uc_set_quota(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, + quota_bytes); + qdf_mutex_release(&ipa_ctx->ipa_lock); + } +} + +QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx, + struct op_msg_type *op_msg) +{ + struct op_msg_type *msg = op_msg; + struct ipa_uc_sharing_stats *uc_sharing_stats; + struct ipa_uc_quota_rsp *uc_quota_rsp; + struct ipa_uc_quota_ind *uc_quota_ind; + struct wlan_ipa_iface_context *iface_ctx; + + if (msg->op_code == WLAN_IPA_UC_OPCODE_SHARING_STATS) { + /* fill-up ipa_uc_sharing_stats structure from FW */ + uc_sharing_stats = (struct ipa_uc_sharing_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + memcpy(&(ipa_ctx->ipa_sharing_stats), uc_sharing_stats, + sizeof(struct ipa_uc_sharing_stats)); + + qdf_event_set(&ipa_ctx->ipa_uc_sharing_stats_comp); + } else if (msg->op_code == WLAN_IPA_UC_OPCODE_QUOTA_RSP) { + /* received set quota response */ + uc_quota_rsp = (struct ipa_uc_quota_rsp *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + memcpy(&(ipa_ctx->ipa_quota_rsp), uc_quota_rsp, + sizeof(struct ipa_uc_quota_rsp)); + + qdf_event_set(&ipa_ctx->ipa_uc_set_quota_comp); + } else if (msg->op_code == WLAN_IPA_UC_OPCODE_QUOTA_IND) { + /* hit quota limit */ + uc_quota_ind = (struct ipa_uc_quota_ind *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + ipa_ctx->ipa_quota_ind.quota_bytes = + uc_quota_ind->quota_bytes; + + /* send quota exceeded indication to IPA */ + iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); + if (iface_ctx) + qdf_ipa_broadcast_wdi_quota_reach_ind( + iface_ctx->dev->ifindex, + uc_quota_ind->quota_bytes); + else + ipa_err("Failed quota_reach_ind: NULL interface"); + } else { + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_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 IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt, + void *data) +{ + struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context(); + struct wlan_ipa_iface_context *iface_ctx; + qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats; + qdf_ipa_set_wifi_quota_t *ipa_set_quota; + QDF_STATUS status; + + ipa_info("event=%d", evt); + + iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); + if (!iface_ctx) { + ipa_err("IPA uC share stats failed - no iface"); + QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) = + 0; + return; + } + + switch (evt) { + case IPA_GET_WDI_SAP_STATS: + /* fill-up ipa_get_wdi_sap_stats structure after getting + * ipa_uc_fw_stats from FW + */ + wdi_sap_stats = data; + + qdf_event_reset(&ipa_ctx->ipa_uc_sharing_stats_comp); + wlan_ipa_uc_sharing_stats_request(ipa_ctx, + QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats)); + status = qdf_wait_for_event_completion( + &ipa_ctx->ipa_uc_sharing_stats_comp, + msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME)); + if (!QDF_IS_STATUS_SUCCESS(status)) { + ipa_err("IPA uC share stats request timed out"); + QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) + = 0; + } else { + QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) + = 1; + + QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv4_rx_packets; + QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv4_rx_bytes; + QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv6_rx_packets; + QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv6_rx_bytes; + QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv4_tx_packets; + QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv4_tx_bytes; + QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv6_tx_packets; + QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv6_tx_bytes; + } + break; + + case IPA_SET_WIFI_QUOTA: + /* get ipa_set_wifi_quota structure from IPA and pass to FW + * through quota_exceeded field in ipa_uc_fw_stats + */ + ipa_set_quota = data; + + qdf_event_reset(&ipa_ctx->ipa_uc_set_quota_comp); + wlan_ipa_uc_set_quota(ipa_ctx, ipa_set_quota->set_quota, + ipa_set_quota->quota_bytes); + + status = qdf_wait_for_event_completion( + &ipa_ctx->ipa_uc_set_quota_comp, + msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME)); + if (!QDF_IS_STATUS_SUCCESS(status)) { + ipa_err("IPA uC set quota request timed out"); + QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = 0; + } else { + QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) = + ((uint64_t)(ipa_ctx->ipa_quota_rsp.quota_hi) + <<32)|ipa_ctx->ipa_quota_rsp.quota_lo; + QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = + ipa_ctx->ipa_quota_rsp.success; + } + break; + } +} +#endif /* FEATURE_METERING */ diff --git a/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h b/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h index f33f7a3159..28b4e80a10 100644 --- a/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h +++ b/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h @@ -60,6 +60,7 @@ void ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, /** * ucfg_ipa_set_txrx_handle() - register pdev txrx handler * @psoc: psoc handle + * @psoc: psoc obj * @txrx_handle: data path pdev txrx handle * * Return: None @@ -69,7 +70,7 @@ void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, /** * ucfg_ipa_set_perf_level() - Set IPA perf level - * @pdev: Pdev obj handle + * @pdev: pdev obj * @tx_packets: Number of packets transmitted in the last sample period * @rx_packets: Number of packets received in the last sample period * @@ -78,6 +79,60 @@ void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, QDF_STATUS ucfg_ipa_set_perf_level(struct wlan_objmgr_pdev *pdev, uint64_t tx_packets, uint64_t rx_packets); +/** + * ucfg_ipa_uc_info() - Print IPA uC resource and session information + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_uc_stat() - Print IPA uC stats + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev); + + +/** + * ucfg_ipa_uc_rt_debug_host_dump() - IPA rt debug host dump + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_dump_info() - Dump IPA context information + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_uc_stat_request() - Get IPA stats from IPA. + * @pdev: pdev obj + * @reason: STAT REQ Reason + * + * Return: None + */ +void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, + uint8_t reason); + +/** + * ucfg_ipa_uc_stat_query() - Query the IPA stats + * @pdev: pdev obj + * @ipa_tx_diff: tx packet count diff from previous tx packet count + * @ipa_rx_diff: rx packet count diff from previous rx packet count + * + * Return: None + */ +void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff); + #else static inline bool ucfg_ipa_is_present(void) @@ -109,5 +164,37 @@ QDF_STATUS ucfg_ipa_set_perf_level(struct wlan_objmgr_pdev *pdev, { return QDF_STATUS_SUCCESS; } + +static inline +void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, + uint8_t reason) +{ +} + +static inline +void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ +} #endif /* IPA_OFFLOAD */ #endif /* _WLAN_IPA_UCFG_API_H_ */ diff --git a/ipa/dispatcher/src/wlan_ipa_ucfg_api.c b/ipa/dispatcher/src/wlan_ipa_ucfg_api.c index 45ab2c47c6..5f419a5748 100644 --- a/ipa/dispatcher/src/wlan_ipa_ucfg_api.c +++ b/ipa/dispatcher/src/wlan_ipa_ucfg_api.c @@ -49,3 +49,35 @@ QDF_STATUS ucfg_ipa_set_perf_level(struct wlan_objmgr_pdev *pdev, { return ipa_rm_set_perf_level(pdev, tx_packets, rx_packets); } + +void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_info(pdev); +} + +void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_stat(pdev); +} + +void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_rt_debug_host_dump(pdev); +} + +void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev) +{ + return ipa_dump_info(pdev); +} + +void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, + uint8_t reason) +{ + return ipa_uc_stat_request(pdev, reason); +} + +void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + return ipa_uc_stat_query(pdev, ipa_tx_diff, ipa_rx_diff); +}