| /* |
| * Copyright (c) 2012-2016 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. |
| */ |
| |
| /** |
| * @file htt_fw_stats.c |
| * @brief Provide functions to process FW status retrieved from FW. |
| */ |
| |
| #include <htc_api.h> /* HTC_PACKET */ |
| #include <htt.h> /* HTT_T2H_MSG_TYPE, etc. */ |
| #include <qdf_nbuf.h> /* qdf_nbuf_t */ |
| #include <qdf_mem.h> /* qdf_mem_set */ |
| #include <ol_fw_tx_dbg.h> /* ol_fw_tx_dbg_ppdu_base */ |
| |
| #include <ol_htt_rx_api.h> |
| #include <ol_txrx_htt_api.h> /* htt_tx_status */ |
| |
| #include <htt_internal.h> |
| |
| #include <wlan_defs.h> |
| |
| #define ROUND_UP_TO_4(val) (((val) + 3) & ~0x3) |
| |
| |
| static char *bw_str_arr[] = {"20MHz", "40MHz", "80MHz", "160MHz"}; |
| |
| /* |
| * Defined the macro tx_rate_stats_print_cmn() |
| * so that this could be used in both |
| * htt_t2h_stats_tx_rate_stats_print() & |
| * htt_t2h_stats_tx_rate_stats_print_v2(). |
| * Each of these functions take a different structure as argument, |
| * but with common fields in the structures--so using a macro |
| * to bypass the strong type-checking of a function seems a simple |
| * trick to use to avoid the code duplication. |
| */ |
| #define tx_rate_stats_print_cmn(_tx_rate_info, _concise) \ |
| { \ |
| qdf_print("TX Rate Info:"); \ |
| \ |
| /* MCS */ \ |
| qdf_print("MCS counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ |
| _tx_rate_info->mcs[0], \ |
| _tx_rate_info->mcs[1], \ |
| _tx_rate_info->mcs[2], \ |
| _tx_rate_info->mcs[3], \ |
| _tx_rate_info->mcs[4], \ |
| _tx_rate_info->mcs[5], \ |
| _tx_rate_info->mcs[6], \ |
| _tx_rate_info->mcs[7], \ |
| _tx_rate_info->mcs[8], \ |
| _tx_rate_info->mcs[9]); \ |
| \ |
| /* SGI */ \ |
| qdf_print("SGI counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ |
| _tx_rate_info->sgi[0], \ |
| _tx_rate_info->sgi[1], \ |
| _tx_rate_info->sgi[2], \ |
| _tx_rate_info->sgi[3], \ |
| _tx_rate_info->sgi[4], \ |
| _tx_rate_info->sgi[5], \ |
| _tx_rate_info->sgi[6], \ |
| _tx_rate_info->sgi[7], \ |
| _tx_rate_info->sgi[8], \ |
| _tx_rate_info->sgi[9]); \ |
| \ |
| /* NSS */ \ |
| qdf_print("NSS counts: 1x1 %d, 2x2 %d, 3x3 %d", \ |
| _tx_rate_info->nss[0], \ |
| _tx_rate_info->nss[1], _tx_rate_info->nss[2]);\ |
| \ |
| /* BW */ \ |
| if (sizeof(_tx_rate_info->bw) / sizeof(_tx_rate_info->bw[0]) == 3)\ |
| qdf_print("BW counts: %s %d, %s %d, %s %d", \ |
| bw_str_arr[0], _tx_rate_info->bw[0], \ |
| bw_str_arr[1], _tx_rate_info->bw[1], \ |
| bw_str_arr[2], _tx_rate_info->bw[2]); \ |
| else if (sizeof(_tx_rate_info->bw) / sizeof(_tx_rate_info->bw[0]) == 4)\ |
| qdf_print("BW counts: %s %d, %s %d, %s %d, %s %d", \ |
| bw_str_arr[0], _tx_rate_info->bw[0], \ |
| bw_str_arr[1], _tx_rate_info->bw[1], \ |
| bw_str_arr[2], _tx_rate_info->bw[2], \ |
| bw_str_arr[3], _tx_rate_info->bw[3]); \ |
| \ |
| \ |
| /* Preamble */ \ |
| qdf_print("Preamble (O C H V) counts: %d, %d, %d, %d",\ |
| _tx_rate_info->pream[0], \ |
| _tx_rate_info->pream[1], \ |
| _tx_rate_info->pream[2], \ |
| _tx_rate_info->pream[3]); \ |
| \ |
| /* STBC rate counts */ \ |
| qdf_print("STBC rate counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ |
| _tx_rate_info->stbc[0], \ |
| _tx_rate_info->stbc[1], \ |
| _tx_rate_info->stbc[2], \ |
| _tx_rate_info->stbc[3], \ |
| _tx_rate_info->stbc[4], \ |
| _tx_rate_info->stbc[5], \ |
| _tx_rate_info->stbc[6], \ |
| _tx_rate_info->stbc[7], \ |
| _tx_rate_info->stbc[8], \ |
| _tx_rate_info->stbc[9]); \ |
| \ |
| /* LDPC and TxBF counts */ \ |
| qdf_print("LDPC Counts: %d", _tx_rate_info->ldpc);\ |
| qdf_print("RTS Counts: %d", _tx_rate_info->rts_cnt);\ |
| /* RSSI Values for last ack frames */ \ |
| qdf_print("Ack RSSI: %d", _tx_rate_info->ack_rssi);\ |
| } |
| |
| static void htt_t2h_stats_tx_rate_stats_print(wlan_dbg_tx_rate_info_t * |
| tx_rate_info, int concise) |
| { |
| tx_rate_stats_print_cmn(tx_rate_info, concise); |
| } |
| |
| static void htt_t2h_stats_tx_rate_stats_print_v2(wlan_dbg_tx_rate_info_v2_t * |
| tx_rate_info, int concise) |
| { |
| tx_rate_stats_print_cmn(tx_rate_info, concise); |
| } |
| |
| /* |
| * Defined the macro rx_rate_stats_print_cmn() |
| * so that this could be used in both |
| * htt_t2h_stats_rx_rate_stats_print() & |
| * htt_t2h_stats_rx_rate_stats_print_v2(). |
| * Each of these functions take a different structure as argument, |
| * but with common fields in the structures -- so using a macro |
| * to bypass the strong type-checking of a function seems a simple |
| * trick to use to avoid the code duplication. |
| */ |
| #define rx_rate_stats_print_cmn(_rx_phy_info, _concise) \ |
| { \ |
| qdf_print("RX Rate Info:"); \ |
| \ |
| /* MCS */ \ |
| qdf_print("MCS counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ |
| _rx_phy_info->mcs[0], \ |
| _rx_phy_info->mcs[1], \ |
| _rx_phy_info->mcs[2], \ |
| _rx_phy_info->mcs[3], \ |
| _rx_phy_info->mcs[4], \ |
| _rx_phy_info->mcs[5], \ |
| _rx_phy_info->mcs[6], \ |
| _rx_phy_info->mcs[7], \ |
| _rx_phy_info->mcs[8], \ |
| _rx_phy_info->mcs[9]); \ |
| \ |
| /* SGI */ \ |
| qdf_print("SGI counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ |
| _rx_phy_info->sgi[0], \ |
| _rx_phy_info->sgi[1], \ |
| _rx_phy_info->sgi[2], \ |
| _rx_phy_info->sgi[3], \ |
| _rx_phy_info->sgi[4], \ |
| _rx_phy_info->sgi[5], \ |
| _rx_phy_info->sgi[6], \ |
| _rx_phy_info->sgi[7], \ |
| _rx_phy_info->sgi[8], \ |
| _rx_phy_info->sgi[9]); \ |
| \ |
| /* NSS */ \ |
| /* nss[0] just holds the count of non-stbc frames that were sent at 1x1 \ |
| * rates and nsts holds the count of frames sent with stbc. \ |
| * It was decided to not include PPDUs sent w/ STBC in nss[0]\ |
| * since it would be easier to change the value that needs to be\ |
| * printed (from "stbc+non-stbc count to only non-stbc count")\ |
| * if needed in the future. Hence the addition in the host code\ |
| * at this line. */ \ |
| qdf_print("NSS counts: 1x1 %d, 2x2 %d, 3x3 %d, 4x4 %d",\ |
| _rx_phy_info->nss[0] + _rx_phy_info->nsts, \ |
| _rx_phy_info->nss[1], \ |
| _rx_phy_info->nss[2], \ |
| _rx_phy_info->nss[3]); \ |
| \ |
| /* NSTS */ \ |
| qdf_print("NSTS count: %d", _rx_phy_info->nsts); \ |
| \ |
| /* BW */ \ |
| if (sizeof(_rx_phy_info->bw) / sizeof(_rx_phy_info->bw[0]) == 3)\ |
| qdf_print("BW counts: %s %d, %s %d, %s %d", \ |
| bw_str_arr[0], _rx_phy_info->bw[0], \ |
| bw_str_arr[1], _rx_phy_info->bw[1], \ |
| bw_str_arr[2], _rx_phy_info->bw[2]); \ |
| else if (sizeof(_rx_phy_info->bw) / sizeof(_rx_phy_info->bw[0]) == 4) \ |
| qdf_print("BW counts: %s %d, %s %d, %s %d, %s %d", \ |
| bw_str_arr[0], _rx_phy_info->bw[0], \ |
| bw_str_arr[1], _rx_phy_info->bw[1], \ |
| bw_str_arr[2], _rx_phy_info->bw[2], \ |
| bw_str_arr[3], _rx_phy_info->bw[3]); \ |
| \ |
| /* Preamble */ \ |
| qdf_print("Preamble counts: %d, %d, %d, %d, %d, %d",\ |
| _rx_phy_info->pream[0], \ |
| _rx_phy_info->pream[1], \ |
| _rx_phy_info->pream[2], \ |
| _rx_phy_info->pream[3], \ |
| _rx_phy_info->pream[4], \ |
| _rx_phy_info->pream[5]); \ |
| \ |
| /* STBC rate counts */ \ |
| qdf_print("STBC rate counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ |
| _rx_phy_info->stbc[0], \ |
| _rx_phy_info->stbc[1], \ |
| _rx_phy_info->stbc[2], \ |
| _rx_phy_info->stbc[3], \ |
| _rx_phy_info->stbc[4], \ |
| _rx_phy_info->stbc[5], \ |
| _rx_phy_info->stbc[6], \ |
| _rx_phy_info->stbc[7], \ |
| _rx_phy_info->stbc[8], \ |
| _rx_phy_info->stbc[9]); \ |
| \ |
| /* LDPC and TxBF counts */ \ |
| qdf_print("LDPC TXBF Counts: %d, %d", \ |
| _rx_phy_info->ldpc, _rx_phy_info->txbf);\ |
| /* RSSI Values for last received frames */ \ |
| qdf_print("RSSI (data, mgmt): %d, %d", _rx_phy_info->data_rssi,\ |
| _rx_phy_info->mgmt_rssi); \ |
| \ |
| qdf_print("RSSI Chain 0 (0x%02x 0x%02x 0x%02x 0x%02x)",\ |
| ((_rx_phy_info->rssi_chain0 >> 24) & 0xff), \ |
| ((_rx_phy_info->rssi_chain0 >> 16) & 0xff), \ |
| ((_rx_phy_info->rssi_chain0 >> 8) & 0xff), \ |
| ((_rx_phy_info->rssi_chain0 >> 0) & 0xff)); \ |
| \ |
| qdf_print("RSSI Chain 1 (0x%02x 0x%02x 0x%02x 0x%02x)",\ |
| ((_rx_phy_info->rssi_chain1 >> 24) & 0xff), \ |
| ((_rx_phy_info->rssi_chain1 >> 16) & 0xff), \ |
| ((_rx_phy_info->rssi_chain1 >> 8) & 0xff), \ |
| ((_rx_phy_info->rssi_chain1 >> 0) & 0xff)); \ |
| \ |
| qdf_print("RSSI Chain 2 (0x%02x 0x%02x 0x%02x 0x%02x)",\ |
| ((_rx_phy_info->rssi_chain2 >> 24) & 0xff), \ |
| ((_rx_phy_info->rssi_chain2 >> 16) & 0xff), \ |
| ((_rx_phy_info->rssi_chain2 >> 8) & 0xff), \ |
| ((_rx_phy_info->rssi_chain2 >> 0) & 0xff)); \ |
| } |
| |
| static void htt_t2h_stats_rx_rate_stats_print(wlan_dbg_rx_rate_info_t * |
| rx_phy_info, int concise) |
| { |
| rx_rate_stats_print_cmn(rx_phy_info, concise); |
| } |
| |
| static void htt_t2h_stats_rx_rate_stats_print_v2(wlan_dbg_rx_rate_info_v2_t * |
| rx_phy_info, int concise) |
| { |
| rx_rate_stats_print_cmn(rx_phy_info, concise); |
| } |
| |
| static void |
| htt_t2h_stats_pdev_stats_print(struct wlan_dbg_stats *wlan_pdev_stats, |
| int concise) |
| { |
| struct wlan_dbg_tx_stats *tx = &wlan_pdev_stats->tx; |
| struct wlan_dbg_rx_stats *rx = &wlan_pdev_stats->rx; |
| |
| qdf_print("WAL Pdev stats:"); |
| qdf_print("\n### Tx ###"); |
| |
| /* Num HTT cookies queued to dispatch list */ |
| qdf_print("comp_queued :\t%d", tx->comp_queued); |
| /* Num HTT cookies dispatched */ |
| qdf_print("comp_delivered :\t%d", tx->comp_delivered); |
| /* Num MSDU queued to WAL */ |
| qdf_print("msdu_enqued :\t%d", tx->msdu_enqued); |
| /* Num MPDU queued to WAL */ |
| qdf_print("mpdu_enqued :\t%d", tx->mpdu_enqued); |
| /* Num MSDUs dropped by WMM limit */ |
| qdf_print("wmm_drop :\t%d", tx->wmm_drop); |
| /* Num Local frames queued */ |
| qdf_print("local_enqued :\t%d", tx->local_enqued); |
| /* Num Local frames done */ |
| qdf_print("local_freed :\t%d", tx->local_freed); |
| /* Num queued to HW */ |
| qdf_print("hw_queued :\t%d", tx->hw_queued); |
| /* Num PPDU reaped from HW */ |
| qdf_print("hw_reaped :\t%d", tx->hw_reaped); |
| /* Num underruns */ |
| qdf_print("mac underrun :\t%d", tx->underrun); |
| /* Num underruns */ |
| qdf_print("phy underrun :\t%d", tx->phy_underrun); |
| /* Num PPDUs cleaned up in TX abort */ |
| qdf_print("tx_abort :\t%d", tx->tx_abort); |
| /* Num MPDUs requed by SW */ |
| qdf_print("mpdus_requed :\t%d", tx->mpdus_requed); |
| /* Excessive retries */ |
| qdf_print("excess retries :\t%d", tx->tx_ko); |
| /* last data rate */ |
| qdf_print("last rc :\t%d", tx->data_rc); |
| /* scheduler self triggers */ |
| qdf_print("sched self trig :\t%d", tx->self_triggers); |
| /* SW retry failures */ |
| qdf_print("ampdu retry failed:\t%d", tx->sw_retry_failure); |
| /* ilegal phy rate errirs */ |
| qdf_print("illegal rate errs :\t%d", tx->illgl_rate_phy_err); |
| /* pdev continous excessive retries */ |
| qdf_print("pdev cont xretry :\t%d", tx->pdev_cont_xretry); |
| /* pdev continous excessive retries */ |
| qdf_print("pdev tx timeout :\t%d", tx->pdev_tx_timeout); |
| /* pdev resets */ |
| qdf_print("pdev resets :\t%d", tx->pdev_resets); |
| /* PPDU > txop duration */ |
| qdf_print("ppdu txop ovf :\t%d", tx->txop_ovf); |
| |
| qdf_print("\n### Rx ###\n"); |
| /* Cnts any change in ring routing mid-ppdu */ |
| qdf_print("ppdu_route_change :\t%d", rx->mid_ppdu_route_change); |
| /* Total number of statuses processed */ |
| qdf_print("status_rcvd :\t%d", rx->status_rcvd); |
| /* Extra frags on rings 0-3 */ |
| qdf_print("r0_frags :\t%d", rx->r0_frags); |
| qdf_print("r1_frags :\t%d", rx->r1_frags); |
| qdf_print("r2_frags :\t%d", rx->r2_frags); |
| qdf_print("r3_frags :\t%d", rx->r3_frags); |
| /* MSDUs / MPDUs delivered to HTT */ |
| qdf_print("htt_msdus :\t%d", rx->htt_msdus); |
| qdf_print("htt_mpdus :\t%d", rx->htt_mpdus); |
| /* MSDUs / MPDUs delivered to local stack */ |
| qdf_print("loc_msdus :\t%d", rx->loc_msdus); |
| qdf_print("loc_mpdus :\t%d", rx->loc_mpdus); |
| /* AMSDUs that have more MSDUs than the status ring size */ |
| qdf_print("oversize_amsdu :\t%d", rx->oversize_amsdu); |
| /* Number of PHY errors */ |
| qdf_print("phy_errs :\t%d", rx->phy_errs); |
| /* Number of PHY errors dropped */ |
| qdf_print("phy_errs dropped :\t%d", rx->phy_err_drop); |
| /* Number of mpdu errors - FCS, MIC, ENC etc. */ |
| qdf_print("mpdu_errs :\t%d", rx->mpdu_errs); |
| |
| } |
| |
| static void |
| htt_t2h_stats_rx_reorder_stats_print(struct rx_reorder_stats *stats_ptr, |
| int concise) |
| { |
| qdf_print("Rx reorder statistics:"); |
| qdf_print(" %u non-QoS frames received", stats_ptr->deliver_non_qos); |
| qdf_print(" %u frames received in-order", |
| stats_ptr->deliver_in_order); |
| qdf_print(" %u frames flushed due to timeout", |
| stats_ptr->deliver_flush_timeout); |
| qdf_print(" %u frames flushed due to moving out of window", |
| stats_ptr->deliver_flush_oow); |
| qdf_print(" %u frames flushed due to receiving DELBA", |
| stats_ptr->deliver_flush_delba); |
| qdf_print(" %u frames discarded due to FCS error", |
| stats_ptr->fcs_error); |
| qdf_print(" %u frames discarded due to invalid peer", |
| stats_ptr->invalid_peer); |
| qdf_print |
| (" %u frames discarded due to duplication (non aggregation)", |
| stats_ptr->dup_non_aggr); |
| qdf_print(" %u frames discarded due to duplication in reorder queue", |
| stats_ptr->dup_in_reorder); |
| qdf_print(" %u frames discarded due to processed before", |
| stats_ptr->dup_past); |
| qdf_print(" %u times reorder timeout happened", |
| stats_ptr->reorder_timeout); |
| qdf_print(" %u times incorrect bar received", |
| stats_ptr->invalid_bar_ssn); |
| qdf_print(" %u times bar ssn reset happened", |
| stats_ptr->ssn_reset); |
| qdf_print(" %u times flushed due to peer delete", |
| stats_ptr->deliver_flush_delpeer); |
| qdf_print(" %u times flushed due to offload", |
| stats_ptr->deliver_flush_offload); |
| qdf_print(" %u times flushed due to ouf of buffer", |
| stats_ptr->deliver_flush_oob); |
| qdf_print(" %u MPDU's dropped due to PN check fail", |
| stats_ptr->pn_fail); |
| qdf_print(" %u MPDU's dropped due to lack of memory", |
| stats_ptr->store_fail); |
| qdf_print(" %u times tid pool alloc succeeded", |
| stats_ptr->tid_pool_alloc_succ); |
| qdf_print(" %u times MPDU pool alloc succeeded", |
| stats_ptr->mpdu_pool_alloc_succ); |
| qdf_print(" %u times MSDU pool alloc succeeded", |
| stats_ptr->msdu_pool_alloc_succ); |
| qdf_print(" %u times tid pool alloc failed", |
| stats_ptr->tid_pool_alloc_fail); |
| qdf_print(" %u times MPDU pool alloc failed", |
| stats_ptr->mpdu_pool_alloc_fail); |
| qdf_print(" %u times MSDU pool alloc failed", |
| stats_ptr->msdu_pool_alloc_fail); |
| qdf_print(" %u times tid pool freed", |
| stats_ptr->tid_pool_free); |
| qdf_print(" %u times MPDU pool freed", |
| stats_ptr->mpdu_pool_free); |
| qdf_print(" %u times MSDU pool freed", |
| stats_ptr->msdu_pool_free); |
| qdf_print(" %u MSDUs undelivered to HTT, queued to Rx MSDU free list", |
| stats_ptr->msdu_queued); |
| qdf_print(" %u MSDUs released from Rx MSDU list to MAC ring", |
| stats_ptr->msdu_recycled); |
| qdf_print(" %u MPDUs with invalid peer but A2 found in AST", |
| stats_ptr->invalid_peer_a2_in_ast); |
| qdf_print(" %u MPDUs with invalid peer but A3 found in AST", |
| stats_ptr->invalid_peer_a3_in_ast); |
| qdf_print(" %u MPDUs with invalid peer, Broadcast or Mulitcast frame", |
| stats_ptr->invalid_peer_bmc_mpdus); |
| qdf_print(" %u MSDUs with err attention word", |
| stats_ptr->rxdesc_err_att); |
| qdf_print(" %u MSDUs with flag of peer_idx_invalid", |
| stats_ptr->rxdesc_err_peer_idx_inv); |
| qdf_print(" %u MSDUs with flag of peer_idx_timeout", |
| stats_ptr->rxdesc_err_peer_idx_to); |
| qdf_print(" %u MSDUs with flag of overflow", |
| stats_ptr->rxdesc_err_ov); |
| qdf_print(" %u MSDUs with flag of msdu_length_err", |
| stats_ptr->rxdesc_err_msdu_len); |
| qdf_print(" %u MSDUs with flag of mpdu_length_err", |
| stats_ptr->rxdesc_err_mpdu_len); |
| qdf_print(" %u MSDUs with flag of tkip_mic_err", |
| stats_ptr->rxdesc_err_tkip_mic); |
| qdf_print(" %u MSDUs with flag of decrypt_err", |
| stats_ptr->rxdesc_err_decrypt); |
| qdf_print(" %u MSDUs with flag of fcs_err", |
| stats_ptr->rxdesc_err_fcs); |
| qdf_print(" %u Unicast frames with invalid peer handler", |
| stats_ptr->rxdesc_uc_msdus_inv_peer); |
| qdf_print(" %u unicast frame directly to DUT with invalid peer handler", |
| stats_ptr->rxdesc_direct_msdus_inv_peer); |
| qdf_print(" %u Broadcast/Multicast frames with invalid peer handler", |
| stats_ptr->rxdesc_bmc_msdus_inv_peer); |
| qdf_print(" %u MSDUs dropped due to no first MSDU flag", |
| stats_ptr->rxdesc_no_1st_msdu); |
| qdf_print(" %u MSDUs dropped due to ring overflow", |
| stats_ptr->msdu_drop_ring_ov); |
| qdf_print(" %u MSDUs dropped due to FC mismatch", |
| stats_ptr->msdu_drop_fc_mismatch); |
| qdf_print(" %u MSDUs dropped due to mgt frame in Remote ring", |
| stats_ptr->msdu_drop_mgmt_remote_ring); |
| qdf_print(" %u MSDUs dropped due to misc non error", |
| stats_ptr->msdu_drop_misc); |
| qdf_print(" %u MSDUs go to offload before reorder", |
| stats_ptr->offload_msdu_wal); |
| qdf_print(" %u data frame dropped by offload after reorder", |
| stats_ptr->offload_msdu_reorder); |
| qdf_print(" %u MPDUs with SN in the past & within BA window", |
| stats_ptr->dup_past_within_window); |
| qdf_print(" %u MPDUs with SN in the past & outside BA window", |
| stats_ptr->dup_past_outside_window); |
| } |
| |
| static void |
| htt_t2h_stats_rx_rem_buf_stats_print( |
| struct rx_remote_buffer_mgmt_stats *stats_ptr, int concise) |
| { |
| qdf_print("Rx Remote Buffer Statistics:"); |
| qdf_print(" %u MSDU's reaped for Rx processing", |
| stats_ptr->remote_reaped); |
| qdf_print(" %u MSDU's recycled within firmware", |
| stats_ptr->remote_recycled); |
| qdf_print(" %u MSDU's stored by Data Rx", |
| stats_ptr->data_rx_msdus_stored); |
| qdf_print(" %u HTT indications from WAL Rx MSDU", |
| stats_ptr->wal_rx_ind); |
| qdf_print(" %u HTT indications unconsumed from WAL Rx MSDU", |
| stats_ptr->wal_rx_ind_unconsumed); |
| qdf_print(" %u HTT indications from Data Rx MSDU", |
| stats_ptr->data_rx_ind); |
| qdf_print(" %u HTT indications unconsumed from Data Rx MSDU", |
| stats_ptr->data_rx_ind_unconsumed); |
| qdf_print(" %u HTT indications from ATHBUF", |
| stats_ptr->athbuf_rx_ind); |
| qdf_print(" %u Remote buffers requested for refill", |
| stats_ptr->refill_buf_req); |
| qdf_print(" %u Remote buffers filled by host", |
| stats_ptr->refill_buf_rsp); |
| qdf_print(" %u times MAC has no buffers", |
| stats_ptr->mac_no_bufs); |
| qdf_print(" %u times f/w write & read indices on MAC ring are equal", |
| stats_ptr->fw_indices_equal); |
| qdf_print(" %u times f/w has no remote buffers to post to MAC", |
| stats_ptr->host_no_bufs); |
| } |
| |
| static void |
| htt_t2h_stats_txbf_info_buf_stats_print( |
| struct wlan_dbg_txbf_data_stats *stats_ptr) |
| { |
| qdf_print("TXBF data Statistics:"); |
| qdf_print("tx_txbf_vht (0..9): %u, %u, %u, %u, %u, %u, %u, %u, %u, %d", |
| stats_ptr->tx_txbf_vht[0], |
| stats_ptr->tx_txbf_vht[1], |
| stats_ptr->tx_txbf_vht[2], |
| stats_ptr->tx_txbf_vht[3], |
| stats_ptr->tx_txbf_vht[4], |
| stats_ptr->tx_txbf_vht[5], |
| stats_ptr->tx_txbf_vht[6], |
| stats_ptr->tx_txbf_vht[7], |
| stats_ptr->tx_txbf_vht[8], |
| stats_ptr->tx_txbf_vht[9]); |
| qdf_print("rx_txbf_vht (0..9): %u, %u, %u, %u, %u, %u, %u, %u, %u, %u", |
| stats_ptr->rx_txbf_vht[0], |
| stats_ptr->rx_txbf_vht[1], |
| stats_ptr->rx_txbf_vht[2], |
| stats_ptr->rx_txbf_vht[3], |
| stats_ptr->rx_txbf_vht[4], |
| stats_ptr->rx_txbf_vht[5], |
| stats_ptr->rx_txbf_vht[6], |
| stats_ptr->rx_txbf_vht[7], |
| stats_ptr->rx_txbf_vht[8], |
| stats_ptr->rx_txbf_vht[9]); |
| qdf_print("tx_txbf_ht (0..7): %u, %u, %u, %u, %u, %u, %u, %u", |
| stats_ptr->tx_txbf_ht[0], |
| stats_ptr->tx_txbf_ht[1], |
| stats_ptr->tx_txbf_ht[2], |
| stats_ptr->tx_txbf_ht[3], |
| stats_ptr->tx_txbf_ht[4], |
| stats_ptr->tx_txbf_ht[5], |
| stats_ptr->tx_txbf_ht[6], |
| stats_ptr->tx_txbf_ht[7]); |
| qdf_print("tx_txbf_ofdm (0..7): %u, %u, %u, %u, %u, %u, %u, %u", |
| stats_ptr->tx_txbf_ofdm[0], |
| stats_ptr->tx_txbf_ofdm[1], |
| stats_ptr->tx_txbf_ofdm[2], |
| stats_ptr->tx_txbf_ofdm[3], |
| stats_ptr->tx_txbf_ofdm[4], |
| stats_ptr->tx_txbf_ofdm[5], |
| stats_ptr->tx_txbf_ofdm[6], |
| stats_ptr->tx_txbf_ofdm[7]); |
| qdf_print("tx_txbf_cck (0..6): %u, %u, %u, %u, %u, %u, %u", |
| stats_ptr->tx_txbf_cck[0], |
| stats_ptr->tx_txbf_cck[1], |
| stats_ptr->tx_txbf_cck[2], |
| stats_ptr->tx_txbf_cck[3], |
| stats_ptr->tx_txbf_cck[4], |
| stats_ptr->tx_txbf_cck[5], |
| stats_ptr->tx_txbf_cck[6]); |
| } |
| |
| static void |
| htt_t2h_stats_txbf_snd_buf_stats_print( |
| struct wlan_dbg_txbf_snd_stats *stats_ptr) |
| { |
| qdf_print("TXBF snd Buffer Statistics:"); |
| qdf_print("cbf_20: %u, %u, %u, %u", |
| stats_ptr->cbf_20[0], |
| stats_ptr->cbf_20[1], |
| stats_ptr->cbf_20[2], |
| stats_ptr->cbf_20[3]); |
| qdf_print("cbf_40: %u, %u, %u, %u", |
| stats_ptr->cbf_40[0], |
| stats_ptr->cbf_40[1], |
| stats_ptr->cbf_40[2], |
| stats_ptr->cbf_40[3]); |
| qdf_print("cbf_80: %u, %u, %u, %u", |
| stats_ptr->cbf_80[0], |
| stats_ptr->cbf_80[1], |
| stats_ptr->cbf_80[2], |
| stats_ptr->cbf_80[3]); |
| qdf_print("sounding: %u, %u, %u, %u, %u, %u, %u, %u, %u", |
| stats_ptr->sounding[0], |
| stats_ptr->sounding[1], |
| stats_ptr->sounding[2], |
| stats_ptr->sounding[3], |
| stats_ptr->sounding[4], |
| stats_ptr->sounding[5], |
| stats_ptr->sounding[6], |
| stats_ptr->sounding[7], |
| stats_ptr->sounding[8]); |
| } |
| |
| static void |
| htt_t2h_stats_tx_selfgen_buf_stats_print( |
| struct wlan_dbg_tx_selfgen_stats *stats_ptr) |
| { |
| qdf_print("Tx selfgen Buffer Statistics:"); |
| qdf_print(" %u su_ndpa", |
| stats_ptr->su_ndpa); |
| qdf_print(" %u mu_ndp", |
| stats_ptr->mu_ndp); |
| qdf_print(" %u mu_ndpa", |
| stats_ptr->mu_ndpa); |
| qdf_print(" %u mu_ndp", |
| stats_ptr->mu_ndp); |
| qdf_print(" %u mu_brpoll_1", |
| stats_ptr->mu_brpoll_1); |
| qdf_print(" %u mu_brpoll_2", |
| stats_ptr->mu_brpoll_2); |
| qdf_print(" %u mu_bar_1", |
| stats_ptr->mu_bar_1); |
| qdf_print(" %u mu_bar_2", |
| stats_ptr->mu_bar_2); |
| qdf_print(" %u cts_burst", |
| stats_ptr->cts_burst); |
| qdf_print(" %u su_ndp_err", |
| stats_ptr->su_ndp_err); |
| qdf_print(" %u su_ndpa_err", |
| stats_ptr->su_ndpa_err); |
| qdf_print(" %u mu_ndp_err", |
| stats_ptr->mu_ndp_err); |
| qdf_print(" %u mu_brp1_err", |
| stats_ptr->mu_brp1_err); |
| qdf_print(" %u mu_brp2_err", |
| stats_ptr->mu_brp2_err); |
| } |
| |
| static void |
| htt_t2h_stats_wifi2_error_stats_print( |
| struct wlan_dbg_wifi2_error_stats *stats_ptr) |
| { |
| int i; |
| |
| qdf_print("Scheduler error Statistics:"); |
| qdf_print("urrn_stats: "); |
| qdf_print("urrn_stats: %d, %d, %d", |
| stats_ptr->urrn_stats[0], |
| stats_ptr->urrn_stats[1], |
| stats_ptr->urrn_stats[2]); |
| qdf_print("flush_errs (0..%d): ", |
| WHAL_DBG_FLUSH_REASON_MAXCNT); |
| for (i = 0; i < WHAL_DBG_FLUSH_REASON_MAXCNT; i++) |
| qdf_print(" %u", stats_ptr->flush_errs[i]); |
| qdf_print("\n"); |
| qdf_print("schd_stall_errs (0..3): "); |
| qdf_print("%d, %d, %d, %d", |
| stats_ptr->schd_stall_errs[0], |
| stats_ptr->schd_stall_errs[1], |
| stats_ptr->schd_stall_errs[2], |
| stats_ptr->schd_stall_errs[3]); |
| qdf_print("schd_cmd_result (0..%d): ", |
| WHAL_DBG_CMD_RESULT_MAXCNT); |
| for (i = 0; i < WHAL_DBG_CMD_RESULT_MAXCNT; i++) |
| qdf_print(" %u", stats_ptr->schd_cmd_result[i]); |
| qdf_print("\n"); |
| qdf_print("sifs_status (0..%d): ", |
| WHAL_DBG_SIFS_STATUS_MAXCNT); |
| for (i = 0; i < WHAL_DBG_SIFS_STATUS_MAXCNT; i++) |
| qdf_print(" %u", stats_ptr->sifs_status[i]); |
| qdf_print("\n"); |
| qdf_print("phy_errs (0..%d): ", |
| WHAL_DBG_PHY_ERR_MAXCNT); |
| for (i = 0; i < WHAL_DBG_PHY_ERR_MAXCNT; i++) |
| qdf_print(" %u", stats_ptr->phy_errs[i]); |
| qdf_print("\n"); |
| qdf_print(" %u rx_rate_inval", |
| stats_ptr->rx_rate_inval); |
| } |
| |
| static void |
| htt_t2h_rx_musu_ndpa_pkts_stats_print( |
| struct rx_txbf_musu_ndpa_pkts_stats *stats_ptr) |
| { |
| qdf_print("Rx TXBF MU/SU Packets and NDPA Statistics:"); |
| qdf_print(" %u Number of TXBF MU packets received", |
| stats_ptr->number_mu_pkts); |
| qdf_print(" %u Number of TXBF SU packets received", |
| stats_ptr->number_su_pkts); |
| qdf_print(" %u Number of TXBF directed NDPA", |
| stats_ptr->txbf_directed_ndpa_count); |
| qdf_print(" %u Number of TXBF retried NDPA", |
| stats_ptr->txbf_ndpa_retry_count); |
| qdf_print(" %u Total number of TXBF NDPA", |
| stats_ptr->txbf_total_ndpa_count); |
| } |
| |
| #define HTT_TICK_TO_USEC(ticks, microsec_per_tick) (ticks * microsec_per_tick) |
| static inline int htt_rate_flags_to_mhz(uint8_t rate_flags) |
| { |
| if (rate_flags & 0x20) |
| return 40; /* WHAL_RC_FLAG_40MHZ */ |
| if (rate_flags & 0x40) |
| return 80; /* WHAL_RC_FLAG_80MHZ */ |
| if (rate_flags & 0x80) |
| return 160; /* WHAL_RC_FLAG_160MHZ */ |
| return 20; |
| } |
| |
| #define HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW 64 |
| |
| static void |
| htt_t2h_tx_ppdu_bitmaps_pr(uint32_t *queued_ptr, uint32_t *acked_ptr) |
| { |
| char queued_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW + 1]; |
| char acked_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW + 1]; |
| int i, j, word; |
| |
| qdf_mem_set(queued_str, HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW, '0'); |
| qdf_mem_set(acked_str, HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW, '-'); |
| i = 0; |
| for (word = 0; word < 2; word++) { |
| uint32_t queued = *(queued_ptr + word); |
| uint32_t acked = *(acked_ptr + word); |
| for (j = 0; j < 32; j++, i++) { |
| if (queued & (1 << j)) { |
| queued_str[i] = '1'; |
| acked_str[i] = (acked & (1 << j)) ? 'y' : 'N'; |
| } |
| } |
| } |
| queued_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW] = '\0'; |
| acked_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW] = '\0'; |
| qdf_print("%s\n", queued_str); |
| qdf_print("%s\n", acked_str); |
| } |
| |
| static inline uint16_t htt_msg_read16(uint16_t *p16) |
| { |
| #ifdef BIG_ENDIAN_HOST |
| /* |
| * During upload, the bytes within each uint32_t word were |
| * swapped by the HIF HW. This results in the lower and upper bytes |
| * of each uint16_t to be in the correct big-endian order with |
| * respect to each other, but for each even-index uint16_t to |
| * have its position switched with its successor neighbor uint16_t. |
| * Undo this uint16_t position swapping. |
| */ |
| return (((size_t) p16) & 0x2) ? *(p16 - 1) : *(p16 + 1); |
| #else |
| return *p16; |
| #endif |
| } |
| |
| static inline uint8_t htt_msg_read8(uint8_t *p8) |
| { |
| #ifdef BIG_ENDIAN_HOST |
| /* |
| * During upload, the bytes within each uint32_t word were |
| * swapped by the HIF HW. |
| * Undo this byte swapping. |
| */ |
| switch (((size_t) p8) & 0x3) { |
| case 0: |
| return *(p8 + 3); |
| case 1: |
| return *(p8 + 1); |
| case 2: |
| return *(p8 - 1); |
| default /* 3 */: |
| return *(p8 - 3); |
| } |
| #else |
| return *p8; |
| #endif |
| } |
| |
| void htt_make_u8_list_str(uint32_t *aligned_data, |
| char *buffer, int space, int max_elems) |
| { |
| uint8_t *p8 = (uint8_t *) aligned_data; |
| char *buf_p = buffer; |
| while (max_elems-- > 0) { |
| int bytes; |
| uint8_t val; |
| |
| val = htt_msg_read8(p8); |
| if (val == 0) |
| /* not enough data to fill the reserved msg buffer*/ |
| break; |
| |
| bytes = qdf_snprint(buf_p, space, "%d,", val); |
| space -= bytes; |
| if (space > 0) |
| buf_p += bytes; |
| else /* not enough print buffer space for all the data */ |
| break; |
| p8++; |
| } |
| if (buf_p == buffer) |
| *buf_p = '\0'; /* nothing was written */ |
| else |
| *(buf_p - 1) = '\0'; /* erase the final comma */ |
| |
| } |
| |
| void htt_make_u16_list_str(uint32_t *aligned_data, |
| char *buffer, int space, int max_elems) |
| { |
| uint16_t *p16 = (uint16_t *) aligned_data; |
| char *buf_p = buffer; |
| while (max_elems-- > 0) { |
| int bytes; |
| uint16_t val; |
| |
| val = htt_msg_read16(p16); |
| if (val == 0) |
| /* not enough data to fill the reserved msg buffer */ |
| break; |
| bytes = qdf_snprint(buf_p, space, "%d,", val); |
| space -= bytes; |
| if (space > 0) |
| buf_p += bytes; |
| else /* not enough print buffer space for all the data */ |
| break; |
| |
| p16++; |
| } |
| if (buf_p == buffer) |
| *buf_p = '\0'; /* nothing was written */ |
| else |
| *(buf_p - 1) = '\0'; /* erase the final comma */ |
| } |
| |
| void |
| htt_t2h_tx_ppdu_log_print(struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr, |
| struct ol_fw_tx_dbg_ppdu_base *record, |
| int length, int concise) |
| { |
| int i; |
| int record_size; |
| int num_records; |
| |
| record_size = |
| sizeof(*record) + |
| hdr->mpdu_bytes_array_len * sizeof(uint16_t) + |
| hdr->mpdu_msdus_array_len * sizeof(uint8_t) + |
| hdr->msdu_bytes_array_len * sizeof(uint16_t); |
| num_records = (length - sizeof(*hdr)) / record_size; |
| qdf_print("Tx PPDU log elements: num_records %d", num_records); |
| |
| for (i = 0; i < num_records; i++) { |
| uint16_t start_seq_num; |
| uint16_t start_pn_lsbs; |
| uint8_t num_mpdus; |
| uint16_t peer_id; |
| uint8_t ext_tid; |
| uint8_t rate_code; |
| uint8_t rate_flags; |
| uint8_t tries; |
| uint8_t complete; |
| uint32_t time_enqueue_us; |
| uint32_t time_completion_us; |
| uint32_t *msg_word = (uint32_t *) record; |
| |
| /* fields used for both concise and complete printouts */ |
| start_seq_num = |
| ((*(msg_word + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_16)) & |
| OL_FW_TX_DBG_PPDU_START_SEQ_NUM_M) >> |
| OL_FW_TX_DBG_PPDU_START_SEQ_NUM_S; |
| complete = |
| ((*(msg_word + OL_FW_TX_DBG_PPDU_COMPLETE_16)) & |
| OL_FW_TX_DBG_PPDU_COMPLETE_M) >> |
| OL_FW_TX_DBG_PPDU_COMPLETE_S; |
| |
| /* fields used only for complete printouts */ |
| if (!concise) { |
| #define BUF_SIZE 80 |
| char buf[BUF_SIZE]; |
| uint8_t *p8; |
| time_enqueue_us = |
| HTT_TICK_TO_USEC(record->timestamp_enqueue, |
| hdr->microsec_per_tick); |
| time_completion_us = |
| HTT_TICK_TO_USEC(record->timestamp_completion, |
| hdr->microsec_per_tick); |
| |
| start_pn_lsbs = |
| ((* |
| (msg_word + |
| OL_FW_TX_DBG_PPDU_START_PN_LSBS_16)) & |
| OL_FW_TX_DBG_PPDU_START_PN_LSBS_M) >> |
| OL_FW_TX_DBG_PPDU_START_PN_LSBS_S; |
| num_mpdus = |
| ((*(msg_word + OL_FW_TX_DBG_PPDU_NUM_MPDUS_16))& |
| OL_FW_TX_DBG_PPDU_NUM_MPDUS_M) >> |
| OL_FW_TX_DBG_PPDU_NUM_MPDUS_S; |
| peer_id = |
| ((*(msg_word + OL_FW_TX_DBG_PPDU_PEER_ID_16)) & |
| OL_FW_TX_DBG_PPDU_PEER_ID_M) >> |
| OL_FW_TX_DBG_PPDU_PEER_ID_S; |
| ext_tid = |
| ((*(msg_word + OL_FW_TX_DBG_PPDU_EXT_TID_16)) & |
| OL_FW_TX_DBG_PPDU_EXT_TID_M) >> |
| OL_FW_TX_DBG_PPDU_EXT_TID_S; |
| rate_code = |
| ((*(msg_word + OL_FW_TX_DBG_PPDU_RATE_CODE_16))& |
| OL_FW_TX_DBG_PPDU_RATE_CODE_M) >> |
| OL_FW_TX_DBG_PPDU_RATE_CODE_S; |
| rate_flags = |
| ((*(msg_word + OL_FW_TX_DBG_PPDU_RATEFLAGS_16))& |
| OL_FW_TX_DBG_PPDU_RATE_FLAGS_M) >> |
| OL_FW_TX_DBG_PPDU_RATE_FLAGS_S; |
| tries = |
| ((*(msg_word + OL_FW_TX_DBG_PPDU_TRIES_16)) & |
| OL_FW_TX_DBG_PPDU_TRIES_M) >> |
| OL_FW_TX_DBG_PPDU_TRIES_S; |
| |
| qdf_print(" - PPDU tx to peer %d, TID %d", peer_id, |
| ext_tid); |
| qdf_print |
| (" start seq num= %u, start PN LSBs= %#04x", |
| start_seq_num, start_pn_lsbs); |
| qdf_print |
| (" PPDU: %d MPDUs, (?) MSDUs, %d bytes", |
| num_mpdus, |
| /* num_msdus - not yet computed in target */ |
| record->num_bytes); |
| if (complete) { |
| qdf_print |
| (" enqueued: %u, completed: %u usec)", |
| time_enqueue_us, time_completion_us); |
| qdf_print |
| (" %d tries, last tx used rate %d ", |
| tries, rate_code); |
| qdf_print("on %d MHz chan (flags = %#x)", |
| htt_rate_flags_to_mhz |
| (rate_flags), rate_flags); |
| qdf_print |
| (" enqueued and acked MPDU bitmaps:"); |
| htt_t2h_tx_ppdu_bitmaps_pr(msg_word + |
| OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_16, |
| msg_word + |
| OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_16); |
| } else { |
| qdf_print |
| (" enqueued: %d us, not yet completed", |
| time_enqueue_us); |
| } |
| /* skip the regular msg fields to reach the tail area */ |
| p8 = (uint8_t *) record; |
| p8 += sizeof(struct ol_fw_tx_dbg_ppdu_base); |
| if (hdr->mpdu_bytes_array_len) { |
| htt_make_u16_list_str((uint32_t *) p8, buf, |
| BUF_SIZE, |
| hdr-> |
| mpdu_bytes_array_len); |
| qdf_print(" MPDU bytes: %s", buf); |
| } |
| p8 += hdr->mpdu_bytes_array_len * sizeof(uint16_t); |
| if (hdr->mpdu_msdus_array_len) { |
| htt_make_u8_list_str((uint32_t *) p8, buf, |
| BUF_SIZE, |
| hdr->mpdu_msdus_array_len); |
| qdf_print(" MPDU MSDUs: %s", buf); |
| } |
| p8 += hdr->mpdu_msdus_array_len * sizeof(uint8_t); |
| if (hdr->msdu_bytes_array_len) { |
| htt_make_u16_list_str((uint32_t *) p8, buf, |
| BUF_SIZE, |
| hdr-> |
| msdu_bytes_array_len); |
| qdf_print(" MSDU bytes: %s", buf); |
| } |
| } else { |
| /* concise */ |
| qdf_print("start seq num = %u ", start_seq_num); |
| qdf_print("enqueued and acked MPDU bitmaps:"); |
| if (complete) { |
| htt_t2h_tx_ppdu_bitmaps_pr(msg_word + |
| OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_16, |
| msg_word + |
| OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_16); |
| } else { |
| qdf_print("(not completed)"); |
| } |
| } |
| record = (struct ol_fw_tx_dbg_ppdu_base *) |
| (((uint8_t *) record) + record_size); |
| } |
| } |
| |
| void htt_t2h_stats_tidq_stats_print( |
| struct wlan_dbg_tidq_stats *tidq_stats, int concise) |
| { |
| qdf_print("TID QUEUE STATS:"); |
| qdf_print("tid_txq_stats: %u", tidq_stats->wlan_dbg_tid_txq_status); |
| qdf_print("num_pkts_queued(0..9):"); |
| qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", |
| tidq_stats->txq_st.num_pkts_queued[0], |
| tidq_stats->txq_st.num_pkts_queued[1], |
| tidq_stats->txq_st.num_pkts_queued[2], |
| tidq_stats->txq_st.num_pkts_queued[3], |
| tidq_stats->txq_st.num_pkts_queued[4], |
| tidq_stats->txq_st.num_pkts_queued[5], |
| tidq_stats->txq_st.num_pkts_queued[6], |
| tidq_stats->txq_st.num_pkts_queued[7], |
| tidq_stats->txq_st.num_pkts_queued[8], |
| tidq_stats->txq_st.num_pkts_queued[9]); |
| qdf_print("tid_hw_qdepth(0..19):"); |
| qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", |
| tidq_stats->txq_st.tid_hw_qdepth[0], |
| tidq_stats->txq_st.tid_hw_qdepth[1], |
| tidq_stats->txq_st.tid_hw_qdepth[2], |
| tidq_stats->txq_st.tid_hw_qdepth[3], |
| tidq_stats->txq_st.tid_hw_qdepth[4], |
| tidq_stats->txq_st.tid_hw_qdepth[5], |
| tidq_stats->txq_st.tid_hw_qdepth[6], |
| tidq_stats->txq_st.tid_hw_qdepth[7], |
| tidq_stats->txq_st.tid_hw_qdepth[8], |
| tidq_stats->txq_st.tid_hw_qdepth[9]); |
| qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", |
| tidq_stats->txq_st.tid_hw_qdepth[10], |
| tidq_stats->txq_st.tid_hw_qdepth[11], |
| tidq_stats->txq_st.tid_hw_qdepth[12], |
| tidq_stats->txq_st.tid_hw_qdepth[13], |
| tidq_stats->txq_st.tid_hw_qdepth[14], |
| tidq_stats->txq_st.tid_hw_qdepth[15], |
| tidq_stats->txq_st.tid_hw_qdepth[16], |
| tidq_stats->txq_st.tid_hw_qdepth[17], |
| tidq_stats->txq_st.tid_hw_qdepth[18], |
| tidq_stats->txq_st.tid_hw_qdepth[19]); |
| qdf_print("tid_sw_qdepth(0..19):"); |
| qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", |
| tidq_stats->txq_st.tid_sw_qdepth[0], |
| tidq_stats->txq_st.tid_sw_qdepth[1], |
| tidq_stats->txq_st.tid_sw_qdepth[2], |
| tidq_stats->txq_st.tid_sw_qdepth[3], |
| tidq_stats->txq_st.tid_sw_qdepth[4], |
| tidq_stats->txq_st.tid_sw_qdepth[5], |
| tidq_stats->txq_st.tid_sw_qdepth[6], |
| tidq_stats->txq_st.tid_sw_qdepth[7], |
| tidq_stats->txq_st.tid_sw_qdepth[8], |
| tidq_stats->txq_st.tid_sw_qdepth[9]); |
| qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", |
| tidq_stats->txq_st.tid_sw_qdepth[10], |
| tidq_stats->txq_st.tid_sw_qdepth[11], |
| tidq_stats->txq_st.tid_sw_qdepth[12], |
| tidq_stats->txq_st.tid_sw_qdepth[13], |
| tidq_stats->txq_st.tid_sw_qdepth[14], |
| tidq_stats->txq_st.tid_sw_qdepth[15], |
| tidq_stats->txq_st.tid_sw_qdepth[16], |
| tidq_stats->txq_st.tid_sw_qdepth[17], |
| tidq_stats->txq_st.tid_sw_qdepth[18], |
| tidq_stats->txq_st.tid_sw_qdepth[19]); |
| } |
| |
| void htt_t2h_stats_tx_mu_stats_print( |
| struct wlan_dbg_tx_mu_stats *tx_mu_stats, int concise) |
| { |
| qdf_print("TX MU STATS:"); |
| qdf_print("mu_sch_nusers_2: %u", tx_mu_stats->mu_sch_nusers_2); |
| qdf_print("mu_sch_nusers_3: %u", tx_mu_stats->mu_sch_nusers_3); |
| qdf_print("mu_mpdus_queued_usr: %u, %u, %u, %u", |
| tx_mu_stats->mu_mpdus_queued_usr[0], |
| tx_mu_stats->mu_mpdus_queued_usr[1], |
| tx_mu_stats->mu_mpdus_queued_usr[2], |
| tx_mu_stats->mu_mpdus_queued_usr[3]); |
| qdf_print("mu_mpdus_tried_usr: %u, %u, %u, %u", |
| tx_mu_stats->mu_mpdus_tried_usr[0], |
| tx_mu_stats->mu_mpdus_tried_usr[1], |
| tx_mu_stats->mu_mpdus_tried_usr[2], |
| tx_mu_stats->mu_mpdus_tried_usr[3]); |
| qdf_print("mu_mpdus_failed_usr: %u, %u, %u, %u", |
| tx_mu_stats->mu_mpdus_failed_usr[0], |
| tx_mu_stats->mu_mpdus_failed_usr[1], |
| tx_mu_stats->mu_mpdus_failed_usr[2], |
| tx_mu_stats->mu_mpdus_failed_usr[3]); |
| qdf_print("mu_mpdus_requeued_usr: %u, %u, %u, %u", |
| tx_mu_stats->mu_mpdus_requeued_usr[0], |
| tx_mu_stats->mu_mpdus_requeued_usr[1], |
| tx_mu_stats->mu_mpdus_requeued_usr[2], |
| tx_mu_stats->mu_mpdus_requeued_usr[3]); |
| qdf_print("mu_err_no_ba_usr: %u, %u, %u, %u", |
| tx_mu_stats->mu_err_no_ba_usr[0], |
| tx_mu_stats->mu_err_no_ba_usr[1], |
| tx_mu_stats->mu_err_no_ba_usr[2], |
| tx_mu_stats->mu_err_no_ba_usr[3]); |
| qdf_print("mu_mpdu_underrun_usr: %u, %u, %u, %u", |
| tx_mu_stats->mu_mpdu_underrun_usr[0], |
| tx_mu_stats->mu_mpdu_underrun_usr[1], |
| tx_mu_stats->mu_mpdu_underrun_usr[2], |
| tx_mu_stats->mu_mpdu_underrun_usr[3]); |
| qdf_print("mu_ampdu_underrun_usr: %u, %u, %u, %u", |
| tx_mu_stats->mu_ampdu_underrun_usr[0], |
| tx_mu_stats->mu_ampdu_underrun_usr[1], |
| tx_mu_stats->mu_ampdu_underrun_usr[2], |
| tx_mu_stats->mu_ampdu_underrun_usr[3]); |
| |
| } |
| |
| void htt_t2h_stats_sifs_resp_stats_print( |
| struct wlan_dbg_sifs_resp_stats *sifs_stats, int concise) |
| { |
| qdf_print("SIFS RESP STATS:"); |
| qdf_print("num of ps-poll trigger frames: %u", |
| sifs_stats->ps_poll_trigger); |
| qdf_print("num of uapsd trigger frames: %u", |
| sifs_stats->uapsd_trigger); |
| qdf_print("num of data trigger frames: %u, %u", |
| sifs_stats->qb_data_trigger[0], |
| sifs_stats->qb_data_trigger[1]); |
| qdf_print("num of bar trigger frames: %u, %u", |
| sifs_stats->qb_bar_trigger[0], |
| sifs_stats->qb_bar_trigger[1]); |
| qdf_print("num of ppdu transmitted at SIFS interval: %u", |
| sifs_stats->sifs_resp_data); |
| qdf_print("num of ppdu failed to meet SIFS resp timing: %u", |
| sifs_stats->sifs_resp_err); |
| } |
| |
| void htt_t2h_stats_print(uint8_t *stats_data, int concise) |
| { |
| uint32_t *msg_word = (uint32_t *) stats_data; |
| enum htt_dbg_stats_type type; |
| enum htt_dbg_stats_status status; |
| int length; |
| |
| type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word); |
| status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word); |
| length = HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); |
| |
| /* check that we've been given a valid stats type */ |
| if (status == HTT_DBG_STATS_STATUS_SERIES_DONE) { |
| return; |
| } else if (status == HTT_DBG_STATS_STATUS_INVALID) { |
| qdf_print("Target doesn't support stats type %d", type); |
| return; |
| } else if (status == HTT_DBG_STATS_STATUS_ERROR) { |
| qdf_print("Target couldn't upload stats type %d (no mem?)", |
| type); |
| return; |
| } |
| /* got valid (though perhaps partial) stats - process them */ |
| switch (type) { |
| case HTT_DBG_STATS_WAL_PDEV_TXRX: |
| { |
| struct wlan_dbg_stats *wlan_dbg_stats_ptr; |
| |
| wlan_dbg_stats_ptr = |
| (struct wlan_dbg_stats *)(msg_word + 1); |
| htt_t2h_stats_pdev_stats_print(wlan_dbg_stats_ptr, |
| concise); |
| break; |
| } |
| case HTT_DBG_STATS_RX_REORDER: |
| { |
| struct rx_reorder_stats *rx_reorder_stats_ptr; |
| |
| rx_reorder_stats_ptr = |
| (struct rx_reorder_stats *)(msg_word + 1); |
| htt_t2h_stats_rx_reorder_stats_print |
| (rx_reorder_stats_ptr, concise); |
| break; |
| } |
| |
| case HTT_DBG_STATS_RX_RATE_INFO: |
| { |
| wlan_dbg_rx_rate_info_t *rx_phy_info; |
| rx_phy_info = |
| (wlan_dbg_rx_rate_info_t *) (msg_word + 1); |
| |
| htt_t2h_stats_rx_rate_stats_print(rx_phy_info, concise); |
| |
| break; |
| } |
| case HTT_DBG_STATS_RX_RATE_INFO_V2: |
| { |
| wlan_dbg_rx_rate_info_v2_t *rx_phy_info; |
| rx_phy_info = |
| (wlan_dbg_rx_rate_info_v2_t *) (msg_word + 1); |
| htt_t2h_stats_rx_rate_stats_print_v2(rx_phy_info, concise); |
| break; |
| } |
| case HTT_DBG_STATS_TX_PPDU_LOG: |
| { |
| struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr; |
| struct ol_fw_tx_dbg_ppdu_base *record; |
| |
| if (status == HTT_DBG_STATS_STATUS_PARTIAL |
| && length == 0) { |
| qdf_print |
| ("HTT_DBG_STATS_TX_PPDU_LOG -- length = 0!"); |
| break; |
| } |
| hdr = |
| (struct ol_fw_tx_dbg_ppdu_msg_hdr *)(msg_word + 1); |
| record = (struct ol_fw_tx_dbg_ppdu_base *)(hdr + 1); |
| htt_t2h_tx_ppdu_log_print(hdr, record, length, concise); |
| } |
| break; |
| case HTT_DBG_STATS_TX_RATE_INFO: |
| { |
| wlan_dbg_tx_rate_info_t *tx_rate_info; |
| tx_rate_info = |
| (wlan_dbg_tx_rate_info_t *) (msg_word + 1); |
| |
| htt_t2h_stats_tx_rate_stats_print(tx_rate_info, concise); |
| |
| break; |
| } |
| case HTT_DBG_STATS_TX_RATE_INFO_V2: |
| { |
| wlan_dbg_tx_rate_info_v2_t *tx_rate_info; |
| tx_rate_info = |
| (wlan_dbg_tx_rate_info_v2_t *) (msg_word + 1); |
| htt_t2h_stats_tx_rate_stats_print_v2(tx_rate_info, concise); |
| break; |
| } |
| case HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO: |
| { |
| struct rx_remote_buffer_mgmt_stats *rx_rem_buf; |
| |
| rx_rem_buf = (struct rx_remote_buffer_mgmt_stats *)(msg_word + 1); |
| htt_t2h_stats_rx_rem_buf_stats_print(rx_rem_buf, concise); |
| break; |
| } |
| case HTT_DBG_STATS_TXBF_INFO: |
| { |
| struct wlan_dbg_txbf_data_stats *txbf_info_buf; |
| |
| txbf_info_buf = |
| (struct wlan_dbg_txbf_data_stats *)(msg_word + 1); |
| htt_t2h_stats_txbf_info_buf_stats_print(txbf_info_buf); |
| break; |
| } |
| case HTT_DBG_STATS_SND_INFO: |
| { |
| struct wlan_dbg_txbf_snd_stats *txbf_snd_buf; |
| |
| txbf_snd_buf = |
| (struct wlan_dbg_txbf_snd_stats *)(msg_word + 1); |
| htt_t2h_stats_txbf_snd_buf_stats_print(txbf_snd_buf); |
| break; |
| } |
| case HTT_DBG_STATS_TX_SELFGEN_INFO: |
| { |
| struct wlan_dbg_tx_selfgen_stats *tx_selfgen_buf; |
| |
| tx_selfgen_buf = |
| (struct wlan_dbg_tx_selfgen_stats *)(msg_word + 1); |
| htt_t2h_stats_tx_selfgen_buf_stats_print(tx_selfgen_buf); |
| break; |
| } |
| case HTT_DBG_STATS_ERROR_INFO: |
| { |
| struct wlan_dbg_wifi2_error_stats *wifi2_error_buf; |
| |
| wifi2_error_buf = |
| (struct wlan_dbg_wifi2_error_stats *)(msg_word + 1); |
| htt_t2h_stats_wifi2_error_stats_print(wifi2_error_buf); |
| break; |
| } |
| case HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT: |
| { |
| struct rx_txbf_musu_ndpa_pkts_stats *rx_musu_ndpa_stats; |
| |
| rx_musu_ndpa_stats = (struct rx_txbf_musu_ndpa_pkts_stats *) |
| (msg_word + 1); |
| htt_t2h_rx_musu_ndpa_pkts_stats_print(rx_musu_ndpa_stats); |
| break; |
| } |
| case HTT_DBG_STATS_TIDQ: |
| { |
| struct wlan_dbg_tidq_stats *tidq_stats; |
| tidq_stats = (struct wlan_dbg_tidq_stats *)(msg_word + 1); |
| |
| htt_t2h_stats_tidq_stats_print(tidq_stats, concise); |
| break; |
| } |
| case HTT_DBG_STATS_TX_MU_INFO: |
| { |
| struct wlan_dbg_tx_mu_stats *tx_mu_stats; |
| tx_mu_stats = (struct wlan_dbg_tx_mu_stats *)(msg_word + 1); |
| |
| htt_t2h_stats_tx_mu_stats_print(tx_mu_stats, concise); |
| break; |
| } |
| case HTT_DBG_STATS_SIFS_RESP_INFO: |
| { |
| struct wlan_dbg_sifs_resp_stats *sifs_stats; |
| sifs_stats = (struct wlan_dbg_sifs_resp_stats *)(msg_word + 1); |
| |
| htt_t2h_stats_sifs_resp_stats_print(sifs_stats, concise); |
| break; |
| } |
| default: |
| break; |
| } |
| } |