| /* |
| * Copyright (c) 2016-2017 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. |
| */ |
| |
| /** |
| * DOC: adf_trace |
| * |
| * ADF trace APIs |
| * |
| * Trace, logging, and debugging definitions and APIs |
| * |
| */ |
| |
| /* Include Files */ |
| #include <adf_trace.h> |
| #include "adf_nbuf.h" |
| #include "adf_os_time.h" |
| #include "vos_trace.h" |
| #include "vos_packet.h" |
| #include "sirDebug.h" |
| #include "debug_linux.h" |
| #include "adf_os_io.h" |
| #include "vos_timer.h" |
| |
| /* Static and Global variables */ |
| static spinlock_t l_dp_trace_lock; |
| |
| static struct adf_dp_trace_record_s |
| g_adf_dp_trace_tbl[MAX_ADF_DP_TRACE_RECORDS]; |
| |
| /* |
| * all the options to configure/control DP trace are |
| * defined in this structure |
| */ |
| static struct s_adf_dp_trace_data g_adf_dp_trace_data; |
| /* |
| * all the call back functions for dumping DPTRACE messages from ring buffer |
| * are stored in adf_dp_trace_cb_table, callbacks are initialized during init |
| */ |
| static tp_adf_dp_trace_cb adf_dp_trace_cb_table[ADF_DP_TRACE_MAX]; |
| |
| /** |
| * adf_dp_trace_init() - enables the DP trace |
| * Called during driver load and it enables DP trace |
| * |
| * Return: None |
| */ |
| void adf_dp_trace_init(void) |
| { |
| uint8_t i; |
| |
| spin_lock_init(&l_dp_trace_lock); |
| g_adf_dp_trace_data.head = INVALID_ADF_DP_TRACE_ADDR; |
| g_adf_dp_trace_data.tail = INVALID_ADF_DP_TRACE_ADDR; |
| g_adf_dp_trace_data.num = 0; |
| g_adf_dp_trace_data.proto_bitmap = NBUF_PKT_TRAC_TYPE_EAPOL | |
| NBUF_PKT_TRAC_TYPE_DHCP | |
| NBUF_PKT_TRAC_TYPE_MGMT_ACTION | |
| NBUF_PKT_TRAC_TYPE_ARP; |
| g_adf_dp_trace_data.no_of_record = 0; |
| g_adf_dp_trace_data.verbosity = ADF_DP_TRACE_VERBOSITY_HIGH; |
| g_adf_dp_trace_data.enable = true; |
| g_adf_dp_trace_data.tx_count = 0; |
| g_adf_dp_trace_data.rx_count = 0; |
| g_adf_dp_trace_data.live_mode = 0; |
| |
| for (i = 0; i < ADF_DP_TRACE_MAX; i++) |
| adf_dp_trace_cb_table[i] = adf_dp_display_record; |
| |
| adf_dp_trace_cb_table[ADF_DP_TRACE_TXRX_PACKET_PTR_RECORD] = |
| adf_dp_trace_cb_table[ADF_DP_TRACE_FREE_PACKET_PTR_RECORD] = |
| adf_dp_display_ptr_record; |
| adf_dp_trace_cb_table[ADF_DP_TRACE_EAPOL_PACKET_RECORD] = |
| adf_dp_trace_cb_table[ADF_DP_TRACE_DHCP_PACKET_RECORD] = |
| adf_dp_trace_cb_table[ADF_DP_TRACE_ARP_PACKET_RECORD] = |
| adf_dp_display_proto_pkt; |
| adf_dp_trace_cb_table[ADF_DP_TRACE_MGMT_PACKET_RECORD] = |
| adf_dp_display_mgmt_pkt; |
| adf_dp_trace_cb_table[ADF_DP_TRACE_EVENT_RECORD] = |
| adf_dp_display_event_record; |
| } |
| |
| /** |
| * adf_dp_trace_set_value() - 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 adf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_record, |
| uint8_t verbosity) |
| { |
| spin_lock_bh(&l_dp_trace_lock); |
| g_adf_dp_trace_data.proto_bitmap = proto_bitmap; |
| g_adf_dp_trace_data.no_of_record = no_of_record; |
| g_adf_dp_trace_data.verbosity = verbosity; |
| spin_unlock_bh(&l_dp_trace_lock); |
| } |
| |
| /** |
| * adf_dp_trace_enable_track() - enable the tracing for netbuf |
| * @code : defines the event |
| * |
| * Return: true or false depends on whether tracing enabled |
| */ |
| static bool adf_dp_trace_enable_track(enum ADF_DP_TRACE_ID code) |
| { |
| switch (g_adf_dp_trace_data.verbosity) { |
| case ADF_DP_TRACE_VERBOSITY_HIGH: |
| return true; |
| case ADF_DP_TRACE_VERBOSITY_MEDIUM: |
| if (code <= ADF_DP_TRACE_MED_VERBOSITY) |
| return true; |
| return false; |
| case ADF_DP_TRACE_VERBOSITY_LOW: |
| if (code <= ADF_DP_TRACE_LOW_VERBOSITY) |
| return true; |
| return false; |
| case ADF_DP_TRACE_VERBOSITY_DEFAULT: |
| if (code <= ADF_DP_TRACE_DEFAULT_VERBOSITY) |
| return true; |
| return false; |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * qdf_dp_get_proto_bitmap() - get dp trace proto bitmap |
| * |
| * Return: proto bitmap |
| */ |
| uint8_t adf_dp_get_proto_bitmap(void) |
| { |
| if (g_adf_dp_trace_data.enable) |
| return g_adf_dp_trace_data.proto_bitmap; |
| else |
| return 0; |
| } |
| |
| /** |
| * adf_dp_trace_set_track() - Marks whether the packet needs to be traced |
| * @nbuf : defines the netbuf |
| * @dir: direction |
| * |
| * Return: None |
| */ |
| void adf_dp_trace_set_track(adf_nbuf_t nbuf, enum adf_proto_dir dir) |
| { |
| uint32_t count = 0; |
| |
| spin_lock_bh(&l_dp_trace_lock); |
| if (ADF_TX == dir) |
| count = ++g_adf_dp_trace_data.tx_count; |
| else if (ADF_RX == dir) |
| count = ++g_adf_dp_trace_data.rx_count; |
| |
| if ((g_adf_dp_trace_data.no_of_record != 0) && |
| (count % g_adf_dp_trace_data.no_of_record == 0)) { |
| if (ADF_TX == dir) |
| ADF_NBUF_CB_TX_DP_TRACE(nbuf) = 1; |
| else if (ADF_RX == dir) |
| ADF_NBUF_CB_RX_DP_TRACE(nbuf) = 1; |
| } |
| spin_unlock_bh(&l_dp_trace_lock); |
| } |
| |
| #define DPTRACE_PRINT(args...) \ |
| VOS_TRACE(VOS_MODULE_ID_ADF, VOS_TRACE_LEVEL_INFO, ## args) |
| |
| /** |
| * dump_hex_trace() - Display the data in buffer |
| * @str: string to print |
| * @buf: buffer which contains data to be displayed |
| * @buf_len: defines the size of the data to be displayed |
| * |
| * Return: None |
| */ |
| static void dump_hex_trace(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); |
| |
| DPTRACE_PRINT("DPT: %s: %s", str, linebuf); |
| } |
| } |
| |
| /** |
| * adf_dp_code_to_string() - convert dptrace code to string |
| * @code: dptrace code |
| * |
| * Return: string version of code |
| */ |
| const char *adf_dp_code_to_string(enum ADF_DP_TRACE_ID code) |
| { |
| switch (code) { |
| case ADF_DP_TRACE_DROP_PACKET_RECORD: |
| return "DROP:"; |
| case ADF_DP_TRACE_EAPOL_PACKET_RECORD: |
| return "EAPOL:"; |
| case ADF_DP_TRACE_DHCP_PACKET_RECORD: |
| return "DHCP:"; |
| case ADF_DP_TRACE_ARP_PACKET_RECORD: |
| return "ARP:"; |
| case ADF_DP_TRACE_MGMT_PACKET_RECORD: |
| return "MGMT:"; |
| case ADF_DP_TRACE_EVENT_RECORD: |
| return "EVENT:"; |
| case ADF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD: |
| return "HDD: TX: PTR:"; |
| case ADF_DP_TRACE_HDD_TX_PACKET_RECORD: |
| return "HDD: TX: DATA:"; |
| case ADF_DP_TRACE_CE_PACKET_PTR_RECORD: |
| return "CE: TX: PTR:"; |
| case ADF_DP_TRACE_FREE_PACKET_PTR_RECORD: |
| return "FREE: TX: PTR:"; |
| case ADF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD: |
| return "HTT: RX: PTR:"; |
| case ADF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD: |
| return "HTT: RX: OF: PTR:"; |
| case ADF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD: |
| return "HDD: RX: PTR:"; |
| case ADF_DP_TRACE_HDD_RX_PACKET_RECORD: |
| return "HDD: RX: DATA:"; |
| case ADF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD: |
| return "TXRX: TX: Q: PTR:"; |
| case ADF_DP_TRACE_TXRX_PACKET_PTR_RECORD: |
| return "TXRX: TX: PTR:"; |
| case ADF_DP_TRACE_HTT_PACKET_PTR_RECORD: |
| return "HTT: TX: PTR:"; |
| case ADF_DP_TRACE_HTC_PACKET_PTR_RECORD: |
| return "HTC: TX: PTR:"; |
| case ADF_DP_TRACE_HIF_PACKET_PTR_RECORD: |
| return "HIF: TX: PTR:"; |
| case ADF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD: |
| return "TXRX: RX: PTR:"; |
| case ADF_DP_TRACE_HDD_TX_TIMEOUT: |
| return "HDD: STA: TO:"; |
| case ADF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: |
| return "HDD: SAP: TO:"; |
| default: |
| return "Invalid"; |
| } |
| } |
| |
| /** |
| * adf_dp_dir_to_str() - convert direction to string |
| * @dir: direction |
| * |
| * Return: string version of direction |
| */ |
| const char *adf_dp_dir_to_str(enum adf_proto_dir dir) |
| { |
| switch (dir) { |
| case ADF_TX: |
| return " --> "; |
| case ADF_RX: |
| return " <-- "; |
| default: |
| return "invalid"; |
| } |
| } |
| |
| /** |
| * adf_dp_type_to_str() - convert packet type to string |
| * @type: type |
| * |
| * Return: string version of packet type |
| */ |
| const char *adf_dp_type_to_str(enum adf_proto_type type) |
| { |
| switch (type) { |
| case ADF_PROTO_TYPE_DHCP: |
| return "DHCP"; |
| case ADF_PROTO_TYPE_EAPOL: |
| return "EAPOL"; |
| case ADF_PROTO_TYPE_ARP: |
| return "ARP"; |
| case ADF_PROTO_TYPE_MGMT: |
| return "MGMT"; |
| case ADF_PROTO_TYPE_EVENT: |
| return "EVENT"; |
| default: |
| return "invalid"; |
| } |
| } |
| |
| /** |
| * adf_dp_subtype_to_str() - convert packet subtype to string |
| * @type: type |
| * |
| * Return: string version of packet subtype |
| */ |
| const char *adf_dp_subtype_to_str(enum adf_proto_subtype subtype) |
| { |
| switch (subtype) { |
| case ADF_PROTO_EAPOL_M1: |
| return "M1"; |
| case ADF_PROTO_EAPOL_M2: |
| return "M2"; |
| case ADF_PROTO_EAPOL_M3: |
| return "M3"; |
| case ADF_PROTO_EAPOL_M4: |
| return "M4"; |
| case ADF_PROTO_DHCP_DISCOVER: |
| return "DISCOVER"; |
| case ADF_PROTO_DHCP_REQUEST: |
| return "REQUEST"; |
| case ADF_PROTO_DHCP_OFFER: |
| return "OFFER"; |
| case ADF_PROTO_DHCP_ACK: |
| return "ACK"; |
| case ADF_PROTO_DHCP_NACK: |
| return "NACK"; |
| case ADF_PROTO_DHCP_RELEASE: |
| return "RELEASE"; |
| case ADF_PROTO_DHCP_INFORM: |
| return "INFORM"; |
| case ADF_PROTO_DHCP_DECLINE: |
| return "DECLINE"; |
| case ADF_PROTO_ARP_REQ: |
| return "REQUEST"; |
| case ADF_PROTO_ARP_RES: |
| return "RESPONSE"; |
| case ADF_PROTO_MGMT_ASSOC: |
| return "ASSOC"; |
| case ADF_PROTO_MGMT_DISASSOC: |
| return "DISASSOC"; |
| case ADF_PROTO_MGMT_AUTH: |
| return "AUTH"; |
| case ADF_PROTO_MGMT_DEAUTH: |
| return "DEAUTH"; |
| case ADF_ROAM_SYNCH: |
| return "ROAM SYNCH"; |
| case ADF_ROAM_COMPLETE: |
| return "ROAM COMPLETE"; |
| case ADF_ROAM_EVENTID: |
| return "ROAM EVENTID"; |
| default: |
| return "invalid"; |
| } |
| } |
| |
| /** |
| * adf_dp_enable_check() - check if dptrace is enable or not |
| * @nbuf: nbuf |
| * @code: dptrace code |
| * |
| * Return: true/false |
| */ |
| bool adf_dp_enable_check(adf_nbuf_t nbuf, enum ADF_DP_TRACE_ID code, |
| enum adf_proto_dir dir) |
| { |
| /* Return when Dp trace is not enabled */ |
| if (!g_adf_dp_trace_data.enable) |
| return false; |
| |
| if (adf_dp_trace_enable_track(code) == false) |
| return false; |
| |
| if ((nbuf) && ((NBUF_GET_PACKET_TRACK(nbuf) != |
| NBUF_TX_PKT_DATA_TRACK) || |
| ((dir == ADF_TX) && (ADF_NBUF_CB_TX_DP_TRACE(nbuf) == 0)) || |
| ((dir == ADF_RX) && (ADF_NBUF_CB_RX_DP_TRACE(nbuf) == 0)))) |
| return false; |
| |
| return true; |
| } |
| |
| /** |
| * adf_dp_add_record() - add dp trace record |
| * @code: dptrace code |
| * @data: data pointer |
| * @size: size of buffer |
| * @print: print it in kmsg |
| * |
| * Return: none |
| */ |
| void adf_dp_add_record(enum ADF_DP_TRACE_ID code, |
| uint8_t *data, uint8_t size, bool print) |
| { |
| struct adf_dp_trace_record_s *rec = NULL; |
| int index; |
| |
| spin_lock_bh(&l_dp_trace_lock); |
| |
| g_adf_dp_trace_data.num++; |
| |
| if (g_adf_dp_trace_data.num > MAX_ADF_DP_TRACE_RECORDS) |
| g_adf_dp_trace_data.num = MAX_ADF_DP_TRACE_RECORDS; |
| |
| if (INVALID_ADF_DP_TRACE_ADDR == g_adf_dp_trace_data.head) { |
| /* first record */ |
| g_adf_dp_trace_data.head = 0; |
| g_adf_dp_trace_data.tail = 0; |
| } else { |
| /* queue is not empty */ |
| g_adf_dp_trace_data.tail++; |
| |
| if (MAX_ADF_DP_TRACE_RECORDS == g_adf_dp_trace_data.tail) |
| g_adf_dp_trace_data.tail = 0; |
| |
| if (g_adf_dp_trace_data.head == g_adf_dp_trace_data.tail) { |
| /* full */ |
| if (MAX_ADF_DP_TRACE_RECORDS == |
| ++g_adf_dp_trace_data.head) |
| g_adf_dp_trace_data.head = 0; |
| } |
| } |
| |
| rec = &g_adf_dp_trace_tbl[g_adf_dp_trace_data.tail]; |
| index = g_adf_dp_trace_data.tail; |
| rec->code = code; |
| rec->size = 0; |
| if (data != NULL && size > 0) { |
| if (size > ADF_DP_TRACE_RECORD_SIZE) |
| size = ADF_DP_TRACE_RECORD_SIZE; |
| |
| rec->size = size; |
| adf_os_mem_copy(rec->data, data, size); |
| |
| } |
| vos_get_time_of_the_day_in_hr_min_sec_usec(rec->time, |
| sizeof(rec->time)); |
| rec->pid = (in_interrupt() ? 0 : current->pid); |
| spin_unlock_bh(&l_dp_trace_lock); |
| |
| if ((g_adf_dp_trace_data.live_mode || print == true) && |
| (rec->code < ADF_DP_TRACE_MAX)) |
| adf_dp_trace_cb_table[rec->code] (rec, index); |
| } |
| |
| /** |
| * adf_log_eapol_pkt() - log EAPOL packet |
| * @session_id: vdev_id |
| * @skb: skb pointer |
| * @dir: direction |
| * |
| * Return: true/false |
| */ |
| bool adf_log_eapol_pkt(uint8_t session_id, struct sk_buff *skb, |
| enum adf_proto_dir dir) |
| { |
| enum adf_proto_subtype subtype; |
| |
| if ((adf_dp_get_proto_bitmap() & NBUF_PKT_TRAC_TYPE_EAPOL) && |
| ((dir == ADF_TX && ADF_NBUF_GET_IS_EAPOL(skb)) || |
| (dir == ADF_RX && adf_nbuf_is_eapol_pkt(skb)))) { |
| |
| subtype = adf_nbuf_get_eapol_subtype(skb); |
| DPTRACE(adf_dp_trace_proto_pkt(ADF_DP_TRACE_EAPOL_PACKET_RECORD, |
| session_id, (skb->data + ADF_NBUF_SRC_MAC_OFFSET), |
| (skb->data + ADF_NBUF_DEST_MAC_OFFSET), |
| ADF_PROTO_TYPE_EAPOL, subtype, |
| dir)); |
| if (ADF_TX == dir) |
| ADF_NBUF_CB_TX_DP_TRACE(skb) = 1; |
| else if (ADF_RX == dir) |
| ADF_NBUF_CB_RX_DP_TRACE(skb) = 1; |
| |
| ADF_NBUF_CB_DP_TRACE_PRINT(skb) = true; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * adf_log_dhcp_pkt() - log DHCP packet |
| * @session_id: vdev_id |
| * @skb: skb pointer |
| * @dir: direction |
| * |
| * Return: true/false |
| */ |
| bool adf_log_dhcp_pkt(uint8_t session_id, struct sk_buff *skb, |
| enum adf_proto_dir dir) |
| { |
| enum adf_proto_subtype subtype = ADF_PROTO_INVALID; |
| |
| if ((adf_dp_get_proto_bitmap() & NBUF_PKT_TRAC_TYPE_DHCP) && |
| ((dir == ADF_TX && ADF_NBUF_GET_IS_DHCP(skb)) || |
| (dir == ADF_RX && adf_nbuf_is_dhcp_pkt(skb)))) { |
| |
| subtype = adf_nbuf_get_dhcp_subtype(skb); |
| DPTRACE(adf_dp_trace_proto_pkt(ADF_DP_TRACE_DHCP_PACKET_RECORD, |
| session_id, (skb->data + ADF_NBUF_SRC_MAC_OFFSET), |
| (skb->data + ADF_NBUF_DEST_MAC_OFFSET), |
| ADF_PROTO_TYPE_DHCP, subtype, |
| dir)); |
| if (ADF_TX == dir) |
| ADF_NBUF_CB_TX_DP_TRACE(skb) = 1; |
| else if (ADF_RX == dir) |
| ADF_NBUF_CB_RX_DP_TRACE(skb) = 1; |
| |
| ADF_NBUF_CB_DP_TRACE_PRINT(skb) = true; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * adf_log_arp_pkt() - log ARP packet |
| * @session_id: vdev_id |
| * @skb: skb pointer |
| * @dir: direction |
| * |
| * Return: true/false |
| */ |
| bool adf_log_arp_pkt(uint8_t session_id, struct sk_buff *skb, |
| enum adf_proto_dir dir) |
| { |
| enum adf_proto_subtype proto_subtype; |
| |
| if ((adf_dp_get_proto_bitmap() & NBUF_PKT_TRAC_TYPE_ARP) && |
| ((dir == ADF_TX && ADF_NBUF_GET_IS_ARP(skb)) || |
| (dir == ADF_RX && adf_nbuf_is_ipv4_arp_pkt(skb)))){ |
| |
| proto_subtype = adf_nbuf_get_arp_subtype(skb); |
| |
| DPTRACE(adf_dp_trace_proto_pkt(ADF_DP_TRACE_ARP_PACKET_RECORD, |
| session_id, (skb->data + ADF_NBUF_SRC_MAC_OFFSET), |
| (skb->data + ADF_NBUF_DEST_MAC_OFFSET), |
| ADF_PROTO_TYPE_ARP, proto_subtype, |
| dir)); |
| if (ADF_TX == dir) |
| ADF_NBUF_CB_TX_DP_TRACE(skb) = 1; |
| else if (ADF_RX == dir) |
| ADF_NBUF_CB_RX_DP_TRACE(skb) = 1; |
| |
| ADF_NBUF_CB_DP_TRACE_PRINT(skb) = true; |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * adf_dp_trace_log_pkt() - log packet type enabled through iwpriv |
| * @session_id: vdev_id |
| * @skb: skb pointer |
| * @dir: direction |
| * |
| * Return: none |
| */ |
| void adf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, |
| enum adf_proto_dir dir) |
| { |
| if (adf_dp_get_proto_bitmap()) { |
| if (adf_log_arp_pkt(session_id, |
| skb, dir) == false) { |
| if (adf_log_dhcp_pkt(session_id, |
| skb, dir) == false) { |
| if (adf_log_eapol_pkt(session_id, |
| skb, dir) == false) { |
| return; |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * adf_dp_display_proto_pkt() - display proto packet |
| * @record: dptrace record |
| * @index: index |
| * |
| * Return: none |
| */ |
| void adf_dp_display_proto_pkt(struct adf_dp_trace_record_s *record, |
| uint16_t index) |
| { |
| struct adf_dp_trace_proto_buf *buf = |
| (struct adf_dp_trace_proto_buf *)record->data; |
| |
| DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d\n", index, |
| record->time, adf_dp_code_to_string(record->code), |
| buf->vdev_id); |
| DPTRACE_PRINT("DPT: SA: " MAC_ADDRESS_STR " %s DA: " MAC_ADDRESS_STR |
| " Type %s Subtype %s\n", |
| MAC_ADDR_ARRAY(buf->sa.bytes), adf_dp_dir_to_str(buf->dir), |
| MAC_ADDR_ARRAY(buf->da.bytes), adf_dp_type_to_str(buf->type), |
| adf_dp_subtype_to_str(buf->subtype)); |
| } |
| |
| /** |
| * adf_dp_trace_proto_pkt() - record proto packet |
| * @code: dptrace code |
| * @vdev_id: vdev id |
| * @sa: source mac address |
| * @da: destination mac address |
| * @type: proto type |
| * @subtype: proto subtype |
| * @dir: direction |
| * |
| * Return: none |
| */ |
| void adf_dp_trace_proto_pkt(enum ADF_DP_TRACE_ID code, uint8_t vdev_id, |
| uint8_t *sa, uint8_t *da, enum adf_proto_type type, |
| enum adf_proto_subtype subtype, enum adf_proto_dir dir) |
| { |
| struct adf_dp_trace_proto_buf buf; |
| int buf_size = sizeof(struct adf_dp_trace_ptr_buf); |
| |
| if (adf_dp_enable_check(NULL, code, dir) == false) |
| return; |
| |
| if (buf_size > ADF_DP_TRACE_RECORD_SIZE) |
| ADF_BUG(0); |
| |
| memcpy(&buf.sa, sa, ETH_ALEN); |
| memcpy(&buf.da, da, ETH_ALEN); |
| buf.dir = dir; |
| buf.type = type; |
| buf.subtype = subtype; |
| buf.vdev_id = vdev_id; |
| adf_dp_add_record(code, (uint8_t *)&buf, buf_size, true); |
| } |
| |
| void adf_dp_display_mgmt_pkt(struct adf_dp_trace_record_s *record, |
| uint16_t index) |
| { |
| struct adf_dp_trace_mgmt_buf *buf = |
| (struct adf_dp_trace_mgmt_buf *)record->data; |
| |
| DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d", index, |
| record->time, adf_dp_code_to_string(record->code), |
| buf->vdev_id); |
| DPTRACE_PRINT("DPT: Type %s Subtype %s", adf_dp_type_to_str(buf->type), |
| adf_dp_subtype_to_str(buf->subtype)); |
| } |
| |
| void adf_dp_trace_mgmt_pkt(enum ADF_DP_TRACE_ID code, uint8_t vdev_id, |
| enum adf_proto_type type, enum adf_proto_subtype subtype) |
| { |
| struct adf_dp_trace_mgmt_buf buf; |
| int buf_size = sizeof(struct adf_dp_trace_mgmt_buf); |
| |
| if (adf_dp_enable_check(NULL, code, ADF_NA) == false) |
| return; |
| |
| if (buf_size > ADF_DP_TRACE_RECORD_SIZE) |
| ADF_BUG(0); |
| |
| buf.type = type; |
| buf.subtype = subtype; |
| buf.vdev_id = vdev_id; |
| adf_dp_add_record(code, (uint8_t *)&buf, buf_size, true); |
| } |
| |
| void adf_dp_display_event_record(struct adf_dp_trace_record_s *record, |
| uint16_t index) |
| { |
| struct adf_dp_trace_event_buf *buf = |
| (struct adf_dp_trace_event_buf *)record->data; |
| |
| DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d", index, |
| record->time, adf_dp_code_to_string(record->code), |
| buf->vdev_id); |
| DPTRACE_PRINT("DPT: Type %s Subtype %s", adf_dp_type_to_str(buf->type), |
| adf_dp_subtype_to_str(buf->subtype)); |
| } |
| |
| void adf_dp_trace_record_event(enum ADF_DP_TRACE_ID code, uint8_t vdev_id, |
| enum adf_proto_type type, enum adf_proto_subtype subtype) |
| { |
| struct adf_dp_trace_event_buf buf; |
| int buf_size = sizeof(struct adf_dp_trace_event_buf); |
| |
| if (adf_dp_enable_check(NULL, code, ADF_NA) == false) |
| return; |
| |
| if (buf_size > ADF_DP_TRACE_RECORD_SIZE) |
| ADF_BUG(0); |
| |
| buf.type = type; |
| buf.subtype = subtype; |
| buf.vdev_id = vdev_id; |
| adf_dp_add_record(code, (uint8_t *)&buf, buf_size, true); |
| } |
| |
| /** |
| * adf_dp_display_ptr_record() - display record |
| * @record: dptrace record |
| * @index: index |
| * |
| * Return: none |
| */ |
| void adf_dp_display_ptr_record(struct adf_dp_trace_record_s *record, |
| uint16_t index) |
| { |
| struct adf_dp_trace_ptr_buf *buf = |
| (struct adf_dp_trace_ptr_buf *)record->data; |
| |
| if (record->code == ADF_DP_TRACE_FREE_PACKET_PTR_RECORD) |
| DPTRACE_PRINT("DPT: %04d: %s: %s msdu_id: %d, status: %d\n", index, |
| record->time, adf_dp_code_to_string(record->code), |
| buf->msdu_id, buf->status); |
| else |
| DPTRACE_PRINT("DPT: %04d: %s: %s msdu_id: %d, vdev_id: %d\n", index, |
| record->time, adf_dp_code_to_string(record->code), |
| buf->msdu_id, buf->status); |
| |
| dump_hex_trace("cookie", (uint8_t *)&buf->cookie, sizeof(buf->cookie)); |
| } |
| |
| /** |
| * adf_dp_trace_ptr() - record dptrace |
| * @code: dptrace code |
| * @data: data |
| * @size: size of data |
| * @msdu_id: msdu_id |
| * @status: return status |
| * |
| * Return: none |
| */ |
| void adf_dp_trace_ptr(adf_nbuf_t nbuf, enum ADF_DP_TRACE_ID code, |
| uint8_t *data, uint8_t size, uint16_t msdu_id, uint16_t status) |
| { |
| struct adf_dp_trace_ptr_buf buf; |
| int buf_size = sizeof(struct adf_dp_trace_ptr_buf); |
| |
| if (adf_dp_enable_check(nbuf, code, ADF_TX) == false) |
| return; |
| |
| if (buf_size > ADF_DP_TRACE_RECORD_SIZE) |
| ADF_BUG(0); |
| |
| adf_os_mem_copy(&buf.cookie, data, size); |
| buf.msdu_id = msdu_id; |
| buf.status = status; |
| adf_dp_add_record(code, (uint8_t *)&buf, buf_size, |
| ADF_NBUF_CB_DP_TRACE_PRINT(nbuf)); |
| } |
| |
| /** |
| * adf_dp_display_trace() - Displays a record in DP trace |
| * @pRecord : pointer to a record in DP trace |
| * @recIndex : record index |
| * |
| * Return: None |
| */ |
| void adf_dp_display_record(struct adf_dp_trace_record_s *pRecord, |
| uint16_t recIndex) |
| { |
| uint8_t rsize = pRecord->size; |
| if (rsize > ADF_DP_TRACE_RECORD_SIZE) |
| rsize = ADF_DP_TRACE_RECORD_SIZE; |
| |
| DPTRACE_PRINT("DPT: %04d: %s: %s\n", recIndex, |
| pRecord->time, adf_dp_code_to_string(pRecord->code)); |
| switch (pRecord->code) { |
| case ADF_DP_TRACE_HDD_TX_TIMEOUT: |
| DPTRACE_PRINT("DPT: HDD TX Timeout\n"); |
| break; |
| case ADF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: |
| DPTRACE_PRINT("DPT: HDD SoftAP TX Timeout\n"); |
| break; |
| case ADF_DP_TRACE_HDD_TX_PACKET_RECORD: |
| case ADF_DP_TRACE_HDD_RX_PACKET_RECORD: |
| dump_hex_trace("DATA", pRecord->data, rsize); |
| break; |
| default: |
| dump_hex_trace("cookie", pRecord->data, rsize); |
| } |
| } |
| |
| /** |
| * adf_dp_trace() - Stores the data in buffer |
| * @nbuf : defines the netbuf |
| * @code : defines the event |
| * @data : defines the data to be stored |
| * @size : defines the size of the data record |
| * |
| * Return: None |
| */ |
| void adf_dp_trace(adf_nbuf_t nbuf, enum ADF_DP_TRACE_ID code, |
| uint8_t *data, uint8_t size, enum adf_proto_dir dir) |
| { |
| |
| if (adf_dp_enable_check(nbuf, code, dir) == false) |
| return; |
| |
| adf_dp_add_record(code, data, size, |
| nbuf ? ADF_NBUF_CB_DP_TRACE_PRINT(nbuf) : false); |
| } |
| |
| /** |
| * adf_dp_trace_enable_live_mode() - enable live mode |
| * |
| * Return: none |
| */ |
| void adf_dp_trace_enable_live_mode(void) |
| { |
| g_adf_dp_trace_data.live_mode = 1; |
| } |
| |
| void adf_dp_trace_clear_buffer(void) |
| { |
| g_adf_dp_trace_data.head = INVALID_ADF_DP_TRACE_ADDR; |
| g_adf_dp_trace_data.tail = INVALID_ADF_DP_TRACE_ADDR; |
| g_adf_dp_trace_data.num = 0; |
| g_adf_dp_trace_data.proto_bitmap = NBUF_PKT_TRAC_TYPE_EAPOL | |
| NBUF_PKT_TRAC_TYPE_DHCP | |
| NBUF_PKT_TRAC_TYPE_MGMT_ACTION | |
| NBUF_PKT_TRAC_TYPE_ARP; |
| g_adf_dp_trace_data.no_of_record = 0; |
| g_adf_dp_trace_data.verbosity = ADF_DP_TRACE_VERBOSITY_HIGH; |
| g_adf_dp_trace_data.enable = true; |
| g_adf_dp_trace_data.tx_count = 0; |
| g_adf_dp_trace_data.rx_count = 0; |
| g_adf_dp_trace_data.live_mode = 0; |
| |
| memset(g_adf_dp_trace_tbl, 0, |
| MAX_ADF_DP_TRACE_RECORDS * sizeof(struct adf_dp_trace_record_s)); |
| |
| } |
| |
| /** |
| * adf_dp_trace_dump_all() - Dump data from ring buffer via call back functions |
| * registered with ADF |
| * @code : Reason code |
| * @count : Number of lines to dump starting from tail to head |
| * |
| * Return : nothing |
| */ |
| void adf_dp_trace_dump_all(uint32_t count) |
| { |
| struct adf_dp_trace_record_s pRecord; |
| int32_t i, tail; |
| |
| if (!g_adf_dp_trace_data.enable) { |
| VOS_TRACE(VOS_MODULE_ID_SYS, |
| VOS_TRACE_LEVEL_ERROR, "Tracing Disabled"); |
| return; |
| } |
| |
| VOS_TRACE(VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_ERROR, |
| "Total Records: %d, Head: %d, Tail: %d", |
| g_adf_dp_trace_data.num, g_adf_dp_trace_data.head, |
| g_adf_dp_trace_data.tail); |
| |
| /* aquire the lock so that only one thread at a time can read |
| * the ring buffer |
| */ |
| spin_lock_bh(&l_dp_trace_lock); |
| |
| if (g_adf_dp_trace_data.head != INVALID_ADF_DP_TRACE_ADDR) { |
| i = g_adf_dp_trace_data.head; |
| tail = g_adf_dp_trace_data.tail; |
| |
| if (count) { |
| if (count > g_adf_dp_trace_data.num) |
| count = g_adf_dp_trace_data.num; |
| if (tail >= (count - 1)) |
| i = tail - count + 1; |
| else if (count != MAX_ADF_DP_TRACE_RECORDS) |
| i = MAX_ADF_DP_TRACE_RECORDS - ((count - 1) - |
| tail); |
| } |
| |
| pRecord = g_adf_dp_trace_tbl[i]; |
| spin_unlock_bh(&l_dp_trace_lock); |
| for (;; ) { |
| adf_dp_trace_cb_table[pRecord. |
| code] (&pRecord, (uint16_t)i); |
| if (i == tail) |
| break; |
| i += 1; |
| |
| spin_lock_bh(&l_dp_trace_lock); |
| if (MAX_ADF_DP_TRACE_RECORDS == i) |
| i = 0; |
| |
| pRecord = g_adf_dp_trace_tbl[i]; |
| spin_unlock_bh(&l_dp_trace_lock); |
| } |
| } else { |
| spin_unlock_bh(&l_dp_trace_lock); |
| } |
| } |