blob: 8742c1ae61e8adab55ea6777b8f874a3d3c4c403 [file] [log] [blame]
/*
* Copyright (c) 2012-2015 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 <adf_nbuf.h> /* adf_nbuf_t */
#include <adf_os_mem.h> /* adf_os_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 void htt_t2h_stats_tx_rate_stats_print(
wlan_dbg_tx_rate_info_t *tx_rate_info, int concise)
{
adf_os_print("TX Rate Info:\n");
/* MCS */
adf_os_print("MCS counts (0..9): ");
adf_os_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
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 */
adf_os_print("SGI counts (0..9): ");
adf_os_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
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 */
adf_os_print("NSS counts: ");
adf_os_print("1x1 %d, 2x2 %d, 3x3 %d\n",
tx_rate_info->nss[0],
tx_rate_info->nss[1],
tx_rate_info->nss[2]
);
/* BW */
adf_os_print("BW counts: ");
adf_os_print("20MHz %d, 40MHz %d, 80MHz %d\n",
tx_rate_info->bw[0],
tx_rate_info->bw[1],
tx_rate_info->bw[2]
);
/* Preamble */
adf_os_print("Preamble (O C H V) counts: ");
adf_os_print("%d, %d, %d, %d\n",
tx_rate_info->pream[0],
tx_rate_info->pream[1],
tx_rate_info->pream[2],
tx_rate_info->pream[3]
);
/* STBC rate counts */
adf_os_print("STBC rate counts (0..9): ");
adf_os_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
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 */
adf_os_print("LDPC Counts: ");
adf_os_print("%d\n", tx_rate_info->ldpc);
adf_os_print("RTS Counts: ");
adf_os_print("%d\n", tx_rate_info->rts_cnt);
/* RSSI Values for last ack frames */
adf_os_print("Ack RSSI: %d\n",tx_rate_info->ack_rssi);
}
static void htt_t2h_stats_rx_rate_stats_print(
wlan_dbg_rx_rate_info_t *rx_phy_info, int concise)
{
adf_os_print("RX Rate Info:\n");
/* MCS */
adf_os_print("MCS counts (0..9): ");
adf_os_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
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 */
adf_os_print("SGI counts (0..9): ");
adf_os_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
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 */
adf_os_print("NSS counts: ");
/* 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. */
adf_os_print("1x1 %d, 2x2 %d, 3x3 %d, 4x4 %d\n",
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 */
adf_os_print("NSTS count: ");
adf_os_print("%d\n", rx_phy_info->nsts);
/* BW */
adf_os_print("BW counts: ");
adf_os_print("20MHz %d, 40MHz %d, 80MHz %d\n",
rx_phy_info->bw[0],
rx_phy_info->bw[1],
rx_phy_info->bw[2]
);
/* Preamble */
adf_os_print("Preamble counts: ");
adf_os_print("%d, %d, %d, %d, %d, %d\n",
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 */
adf_os_print("STBC rate counts (0..9): ");
adf_os_print("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
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 */
adf_os_print("LDPC TXBF Counts: ");
adf_os_print("%d, %d\n", rx_phy_info->ldpc, rx_phy_info->txbf);
/* RSSI Values for last received frames */
adf_os_print("RSSI (data, mgmt): %d, %d\n",rx_phy_info->data_rssi,
rx_phy_info->mgmt_rssi);
adf_os_print("RSSI Chain 0 (0x%02x 0x%02x 0x%02x 0x%02x)\n",
((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));
adf_os_print("RSSI Chain 1 (0x%02x 0x%02x 0x%02x 0x%02x)\n",
((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));
adf_os_print("RSSI Chain 2 (0x%02x 0x%02x 0x%02x 0x%02x)\n",
((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_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;
adf_os_print("WAL Pdev stats:\n");
adf_os_print("\n### Tx ###\n");
/* Num HTT cookies queued to dispatch list */
adf_os_print("comp_queued :\t%d\n",tx->comp_queued);
/* Num HTT cookies dispatched */
adf_os_print("comp_delivered :\t%d\n",tx->comp_delivered);
/* Num MSDU queued to WAL */
adf_os_print("msdu_enqued :\t%d\n",tx->msdu_enqued);
/* Num MPDU queued to WAL */
adf_os_print("mpdu_enqued :\t%d\n",tx->mpdu_enqued);
/* Num MSDUs dropped by WMM limit */
adf_os_print("wmm_drop :\t%d\n",tx->wmm_drop);
/* Num Local frames queued */
adf_os_print("local_enqued :\t%d\n",tx->local_enqued);
/* Num Local frames done */
adf_os_print("local_freed :\t%d\n",tx->local_freed);
/* Num queued to HW */
adf_os_print("hw_queued :\t%d\n",tx->hw_queued);
/* Num PPDU reaped from HW */
adf_os_print("hw_reaped :\t%d\n",tx->hw_reaped);
/* Num underruns */
adf_os_print("mac underrun :\t%d\n",tx->underrun);
/* Num underruns */
adf_os_print("phy underrun :\t%d\n",tx->phy_underrun);
/* Num PPDUs cleaned up in TX abort */
adf_os_print("tx_abort :\t%d\n",tx->tx_abort);
/* Num MPDUs requed by SW */
adf_os_print("mpdus_requed :\t%d\n",tx->mpdus_requed);
/* Excessive retries */
adf_os_print("excess retries :\t%d\n",tx->tx_ko);
/* last data rate */
adf_os_print("last rc :\t%d\n",tx->data_rc);
/* scheduler self triggers */
adf_os_print("sched self trig :\t%d\n",tx->self_triggers);
/* SW retry failures */
adf_os_print("ampdu retry failed:\t%d\n",tx->sw_retry_failure);
/* ilegal phy rate errirs */
adf_os_print("illegal rate errs :\t%d\n",tx->illgl_rate_phy_err);
/* pdev continous excessive retries */
adf_os_print("pdev cont xretry :\t%d\n",tx->pdev_cont_xretry);
/* pdev continous excessive retries */
adf_os_print("pdev tx timeout :\t%d\n",tx->pdev_tx_timeout);
/* pdev resets */
adf_os_print("pdev resets :\t%d\n",tx->pdev_resets);
/* PPDU > txop duration */
adf_os_print("ppdu txop ovf :\t%d\n",tx->txop_ovf);
adf_os_print("\n### Rx ###\n");
/* Cnts any change in ring routing mid-ppdu */
adf_os_print("ppdu_route_change :\t%d\n",rx->mid_ppdu_route_change);
/* Total number of statuses processed */
adf_os_print("status_rcvd :\t%d\n",rx->status_rcvd);
/* Extra frags on rings 0-3 */
adf_os_print("r0_frags :\t%d\n",rx->r0_frags);
adf_os_print("r1_frags :\t%d\n",rx->r1_frags);
adf_os_print("r2_frags :\t%d\n",rx->r2_frags);
adf_os_print("r3_frags :\t%d\n",rx->r3_frags);
/* MSDUs / MPDUs delivered to HTT */
adf_os_print("htt_msdus :\t%d\n",rx->htt_msdus);
adf_os_print("htt_mpdus :\t%d\n",rx->htt_mpdus);
/* MSDUs / MPDUs delivered to local stack */
adf_os_print("loc_msdus :\t%d\n",rx->loc_msdus);
adf_os_print("loc_mpdus :\t%d\n",rx->loc_mpdus);
/* AMSDUs that have more MSDUs than the status ring size */
adf_os_print("oversize_amsdu :\t%d\n",rx->oversize_amsdu);
/* Number of PHY errors */
adf_os_print("phy_errs :\t%d\n",rx->phy_errs);
/* Number of PHY errors dropped */
adf_os_print("phy_errs dropped :\t%d\n",rx->phy_err_drop);
/* Number of mpdu errors - FCS, MIC, ENC etc. */
adf_os_print("mpdu_errs :\t%d\n",rx->mpdu_errs);
}
static void
htt_t2h_stats_rx_reorder_stats_print(
struct rx_reorder_stats *stats_ptr, int concise)
{
adf_os_print("Rx reorder statistics:\n");
adf_os_print(" %u non-QoS frames received\n",
stats_ptr->deliver_non_qos);
adf_os_print(" %u frames received in-order\n",
stats_ptr->deliver_in_order);
adf_os_print(" %u frames flushed due to timeout\n",
stats_ptr->deliver_flush_timeout);
adf_os_print(" %u frames flushed due to moving out of window\n",
stats_ptr->deliver_flush_oow);
adf_os_print(" %u frames flushed due to receiving DELBA\n",
stats_ptr->deliver_flush_delba);
adf_os_print(" %u frames discarded due to FCS error\n",
stats_ptr->fcs_error);
adf_os_print(" %u frames discarded due to invalid peer\n",
stats_ptr->invalid_peer);
adf_os_print(" %u frames discarded due to duplication (non aggregation)\n",
stats_ptr->dup_non_aggr);
adf_os_print(" %u frames discarded due to duplication in "
"reorder queue\n", stats_ptr->dup_in_reorder);
adf_os_print(" %u frames discarded due to processed before\n",
stats_ptr->dup_past);
adf_os_print(" %u times reorder timeout happened\n",
stats_ptr->reorder_timeout);
adf_os_print(" %u times incorrect bar received\n",
stats_ptr->invalid_bar_ssn);
adf_os_print(" %u times bar ssn reset happened\n",
stats_ptr->ssn_reset);
adf_os_print(" %u times flushed due to peer delete\n",
stats_ptr->deliver_flush_delpeer);
adf_os_print(" %u times flushed due to offload\n",
stats_ptr->deliver_flush_offload);
adf_os_print(" %u times flushed due to ouf of buffer\n",
stats_ptr->deliver_flush_oob);
adf_os_print(" %u MPDU's dropped due to PN check fail\n",
stats_ptr->pn_fail);
adf_os_print(" %u MPDU's dropped due to lack of memory\n",
stats_ptr->store_fail);
adf_os_print(" %u times tid pool alloc succeeded\n",
stats_ptr->tid_pool_alloc_succ);
adf_os_print(" %u times MPDU pool alloc succeeded\n",
stats_ptr->mpdu_pool_alloc_succ);
adf_os_print(" %u times MSDU pool alloc succeeded\n",
stats_ptr->msdu_pool_alloc_succ);
adf_os_print(" %u times tid pool alloc failed\n",
stats_ptr->tid_pool_alloc_fail);
adf_os_print(" %u times MPDU pool alloc failed\n",
stats_ptr->mpdu_pool_alloc_fail);
adf_os_print(" %u times MSDU pool alloc failed\n",
stats_ptr->msdu_pool_alloc_fail);
adf_os_print(" %u times tid pool freed\n",
stats_ptr->tid_pool_free);
adf_os_print(" %u times MPDU pool freed\n",
stats_ptr->mpdu_pool_free);
adf_os_print(" %u times MSDU pool freed\n",
stats_ptr->msdu_pool_free);
adf_os_print(" %u MSDUs undelivered to HTT, queued to Rx MSDU free list\n",
stats_ptr->msdu_queued);
adf_os_print(" %u MSDUs released from Rx MSDU list to MAC ring\n",
stats_ptr->msdu_recycled);
adf_os_print(" %u MPDUs with invalid peer but A2 found in AST\n",
stats_ptr->invalid_peer_a2_in_ast);
adf_os_print(" %u MPDUs with invalid peer but A3 found in AST\n",
stats_ptr->invalid_peer_a3_in_ast);
adf_os_print(" %u MPDUs with invalid peer, Broadcast or Mulitcast frame\n",
stats_ptr->invalid_peer_bmc_mpdus);
adf_os_print(" %u MSDUs with err attention word\n",
stats_ptr->rxdesc_err_att);
adf_os_print(" %u MSDUs with flag of peer_idx_invalid\n",
stats_ptr->rxdesc_err_peer_idx_inv);
adf_os_print(" %u MSDUs with flag of peer_idx_timeout\n",
stats_ptr->rxdesc_err_peer_idx_to);
adf_os_print(" %u MSDUs with flag of overflow\n",
stats_ptr->rxdesc_err_ov);
adf_os_print(" %u MSDUs with flag of msdu_length_err\n",
stats_ptr->rxdesc_err_msdu_len);
adf_os_print(" %u MSDUs with flag of mpdu_length_err\n",
stats_ptr->rxdesc_err_mpdu_len);
adf_os_print(" %u MSDUs with flag of tkip_mic_err\n",
stats_ptr->rxdesc_err_tkip_mic);
adf_os_print(" %u MSDUs with flag of decrypt_err\n",
stats_ptr->rxdesc_err_decrypt);
adf_os_print(" %u MSDUs with flag of fcs_err\n",
stats_ptr->rxdesc_err_fcs);
adf_os_print(" %u Unicast frames with invalid peer handler\n",
stats_ptr->rxdesc_uc_msdus_inv_peer);
adf_os_print(" %u unicast frame directly to DUT with invalid peer handler\n",
stats_ptr->rxdesc_direct_msdus_inv_peer);
adf_os_print(" %u Broadcast/Multicast frames with invalid peer handler\n",
stats_ptr->rxdesc_bmc_msdus_inv_peer);
adf_os_print(" %u MSDUs dropped due to no first MSDU flag\n",
stats_ptr->rxdesc_no_1st_msdu);
adf_os_print(" %u MSDUs dropped due to ring overflow\n",
stats_ptr->msdu_drop_ring_ov);
adf_os_print(" %u MSDUs dropped due to FC mismatch\n",
stats_ptr->msdu_drop_fc_mismatch);
adf_os_print(" %u MSDUs dropped due to mgt frame in Remote ring\n",
stats_ptr->msdu_drop_mgmt_remote_ring);
adf_os_print(" %u MSDUs dropped due to misc non error\n",
stats_ptr->msdu_drop_misc);
adf_os_print(" %u MSDUs go to offload before reorder\n",
stats_ptr->offload_msdu_wal);
adf_os_print(" %u data frame dropped by offload after reorder\n",
stats_ptr->offload_msdu_reorder);
adf_os_print(" %u MPDUs with SN in the past & within BA window\n",
stats_ptr->dup_past_within_window);
adf_os_print(" %u MPDUs with SN in the past & outside BA window\n",
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)
{
adf_os_print("Rx Remote Buffer Statistics:\n");
adf_os_print(" %u MSDU's reaped for Rx processing\n",
stats_ptr->remote_reaped);
adf_os_print(" %u MSDU's recycled within firmware\n",
stats_ptr->remote_recycled);
adf_os_print(" %u MSDU's stored by Data Rx\n",
stats_ptr->data_rx_msdus_stored);
adf_os_print(" %u HTT indications from WAL Rx MSDU\n",
stats_ptr->wal_rx_ind);
adf_os_print(" %u HTT indications unconsumed from WAL Rx MSDU\n",
stats_ptr->wal_rx_ind_unconsumed);
adf_os_print(" %u HTT indications from Data Rx MSDU\n",
stats_ptr->data_rx_ind);
adf_os_print(" %u HTT indications unconsumed from Data Rx MSDU\n",
stats_ptr->data_rx_ind_unconsumed);
adf_os_print(" %u HTT indications from ATHBUF\n",
stats_ptr->athbuf_rx_ind);
adf_os_print(" %u Remote buffers requested for refill\n",
stats_ptr->refill_buf_req);
adf_os_print(" %u Remote buffers filled by host\n",
stats_ptr->refill_buf_rsp);
adf_os_print(" %u times MAC has no buffers\n",
stats_ptr->mac_no_bufs);
adf_os_print(" %u times f/w write & read indices on MAC ring are equal\n",
stats_ptr->fw_indices_equal);
adf_os_print(" %u times f/w has no remote buffers to post to MAC\n",
stats_ptr->host_no_bufs);
}
static void
htt_t2h_rx_musu_ndpa_pkts_stats_print(
struct rx_txbf_musu_ndpa_pkts_stats *stats_ptr, int concise)
{
adf_os_print("Rx TXBF MU/SU Packets and NDPA Statistics:\n");
adf_os_print(" %u Number of TXBF MU packets received\n",
stats_ptr->number_mu_pkts);
adf_os_print(" %u Number of TXBF SU packets received\n",
stats_ptr->number_su_pkts);
adf_os_print(" %u Number of TXBF directed NDPA\n",
stats_ptr->txbf_directed_ndpa_count);
adf_os_print(" %u Number of TXBF retried NDPA\n",
stats_ptr->txbf_ndpa_retry_count);
adf_os_print(" %u Total number of TXBF NDPA\n",
stats_ptr->txbf_total_ndpa_count);
}
#define HTT_T2H_STATS_TX_PPDU_TIME_TO_MICROSEC(ticks, microsec_per_tick) \
(ticks * microsec_per_tick)
static inline int
HTT_T2H_STATS_TX_PPDU_RATE_FLAGS_TO_MHZ(u_int8_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_log_bitmaps_print(
u_int32_t *queued_ptr,
u_int32_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;
adf_os_mem_set(queued_str, '0', HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW);
adf_os_mem_set(acked_str, '-', HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW);
i = 0;
for (word = 0; word < 2; word++) {
u_int32_t queued = *(queued_ptr + word);
u_int32_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';
adf_os_print("%s\n", queued_str);
adf_os_print("%s\n", acked_str);
}
static inline u_int16_t htt_msg_read16(u_int16_t *p16)
{
#ifdef BIG_ENDIAN_HOST
/*
* During upload, the bytes within each u_int32_t word were
* swapped by the HIF HW. This results in the lower and upper bytes
* of each u_int16_t to be in the correct big-endian order with
* respect to each other, but for each even-index u_int16_t to
* have its position switched with its successor neighbor u_int16_t.
* Undo this u_int16_t position swapping.
*/
return (((size_t) p16) & 0x2) ? *(p16 - 1) : *(p16 + 1);
#else
return *p16;
#endif
}
static inline u_int8_t htt_msg_read8(u_int8_t *p8)
{
#ifdef BIG_ENDIAN_HOST
/*
* During upload, the bytes within each u_int32_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(
u_int32_t *aligned_data,
char *buffer,
int space,
int max_elems)
{
u_int8_t *p8 = (u_int8_t *) aligned_data;
char *buf_p = buffer;
while (max_elems-- > 0) {
int bytes;
u_int8_t val;
val = htt_msg_read8(p8);
if (val == 0) {
break; /* not enough data to fill the reserved msg buffer space */
}
bytes = adf_os_snprint(buf_p, space, "%d,", val);
space -= bytes;
if (space > 0) {
buf_p += bytes;
} else {
break; /* not enough print buffer space for all the data */
}
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(
u_int32_t *aligned_data,
char *buffer,
int space,
int max_elems)
{
u_int16_t *p16 = (u_int16_t *) aligned_data;
char *buf_p = buffer;
while (max_elems-- > 0) {
int bytes;
u_int16_t val;
val = htt_msg_read16(p16);
if (val == 0) {
break; /* not enough data to fill the reserved msg buffer space */
}
bytes = adf_os_snprint(buf_p, space, "%d,", val);
space -= bytes;
if (space > 0) {
buf_p += bytes;
} else {
break; /* not enough print buffer space for all the data */
}
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(u_int16_t) +
hdr->mpdu_msdus_array_len * sizeof(u_int8_t) +
hdr->msdu_bytes_array_len * sizeof(u_int16_t);
num_records = (length - sizeof(*hdr)) / record_size;
adf_os_print("Tx PPDU log elements:\n");
for (i = 0; i < num_records; i++) {
u_int16_t start_seq_num;
u_int16_t start_pn_lsbs;
u_int8_t num_mpdus;
u_int16_t peer_id;
u_int8_t ext_tid;
u_int8_t rate_code;
u_int8_t rate_flags;
u_int8_t tries;
u_int8_t complete;
u_int32_t time_enqueue_us;
u_int32_t time_completion_us;
u_int32_t *msg_word = (u_int32_t *) record;
/* fields used for both concise and complete printouts */
start_seq_num =
((*(msg_word + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_WORD)) &
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_WORD)) &
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];
u_int8_t *p8;
time_enqueue_us = HTT_T2H_STATS_TX_PPDU_TIME_TO_MICROSEC(
record->timestamp_enqueue, hdr->microsec_per_tick);
time_completion_us = HTT_T2H_STATS_TX_PPDU_TIME_TO_MICROSEC(
record->timestamp_completion, hdr->microsec_per_tick);
start_pn_lsbs =
((*(msg_word + OL_FW_TX_DBG_PPDU_START_PN_LSBS_WORD)) &
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_WORD)) &
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_WORD)) &
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_WORD)) &
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_WORD)) &
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_RATE_FLAGS_WORD)) &
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_WORD)) &
OL_FW_TX_DBG_PPDU_TRIES_M) >>
OL_FW_TX_DBG_PPDU_TRIES_S;
adf_os_print(" - PPDU tx to peer %d, TID %d\n", peer_id, ext_tid);
adf_os_print(" start seq num = %u, start PN LSBs = %#04x\n",
start_seq_num, start_pn_lsbs);
adf_os_print(" PPDU is %d MPDUs, (unknown) MSDUs, %d bytes\n",
num_mpdus,
//num_msdus, /* not yet being computed in target */
record->num_bytes);
if (complete) {
adf_os_print(" enqueued at %u, completed at %u (microsec)\n",
time_enqueue_us, time_completion_us);
adf_os_print(
" %d total tries, last tx used rate %d "
"on %d MHz chan (flags = %#x)\n",
tries, rate_code,
HTT_T2H_STATS_TX_PPDU_RATE_FLAGS_TO_MHZ(rate_flags),
rate_flags);
adf_os_print(" enqueued and acked MPDU bitmaps:\n");
htt_t2h_tx_ppdu_log_bitmaps_print(
msg_word + OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_WORD,
msg_word + OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_WORD);
} else {
adf_os_print(
" enqueued at %d ms (microsec), not yet completed\n",
time_enqueue_us);
}
/* skip past the regular message fields to reach the tail area */
p8 = (u_int8_t *) record;
p8 += sizeof(struct ol_fw_tx_dbg_ppdu_base);
if (hdr->mpdu_bytes_array_len) {
htt_make_u16_list_str(
(u_int32_t *) p8, buf, BUF_SIZE, hdr->mpdu_bytes_array_len);
adf_os_print(" MPDU bytes: %s\n", buf);
}
p8 += hdr->mpdu_bytes_array_len * sizeof(u_int16_t);
if (hdr->mpdu_msdus_array_len) {
htt_make_u8_list_str(
(u_int32_t *) p8, buf, BUF_SIZE, hdr->mpdu_msdus_array_len);
adf_os_print(" MPDU MSDUs: %s\n", buf);
}
p8 += hdr->mpdu_msdus_array_len * sizeof(u_int8_t);
if (hdr->msdu_bytes_array_len) {
htt_make_u16_list_str(
(u_int32_t *) p8, buf, BUF_SIZE, hdr->msdu_bytes_array_len);
adf_os_print(" MSDU bytes: %s\n", buf);
}
} else {
/* concise */
adf_os_print(
"start seq num = %u, enqueued and acked MPDU bitmaps:\n",
start_seq_num);
if (complete) {
htt_t2h_tx_ppdu_log_bitmaps_print(
msg_word + OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_WORD,
msg_word + OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_WORD);
} else {
adf_os_print("(not completed)\n");
}
}
record = (struct ol_fw_tx_dbg_ppdu_base *)
(((u_int8_t *) record) + record_size);
}
}
void
htt_t2h_stats_print(u_int8_t *stats_data, int concise)
{
u_int32_t *msg_word = (u_int32_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) {
adf_os_print(
"Target doesn't support stats type %d\n", type);
return;
} else if (status == HTT_DBG_STATS_STATUS_ERROR) {
adf_os_print(
"Target couldn't upload stats type %d (no mem?)\n", 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_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) {
adf_os_print("HTT_DBG_STATS_TX_PPDU_LOG -- length = 0!\n");
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_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_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, concise);
break;
}
default:
break;
}
}