|
@@ -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 */
|