diff --git a/qdf/inc/qdf_trace.h b/qdf/inc/qdf_trace.h index 0546cc241c..530e7abfa8 100644 --- a/qdf/inc/qdf_trace.h +++ b/qdf/inc/qdf_trace.h @@ -99,9 +99,18 @@ void qdf_trace(uint8_t module, uint8_t code, uint16_t session, uint32_t data); #define INVALID_QDF_TRACE_ADDR 0xffffffff #define DEFAULT_QDF_TRACE_DUMP_COUNT 0 -#define DUMP_DP_TRACE 0 +/* + * first parameter to iwpriv command - dump_dp_trace + * iwpriv wlan0 dump_dp_trace 0 0 -> dump full buffer + * iwpriv wlan0 dump_dp_trace 1 0 -> enable live view mode + * iwpriv wlan0 dump_dp_trace 2 0 -> clear dp trace buffer + * iwpriv wlan0 dump_dp_trace 3 0 -> disable live view mode + */ +#define DUMP_DP_TRACE 0 #define ENABLE_DP_TRACE_LIVE_MODE 1 -#define CLEAR_DP_TRACE_BUFFER 2 +#define CLEAR_DP_TRACE_BUFFER 2 +#define DISABLE_DP_TRACE_LIVE_MODE 3 + #ifdef TRACE_RECORD @@ -160,7 +169,7 @@ typedef struct s_qdf_trace_data { #define QDF_DP_TRACE_VERBOSITY_HIGH 3 #define QDF_DP_TRACE_VERBOSITY_MEDIUM 2 #define QDF_DP_TRACE_VERBOSITY_LOW 1 -#define QDF_DP_TRACE_VERBOSITY_DEFAULT 0 +#define QDF_DP_TRACE_VERBOSITY_BASE 0 /** * enum QDF_DP_TRACE_ID - Generic ID to identify various events in data path @@ -170,21 +179,24 @@ typedef struct s_qdf_trace_data { * @QDF_DP_TRACE_DHCP_PACKET_RECORD - record DHCP packet * @QDF_DP_TRACE_ARP_PACKET_RECORD - record ARP packet * @QDF_DP_TRACE_MGMT_PACKET_RECORD - record MGMT pacekt - * @QDF_DP_TRACE_ICMP_PACKET_RECORD - record ICMP packet * QDF_DP_TRACE_EVENT_RECORD - record events - * @QDF_DP_TRACE_DEFAULT_VERBOSITY - below this are part of default verbosity + * @QDF_DP_TRACE_BASE_VERBOSITY - below this are part of base verbosity + * @QDF_DP_TRACE_ICMP_PACKET_RECORD - record ICMP packets + * @QDF_DP_TRACE_HDD_TX_PACKET_RECORD - record 32 bytes of tx pkt at HDD + * @QDF_DP_TRACE_HDD_RX_PACKET_RECORD - record 32 bytes of rx pkt at HDD * @QDF_DP_TRACE_HDD_TX_TIMEOUT - HDD tx timeout * @QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT- SOFTAP HDD tx timeout + * @QDF_DP_TRACE_FREE_PACKET_PTR_RECORD - tx completion ptr record + * @QDF_DP_TRACE_LOW_VERBOSITY - below this are part of low verbosity * @QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD - HDD layer ptr record * @QDF_DP_TRACE_LI_DP_TX_PACKET_PTR_RECORD - Lithium DP layer ptr record * @QDF_DP_TRACE_CE_PACKET_PTR_RECORD - CE layer ptr record * @QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD- CE fastpath ptr record - * @QDF_DP_TRACE_FREE_PACKET_PTR_RECORD - tx completion ptr record * @QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD - HTT RX record * @QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD- HTT RX offload record * @QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD - HDD RX record * @QDF_DP_TRACE_RX_LI_DP_PACKET_PTR_RECORD - Lithium DP RX record - * @QDF_DP_TRACE_LOW_VERBOSITY - below this are part of low verbosity + * @QDF_DP_TRACE_MED_VERBOSITY - below this are part of med verbosity * @QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD -tx queue ptr record * @QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD - txrx packet ptr record * @QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD - txrx fast path record @@ -192,9 +204,6 @@ typedef struct s_qdf_trace_data { * @QDF_DP_TRACE_HTC_PACKET_PTR_RECORD - htc packet ptr record * @QDF_DP_TRACE_HIF_PACKET_PTR_RECORD - hif packet ptr record * @QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD - txrx packet ptr record - * @QDF_DP_TRACE_MED_VERBOSITY - below this are part of med verbosity - * @QDF_DP_TRACE_HDD_TX_PACKET_RECORD - record 32 bytes of tx pkt at HDD - * @QDF_DP_TRACE_HDD_RX_PACKET_RECORD - record 32 bytes of rx pkt at HDD * @QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD - record 32 bytes of tx pkt at LI_DP * @QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD - record 32 bytes of rx pkt at LI_DP * @QDF_DP_TRACE_LI_DP_NULL_RX_PACKET_RECORD @@ -208,21 +217,24 @@ enum QDF_DP_TRACE_ID { QDF_DP_TRACE_DHCP_PACKET_RECORD, QDF_DP_TRACE_ARP_PACKET_RECORD, QDF_DP_TRACE_MGMT_PACKET_RECORD, - QDF_DP_TRACE_ICMP_PACKET_RECORD, QDF_DP_TRACE_EVENT_RECORD, - QDF_DP_TRACE_DEFAULT_VERBOSITY, + QDF_DP_TRACE_BASE_VERBOSITY, + QDF_DP_TRACE_ICMP_PACKET_RECORD, + QDF_DP_TRACE_HDD_TX_PACKET_RECORD, + QDF_DP_TRACE_HDD_RX_PACKET_RECORD, QDF_DP_TRACE_HDD_TX_TIMEOUT, QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT, + QDF_DP_TRACE_FREE_PACKET_PTR_RECORD, + QDF_DP_TRACE_LOW_VERBOSITY, QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD, QDF_DP_TRACE_LI_DP_TX_PACKET_PTR_RECORD, + QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD, QDF_DP_TRACE_CE_PACKET_PTR_RECORD, QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD, - QDF_DP_TRACE_FREE_PACKET_PTR_RECORD, QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD, QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD, - QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD, QDF_DP_TRACE_RX_LI_DP_PACKET_PTR_RECORD, - QDF_DP_TRACE_LOW_VERBOSITY, + QDF_DP_TRACE_MED_VERBOSITY, QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD, QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD, QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD, @@ -230,9 +242,6 @@ enum QDF_DP_TRACE_ID { QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, QDF_DP_TRACE_HIF_PACKET_PTR_RECORD, QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD, - QDF_DP_TRACE_MED_VERBOSITY, - QDF_DP_TRACE_HDD_TX_PACKET_RECORD, - QDF_DP_TRACE_HDD_RX_PACKET_RECORD, QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD, QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD, QDF_DP_TRACE_LI_DP_NULL_RX_PACKET_RECORD, @@ -333,6 +342,17 @@ struct qdf_dp_trace_record_s { * @verbosity : defines verbosity level * @enable: enable/disable DP trace * @count: current packet number + * @live_mode_config: configuration as received during initialization + * @live_mode: current live mode, enabled or disabled. + * @print_pkt_cnt: count of number of packets printed in live mode + *.@high_tput_thresh: thresh beyond which live mode is turned off + *.@thresh_time_limit: max time, in terms of BW timer intervals to wait, + * for determining if high_tput_thresh has been crossed. ~1s + *.@arp_req: stats for arp reqs + *.@arp_resp: stats for arp resps + *.@icmp_req: stats for icmp reqs + *.@icmp_req: stats for icmp resps + */ struct s_qdf_dp_trace_data { uint32_t head; @@ -342,9 +362,18 @@ struct s_qdf_dp_trace_data { uint8_t no_of_record; uint8_t verbosity; bool enable; + bool live_mode_config; + bool live_mode; + uint8_t print_pkt_cnt; + uint8_t high_tput_thresh; + uint16_t thresh_time_limit; + /* Stats */ uint32_t tx_count; uint32_t rx_count; - bool live_mode; + uint32_t arp_req; + uint32_t arp_resp; + uint32_t icmp_req; + uint32_t icmp_resp; }; @@ -401,9 +430,11 @@ void qdf_trace_dump_all(void *, uint8_t, uint8_t, uint32_t, uint32_t); void qdf_dp_set_proto_bitmap(uint32_t val); void qdf_dp_trace_set_verbosity(uint32_t val); void qdf_dp_set_no_of_record(uint32_t val); -void qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, +bool qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, enum qdf_proto_dir dir, uint8_t pdev_id); -void qdf_dp_trace_init(void); +void qdf_dp_trace_init(bool live_mode_config, uint8_t thresh, + uint16_t time_limit, uint8_t verbosity, + uint8_t proto_bitmap); void qdf_dp_trace_spin_lock_init(void); void qdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_records, uint8_t verbosity); @@ -412,15 +443,17 @@ 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); typedef void (*tp_qdf_dp_trace_cb)(struct qdf_dp_trace_record_s*, - uint16_t, uint8_t); + uint16_t, uint8_t, bool live); void qdf_dp_display_record(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id); + uint16_t index, uint8_t pdev_id, bool live); void qdf_dp_trace_ptr(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code, uint8_t pdev_id, uint8_t *data, uint8_t size, uint16_t msdu_id, uint16_t status); - +void qdf_dp_trace_throttle_live_mode(bool high_bw_request); void qdf_dp_display_ptr_record(struct qdf_dp_trace_record_s *pRecord, - uint16_t recIndex, uint8_t pdev_id); + uint16_t recIndex, uint8_t pdev_id, bool live); +void qdf_dp_display_proto_pkt(struct qdf_dp_trace_record_s *record, + uint16_t index, uint8_t pdev_id, bool live); uint8_t qdf_dp_get_proto_bitmap(void); uint8_t qdf_dp_get_verbosity(void); uint8_t qdf_dp_get_no_of_record(void); @@ -428,29 +461,31 @@ void qdf_dp_trace_proto_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, uint8_t *sa, uint8_t *da, enum qdf_proto_type type, enum qdf_proto_subtype subtype, enum qdf_proto_dir dir, - uint8_t pdev_id); -void qdf_dp_display_proto_pkt(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id); + uint8_t pdev_id, bool print); +void qdf_dp_trace_disable_live_mode(void); void qdf_dp_trace_enable_live_mode(void); void qdf_dp_trace_clear_buffer(void); void qdf_dp_trace_mgmt_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, uint8_t pdev_id, enum qdf_proto_type type, enum qdf_proto_subtype subtype); void qdf_dp_display_mgmt_pkt(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id); + uint16_t index, uint8_t pdev_id, bool live); void qdf_dp_display_event_record(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id); + uint16_t index, uint8_t pdev_id, bool live); void qdf_dp_trace_record_event(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, uint8_t pdev_id, enum qdf_proto_type type, enum qdf_proto_subtype subtype); #else static inline -void qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, +bool qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, enum qdf_proto_dir dir, uint8_t pdev_id) { + return false; } static inline -void qdf_dp_trace_init(void) +void qdf_dp_trace_init(bool live_mode_config, uint8_t thresh, + uint16_t time_limit, uint8_t verbosity, + uint8_t proto_bitmap) { } static inline @@ -467,11 +502,21 @@ void qdf_dp_trace_dump_all(uint32_t count, uint8_t pdev_id) { } +static inline +void qdf_dp_trace_disable_live_mode(void) +{ +} + static inline void qdf_dp_trace_enable_live_mode(void) { } +static inline +void qdf_dp_trace_throttle_live_mode(bool high_bw_request) +{ +} + static inline void qdf_dp_trace_clear_buffer(void) { diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c index 8cdc6edd98..6d0d595803 100644 --- a/qdf/linux/src/qdf_trace.c +++ b/qdf/linux/src/qdf_trace.c @@ -125,7 +125,7 @@ static struct s_qdf_dp_trace_data g_qdf_dp_trace_data; * all the call back functions for dumping DPTRACE messages from ring buffer * are stored in qdf_dp_trace_cb_table, callbacks are initialized during init */ -static tp_qdf_dp_trace_cb qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX+1]; +static tp_qdf_dp_trace_cb qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX + 1]; #endif /** @@ -592,7 +592,7 @@ void qdf_trace_dump_all(void *p_mac, uint8_t code, uint8_t session, } QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO, - "Total Records: %d, Head: %d, Tail: %d", + "DPT: Total Records: %d, Head: %d, Tail: %d", g_qdf_trace_data.num, g_qdf_trace_data.head, g_qdf_trace_data.tail); @@ -728,7 +728,7 @@ EXPORT_SYMBOL(qdf_state_info_dump_all); #ifdef CONFIG_DP_TRACE static void qdf_dp_unused(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id) + uint16_t index, uint8_t pdev_id, bool live) { qdf_print("%s: QDF_DP_TRACE_MAX event should not be generated", __func__); @@ -736,16 +736,39 @@ static void qdf_dp_unused(struct qdf_dp_trace_record_s *record, /** * qdf_dp_trace_init() - enables the DP trace - * Called during driver load and it enables DP trace + * @live_mode_config: live mode configuration + * @thresh: high throughput threshold for disabling live mode + * @thresh_time_limit: max time to wait before deciding if thresh is crossed + * @verbosity: dptrace verbosity level + * @proto_bitmap: bitmap to enable/disable specific protocols * + * Called during driver load to init dptrace + * + * A brief note on the 'thresh' param - + * Total # of packets received in a bandwidth timer interval beyond which + * DP Trace logging for data packets (including ICMP) will be disabled. + * In memory logging will still continue for these packets. Other packets for + * which proto.bitmap is set will continue to be recorded in logs and in memory. + * Return: None */ -void qdf_dp_trace_init(void) +void qdf_dp_trace_init(bool live_mode_config, uint8_t thresh, + uint16_t time_limit, uint8_t verbosity, + uint8_t proto_bitmap) { uint8_t i; qdf_dp_trace_spin_lock_init(); qdf_dp_trace_clear_buffer(); + g_qdf_dp_trace_data.enable = true; + g_qdf_dp_trace_data.no_of_record = 1; + + g_qdf_dp_trace_data.live_mode_config = live_mode_config; + g_qdf_dp_trace_data.live_mode = live_mode_config; + g_qdf_dp_trace_data.high_tput_thresh = thresh; + g_qdf_dp_trace_data.thresh_time_limit = time_limit; + g_qdf_dp_trace_data.proto_bitmap = proto_bitmap; + g_qdf_dp_trace_data.verbosity = verbosity; for (i = 0; i < ARRAY_SIZE(qdf_dp_trace_cb_table); i++) qdf_dp_trace_cb_table[i] = qdf_dp_display_record; @@ -871,8 +894,8 @@ static bool qdf_dp_trace_enable_track(enum QDF_DP_TRACE_ID code) if (code <= QDF_DP_TRACE_LOW_VERBOSITY) return true; return false; - case QDF_DP_TRACE_VERBOSITY_DEFAULT: - if (code <= QDF_DP_TRACE_DEFAULT_VERBOSITY) + case QDF_DP_TRACE_VERBOSITY_BASE: + if (code <= QDF_DP_TRACE_BASE_VERBOSITY) return true; return false; default: @@ -905,6 +928,9 @@ void qdf_dp_trace_set_track(qdf_nbuf_t nbuf, enum qdf_proto_dir dir) { uint32_t count = 0; + if (!g_qdf_dp_trace_data.enable) + return; + spin_lock_bh(&l_dp_trace_lock); if (QDF_TX == dir) count = ++g_qdf_dp_trace_data.tx_count; @@ -933,7 +959,7 @@ EXPORT_SYMBOL(qdf_dp_trace_set_track); * * Return: None */ -static void dump_hex_trace(char *str, uint8_t *buf, uint8_t buf_len) +static void dump_dp_hex_trace(char *str, uint8_t *buf, uint8_t buf_len) { unsigned char linebuf[BUFFER_SIZE]; const u8 *ptr = buf; @@ -947,7 +973,7 @@ static void dump_hex_trace(char *str, uint8_t *buf, uint8_t buf_len) hex_dump_to_buffer(ptr + i, linelen, ROW_SIZE, 1, linebuf, sizeof(linebuf), false); - DPTRACE_PRINT("DPT: %s: %s", str, linebuf); + DPTRACE_PRINT("DPT: %s %s", str, linebuf); } } @@ -1088,27 +1114,27 @@ static const char *qdf_dp_subtype_to_str(enum qdf_proto_subtype subtype) case QDF_PROTO_EAPOL_M4: return "M4"; case QDF_PROTO_DHCP_DISCOVER: - return "DISCOVER"; + return "DISC"; case QDF_PROTO_DHCP_REQUEST: - return "REQUEST"; + return "REQ"; case QDF_PROTO_DHCP_OFFER: - return "OFFER"; + return "OFF"; case QDF_PROTO_DHCP_ACK: return "ACK"; case QDF_PROTO_DHCP_NACK: return "NACK"; case QDF_PROTO_DHCP_RELEASE: - return "RELEASE"; + return "REL"; case QDF_PROTO_DHCP_INFORM: return "INFORM"; case QDF_PROTO_DHCP_DECLINE: - return "DECLINE"; + return "DECL"; case QDF_PROTO_ARP_REQ: case QDF_PROTO_ICMP_REQ: - return "REQUEST"; + return "REQ"; case QDF_PROTO_ARP_RES: case QDF_PROTO_ICMP_RES: - return "RESPONSE"; + return "RSP"; case QDF_PROTO_MGMT_ASSOC: return "ASSOC"; case QDF_PROTO_MGMT_DISASSOC: @@ -1120,7 +1146,7 @@ static const char *qdf_dp_subtype_to_str(enum qdf_proto_subtype subtype) case QDF_ROAM_SYNCH: return "ROAM SYNCH"; case QDF_ROAM_COMPLETE: - return "ROAM COMPLETE"; + return "ROAM COMP"; case QDF_ROAM_EVENTID: return "ROAM EVENTID"; default: @@ -1213,13 +1239,76 @@ static void qdf_dp_add_record(enum QDF_DP_TRACE_ID code, uint8_t *data, rec->pid = (in_interrupt() ? 0 : current->pid); spin_unlock_bh(&l_dp_trace_lock); - if ((g_qdf_dp_trace_data.live_mode || (print == true)) && - (rec->code < QDF_DP_TRACE_MAX)) + + if (rec->code >= QDF_DP_TRACE_MAX) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "invalid record code %u, max code %u", rec->code, + QDF_DP_TRACE_MAX); + return; + } + + if (print == true) { qdf_dp_trace_cb_table[rec->code] (rec, index, - QDF_TRACE_DEFAULT_PDEV_ID); + QDF_TRACE_DEFAULT_PDEV_ID, true); + return; + } + + if (g_qdf_dp_trace_data.live_mode_config) { + spin_lock_bh(&l_dp_trace_lock); + g_qdf_dp_trace_data.print_pkt_cnt++; + if ((g_qdf_dp_trace_data.live_mode == 1) && + (g_qdf_dp_trace_data.print_pkt_cnt > + g_qdf_dp_trace_data.high_tput_thresh)) + g_qdf_dp_trace_data.live_mode = 0; + spin_unlock_bh(&l_dp_trace_lock); + } + + if (g_qdf_dp_trace_data.live_mode == true) { + qdf_dp_trace_cb_table[rec->code] (rec, index, + QDF_TRACE_DEFAULT_PDEV_ID, true); + return; + } } +/** + * qdf_log_icmp_pkt() - log ICMP packet + * @session_id: vdev_id + * @skb: skb pointer + * @dir: direction + * + * Return: true/false + */ +static bool qdf_log_icmp_pkt(uint8_t session_id, struct sk_buff *skb, + enum qdf_proto_dir dir, uint8_t pdev_id) +{ + enum qdf_proto_subtype proto_subtype; + + if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ICMP) && + (qdf_nbuf_is_icmp_pkt(skb) == true)) { + + proto_subtype = qdf_nbuf_get_icmp_subtype(skb); + DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ICMP_PACKET_RECORD, + session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET), + (skb->data + QDF_NBUF_DEST_MAC_OFFSET), + QDF_PROTO_TYPE_ICMP, proto_subtype, dir, pdev_id, false)); + if (QDF_TX == dir) + QDF_NBUF_CB_TX_DP_TRACE(skb) = 1; + else if (QDF_RX == dir) + QDF_NBUF_CB_RX_DP_TRACE(skb) = 1; + + QDF_NBUF_CB_DP_TRACE_PRINT(skb) = false; + + if (proto_subtype == QDF_PROTO_ICMP_REQ) + g_qdf_dp_trace_data.icmp_req++; + else + g_qdf_dp_trace_data.icmp_resp++; + + return true; + } + return false; +} + /** * qdf_log_eapol_pkt() - log EAPOL packet * @session_id: vdev_id @@ -1243,7 +1332,7 @@ static bool qdf_log_eapol_pkt(uint8_t session_id, struct sk_buff *skb, DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_EAPOL_PACKET_RECORD, session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET), (skb->data + QDF_NBUF_DEST_MAC_OFFSET), - QDF_PROTO_TYPE_EAPOL, subtype, dir, pdev_id)); + QDF_PROTO_TYPE_EAPOL, subtype, dir, pdev_id, true)); if (QDF_TX == dir) QDF_NBUF_CB_TX_DP_TRACE(skb) = 1; else if (QDF_RX == dir) @@ -1278,7 +1367,8 @@ static bool qdf_log_dhcp_pkt(uint8_t session_id, struct sk_buff *skb, DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_DHCP_PACKET_RECORD, session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET), (skb->data + QDF_NBUF_DEST_MAC_OFFSET), - QDF_PROTO_TYPE_DHCP, subtype, dir, pdev_id)); + QDF_PROTO_TYPE_DHCP, subtype, dir, pdev_id, true)); + if (QDF_TX == dir) QDF_NBUF_CB_TX_DP_TRACE(skb) = 1; else if (QDF_RX == dir) @@ -1313,51 +1403,24 @@ static bool qdf_log_arp_pkt(uint8_t session_id, struct sk_buff *skb, DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ARP_PACKET_RECORD, session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET), (skb->data + QDF_NBUF_DEST_MAC_OFFSET), - QDF_PROTO_TYPE_ARP, proto_subtype, dir, pdev_id)); + QDF_PROTO_TYPE_ARP, proto_subtype, dir, pdev_id, true)); if (QDF_TX == dir) QDF_NBUF_CB_TX_DP_TRACE(skb) = 1; else if (QDF_RX == dir) QDF_NBUF_CB_RX_DP_TRACE(skb) = 1; QDF_NBUF_CB_DP_TRACE_PRINT(skb) = true; + + if (QDF_PROTO_ARP_REQ == proto_subtype) + g_qdf_dp_trace_data.arp_req++; + else + g_qdf_dp_trace_data.arp_resp++; + return true; } return false; } -/** - * qdf_log_icmp_pkt() - log ICMP packet - * @session_id: vdev_id - * @skb: skb pointer - * @dir: direction - * - * Return: true/false - */ -static bool qdf_log_icmp_pkt(uint8_t session_id, struct sk_buff *skb, - enum qdf_proto_dir dir, uint8_t pdev_id) -{ - enum qdf_proto_subtype proto_subtype; - - if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ICMP) && - (qdf_nbuf_is_icmp_pkt(skb) == true)) { - - proto_subtype = qdf_nbuf_get_icmp_subtype(skb); - DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ICMP_PACKET_RECORD, - session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET), - (skb->data + QDF_NBUF_DEST_MAC_OFFSET), - QDF_PROTO_TYPE_ICMP, proto_subtype, dir, pdev_id)); - if (QDF_TX == dir) - QDF_NBUF_CB_TX_DP_TRACE(skb) = 1; - else if (QDF_RX == dir) - QDF_NBUF_CB_RX_DP_TRACE(skb) = 1; - - QDF_NBUF_CB_DP_TRACE_PRINT(skb) = true; - return true; - } - - return false; -} - /** * qdf_dp_trace_log_pkt() - log packet type enabled through iwpriv @@ -1366,22 +1429,22 @@ static bool qdf_log_icmp_pkt(uint8_t session_id, struct sk_buff *skb, * @dir: direction * @pdev_id: pdev_id * - * Return: none + * Return: true: some protocol was logged, false: no protocol was logged. */ -void qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, +bool qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, enum qdf_proto_dir dir, uint8_t pdev_id) { if (!qdf_dp_get_proto_bitmap()) - return; + return false; if (qdf_log_arp_pkt(session_id, skb, dir, pdev_id)) - return; + return true; if (qdf_log_dhcp_pkt(session_id, skb, dir, pdev_id)) - return; + return true; if (qdf_log_eapol_pkt(session_id, skb, dir, pdev_id)) - return; + return true; if (qdf_log_icmp_pkt(session_id, skb, dir, pdev_id)) - return; - + return true; + return false; } EXPORT_SYMBOL(qdf_dp_trace_log_pkt); @@ -1389,19 +1452,22 @@ EXPORT_SYMBOL(qdf_dp_trace_log_pkt); * qdf_dp_display_mgmt_pkt() - display proto packet * @record: dptrace record * @index: index + * @live : live mode or dump mode * * Return: none */ void qdf_dp_display_mgmt_pkt(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id) + uint16_t index, uint8_t pdev_id, bool live) { struct qdf_dp_trace_mgmt_buf *buf = (struct qdf_dp_trace_mgmt_buf *)record->data; - DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d", index, - record->time, qdf_dp_code_to_string(record->code), - buf->vdev_id); - DPTRACE_PRINT("DPT: Type %s Subtype %s", qdf_dp_type_to_str(buf->type), + DPTRACE_PRINT("DPT: %04d: %s [%d] [%s %s %s]", + index, + (live == true) ? " " : 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)); } EXPORT_SYMBOL(qdf_dp_display_mgmt_pkt); @@ -1440,19 +1506,22 @@ EXPORT_SYMBOL(qdf_dp_trace_mgmt_pkt); * qdf_dp_display_event_record() - display event records * @record: dptrace record * @index: index + * @live : live mode or dump mode * * Return: none */ void qdf_dp_display_event_record(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id) + uint16_t index, uint8_t pdev_id, bool live) { struct qdf_dp_trace_event_buf *buf = (struct qdf_dp_trace_event_buf *)record->data; - DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d", index, - record->time, qdf_dp_code_to_string(record->code), - buf->vdev_id); - DPTRACE_PRINT("DPT: Type %s Subtype %s", qdf_dp_type_to_str(buf->type), + DPTRACE_PRINT("DPT: %04d: %s [%d] [%s %s %s]", + index, + (live == true) ? "" : 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)); } EXPORT_SYMBOL(qdf_dp_display_event_record); @@ -1491,24 +1560,26 @@ EXPORT_SYMBOL(qdf_dp_trace_record_event); * qdf_dp_display_proto_pkt() - display proto packet * @record: dptrace record * @index: index + * @live : live mode or dump mode * * Return: none */ void qdf_dp_display_proto_pkt(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id) + uint16_t index, uint8_t pdev_id, bool live) { struct qdf_dp_trace_proto_buf *buf = (struct qdf_dp_trace_proto_buf *)record->data; - DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d", index, - record->time, qdf_dp_code_to_string(record->code), - buf->vdev_id); - DPTRACE_PRINT("DPT: SA: " QDF_MAC_ADDRESS_STR " %s DA: " - QDF_MAC_ADDRESS_STR " Type %s Subtype %s", - QDF_MAC_ADDR_ARRAY(buf->sa.bytes), qdf_dp_dir_to_str(buf->dir), - QDF_MAC_ADDR_ARRAY(buf->da.bytes), - qdf_dp_type_to_str(buf->type), - qdf_dp_subtype_to_str(buf->subtype)); + DPTRACE_PRINT("DPT: %04d: %s [%d] [%s%s] SA: " + QDF_MAC_ADDRESS_STR " %s DA: " + QDF_MAC_ADDRESS_STR, + index, + (live == true) ? "" : 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)); } EXPORT_SYMBOL(qdf_dp_display_proto_pkt); @@ -1522,13 +1593,14 @@ EXPORT_SYMBOL(qdf_dp_display_proto_pkt); * @subtype: proto subtype * @dir: direction * @pdev_id: pdev id + * @print: to print this proto pkt or not * * Return: none */ void qdf_dp_trace_proto_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, uint8_t *sa, uint8_t *da, enum qdf_proto_type type, enum qdf_proto_subtype subtype, enum qdf_proto_dir dir, - uint8_t pdev_id) + uint8_t pdev_id, bool print) { struct qdf_dp_trace_proto_buf buf; int buf_size = sizeof(struct qdf_dp_trace_ptr_buf); @@ -1545,7 +1617,7 @@ void qdf_dp_trace_proto_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, buf.type = type; buf.subtype = subtype; buf.vdev_id = vdev_id; - qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, pdev_id, true); + qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, pdev_id, print); } EXPORT_SYMBOL(qdf_dp_trace_proto_pkt); @@ -1553,26 +1625,33 @@ EXPORT_SYMBOL(qdf_dp_trace_proto_pkt); * qdf_dp_display_ptr_record() - display record * @record: dptrace record * @index: index + * @live : live mode or dump mode * * Return: none */ void qdf_dp_display_ptr_record(struct qdf_dp_trace_record_s *record, - uint16_t index, uint8_t pdev_id) + uint16_t index, uint8_t pdev_id, bool live) { + char prepend_str[100] = {'\0'}; struct qdf_dp_trace_ptr_buf *buf = (struct qdf_dp_trace_ptr_buf *)record->data; - if (record->code == QDF_DP_TRACE_FREE_PACKET_PTR_RECORD) - DPTRACE_PRINT("DPT: %04d: %s: %s msdu_id: %d, status: %d", - index, record->time, - qdf_dp_code_to_string(record->code), buf->msdu_id, - buf->status); - else - DPTRACE_PRINT("DPT: %04d: %s: %s msdu_id: %d, vdev_id: %d", - index, - record->time, qdf_dp_code_to_string(record->code), - buf->msdu_id, buf->status); - dump_hex_trace("cookie", (uint8_t *)&buf->cookie, sizeof(buf->cookie)); + snprintf(prepend_str, sizeof(prepend_str), + "%04d: %s [%s] [msdu id %d %s %d]", + index, + (live == true) ? "" : 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); + + if (live == true) { + /* In live mode donot dump the contents of the cookie */ + DPTRACE_PRINT("DPT: %s", prepend_str); + } else { + dump_dp_hex_trace(prepend_str, (uint8_t *)&buf->cookie, + sizeof(buf->cookie)); + } } EXPORT_SYMBOL(qdf_dp_display_ptr_record); @@ -1612,36 +1691,43 @@ EXPORT_SYMBOL(qdf_dp_trace_ptr); * qdf_dp_display_trace() - Displays a record in DP trace * @pRecord : pointer to a record in DP trace * @recIndex : record index + * @live : live mode or dump mode * * Return: None */ void qdf_dp_display_record(struct qdf_dp_trace_record_s *pRecord, - uint16_t recIndex, uint8_t pdev_id) -{ - if (pdev_id == QDF_TRACE_DEFAULT_PDEV_ID || - pdev_id == pRecord->pdev_id) { + uint16_t recIndex, uint8_t pdev_id, bool live) - DPTRACE_PRINT("DPT: %04d: PDEV_ID = %d: %s: %s", recIndex, - pRecord->pdev_id, pRecord->time, - qdf_dp_code_to_string(pRecord->code)); - switch (pRecord->code) { - case QDF_DP_TRACE_HDD_TX_TIMEOUT: - DPTRACE_PRINT("DPT: HDD TX Timeout\n"); - break; - case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: - DPTRACE_PRINT("DPT: HDD SoftAP TX Timeout\n"); - break; - case QDF_DP_TRACE_HDD_TX_PACKET_RECORD: - case QDF_DP_TRACE_HDD_RX_PACKET_RECORD: - case QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD: - case QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD: - case QDF_DP_TRACE_LI_DP_NULL_RX_PACKET_RECORD: - dump_hex_trace("DATA", pRecord->data, pRecord->size); - break; - default: - dump_hex_trace("cookie", pRecord->data, pRecord->size); - } - } +{ + char prepend_str[50] = {'\0'}; + + if (!(pdev_id == QDF_TRACE_DEFAULT_PDEV_ID || + pdev_id == pRecord->pdev_id)) + return; + + snprintf(prepend_str, sizeof(prepend_str), + "%04d PDEV_ID = %02d: %s %s", + recIndex, + pRecord->pdev_id, + (live == true) ? "" : pRecord->time, + qdf_dp_code_to_string(pRecord->code)); + + switch (pRecord->code) { + case QDF_DP_TRACE_HDD_TX_TIMEOUT: + DPTRACE_PRINT(" %s: HDD TX Timeout", prepend_str); + break; + case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: + DPTRACE_PRINT(" %s: HDD SoftAP TX Timeout", prepend_str); + break; + case QDF_DP_TRACE_HDD_TX_PACKET_RECORD: + case QDF_DP_TRACE_HDD_RX_PACKET_RECORD: + case QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD: + case QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD: + case QDF_DP_TRACE_LI_DP_NULL_RX_PACKET_RECORD: + default: + dump_dp_hex_trace(prepend_str, pRecord->data, pRecord->size); + break; + }; } EXPORT_SYMBOL(qdf_dp_display_record); @@ -1681,6 +1767,17 @@ void qdf_dp_trace_spin_lock_init(void) } EXPORT_SYMBOL(qdf_dp_trace_spin_lock_init); +/** + * qdf_dp_trace_disable_live_mode - disable live mode for dptrace + * + * Return: none + */ +void qdf_dp_trace_disable_live_mode(void) +{ + g_qdf_dp_trace_data.live_mode = 0; +} +EXPORT_SYMBOL(qdf_dp_trace_disable_live_mode); + /** * qdf_dp_trace_enable_live_mode() - enable live mode for dptrace * @@ -1689,11 +1786,9 @@ EXPORT_SYMBOL(qdf_dp_trace_spin_lock_init); void qdf_dp_trace_enable_live_mode(void) { g_qdf_dp_trace_data.live_mode = 1; - } EXPORT_SYMBOL(qdf_dp_trace_enable_live_mode); - /** * qdf_dp_trace_clear_buffer() - clear dp trace buffer * @@ -1704,18 +1799,6 @@ void qdf_dp_trace_clear_buffer(void) g_qdf_dp_trace_data.head = INVALID_QDF_DP_TRACE_ADDR; g_qdf_dp_trace_data.tail = INVALID_QDF_DP_TRACE_ADDR; g_qdf_dp_trace_data.num = 0; - g_qdf_dp_trace_data.proto_bitmap = QDF_NBUF_PKT_TRAC_TYPE_EAPOL | - QDF_NBUF_PKT_TRAC_TYPE_DHCP | - QDF_NBUF_PKT_TRAC_TYPE_MGMT_ACTION | - QDF_NBUF_PKT_TRAC_TYPE_ARP | - QDF_NBUF_PKT_TRAC_TYPE_ICMP; - g_qdf_dp_trace_data.no_of_record = 0; - g_qdf_dp_trace_data.verbosity = QDF_DP_TRACE_VERBOSITY_HIGH; - g_qdf_dp_trace_data.enable = true; - g_qdf_dp_trace_data.tx_count = 0; - g_qdf_dp_trace_data.rx_count = 0; - g_qdf_dp_trace_data.live_mode = 0; - memset(g_qdf_dp_trace_tbl, 0, MAX_QDF_DP_TRACE_RECORDS * sizeof(struct qdf_dp_trace_record_s)); } @@ -1739,7 +1822,24 @@ void qdf_dp_trace_dump_all(uint32_t count, uint8_t pdev_id) return; } - DPTRACE_PRINT("Total Records: %d, Head: %d, Tail: %d", + DPTRACE_PRINT( + "DPT: config - bitmap 0x%x verb %u #rec %u live_config %u thresh %u time_limit %u", + 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); + + DPTRACE_PRINT("DPT: stats - tx %u rx %u icmp(%u %u) arp(%u %u)", + g_qdf_dp_trace_data.tx_count, + g_qdf_dp_trace_data.rx_count, + 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); + + DPTRACE_PRINT("DPT: Total Records: %d, Head: %d, Tail: %d", g_qdf_dp_trace_data.num, g_qdf_dp_trace_data.head, g_qdf_dp_trace_data.tail); @@ -1765,9 +1865,8 @@ void qdf_dp_trace_dump_all(uint32_t count, uint8_t pdev_id) p_record = g_qdf_dp_trace_tbl[i]; spin_unlock_bh(&l_dp_trace_lock); for (;; ) { - - qdf_dp_trace_cb_table[p_record. - code] (&p_record, (uint16_t)i, pdev_id); + qdf_dp_trace_cb_table[p_record.code](&p_record, + (uint16_t)i, pdev_id, false); if (i == tail) break; i += 1; @@ -1992,6 +2091,53 @@ void qdf_trace_msg_cmn(unsigned int idx, } EXPORT_SYMBOL(qdf_trace_msg_cmn); +/** + * qdf_dp_trace_throttle_live_mode() - Throttle DP Trace live mode + * @high_bw_request: whether this is a high BW req or not + * + * The function tries to prevent excessive logging into the live buffer by + * having an upper limit on number of packets that can be logged per second. + * + * The intention is to allow occasional pings and data packets and really low + * throughput levels while suppressing bursts and higher throughput levels so + * that we donot hog the live buffer. + * + * If the number of packets printed in a particular second exceeds the thresh, + * disable printing in the next second. + * + * Return: None + */ +void qdf_dp_trace_throttle_live_mode(bool high_bw_request) +{ + static int bw_interval_counter; + + if (g_qdf_dp_trace_data.enable == false || + g_qdf_dp_trace_data.live_mode_config == false) + return; + + if (high_bw_request) { + g_qdf_dp_trace_data.live_mode = 0; + bw_interval_counter = 0; + return; + } + + bw_interval_counter++; + + if (0 == (bw_interval_counter % + g_qdf_dp_trace_data.thresh_time_limit)) { + + spin_lock_bh(&l_dp_trace_lock); + if (g_qdf_dp_trace_data.print_pkt_cnt <= + g_qdf_dp_trace_data.high_tput_thresh) + g_qdf_dp_trace_data.live_mode = 1; + + g_qdf_dp_trace_data.print_pkt_cnt = 0; + spin_unlock_bh(&l_dp_trace_lock); + } + +} +EXPORT_SYMBOL(qdf_dp_trace_throttle_live_mode); + QDF_STATUS qdf_print_setup(void) { int i;