blob: 4a7b30aea52c93f652a5594cf91be2410219f7a0 [file] [log] [blame]
/*
* 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);
}
}