# # Copyright (c) 2012-2014,2016,2019 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. # # trace-cmd plugin for ath10k, QCA Linux wireless driver import struct import binascii # enum htt_t2h_msg_type HTT_T2H_MSG_TYPE_VERSION_CONF = 0x0 HTT_T2H_MSG_TYPE_RX_IND = 0x1 HTT_T2H_MSG_TYPE_RX_FLUSH = 0x2 HTT_T2H_MSG_TYPE_PEER_MAP = 0x3 HTT_T2H_MSG_TYPE_PEER_UNMAP = 0x4 HTT_T2H_MSG_TYPE_RX_ADDBA = 0x5 HTT_T2H_MSG_TYPE_RX_DELBA = 0x6 HTT_T2H_MSG_TYPE_TX_COMPL_IND = 0x7 HTT_T2H_MSG_TYPE_PKTLOG = 0x8 HTT_T2H_MSG_TYPE_STATS_CONF = 0x9 HTT_T2H_MSG_TYPE_RX_FRAG_IND = 0xa HTT_T2H_MSG_TYPE_SEC_IND = 0xb HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10 HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11 HTT_T2H_MSG_TYPE_TEST = 0x12 # enum htt_dbg_stats_status HTT_DBG_STATS_STATUS_PRESENT = 0 HTT_DBG_STATS_STATUS_PARTIAL = 1 HTT_DBG_STATS_STATUS_ERROR = 2 HTT_DBG_STATS_STATUS_INVALID = 3 HTT_DBG_STATS_STATUS_SERIES_DONE = 7 # enum htt_dbg_stats_type HTT_DBG_STATS_WAL_PDEV_TXRX = 0 HTT_DBG_STATS_RX_REORDER = 1 HTT_DBG_STATS_RX_RATE_INFO = 2 HTT_DBG_STATS_TX_PPDU_LOG = 3 HTT_DBG_STATS_TX_RATE_INFO = 4 HTT_DBG_STATS_TIDQ = 5 HTT_DBG_STATS_TXBF_INFO = 6 HTT_DBG_STATS_SND_INFO = 7 HTT_DBG_STATS_ERROR_INFO = 8 HTT_DBG_STATS_TX_SELFGEN_INFO = 9 HTT_DBG_STATS_TX_MU_INFO = 10 HTT_DBG_STATS_SIFS_RESP_INFO = 11 HTT_DBG_STATS_RESET_INFO = 12 HTT_DBG_STATS_MAC_WDOG_INFO = 13 HTT_DBG_STATS_TX_DESC_INFO = 14 HTT_DBG_STATS_TX_FETCH_MGR_INFO = 15 HTT_DBG_STATS_TX_PFSCHED_INFO = 16 def hexdump(buf, prefix=None): s = binascii.b2a_hex(buf) s_len = len(s) result = "" if prefix is None: prefix = "" for i in range(s_len / 2): if i % 16 == 0: result = result + ("%s%04x: " % (prefix, i)) result = result + (s[2 * i] + s[2 * i + 1] + " ") if (i + 1) % 16 == 0: result = result + "\n" # FIXME: if len(s) % 16 == 0 there's an extra \n in the end return result wmi_scan_event_names = [ [0x1, "WMI_SCAN_EVENT_STARTED"], [0x2, "WMI_SCAN_EVENT_COMPLETED"], [0x4, "WMI_SCAN_EVENT_BSS_CHANNEL"], [0x8, "WMI_SCAN_EVENT_FOREIGN_CHANNEL"], [0x10, "WMI_SCAN_EVENT_DEQUEUED"], [0x20, "WMI_SCAN_EVENT_PREEMPTED"], [0x40, "WMI_SCAN_EVENT_START_FAILED"], ] def wmi_event_scan(pevent, trace_seq, event, buf): hdr = struct.unpack("> 24) & 0xff, (rssi_chain0 >> 16) & 0xff, (rssi_chain0 >> 8) & 0xff, (rssi_chain0 >> 0) & 0xff, (rssi_chain1 >> 24) & 0xff, (rssi_chain1 >> 16) & 0xff, (rssi_chain1 >> 8) & 0xff, (rssi_chain1 >> 0) & 0xff, (rssi_chain2 >> 24) & 0xff, (rssi_chain2 >> 16) & 0xff, (rssi_chain2 >> 8) & 0xff, (rssi_chain2 >> 0) & 0xff, (rssi_chain3 >> 24) & 0xff, (rssi_chain3 >> 16) & 0xff, (rssi_chain3 >> 8) & 0xff, (rssi_chain3 >> 0) & 0xff, (rssis >> 16) & 0xff, (rssis >> 0) & 0xff, (rssis >> 8) & 0xff, mgmt_rssi, data_rssi, rssi_comb_ht, nf_dbm, rssi_dbm)) def parse_htt_stats_tx_ppdu_log(pevent, trace_seq, buf, tlv_length): msg_hdr_len = 8 msg_base_len = 40 # struct ol_fw_tx_dbg_ppdu_msg_hdr l = msg_hdr_len hdr = struct.unpack("> 5 timestamp_enqueue = hdr[6] timestamp_completion = hdr[7] block_ack_bitmap_lsbs = hdr[8] block_ack_bitmap_msbs = hdr[9] enqueued_bitmap_lsbs = hdr[10] enqueued_bitmap_msbs = hdr[11] rate_code = hdr[12] rate_flags = hdr[13] tries = hdr[14] complete = hdr[15] trace_seq.puts("\t\t\t %d: start_seq_num %d start_pn_lsbs %d num_bytes %d num_msdus %d num_mpdus %d tid %d peer_id %d timestamp_enqueue %d timestamp_completion %d back %08x%08x enqueued %08x%08x rate_code 0x%x rate_flags 0x%x tries %d complete %d\n" % (i, start_seq_num, start_pn_lsbs, num_bytes, num_msdus, num_mpdus, tid, peer_id, timestamp_enqueue, timestamp_completion, block_ack_bitmap_msbs, block_ack_bitmap_lsbs, enqueued_bitmap_msbs, enqueued_bitmap_lsbs, rate_code, rate_flags, tries, complete)) def parse_htt_stats_tx_rate_info(pevent, trace_seq, buf, tlv_length): msg_base_len = 4 trace_seq.puts("\t\t\tTx Rate Info\n\t\t MCS_counts ") for i in range(10): l = msg_base_len hdr = struct.unpack("> 0), (((word1) & 0xFFFF0000) >> 16))) for i in range(9): msg_base_len = 24 l = msg_base_len hdr = struct.unpack("> 0) & 0xFF), ((cfg_min_bin_idx >> 16) & 0xFFFF), ( (cfg_prio_cfg_max >> 0) & 0xFFFF), ((cfg_prio_cfg_max >> 16) & 0xFF), ((curr_total_cfg_bin_hist_th >> 0) & 0xFFFF), ((curr_total_cfg_bin_hist_th >> 16) & 0xFFFF), ((bin_max_pre_alloc_cnt >> 0) & 0xFFFF), ((bin_max_pre_alloc_cnt >> 16) & 0xFFFF), bin_hist_low, bin_hist_high)) def parse_htt_stats_tx_fetch_mgr(pevent, trace_seq, buf, tlv_length): msg_base_len = 4 l = msg_base_len trace_seq.puts("\t\t\t Fetch Manager Stats\n") for i in range(4): hdr = struct.unpack("> 0), (((fetch_desc_fetch_dur) & 0xFFFF0000) >> 16))) hdr = struct.unpack("> 0) & 0x1f # enum htt_dbg_stats_status: HTT_DBG_STATS_STATUS_* tlv_status = (tlv & 0xe0) >> 5 tlv_length = (tlv & 0xffff0000) >> 16 if tlv_length > len(buf): return False if tlv_status == HTT_DBG_STATS_STATUS_SERIES_DONE: return False if tlv_status != HTT_DBG_STATS_STATUS_PRESENT and \ tlv_status != HTT_DBG_STATS_STATUS_PARTIAL: return True trace_seq.puts("\t\tcookie 0x%016x tlv_type %d tlv_status %d tlv_length %d\n" % (cookie, tlv_type, tlv_status, tlv_length)) if tlv_type == HTT_DBG_STATS_WAL_PDEV_TXRX: parse_htt_stats_wal_pdev_txrx(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_RX_REORDER: parse_htt_stats_rx_reorder(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_RX_RATE_INFO: parse_htt_stats_rx_rate_info(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TX_PPDU_LOG: parse_htt_stats_tx_ppdu_log(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TX_RATE_INFO: parse_htt_stats_tx_rate_info(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TIDQ: parse_htt_stats_tidq(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TXBF_INFO: parse_htt_stats_txbf_data_info(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_SND_INFO: parse_htt_stats_txbf_send_info(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TX_SELFGEN_INFO: parse_htt_stats_tx_selfgen(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TX_MU_INFO: parse_htt_stats_tx_mu(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_SIFS_RESP_INFO: parse_htt_stats_sifs_resp(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_RESET_INFO: parse_htt_stats_reset(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_MAC_WDOG_INFO: parse_htt_stats_mac_wdog(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TX_DESC_INFO: parse_htt_stats_tx_desc(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TX_FETCH_MGR_INFO: parse_htt_stats_tx_fetch_mgr(pevent, trace_seq, buf, tlv_length) elif tlv_type == HTT_DBG_STATS_TX_PFSCHED_INFO: parse_htt_stats_tx_pf_sched(pevent, trace_seq, buf, tlv_length) return True def parse_htt_stats_conf_msg(pevent, trace_seq, buf): # parse HTT_T2H_STATS_CONF_TLV l = 12 hdr = struct.unpack("> 16 while len(buf) > tlv_length+4: buf = buf[tlv_length:] l = 4 hdr = struct.unpack("> 16 if tlv_length == 0: continue if parse_one_htt_stats_conf_msg(pevent, trace_seq, buf, tlv, cookie) == False: break def ath10k_htt_stats_handler(pevent, trace_seq, event): buf_len = int(event['buf_len']) buf = event['buf'].data l = 4 hdr = struct.unpack("