From dcd073313e72a68ae4aa7c10d3ec10c9ad7c0584 Mon Sep 17 00:00:00 2001 From: Rakshith Suresh Patkar Date: Fri, 20 Apr 2018 12:52:08 +0530 Subject: [PATCH] qcacmn: ADD APIs to set/dump dp trace buffer Add APIs to dump dp trace buffer and set proto bitmap, number of records and verbosity of dp trace. Change-Id: I23cda36515e1f3299d6c1c28dee2489a89bb15d9 CRs-Fixed: 2180984 --- qdf/inc/qdf_trace.h | 68 +++++++ qdf/inc/qdf_types.h | 2 + qdf/linux/src/i_qdf_types.h | 3 + qdf/linux/src/qdf_trace.c | 348 ++++++++++++++++++++++++++++++++++++ 4 files changed, 421 insertions(+) diff --git a/qdf/inc/qdf_trace.h b/qdf/inc/qdf_trace.h index 9fe308ec7a..b0f74321f5 100644 --- a/qdf/inc/qdf_trace.h +++ b/qdf/inc/qdf_trace.h @@ -40,6 +40,8 @@ #include #include #include +#include + /* Type declarations */ @@ -381,6 +383,8 @@ struct s_qdf_dp_trace_data { bool enable; bool live_mode_config; bool live_mode; + uint32_t curr_pos; + uint32_t saved_tail; uint8_t print_pkt_cnt; uint8_t high_tput_thresh; uint16_t thresh_time_limit; @@ -410,6 +414,20 @@ struct s_qdf_dp_trace_data { u16 icmpv6_ra; }; +/** + * struct qdf_dpt_debugfs_state - state to control read to debugfs file + * @QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INVALID: invalid state + * @QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INIT: initial state + * @QDF_DPT_DEBUGFS_STATE_SHOW_IN_PROGRESS: read is in progress + * @QDF_DPT_DEBUGFS_STATE_SHOW_COMPLETE: read complete + */ + +enum qdf_dpt_debugfs_state { + QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INVALID, + QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INIT, + QDF_DPT_DEBUGFS_STATE_SHOW_IN_PROGRESS, + QDF_DPT_DEBUGFS_STATE_SHOW_COMPLETE, +}; /* Function declarations and documenation */ @@ -506,6 +524,37 @@ void qdf_dp_trace_set_track(qdf_nbuf_t nbuf, enum qdf_proto_dir dir); void qdf_dp_trace(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code, uint8_t pdev_id, uint8_t *data, uint8_t size, enum qdf_proto_dir dir); void qdf_dp_trace_dump_all(uint32_t count, uint8_t pdev_id); + +/** + * qdf_dpt_get_curr_pos_debugfs() - get curr position to start read + * @file: debugfs file to read + * @state: state to control read to debugfs file + * + * Return: curr pos + */ +uint32_t qdf_dpt_get_curr_pos_debugfs(qdf_debugfs_file_t file, + enum qdf_dpt_debugfs_state state); +/** + * qdf_dpt_dump_stats_debugfs() - dump DP Trace stats to debugfs file + * @file: debugfs file to read + * @curr_pos: curr position to start read + * + * Return: QDF_STATUS + */ +QDF_STATUS qdf_dpt_dump_stats_debugfs(qdf_debugfs_file_t file, + uint32_t curr_pos); + +/** + * qdf_dpt_set_value_debugfs() - dump DP Trace stats to debugfs file + * @file: debugfs file to read + * @curr_pos: curr position to start read + * + * Return: none + */ +void qdf_dpt_set_value_debugfs(uint8_t proto_bitmap, uint8_t no_of_record, + uint8_t verbosity); + + /** * qdf_dp_trace_dump_stats() - dump DP Trace stats * @@ -567,11 +616,30 @@ void qdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_records, uint8_t verbosity) { } + static inline void qdf_dp_trace_dump_all(uint32_t count, uint8_t pdev_id) { } +static inline +uint32_t qdf_dpt_get_curr_pos_debugfs(qdf_debugfs_file_t file, + enum qdf_dpt_debugfs_state state) +{ +} + +static inline +QDF_STATUS qdf_dpt_dump_stats_debugfs(qdf_debugfs_file_t file, + uint32_t curr_pos) +{ +} + +static inline +void qdf_dpt_set_value_debugfs(uint8_t proto_bitmap, uint8_t no_of_record, + uint8_t verbosity) +{ +} + static inline void qdf_dp_trace_dump_stats(void) { } diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h index 31cb46ade8..4507437e43 100644 --- a/qdf/inc/qdf_types.h +++ b/qdf/inc/qdf_types.h @@ -635,6 +635,8 @@ void qdf_vtrace_msg(QDF_MODULE_ID module, QDF_TRACE_LEVEL level, #define qdf_vprint __qdf_vprint #define qdf_snprint __qdf_snprint +#define qdf_kstrtoint __qdf_kstrtoint + #ifdef WLAN_OPEN_P2P_INTERFACE /* This should match with WLAN_MAX_INTERFACES */ #define QDF_MAX_CONCURRENCY_PERSONA (4) diff --git a/qdf/linux/src/i_qdf_types.h b/qdf/linux/src/i_qdf_types.h index 851c939bc8..395ddef41e 100644 --- a/qdf/linux/src/i_qdf_types.h +++ b/qdf/linux/src/i_qdf_types.h @@ -323,6 +323,9 @@ enum __qdf_net_wireless_evcode { #define __qdf_snprint snprintf #define __qdf_vsnprint vsnprintf #define __qdf_toupper toupper +#define qdf_kstrtoint __qdf_kstrtoint + +#define __qdf_kstrtoint kstrtoint #define __QDF_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL #define __QDF_DMA_TO_DEVICE DMA_TO_DEVICE diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c index f15a1a6b61..ee7d2a71ff 100644 --- a/qdf/linux/src/qdf_trace.c +++ b/qdf/linux/src/qdf_trace.c @@ -1957,6 +1957,354 @@ void qdf_dp_trace_dump_stats(void) g_qdf_dp_trace_data.eapol_m4, g_qdf_dp_trace_data.eapol_others); } +qdf_export_symbol(qdf_dp_trace_dump_stats); + +/** + * qdf_dpt_dump_hex_trace_debugfs() - read data in file + * @file: file to read + * @str: string to prepend the hexdump with. + * @buf: buffer which contains data to be written + * @buf_len: defines the size of the data to be written + * + * Return: None + */ +static void qdf_dpt_dump_hex_trace_debugfs(qdf_debugfs_file_t file, + char *str, uint8_t *buf, uint8_t buf_len) +{ + unsigned char linebuf[BUFFER_SIZE]; + const u8 *ptr = buf; + int i, linelen, remaining = buf_len; + + /* Dump the bytes in the last line */ + for (i = 0; i < buf_len; i += ROW_SIZE) { + linelen = min(remaining, ROW_SIZE); + remaining -= ROW_SIZE; + + hex_dump_to_buffer(ptr + i, linelen, ROW_SIZE, 1, + linebuf, sizeof(linebuf), false); + + qdf_debugfs_printf(file, "DPT: %s %s\n", + str, linebuf); + } +} + +/** + * qdf_dpt_display_proto_pkt_debugfs() - display proto packet + * @file: file to read + * @record: dptrace record + * @index: index + * + * Return: none + */ +static void qdf_dpt_display_proto_pkt_debugfs(qdf_debugfs_file_t file, + struct qdf_dp_trace_record_s *record, + uint32_t index) +{ + struct qdf_dp_trace_proto_buf *buf = + (struct qdf_dp_trace_proto_buf *)record->data; + + qdf_debugfs_printf(file, "DPT: %04d: %s [%d] [%s%s] SA: " + QDF_MAC_ADDR_STR " %s DA: " + QDF_MAC_ADDR_STR, + index, record->time, buf->vdev_id, + qdf_dp_code_to_string(record->code), + qdf_dp_subtype_to_str(buf->subtype), + QDF_MAC_ADDR_ARRAY(buf->sa.bytes), + qdf_dp_dir_to_str(buf->dir), + QDF_MAC_ADDR_ARRAY(buf->da.bytes)); + qdf_debugfs_printf(file, "\n"); +} + +/** + * qdf_dpt_display_mgmt_pkt_debugfs() - display mgmt packet + * @file: file to read + * @record: dptrace record + * @index: index + * + * Return: none + */ +static void qdf_dpt_display_mgmt_pkt_debugfs(qdf_debugfs_file_t file, + struct qdf_dp_trace_record_s *record, + uint32_t index) +{ + struct qdf_dp_trace_mgmt_buf *buf = + (struct qdf_dp_trace_mgmt_buf *)record->data; + + qdf_debugfs_printf(file, "DPT: %04d: %s [%d] [%s %s %s]\n", + index, record->time, buf->vdev_id, + qdf_dp_code_to_string(record->code), + qdf_dp_type_to_str(buf->type), + qdf_dp_subtype_to_str(buf->subtype)); +} + +/** + * qdf_dpt_display_event_record_debugfs() - display event records + * @file: file to read + * @record: dptrace record + * @index: index + * + * Return: none + */ +static void qdf_dpt_display_event_record_debugfs(qdf_debugfs_file_t file, + struct qdf_dp_trace_record_s *record, + uint32_t index) +{ + struct qdf_dp_trace_event_buf *buf = + (struct qdf_dp_trace_event_buf *)record->data; + + qdf_debugfs_printf(file, "DPT: %04d: %s [%d] [%s %s %s]\n", + index, record->time, buf->vdev_id, + qdf_dp_code_to_string(record->code), + qdf_dp_type_to_str(buf->type), + qdf_dp_subtype_to_str(buf->subtype)); +} + +/** + * qdf_dpt_display_ptr_record_debugfs() - display record ptr + * @file: file to read + * @record: dptrace record + * @index: index + * + * Return: none + */ +static void qdf_dpt_display_ptr_record_debugfs(qdf_debugfs_file_t file, + struct qdf_dp_trace_record_s *record, + uint32_t index) +{ + + char prepend_str[100] = {'\0'}; + struct qdf_dp_trace_ptr_buf *buf = + (struct qdf_dp_trace_ptr_buf *)record->data; + + snprintf(prepend_str, sizeof(prepend_str), + "%04d: %s [%s] [msdu id %d %s %d]", + index, + record->time, + qdf_dp_code_to_string(record->code), buf->msdu_id, + (record->code == QDF_DP_TRACE_FREE_PACKET_PTR_RECORD) ? + "status" : "vdev_id", + buf->status); + qdf_dpt_dump_hex_trace_debugfs(file, prepend_str, + (uint8_t *)&buf->cookie, + sizeof(buf->cookie)); +} + +/** + * qdf_dpt_display_ptr_record_debugfs() - display record + * @file: file to read + * @record: dptrace record + * @index: index + * + * Return: none + */ +static void qdf_dpt_display_record_debugfs(qdf_debugfs_file_t file, + struct qdf_dp_trace_record_s *record, + uint32_t index) +{ + + char prepend_str[50] = {'\0'}; + + snprintf(prepend_str, sizeof(prepend_str), + "%04d: %s %s", + index, + record->time, + qdf_dp_code_to_string(record->code)); + qdf_dpt_dump_hex_trace_debugfs(file, prepend_str, + record->data, record->size); +} + +uint32_t qdf_dpt_get_curr_pos_debugfs(qdf_debugfs_file_t file, + enum qdf_dpt_debugfs_state state) +{ + uint32_t i = 0; + uint32_t tail; + uint32_t count = g_qdf_dp_trace_data.num; + + if (!g_qdf_dp_trace_data.enable) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + "%s: Tracing Disabled", __func__); + return QDF_STATUS_E_EMPTY; + } + + if (!count) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + "%s: no packets", __func__); + return QDF_STATUS_E_EMPTY; + } + + if (state == QDF_DPT_DEBUGFS_STATE_SHOW_IN_PROGRESS) + return g_qdf_dp_trace_data.curr_pos; + + qdf_debugfs_printf(file, + "DPT: config - bitmap 0x%x verb %u #rec %u live_config %u thresh %u time_limit %u\n", + g_qdf_dp_trace_data.proto_bitmap, + g_qdf_dp_trace_data.verbosity, + g_qdf_dp_trace_data.no_of_record, + g_qdf_dp_trace_data.live_mode_config, + g_qdf_dp_trace_data.high_tput_thresh, + g_qdf_dp_trace_data.thresh_time_limit); + + qdf_debugfs_printf(file, + "STATS |DPT: icmp(%u %u) arp(%u %u) icmpv6(%u %u %u %u %u %u) dhcp(%u %u %u %u %u %u) eapol(%u %u %u %u %u)\n", + g_qdf_dp_trace_data.icmp_req, + g_qdf_dp_trace_data.icmp_resp, + g_qdf_dp_trace_data.arp_req, + g_qdf_dp_trace_data.arp_resp, + g_qdf_dp_trace_data.icmpv6_req, + g_qdf_dp_trace_data.icmpv6_resp, + g_qdf_dp_trace_data.icmpv6_ns, + g_qdf_dp_trace_data.icmpv6_na, + g_qdf_dp_trace_data.icmpv6_rs, + g_qdf_dp_trace_data.icmpv6_ra, + g_qdf_dp_trace_data.dhcp_disc, + g_qdf_dp_trace_data.dhcp_off, + g_qdf_dp_trace_data.dhcp_req, + g_qdf_dp_trace_data.dhcp_ack, + g_qdf_dp_trace_data.dhcp_nack, + g_qdf_dp_trace_data.dhcp_others, + g_qdf_dp_trace_data.eapol_m1, + g_qdf_dp_trace_data.eapol_m2, + g_qdf_dp_trace_data.eapol_m3, + g_qdf_dp_trace_data.eapol_m4, + g_qdf_dp_trace_data.eapol_others); + + qdf_debugfs_printf(file, + "DPT: Total Records: %d, Head: %d, Tail: %d\n", + g_qdf_dp_trace_data.num, g_qdf_dp_trace_data.head, + g_qdf_dp_trace_data.tail); + + spin_lock_bh(&l_dp_trace_lock); + if (g_qdf_dp_trace_data.head != INVALID_QDF_DP_TRACE_ADDR) { + i = g_qdf_dp_trace_data.head; + tail = g_qdf_dp_trace_data.tail; + + if (count > g_qdf_dp_trace_data.num) + count = g_qdf_dp_trace_data.num; + + if (tail >= (count - 1)) + i = tail - count + 1; + else if (count != MAX_QDF_DP_TRACE_RECORDS) + i = MAX_QDF_DP_TRACE_RECORDS - ((count - 1) - + tail); + g_qdf_dp_trace_data.curr_pos = 0; + g_qdf_dp_trace_data.saved_tail = tail; + } + spin_unlock_bh(&l_dp_trace_lock); + return i; +} +qdf_export_symbol(qdf_dpt_get_curr_pos_debugfs); + +QDF_STATUS qdf_dpt_dump_stats_debugfs(qdf_debugfs_file_t file, + uint32_t curr_pos) +{ + struct qdf_dp_trace_record_s p_record; + uint32_t i = curr_pos; + uint32_t tail = g_qdf_dp_trace_data.saved_tail; + + spin_lock_bh(&l_dp_trace_lock); + + p_record = g_qdf_dp_trace_tbl[i]; + spin_unlock_bh(&l_dp_trace_lock); + for (;; ) { + if ((file->size - file->count) < 100) { + spin_lock_bh(&l_dp_trace_lock); + g_qdf_dp_trace_data.curr_pos = i; + spin_unlock_bh(&l_dp_trace_lock); + return QDF_STATUS_E_FAILURE; + } + + switch (p_record.code) { + case QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD: + case QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD: + case QDF_DP_TRACE_FREE_PACKET_PTR_RECORD: + qdf_dpt_display_ptr_record_debugfs(file, &p_record, i); + break; + + case QDF_DP_TRACE_EAPOL_PACKET_RECORD: + case QDF_DP_TRACE_DHCP_PACKET_RECORD: + case QDF_DP_TRACE_ARP_PACKET_RECORD: + case QDF_DP_TRACE_ICMP_PACKET_RECORD: + case QDF_DP_TRACE_ICMPv6_PACKET_RECORD: + qdf_dpt_display_proto_pkt_debugfs(file, &p_record, i); + break; + + case QDF_DP_TRACE_MGMT_PACKET_RECORD: + qdf_dpt_display_mgmt_pkt_debugfs(file, &p_record, i); + break; + + case QDF_DP_TRACE_EVENT_RECORD: + qdf_dpt_display_event_record_debugfs(file, &p_record, + i); + break; + + case QDF_DP_TRACE_HDD_TX_TIMEOUT: + qdf_debugfs_printf(file, "DPT: %04d: %s %s\n", + i, p_record.time, + qdf_dp_code_to_string(p_record.code)); + qdf_debugfs_printf(file, "%s: HDD TX Timeout\n"); + break; + + case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: + qdf_debugfs_printf(file, "%04d: %s %s\n", + i, p_record.time, + qdf_dp_code_to_string(p_record.code)); + qdf_debugfs_printf(file, + "%s: HDD SoftAP TX Timeout\n"); + break; + + case QDF_DP_TRACE_CE_FAST_PACKET_ERR_RECORD: + qdf_debugfs_printf(file, "DPT: %04d: %s %s\n", + i, p_record.time, + qdf_dp_code_to_string(p_record.code)); + qdf_debugfs_printf(file, + "%s: CE Fast Packet Error\n"); + break; + + case QDF_DP_TRACE_MAX: + qdf_debugfs_printf(file, + "%s: QDF_DP_TRACE_MAX event should not be generated\n", + __func__); + break; + + case QDF_DP_TRACE_HDD_TX_PACKET_RECORD: + case QDF_DP_TRACE_HDD_RX_PACKET_RECORD: + default: + qdf_dpt_display_record_debugfs(file, &p_record, i); + break; + } + + if (i == tail) + break; + i += 1; + + spin_lock_bh(&l_dp_trace_lock); + if (i == MAX_QDF_DP_TRACE_RECORDS) + i = 0; + + p_record = g_qdf_dp_trace_tbl[i]; + spin_unlock_bh(&l_dp_trace_lock); + } + return QDF_STATUS_SUCCESS; +} +qdf_export_symbol(qdf_dpt_dump_stats_debugfs); + +/** + * qdf_dpt_set_value_debugfs() - Configure the value to control DP trace + * @proto_bitmap: defines the protocol to be tracked + * @no_of_records: defines the nth packet which is traced + * @verbosity: defines the verbosity level + * + * Return: None + */ +void qdf_dpt_set_value_debugfs(uint8_t proto_bitmap, uint8_t no_of_record, + uint8_t verbosity) +{ + g_qdf_dp_trace_data.proto_bitmap = proto_bitmap; + g_qdf_dp_trace_data.no_of_record = no_of_record; + g_qdf_dp_trace_data.verbosity = verbosity; +} +qdf_export_symbol(qdf_dpt_set_value_debugfs); + /** * qdf_dp_trace_dump_all() - Dump data from ring buffer via call back functions