
Set "QDF_TRACE_LEVEL_WARN" as the default log level of management Rx reorder module. Change-Id: I846f706a06c0f4dc098ee281fc802dc7b1698aa2 CRs-Fixed: 3593922
4449 lines
122 KiB
C
4449 lines
122 KiB
C
/*
|
|
* Copyright (c) 2014-2021 The Linux Foundation. All rights reserved.
|
|
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* DOC: qdf_trace
|
|
* QCA driver framework (QDF) trace APIs
|
|
* Trace, logging, and debugging definitions and APIs
|
|
*/
|
|
|
|
/* Include Files */
|
|
#include "qdf_str.h"
|
|
#include <qdf_trace.h>
|
|
#include <qdf_parse.h>
|
|
#include <qdf_module.h>
|
|
#include <qdf_util.h>
|
|
#include <qdf_mem.h>
|
|
#include <qdf_list.h>
|
|
|
|
/* macro to map qdf trace levels into the bitmask */
|
|
#define QDF_TRACE_LEVEL_TO_MODULE_BITMASK(_level) ((1 << (_level)))
|
|
|
|
#include <wlan_logging_sock_svc.h>
|
|
#include <qdf_module.h>
|
|
static int qdf_pidx = -1;
|
|
static bool qdf_log_dump_at_kernel_enable = true;
|
|
qdf_declare_param(qdf_log_dump_at_kernel_enable, bool);
|
|
|
|
/* This value of 0 will disable the timer by default. */
|
|
static uint32_t qdf_log_flush_timer_period;
|
|
qdf_declare_param(qdf_log_flush_timer_period, uint);
|
|
|
|
#include "qdf_time.h"
|
|
#include "qdf_mc_timer.h"
|
|
#include <host_diag_core_log.h>
|
|
|
|
#ifdef CONNECTIVITY_DIAG_EVENT
|
|
#include <wlan_connectivity_logging.h>
|
|
#include "i_host_diag_core_event.h"
|
|
#endif
|
|
|
|
/* Global qdf print id */
|
|
|
|
/* Preprocessor definitions and constants */
|
|
|
|
enum qdf_timestamp_unit qdf_log_timestamp_type = QDF_LOG_TIMESTAMP_UNIT;
|
|
|
|
#define DP_TRACE_META_DATA_STRLEN 50
|
|
|
|
#ifdef TRACE_RECORD
|
|
/* Static and Global variables */
|
|
static spinlock_t ltrace_lock;
|
|
/* global qdf trace data */
|
|
static t_qdf_trace_data g_qdf_trace_data;
|
|
/*
|
|
* all the call back functions for dumping MTRACE messages from ring buffer
|
|
* are stored in qdf_trace_cb_table,these callbacks are initialized during init
|
|
* only so, we will make a copy of these call back functions and maintain in to
|
|
* qdf_trace_restore_cb_table. Incase if we make modifications to
|
|
* qdf_trace_cb_table, we can certainly retrieve all the call back functions
|
|
* back from Restore Table
|
|
*/
|
|
static tp_qdf_trace_cb qdf_trace_cb_table[QDF_MODULE_ID_MAX];
|
|
static tp_qdf_trace_cb qdf_trace_restore_cb_table[QDF_MODULE_ID_MAX];
|
|
|
|
#ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
|
|
static qdf_trace_record_t *g_qdf_trace_tbl;
|
|
#else
|
|
static qdf_trace_record_t g_qdf_trace_tbl[MAX_QDF_TRACE_RECORDS];
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef WLAN_FEATURE_MEMDUMP_ENABLE
|
|
static tp_qdf_state_info_cb qdf_state_info_table[QDF_MODULE_ID_MAX];
|
|
#endif
|
|
|
|
#ifdef CONFIG_DP_TRACE
|
|
/* Static and Global variables */
|
|
#ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
|
|
static struct qdf_dp_trace_record_s *g_qdf_dp_trace_tbl;
|
|
#else
|
|
static struct qdf_dp_trace_record_s
|
|
g_qdf_dp_trace_tbl[MAX_QDF_DP_TRACE_RECORDS];
|
|
#endif
|
|
static spinlock_t l_dp_trace_lock;
|
|
|
|
/*
|
|
* all the options to configure/control DP trace are
|
|
* defined in this structure
|
|
*/
|
|
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];
|
|
#endif
|
|
|
|
#ifdef QCA_WIFI_MODULE_PARAMS_FROM_INI
|
|
#define QDF_PARAM_STR_LENGTH 40
|
|
|
|
enum qdf_num_module_param {
|
|
MEM_DEBUG_DISABLED,
|
|
QDF_DBG_MASK,
|
|
PREALLOC_DISABLED,
|
|
QDF_LOG_DUMP_AT_KERNEL_ENABLE,
|
|
QDF_DBG_ARR,
|
|
QDF_LOG_FLUSH_TIMER_PERIOD,
|
|
QDF_PARAM_MAX,
|
|
};
|
|
|
|
static char qdf_module_param[QDF_PARAM_MAX][QDF_PARAM_STR_LENGTH] = {
|
|
"mem_debug_disabled",
|
|
"qdf_dbg_mask",
|
|
"prealloc_disabled",
|
|
"qdf_log_dump_at_kernel_enable",
|
|
"qdf_dbg_arr",
|
|
"qdf_log_flush_timer_period",
|
|
};
|
|
#endif
|
|
|
|
int qdf_snprintf(char *str_buffer, unsigned int size, char *str_format, ...)
|
|
{
|
|
va_list args;
|
|
int i;
|
|
|
|
va_start(args, str_format);
|
|
i = vsnprintf(str_buffer, size, str_format, args);
|
|
va_end(args);
|
|
|
|
return i;
|
|
}
|
|
qdf_export_symbol(qdf_snprintf);
|
|
|
|
#ifdef QDF_ENABLE_TRACING
|
|
|
|
void qdf_trace_msg(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
|
|
const char *str_format, ...)
|
|
{
|
|
va_list val;
|
|
|
|
va_start(val, str_format);
|
|
qdf_trace_msg_cmn(qdf_pidx, module, level, str_format, val);
|
|
va_end(val);
|
|
}
|
|
qdf_export_symbol(qdf_trace_msg);
|
|
|
|
void qdf_vtrace_msg(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
|
|
const char *str_format, va_list val)
|
|
{
|
|
qdf_trace_msg_cmn(qdf_pidx, module, level, str_format, val);
|
|
}
|
|
qdf_export_symbol(qdf_vtrace_msg);
|
|
|
|
#define ROW_SIZE 16
|
|
/* Buffer size = data bytes(2 hex chars plus space) + NULL */
|
|
#define BUFFER_SIZE ((QDF_DP_TRACE_RECORD_SIZE * 3) + 1)
|
|
|
|
static void __qdf_trace_hex_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
|
|
void *data, int buf_len, bool print_ascii)
|
|
{
|
|
const u8 *ptr = data;
|
|
int i = 0;
|
|
|
|
if (!qdf_print_is_verbose_enabled(qdf_pidx, module, level))
|
|
return;
|
|
|
|
while (buf_len > 0) {
|
|
unsigned char linebuf[BUFFER_SIZE] = {0};
|
|
int linelen = min(buf_len, ROW_SIZE);
|
|
|
|
buf_len -= ROW_SIZE;
|
|
|
|
hex_dump_to_buffer(ptr, linelen, ROW_SIZE, 1,
|
|
linebuf, sizeof(linebuf), print_ascii);
|
|
|
|
qdf_trace_msg(module, level, "%.8x: %s", i, linebuf);
|
|
ptr += ROW_SIZE;
|
|
i += ROW_SIZE;
|
|
}
|
|
}
|
|
|
|
void qdf_trace_hex_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
|
|
void *data, int buf_len)
|
|
{
|
|
__qdf_trace_hex_dump(module, level, data, buf_len, false);
|
|
}
|
|
|
|
qdf_export_symbol(qdf_trace_hex_dump);
|
|
|
|
void qdf_trace_hex_ascii_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
|
|
void *data, int buf_len)
|
|
{
|
|
__qdf_trace_hex_dump(module, level, data, buf_len, true);
|
|
}
|
|
|
|
qdf_export_symbol(qdf_trace_hex_ascii_dump);
|
|
|
|
#endif
|
|
|
|
#ifdef TRACE_RECORD
|
|
|
|
#ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
|
|
static inline QDF_STATUS allocate_g_qdf_trace_tbl_buffer(void)
|
|
{
|
|
g_qdf_trace_tbl = qdf_mem_valloc(MAX_QDF_TRACE_RECORDS *
|
|
sizeof(*g_qdf_trace_tbl));
|
|
QDF_BUG(g_qdf_trace_tbl);
|
|
return g_qdf_trace_tbl ? QDF_STATUS_SUCCESS : QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
static inline void free_g_qdf_trace_tbl_buffer(void)
|
|
{
|
|
qdf_mem_vfree(g_qdf_trace_tbl);
|
|
g_qdf_trace_tbl = NULL;
|
|
}
|
|
#else
|
|
static inline QDF_STATUS allocate_g_qdf_trace_tbl_buffer(void)
|
|
{
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
static inline void free_g_qdf_trace_tbl_buffer(void)
|
|
{ }
|
|
#endif
|
|
void qdf_trace_enable(uint32_t bitmask_of_module_id, uint8_t enable)
|
|
{
|
|
int i;
|
|
|
|
if (bitmask_of_module_id) {
|
|
for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
|
|
if (((bitmask_of_module_id >> i) & 1)) {
|
|
if (enable) {
|
|
if (NULL !=
|
|
qdf_trace_restore_cb_table[i]) {
|
|
qdf_trace_cb_table[i] =
|
|
qdf_trace_restore_cb_table[i];
|
|
}
|
|
} else {
|
|
qdf_trace_restore_cb_table[i] =
|
|
qdf_trace_cb_table[i];
|
|
qdf_trace_cb_table[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (enable) {
|
|
for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
|
|
if (qdf_trace_restore_cb_table[i]) {
|
|
qdf_trace_cb_table[i] =
|
|
qdf_trace_restore_cb_table[i];
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
|
|
qdf_trace_restore_cb_table[i] =
|
|
qdf_trace_cb_table[i];
|
|
qdf_trace_cb_table[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_trace_enable);
|
|
|
|
void qdf_trace_init(void)
|
|
{
|
|
uint8_t i;
|
|
|
|
if (allocate_g_qdf_trace_tbl_buffer() != QDF_STATUS_SUCCESS)
|
|
return;
|
|
g_qdf_trace_data.head = INVALID_QDF_TRACE_ADDR;
|
|
g_qdf_trace_data.tail = INVALID_QDF_TRACE_ADDR;
|
|
g_qdf_trace_data.num = 0;
|
|
g_qdf_trace_data.enable = true;
|
|
g_qdf_trace_data.dump_count = DEFAULT_QDF_TRACE_DUMP_COUNT;
|
|
g_qdf_trace_data.num_since_last_dump = 0;
|
|
|
|
for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
|
|
qdf_trace_cb_table[i] = NULL;
|
|
qdf_trace_restore_cb_table[i] = NULL;
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_trace_init);
|
|
|
|
void qdf_trace_deinit(void)
|
|
{
|
|
g_qdf_trace_data.enable = false;
|
|
g_qdf_trace_data.num = 0;
|
|
g_qdf_trace_data.head = INVALID_QDF_TRACE_ADDR;
|
|
g_qdf_trace_data.tail = INVALID_QDF_TRACE_ADDR;
|
|
|
|
free_g_qdf_trace_tbl_buffer();
|
|
}
|
|
|
|
qdf_export_symbol(qdf_trace_deinit);
|
|
|
|
void qdf_trace(uint8_t module, uint16_t code, uint16_t session, uint32_t data)
|
|
{
|
|
tp_qdf_trace_record rec = NULL;
|
|
unsigned long flags;
|
|
char time[18];
|
|
|
|
if (!g_qdf_trace_data.enable)
|
|
return;
|
|
|
|
/* if module is not registered, don't record for that module */
|
|
if (!qdf_trace_cb_table[module])
|
|
return;
|
|
|
|
qdf_get_time_of_the_day_in_hr_min_sec_usec(time, sizeof(time));
|
|
/* Acquire the lock so that only one thread at a time can fill the ring
|
|
* buffer
|
|
*/
|
|
spin_lock_irqsave(<race_lock, flags);
|
|
|
|
g_qdf_trace_data.num++;
|
|
|
|
if (g_qdf_trace_data.num > MAX_QDF_TRACE_RECORDS)
|
|
g_qdf_trace_data.num = MAX_QDF_TRACE_RECORDS;
|
|
|
|
if (INVALID_QDF_TRACE_ADDR == g_qdf_trace_data.head) {
|
|
/* first record */
|
|
g_qdf_trace_data.head = 0;
|
|
g_qdf_trace_data.tail = 0;
|
|
} else {
|
|
/* queue is not empty */
|
|
uint32_t tail = g_qdf_trace_data.tail + 1;
|
|
|
|
if (MAX_QDF_TRACE_RECORDS == tail)
|
|
tail = 0;
|
|
|
|
if (g_qdf_trace_data.head == tail) {
|
|
/* full */
|
|
if (MAX_QDF_TRACE_RECORDS == ++g_qdf_trace_data.head)
|
|
g_qdf_trace_data.head = 0;
|
|
}
|
|
g_qdf_trace_data.tail = tail;
|
|
}
|
|
|
|
rec = &g_qdf_trace_tbl[g_qdf_trace_data.tail];
|
|
rec->code = code;
|
|
rec->session = session;
|
|
rec->data = data;
|
|
rec->qtime = qdf_get_log_timestamp();
|
|
scnprintf(rec->time, sizeof(rec->time), "%s", time);
|
|
rec->module = module;
|
|
rec->pid = (in_interrupt() ? 0 : current->pid);
|
|
g_qdf_trace_data.num_since_last_dump++;
|
|
spin_unlock_irqrestore(<race_lock, flags);
|
|
}
|
|
qdf_export_symbol(qdf_trace);
|
|
|
|
#ifdef ENABLE_MTRACE_LOG
|
|
void qdf_mtrace_log(QDF_MODULE_ID src_module, QDF_MODULE_ID dst_module,
|
|
uint16_t message_id, uint8_t vdev_id)
|
|
{
|
|
uint32_t trace_log, payload;
|
|
static uint16_t counter;
|
|
|
|
trace_log = (src_module << 23) | (dst_module << 15) | message_id;
|
|
payload = (vdev_id << 16) | counter++;
|
|
|
|
QDF_TRACE(src_module, QDF_TRACE_LEVEL_TRACE, "%x %x",
|
|
trace_log, payload);
|
|
}
|
|
|
|
qdf_export_symbol(qdf_mtrace_log);
|
|
#endif
|
|
|
|
void qdf_mtrace(QDF_MODULE_ID src_module, QDF_MODULE_ID dst_module,
|
|
uint16_t message_id, uint8_t vdev_id, uint32_t data)
|
|
{
|
|
qdf_trace(src_module, message_id, vdev_id, data);
|
|
qdf_mtrace_log(src_module, dst_module, message_id, vdev_id);
|
|
}
|
|
|
|
qdf_export_symbol(qdf_mtrace);
|
|
|
|
QDF_STATUS qdf_trace_spin_lock_init(void)
|
|
{
|
|
spin_lock_init(<race_lock);
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
qdf_export_symbol(qdf_trace_spin_lock_init);
|
|
|
|
void qdf_trace_register(QDF_MODULE_ID module_id,
|
|
tp_qdf_trace_cb qdf_trace_callback)
|
|
{
|
|
qdf_trace_cb_table[module_id] = qdf_trace_callback;
|
|
}
|
|
qdf_export_symbol(qdf_trace_register);
|
|
|
|
void qdf_trace_dump_all(void *p_mac, uint8_t code, uint8_t session,
|
|
uint32_t count, uint32_t bitmask_of_module)
|
|
{
|
|
qdf_trace_record_t p_record;
|
|
int32_t i, tail;
|
|
|
|
if (!g_qdf_trace_data.enable) {
|
|
QDF_TRACE(QDF_MODULE_ID_SYS,
|
|
QDF_TRACE_LEVEL_ERROR, "Tracing Disabled");
|
|
return;
|
|
}
|
|
|
|
QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO,
|
|
"DPT: Total Records: %d, Head: %d, Tail: %d",
|
|
g_qdf_trace_data.num, g_qdf_trace_data.head,
|
|
g_qdf_trace_data.tail);
|
|
|
|
/* acquire the lock so that only one thread at a time can read
|
|
* the ring buffer
|
|
*/
|
|
spin_lock(<race_lock);
|
|
|
|
if (g_qdf_trace_data.head != INVALID_QDF_TRACE_ADDR) {
|
|
i = g_qdf_trace_data.head;
|
|
tail = g_qdf_trace_data.tail;
|
|
|
|
if (count) {
|
|
if (count > g_qdf_trace_data.num)
|
|
count = g_qdf_trace_data.num;
|
|
if (tail >= (count - 1))
|
|
i = tail - count + 1;
|
|
else if (count != MAX_QDF_TRACE_RECORDS)
|
|
i = MAX_QDF_TRACE_RECORDS - ((count - 1) -
|
|
tail);
|
|
}
|
|
|
|
p_record = g_qdf_trace_tbl[i];
|
|
/* right now we are not using num_since_last_dump member but
|
|
* in future we might re-visit and use this member to track
|
|
* how many latest messages got added while we were dumping
|
|
* from ring buffer
|
|
*/
|
|
g_qdf_trace_data.num_since_last_dump = 0;
|
|
spin_unlock(<race_lock);
|
|
for (;; ) {
|
|
if ((code == 0 || (code == p_record.code)) &&
|
|
(qdf_trace_cb_table[p_record.module])) {
|
|
if (0 == bitmask_of_module) {
|
|
qdf_trace_cb_table[p_record.
|
|
module] (p_mac,
|
|
&p_record,
|
|
(uint16_t)
|
|
i);
|
|
} else {
|
|
if (bitmask_of_module &
|
|
(1 << p_record.module)) {
|
|
qdf_trace_cb_table[p_record.
|
|
module]
|
|
(p_mac, &p_record,
|
|
(uint16_t) i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i == tail)
|
|
break;
|
|
i += 1;
|
|
|
|
spin_lock(<race_lock);
|
|
if (MAX_QDF_TRACE_RECORDS == i) {
|
|
i = 0;
|
|
p_record = g_qdf_trace_tbl[0];
|
|
} else {
|
|
p_record = g_qdf_trace_tbl[i];
|
|
}
|
|
spin_unlock(<race_lock);
|
|
}
|
|
} else {
|
|
spin_unlock(<race_lock);
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_trace_dump_all);
|
|
#endif
|
|
|
|
#ifdef WLAN_FEATURE_MEMDUMP_ENABLE
|
|
void qdf_register_debugcb_init(void)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0; i < QDF_MODULE_ID_MAX; i++)
|
|
qdf_state_info_table[i] = NULL;
|
|
}
|
|
qdf_export_symbol(qdf_register_debugcb_init);
|
|
|
|
void qdf_register_debug_callback(QDF_MODULE_ID module_id,
|
|
tp_qdf_state_info_cb qdf_state_infocb)
|
|
{
|
|
qdf_state_info_table[module_id] = qdf_state_infocb;
|
|
}
|
|
qdf_export_symbol(qdf_register_debug_callback);
|
|
|
|
QDF_STATUS qdf_state_info_dump_all(char *buf, uint16_t size,
|
|
uint16_t *driver_dump_size)
|
|
{
|
|
uint8_t module, ret = QDF_STATUS_SUCCESS;
|
|
uint16_t buf_len = size;
|
|
char *buf_ptr = buf;
|
|
|
|
for (module = 0; module < QDF_MODULE_ID_MAX; module++) {
|
|
if (qdf_state_info_table[module]) {
|
|
qdf_state_info_table[module](&buf_ptr, &buf_len);
|
|
if (!buf_len) {
|
|
ret = QDF_STATUS_E_NOMEM;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
*driver_dump_size = size - buf_len;
|
|
return ret;
|
|
}
|
|
qdf_export_symbol(qdf_state_info_dump_all);
|
|
#endif
|
|
|
|
#ifdef CONFIG_DP_TRACE
|
|
|
|
#ifdef WLAN_LOGGING_BUFFERS_DYNAMICALLY
|
|
static inline QDF_STATUS allocate_g_qdf_dp_trace_tbl_buffer(void)
|
|
{
|
|
g_qdf_dp_trace_tbl = qdf_mem_valloc(MAX_QDF_DP_TRACE_RECORDS *
|
|
sizeof(*g_qdf_dp_trace_tbl));
|
|
QDF_BUG(g_qdf_dp_trace_tbl);
|
|
return g_qdf_dp_trace_tbl ? QDF_STATUS_SUCCESS : QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
static inline void free_g_qdf_dp_trace_tbl_buffer(void)
|
|
{
|
|
qdf_mem_vfree(g_qdf_dp_trace_tbl);
|
|
g_qdf_dp_trace_tbl = NULL;
|
|
}
|
|
#else
|
|
static inline QDF_STATUS allocate_g_qdf_dp_trace_tbl_buffer(void)
|
|
{
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
static inline void free_g_qdf_dp_trace_tbl_buffer(void)
|
|
{ }
|
|
#endif
|
|
|
|
#define QDF_DP_TRACE_PREPEND_STR_SIZE 100
|
|
/*
|
|
* one dp trace record can't be greater than 300 bytes.
|
|
* Max Size will be QDF_DP_TRACE_PREPEND_STR_SIZE(100) + BUFFER_SIZE(121).
|
|
* Always make sure to change this QDF_DP_TRACE_MAX_RECORD_SIZE
|
|
* value accordingly whenever above two mentioned MACRO value changes.
|
|
*/
|
|
#define QDF_DP_TRACE_MAX_RECORD_SIZE 300
|
|
|
|
static void qdf_dp_unused(struct qdf_dp_trace_record_s *record,
|
|
uint16_t index, uint8_t pdev_id, uint8_t info)
|
|
{
|
|
qdf_print("%s: QDF_DP_TRACE_MAX event should not be generated",
|
|
__func__);
|
|
}
|
|
|
|
void qdf_dp_trace_init(bool live_mode_config, uint8_t thresh,
|
|
uint16_t time_limit, uint8_t verbosity,
|
|
uint32_t proto_bitmap)
|
|
{
|
|
uint8_t i;
|
|
|
|
if (allocate_g_qdf_dp_trace_tbl_buffer() != QDF_STATUS_SUCCESS) {
|
|
QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
|
|
"Failed!!! DP Trace buffer allocation");
|
|
return;
|
|
}
|
|
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;
|
|
g_qdf_dp_trace_data.ini_conf_verbosity = verbosity;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(qdf_dp_trace_cb_table); i++)
|
|
qdf_dp_trace_cb_table[i] = qdf_dp_display_record;
|
|
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_HDD_TX_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_HDD_RX_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_TX_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_RX_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_DROP_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD] =
|
|
qdf_dp_display_data_pkt_record;
|
|
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_FREE_PACKET_PTR_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_LI_DP_FREE_PACKET_PTR_RECORD] =
|
|
qdf_dp_display_ptr_record;
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_EAPOL_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_DHCP_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_ARP_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_ICMP_PACKET_RECORD] =
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_ICMPv6_PACKET_RECORD] =
|
|
qdf_dp_display_proto_pkt;
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_MGMT_PACKET_RECORD] =
|
|
qdf_dp_display_mgmt_pkt;
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_TX_CREDIT_RECORD] =
|
|
qdf_dp_display_credit_record;
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_EVENT_RECORD] =
|
|
qdf_dp_display_event_record;
|
|
|
|
qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX] = qdf_dp_unused;
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_init);
|
|
|
|
void qdf_dp_trace_deinit(void)
|
|
{
|
|
if (!g_qdf_dp_trace_data.enable)
|
|
return;
|
|
spin_lock_bh(&l_dp_trace_lock);
|
|
g_qdf_dp_trace_data.enable = false;
|
|
g_qdf_dp_trace_data.no_of_record = 0;
|
|
spin_unlock_bh(&l_dp_trace_lock);
|
|
|
|
free_g_qdf_dp_trace_tbl_buffer();
|
|
}
|
|
|
|
void qdf_dp_trace_set_value(uint32_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;
|
|
g_qdf_dp_trace_data.dynamic_verbosity_modify = true;
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_set_value);
|
|
|
|
void qdf_dp_trace_set_verbosity(uint32_t val)
|
|
{
|
|
g_qdf_dp_trace_data.verbosity = val;
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_set_verbosity);
|
|
|
|
/**
|
|
* qdf_dp_get_verbosity() - get verbosity value
|
|
*
|
|
* Return: int
|
|
*/
|
|
uint8_t qdf_dp_get_verbosity(void)
|
|
{
|
|
return g_qdf_dp_trace_data.verbosity;
|
|
}
|
|
qdf_export_symbol(qdf_dp_get_verbosity);
|
|
|
|
void qdf_dp_set_proto_bitmap(uint32_t val)
|
|
{
|
|
g_qdf_dp_trace_data.proto_bitmap = val;
|
|
}
|
|
qdf_export_symbol(qdf_dp_set_proto_bitmap);
|
|
|
|
void qdf_dp_set_proto_event_bitmap(uint32_t value)
|
|
{
|
|
g_qdf_dp_trace_data.proto_event_bitmap = value;
|
|
}
|
|
|
|
qdf_export_symbol(qdf_dp_set_proto_event_bitmap);
|
|
|
|
static uint32_t qdf_dp_get_proto_event_bitmap(void)
|
|
{
|
|
return g_qdf_dp_trace_data.proto_event_bitmap;
|
|
}
|
|
|
|
void qdf_dp_set_no_of_record(uint32_t val)
|
|
{
|
|
g_qdf_dp_trace_data.no_of_record = val;
|
|
}
|
|
qdf_export_symbol(qdf_dp_set_no_of_record);
|
|
|
|
uint8_t qdf_dp_get_no_of_record(void)
|
|
{
|
|
return g_qdf_dp_trace_data.no_of_record;
|
|
}
|
|
qdf_export_symbol(qdf_dp_get_no_of_record);
|
|
|
|
|
|
/**
|
|
* qdf_dp_trace_verbosity_check() - check whether verbosity level is enabled
|
|
* @code: defines the event
|
|
*
|
|
* In High verbosity all codes are logged.
|
|
* For Med/Low and Default case code which has
|
|
* less value than corresponding verbosity codes
|
|
* are logged.
|
|
*
|
|
* Return: true or false depends on whether tracing enabled
|
|
*/
|
|
static bool qdf_dp_trace_verbosity_check(enum QDF_DP_TRACE_ID code)
|
|
{
|
|
switch (g_qdf_dp_trace_data.verbosity) {
|
|
case QDF_DP_TRACE_VERBOSITY_HIGH:
|
|
return true;
|
|
case QDF_DP_TRACE_VERBOSITY_MEDIUM:
|
|
if (code <= QDF_DP_TRACE_MED_VERBOSITY)
|
|
return true;
|
|
return false;
|
|
case QDF_DP_TRACE_VERBOSITY_LOW:
|
|
if (code <= QDF_DP_TRACE_LOW_VERBOSITY)
|
|
return true;
|
|
return false;
|
|
case QDF_DP_TRACE_VERBOSITY_ULTRA_LOW:
|
|
if (code <= QDF_DP_TRACE_ULTRA_LOW_VERBOSITY)
|
|
return true;
|
|
return false;
|
|
case QDF_DP_TRACE_VERBOSITY_BASE:
|
|
if (code <= QDF_DP_TRACE_BASE_VERBOSITY)
|
|
return true;
|
|
return false;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
uint32_t qdf_dp_get_proto_bitmap(void)
|
|
{
|
|
if (g_qdf_dp_trace_data.enable)
|
|
return g_qdf_dp_trace_data.proto_bitmap;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
else if (QDF_RX == dir)
|
|
count = ++g_qdf_dp_trace_data.rx_count;
|
|
|
|
if ((g_qdf_dp_trace_data.no_of_record != 0) &&
|
|
(count % g_qdf_dp_trace_data.no_of_record == 0)) {
|
|
if (QDF_TX == dir)
|
|
QDF_NBUF_CB_TX_DP_TRACE(nbuf) = 1;
|
|
else if (QDF_RX == dir)
|
|
QDF_NBUF_CB_RX_DP_TRACE(nbuf) = 1;
|
|
}
|
|
spin_unlock_bh(&l_dp_trace_lock);
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_set_track);
|
|
|
|
/* Number of bytes to be grouped together while printing DP-Trace data */
|
|
#define QDF_DUMP_DP_GROUP_SIZE 6
|
|
|
|
/**
|
|
* dump_dp_hex_trace() - Display the data in buffer
|
|
* @prepend_str: string to prepend the hexdump with.
|
|
* @inbuf: buffer which contains data to be displayed
|
|
* @inbuf_len: defines the size of the data to be displayed
|
|
*
|
|
* Return: None
|
|
*/
|
|
static void
|
|
dump_dp_hex_trace(char *prepend_str, uint8_t *inbuf, uint8_t inbuf_len)
|
|
{
|
|
unsigned char outbuf[BUFFER_SIZE];
|
|
const uint8_t *inbuf_ptr = inbuf;
|
|
char *outbuf_ptr = outbuf;
|
|
int outbytes_written = 0;
|
|
|
|
qdf_mem_zero(outbuf, sizeof(outbuf));
|
|
do {
|
|
outbytes_written += scnprintf(outbuf_ptr,
|
|
BUFFER_SIZE - outbytes_written,
|
|
"%02x", *inbuf_ptr);
|
|
outbuf_ptr = outbuf + outbytes_written;
|
|
|
|
if ((inbuf_ptr - inbuf) &&
|
|
(inbuf_ptr - inbuf + 1) % QDF_DUMP_DP_GROUP_SIZE == 0) {
|
|
outbytes_written += scnprintf(outbuf_ptr,
|
|
BUFFER_SIZE - outbytes_written,
|
|
" ");
|
|
outbuf_ptr = outbuf + outbytes_written;
|
|
}
|
|
inbuf_ptr++;
|
|
} while (inbuf_ptr < (inbuf + inbuf_len));
|
|
DPTRACE_PRINT("%s %s", prepend_str, outbuf);
|
|
}
|
|
|
|
/**
|
|
* qdf_dp_code_to_string() - convert dptrace code to string
|
|
* @code: dptrace code
|
|
*
|
|
* Return: string version of code
|
|
*/
|
|
static
|
|
const char *qdf_dp_code_to_string(enum QDF_DP_TRACE_ID code)
|
|
{
|
|
switch (code) {
|
|
case QDF_DP_TRACE_DROP_PACKET_RECORD:
|
|
return "DROP:";
|
|
case QDF_DP_TRACE_EAPOL_PACKET_RECORD:
|
|
return "EAPOL:";
|
|
case QDF_DP_TRACE_DHCP_PACKET_RECORD:
|
|
return "DHCP:";
|
|
case QDF_DP_TRACE_ARP_PACKET_RECORD:
|
|
return "ARP:";
|
|
case QDF_DP_TRACE_ICMP_PACKET_RECORD:
|
|
return "ICMP:";
|
|
case QDF_DP_TRACE_ICMPv6_PACKET_RECORD:
|
|
return "ICMPv6:";
|
|
case QDF_DP_TRACE_MGMT_PACKET_RECORD:
|
|
return "MGMT:";
|
|
case QDF_DP_TRACE_TX_CREDIT_RECORD:
|
|
return "CREDIT:";
|
|
case QDF_DP_TRACE_EVENT_RECORD:
|
|
return "EVENT:";
|
|
case QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD:
|
|
return "HDD: TX: PTR:";
|
|
case QDF_DP_TRACE_LI_DP_TX_PACKET_PTR_RECORD:
|
|
return "LI_DP: TX: PTR:";
|
|
case QDF_DP_TRACE_HDD_TX_PACKET_RECORD:
|
|
return "HDD: TX: DATA:";
|
|
case QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD:
|
|
case QDF_DP_TRACE_TX_PACKET_RECORD:
|
|
return "TX:";
|
|
case QDF_DP_TRACE_CE_PACKET_PTR_RECORD:
|
|
return "CE: TX: PTR:";
|
|
case QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD:
|
|
return "CE: TX: FAST: PTR:";
|
|
case QDF_DP_TRACE_CE_FAST_PACKET_ERR_RECORD:
|
|
return "CE: TX: FAST: ERR:";
|
|
case QDF_DP_TRACE_LI_DP_FREE_PACKET_PTR_RECORD:
|
|
case QDF_DP_TRACE_FREE_PACKET_PTR_RECORD:
|
|
return "FREE: TX: PTR:";
|
|
case QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD:
|
|
return "HTT: RX: PTR:";
|
|
case QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD:
|
|
return "HTT: RX: OF: PTR:";
|
|
case QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD:
|
|
return "HDD: RX: PTR:";
|
|
case QDF_DP_TRACE_RX_LI_DP_PACKET_PTR_RECORD:
|
|
return "LI_DP: RX: PTR:";
|
|
case QDF_DP_TRACE_HDD_RX_PACKET_RECORD:
|
|
return "HDD: RX: DATA:";
|
|
case QDF_DP_TRACE_LI_DP_NULL_RX_PACKET_RECORD:
|
|
return "LI_DP_NULL: RX: DATA:";
|
|
case QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD:
|
|
case QDF_DP_TRACE_RX_PACKET_RECORD:
|
|
return "RX:";
|
|
case QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD:
|
|
return "TXRX: TX: Q: PTR:";
|
|
case QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD:
|
|
return "TXRX: TX: PTR:";
|
|
case QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD:
|
|
return "TXRX: TX: FAST: PTR:";
|
|
case QDF_DP_TRACE_HTT_PACKET_PTR_RECORD:
|
|
return "HTT: TX: PTR:";
|
|
case QDF_DP_TRACE_HTC_PACKET_PTR_RECORD:
|
|
return "HTC: TX: PTR:";
|
|
case QDF_DP_TRACE_HIF_PACKET_PTR_RECORD:
|
|
return "HIF: TX: PTR:";
|
|
case QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD:
|
|
return "TXRX: RX: PTR:";
|
|
case QDF_DP_TRACE_HDD_TX_TIMEOUT:
|
|
return "HDD: STA: TO:";
|
|
case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
|
|
return "HDD: SAP: TO:";
|
|
default:
|
|
return "Invalid";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* qdf_dp_dir_to_str() - convert direction to string
|
|
* @dir: direction
|
|
*
|
|
* Return: string version of direction
|
|
*/
|
|
static const char *qdf_dp_dir_to_str(enum qdf_proto_dir dir)
|
|
{
|
|
switch (dir) {
|
|
case QDF_TX:
|
|
return " --> ";
|
|
case QDF_RX:
|
|
return " <-- ";
|
|
default:
|
|
return "invalid";
|
|
}
|
|
}
|
|
|
|
static const char *qdf_dp_credit_source_to_str(
|
|
enum QDF_CREDIT_UPDATE_SOURCE source)
|
|
{
|
|
switch (source) {
|
|
case QDF_TX_SCHED:
|
|
return "TX SCHED";
|
|
case QDF_TX_COMP:
|
|
return "TX COMP";
|
|
case QDF_TX_CREDIT_UPDATE:
|
|
return "CREDIT UP";
|
|
case QDF_TX_HTT_MSG:
|
|
return "HTT TX MSG";
|
|
case QDF_HTT_ATTACH:
|
|
return "HTT ATTACH";
|
|
default:
|
|
return "invalid";
|
|
}
|
|
}
|
|
|
|
static const char *qdf_dp_operation_to_str(enum QDF_CREDIT_OPERATION op)
|
|
{
|
|
switch (op) {
|
|
case QDF_CREDIT_INC:
|
|
return "+";
|
|
case QDF_CREDIT_DEC:
|
|
return "-";
|
|
case QDF_CREDIT_ABS:
|
|
return "ABS";
|
|
default:
|
|
return "invalid";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* qdf_dp_type_to_str() - convert packet type to string
|
|
* @type: type
|
|
*
|
|
* Return: string version of packet type
|
|
*/
|
|
static const char *qdf_dp_type_to_str(enum qdf_proto_type type)
|
|
{
|
|
switch (type) {
|
|
case QDF_PROTO_TYPE_DHCP:
|
|
return "DHCP";
|
|
case QDF_PROTO_TYPE_EAPOL:
|
|
return "EAPOL";
|
|
case QDF_PROTO_TYPE_ARP:
|
|
return "ARP";
|
|
case QDF_PROTO_TYPE_ICMP:
|
|
return "ICMP";
|
|
case QDF_PROTO_TYPE_ICMPv6:
|
|
return "ICMPv6";
|
|
case QDF_PROTO_TYPE_MGMT:
|
|
return "MGMT";
|
|
case QDF_PROTO_TYPE_EVENT:
|
|
return "EVENT";
|
|
default:
|
|
return "invalid";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* qdf_dp_subtype_to_str() - convert packet subtype to string
|
|
* @subtype: subtype
|
|
*
|
|
* Return: string version of packet subtype
|
|
*/
|
|
static const char *qdf_dp_subtype_to_str(enum qdf_proto_subtype subtype)
|
|
{
|
|
switch (subtype) {
|
|
case QDF_PROTO_EAPOL_M1:
|
|
return "M1";
|
|
case QDF_PROTO_EAPOL_M2:
|
|
return "M2";
|
|
case QDF_PROTO_EAPOL_M3:
|
|
return "M3";
|
|
case QDF_PROTO_EAPOL_M4:
|
|
return "M4";
|
|
case QDF_PROTO_DHCP_DISCOVER:
|
|
return "DISC";
|
|
case QDF_PROTO_DHCP_REQUEST:
|
|
return "REQ";
|
|
case QDF_PROTO_DHCP_OFFER:
|
|
return "OFF";
|
|
case QDF_PROTO_DHCP_ACK:
|
|
return "ACK";
|
|
case QDF_PROTO_DHCP_NACK:
|
|
return "NACK";
|
|
case QDF_PROTO_DHCP_RELEASE:
|
|
return "REL";
|
|
case QDF_PROTO_DHCP_INFORM:
|
|
return "INFORM";
|
|
case QDF_PROTO_DHCP_DECLINE:
|
|
return "DECL";
|
|
case QDF_PROTO_ARP_REQ:
|
|
case QDF_PROTO_ICMP_REQ:
|
|
case QDF_PROTO_ICMPV6_REQ:
|
|
return "REQ";
|
|
case QDF_PROTO_ARP_RES:
|
|
case QDF_PROTO_ICMP_RES:
|
|
case QDF_PROTO_ICMPV6_RES:
|
|
return "RSP";
|
|
case QDF_PROTO_ICMPV6_RS:
|
|
return "RS";
|
|
case QDF_PROTO_ICMPV6_RA:
|
|
return "RA";
|
|
case QDF_PROTO_ICMPV6_NS:
|
|
return "NS";
|
|
case QDF_PROTO_ICMPV6_NA:
|
|
return "NA";
|
|
case QDF_PROTO_MGMT_ASSOC:
|
|
return "ASSOC";
|
|
case QDF_PROTO_MGMT_DISASSOC:
|
|
return "DISASSOC";
|
|
case QDF_PROTO_MGMT_AUTH:
|
|
return "AUTH";
|
|
case QDF_PROTO_MGMT_DEAUTH:
|
|
return "DEAUTH";
|
|
case QDF_ROAM_SYNCH:
|
|
return "ROAM SYNCH";
|
|
case QDF_ROAM_COMPLETE:
|
|
return "ROAM COMP";
|
|
case QDF_ROAM_EVENTID:
|
|
return "ROAM EVENTID";
|
|
case QDF_PROTO_EAP_REQUEST:
|
|
return "EAP REQ";
|
|
case QDF_PROTO_EAP_RESPONSE:
|
|
return "EAP RSP";
|
|
case QDF_PROTO_EAP_SUCCESS:
|
|
return "EAP SUC";
|
|
case QDF_PROTO_EAP_FAILURE:
|
|
return "EAP FAIL";
|
|
case QDF_PROTO_EAP_INITIATE:
|
|
return "EAP INIT";
|
|
case QDF_PROTO_EAP_FINISH:
|
|
return "EAP FINISH";
|
|
case QDF_PROTO_EAPOL_START:
|
|
return "START";
|
|
case QDF_PROTO_EAPOL_LOGOFF:
|
|
return "LOGOFF";
|
|
case QDF_PROTO_EAPOL_ASF:
|
|
return "ASF";
|
|
case QDF_PROTO_EAP_REQ_ID:
|
|
return "EAP REQ ID";
|
|
case QDF_PROTO_EAP_RSP_ID:
|
|
return "EAP RSP ID";
|
|
case QDF_PROTO_EAP_M1:
|
|
return "EAP M1";
|
|
case QDF_PROTO_EAP_M2:
|
|
return "EAP M2";
|
|
case QDF_PROTO_EAP_M3:
|
|
return "EAP M3";
|
|
case QDF_PROTO_EAP_M4:
|
|
return "EAP M4";
|
|
case QDF_PROTO_EAP_M5:
|
|
return "EAP M5";
|
|
case QDF_PROTO_EAP_M6:
|
|
return "EAP M6";
|
|
case QDF_PROTO_EAP_M7:
|
|
return "EAP M7";
|
|
case QDF_PROTO_EAP_M8:
|
|
return "EAP M8";
|
|
case QDF_PROTO_EAP_WSC_START:
|
|
return "EAP WSC START";
|
|
case QDF_PROTO_EAP_WSC_DONE:
|
|
return "EAP WSC DONE";
|
|
case QDF_PROTO_EAP_WSC_ACK:
|
|
return "EAP WSC ACK";
|
|
case QDF_PROTO_EAP_WSC_NACK:
|
|
return "EAP WSC NACK";
|
|
case QDF_PROTO_EAP_WSC_FRAG_ACK:
|
|
return "EAP WSC FRAG ACK";
|
|
default:
|
|
return "invalid";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* qdf_dp_enable_check() - check if dptrace, TX/RX tracing is enabled
|
|
* @nbuf: nbuf
|
|
* @code: dptrace code
|
|
* @dir: TX or RX direction
|
|
*
|
|
* Return: true/false
|
|
*/
|
|
static bool qdf_dp_enable_check(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code,
|
|
enum qdf_proto_dir dir)
|
|
{
|
|
/* Return when Dp trace is not enabled */
|
|
if (!g_qdf_dp_trace_data.enable)
|
|
return false;
|
|
|
|
if (qdf_dp_trace_verbosity_check(code) == false)
|
|
return false;
|
|
|
|
if (nbuf && (dir == QDF_TX && ((QDF_NBUF_CB_TX_DP_TRACE(nbuf) == 0) ||
|
|
(QDF_NBUF_CB_TX_PACKET_TRACK(nbuf) !=
|
|
QDF_NBUF_TX_PKT_DATA_TRACK))))
|
|
return false;
|
|
|
|
if (nbuf && (dir == QDF_RX && (QDF_NBUF_CB_RX_DP_TRACE(nbuf) == 0)))
|
|
return false;
|
|
|
|
/*
|
|
* Special packets called with NULL nbuf and this API is expected to
|
|
* return true
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* qdf_dp_trace_fill_meta_str() - fill up a common meta string
|
|
* @prepend_str: pointer to string
|
|
* @size: size of prepend_str
|
|
* @rec_index: index of record
|
|
* @info: info related to the record
|
|
* @record: pointer to the record
|
|
*
|
|
* Return: ret value from scnprintf
|
|
*/
|
|
static inline
|
|
int qdf_dp_trace_fill_meta_str(char *prepend_str, int size,
|
|
int rec_index, uint8_t info,
|
|
struct qdf_dp_trace_record_s *record)
|
|
{
|
|
char buffer[20];
|
|
int ret = 0;
|
|
bool live = info & QDF_DP_TRACE_RECORD_INFO_LIVE ? true : false;
|
|
bool throttled = info & QDF_DP_TRACE_RECORD_INFO_THROTTLED ?
|
|
true : false;
|
|
|
|
scnprintf(buffer, sizeof(buffer), "%llu", record->time);
|
|
ret = scnprintf(prepend_str, size,
|
|
"%s DPT: %04d:%02d%s %s",
|
|
throttled ? "*" : "",
|
|
rec_index,
|
|
record->pdev_id,
|
|
live ? "" : buffer,
|
|
qdf_dp_code_to_string(record->code));
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* qdf_dp_fill_record_data() - fill meta data and data into the record
|
|
* @rec: pointer to record data
|
|
* @data: pointer to data
|
|
* @data_size: size of the data
|
|
* @meta_data: pointer to metadata
|
|
* @metadata_size: size of metadata
|
|
*
|
|
* Should be called from within a spin_lock for the qdf record.
|
|
* Fills up rec->data with |metadata|data|
|
|
*
|
|
* Return: none
|
|
*/
|
|
static void qdf_dp_fill_record_data
|
|
(struct qdf_dp_trace_record_s *rec,
|
|
uint8_t *data, uint8_t data_size,
|
|
uint8_t *meta_data, uint8_t metadata_size)
|
|
{
|
|
int32_t available = QDF_DP_TRACE_RECORD_SIZE;
|
|
uint8_t *rec_data = rec->data;
|
|
uint8_t data_to_copy = 0;
|
|
|
|
qdf_mem_zero(rec_data, QDF_DP_TRACE_RECORD_SIZE);
|
|
|
|
/* copy meta data */
|
|
if (meta_data) {
|
|
if (metadata_size > available) {
|
|
QDF_TRACE_WARN(QDF_MODULE_ID_QDF,
|
|
"%s: meta data does not fit into the record",
|
|
__func__);
|
|
goto end;
|
|
}
|
|
qdf_mem_copy(rec_data, meta_data, metadata_size);
|
|
available = available - metadata_size;
|
|
} else {
|
|
metadata_size = 0;
|
|
}
|
|
|
|
/* copy data */
|
|
if (data && (data_size > 0) && (available > 0)) {
|
|
data_to_copy = data_size;
|
|
if (data_size > available)
|
|
data_to_copy = available;
|
|
qdf_mem_copy(&rec_data[metadata_size], data, data_to_copy);
|
|
}
|
|
end:
|
|
rec->size = data_to_copy;
|
|
}
|
|
|
|
/**
|
|
* qdf_dp_add_record() - add dp trace record
|
|
* @code: dptrace code
|
|
* @pdev_id: pdev_id
|
|
* @print: true to print it in kmsg
|
|
* @data: data pointer
|
|
* @data_size: size of data to be copied
|
|
* @meta_data: meta data to be prepended to data
|
|
* @metadata_size: sizeof meta data
|
|
* @print: whether to print record
|
|
*
|
|
* Return: none
|
|
*/
|
|
static void qdf_dp_add_record(enum QDF_DP_TRACE_ID code, uint8_t pdev_id,
|
|
uint8_t *data, uint8_t data_size,
|
|
uint8_t *meta_data, uint8_t metadata_size,
|
|
bool print)
|
|
|
|
{
|
|
struct qdf_dp_trace_record_s *rec = NULL;
|
|
int index;
|
|
bool print_this_record = false;
|
|
u8 info = 0;
|
|
|
|
if (code >= QDF_DP_TRACE_MAX) {
|
|
QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
|
|
"invalid record code %u, max code %u",
|
|
code, QDF_DP_TRACE_MAX);
|
|
return;
|
|
}
|
|
|
|
spin_lock_bh(&l_dp_trace_lock);
|
|
|
|
if (print || g_qdf_dp_trace_data.force_live_mode) {
|
|
print_this_record = true;
|
|
} else if (g_qdf_dp_trace_data.live_mode == 1) {
|
|
print_this_record = true;
|
|
g_qdf_dp_trace_data.print_pkt_cnt++;
|
|
if (g_qdf_dp_trace_data.print_pkt_cnt >
|
|
g_qdf_dp_trace_data.high_tput_thresh) {
|
|
g_qdf_dp_trace_data.live_mode = 0;
|
|
g_qdf_dp_trace_data.verbosity =
|
|
QDF_DP_TRACE_VERBOSITY_ULTRA_LOW;
|
|
info |= QDF_DP_TRACE_RECORD_INFO_THROTTLED;
|
|
}
|
|
}
|
|
|
|
g_qdf_dp_trace_data.num++;
|
|
|
|
if (g_qdf_dp_trace_data.num > MAX_QDF_DP_TRACE_RECORDS)
|
|
g_qdf_dp_trace_data.num = MAX_QDF_DP_TRACE_RECORDS;
|
|
|
|
if (INVALID_QDF_DP_TRACE_ADDR == g_qdf_dp_trace_data.head) {
|
|
/* first record */
|
|
g_qdf_dp_trace_data.head = 0;
|
|
g_qdf_dp_trace_data.tail = 0;
|
|
} else {
|
|
/* queue is not empty */
|
|
g_qdf_dp_trace_data.tail++;
|
|
|
|
if (MAX_QDF_DP_TRACE_RECORDS == g_qdf_dp_trace_data.tail)
|
|
g_qdf_dp_trace_data.tail = 0;
|
|
|
|
if (g_qdf_dp_trace_data.head == g_qdf_dp_trace_data.tail) {
|
|
/* full */
|
|
if (MAX_QDF_DP_TRACE_RECORDS ==
|
|
++g_qdf_dp_trace_data.head)
|
|
g_qdf_dp_trace_data.head = 0;
|
|
}
|
|
}
|
|
|
|
rec = &g_qdf_dp_trace_tbl[g_qdf_dp_trace_data.tail];
|
|
index = g_qdf_dp_trace_data.tail;
|
|
rec->code = code;
|
|
rec->pdev_id = pdev_id;
|
|
rec->size = 0;
|
|
qdf_dp_fill_record_data(rec, data, data_size,
|
|
meta_data, metadata_size);
|
|
rec->time = qdf_get_log_timestamp();
|
|
rec->pid = (in_interrupt() ? 0 : current->pid);
|
|
|
|
if (rec->code >= QDF_DP_TRACE_MAX) {
|
|
QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
|
|
"invalid record code %u, max code %u",
|
|
rec->code, QDF_DP_TRACE_MAX);
|
|
return;
|
|
}
|
|
|
|
spin_unlock_bh(&l_dp_trace_lock);
|
|
|
|
info |= QDF_DP_TRACE_RECORD_INFO_LIVE;
|
|
if (print_this_record)
|
|
qdf_dp_trace_cb_table[rec->code] (rec, index,
|
|
QDF_TRACE_DEFAULT_PDEV_ID, info);
|
|
}
|
|
|
|
/**
|
|
* qdf_get_rate_limit_by_type() - Get the rate limit by pkt type
|
|
* @type: packet type
|
|
*
|
|
* Return: Rate limit value for a particular packet type
|
|
*/
|
|
static inline
|
|
uint8_t qdf_get_rate_limit_by_type(uint8_t type)
|
|
{
|
|
switch (type) {
|
|
case QDF_PROTO_TYPE_DHCP:
|
|
return QDF_MAX_DHCP_PKTS_PER_SEC;
|
|
case QDF_PROTO_TYPE_EAPOL:
|
|
return QDF_MAX_EAPOL_PKTS_PER_SEC;
|
|
case QDF_PROTO_TYPE_ARP:
|
|
return QDF_MAX_ARP_PKTS_PER_SEC;
|
|
case QDF_PROTO_TYPE_DNS:
|
|
return QDF_MAX_DNS_PKTS_PER_SEC;
|
|
default:
|
|
return QDF_MAX_OTHER_PKTS_PER_SEC;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* qdf_get_pkt_type_string() - Get the string based on pkt type
|
|
* @type: packet type
|
|
* @subtype: packet subtype
|
|
*
|
|
* Return: String based on pkt type
|
|
*/
|
|
static
|
|
uint8_t *qdf_get_pkt_type_string(uint8_t type, uint8_t subtype)
|
|
{
|
|
switch (subtype) {
|
|
case QDF_PROTO_EAPOL_M1:
|
|
return "EAPOL-1";
|
|
case QDF_PROTO_EAPOL_M2:
|
|
return "EAPOL-2";
|
|
case QDF_PROTO_EAPOL_M3:
|
|
return "EAPOL-3";
|
|
case QDF_PROTO_EAPOL_M4:
|
|
return "EAPOL-4";
|
|
case QDF_PROTO_DHCP_DISCOVER:
|
|
return "DHCP-D";
|
|
case QDF_PROTO_DHCP_REQUEST:
|
|
return "DHCP-R";
|
|
case QDF_PROTO_DHCP_OFFER:
|
|
return "DHCP-O";
|
|
case QDF_PROTO_DHCP_ACK:
|
|
return "DHCP-A";
|
|
case QDF_PROTO_DHCP_NACK:
|
|
return "DHCP-NA";
|
|
case QDF_PROTO_DHCP_RELEASE:
|
|
return "DHCP-REL";
|
|
case QDF_PROTO_DHCP_INFORM:
|
|
return "DHCP-IN";
|
|
case QDF_PROTO_DHCP_DECLINE:
|
|
return "DHCP-DEC";
|
|
case QDF_PROTO_ARP_REQ:
|
|
return "ARP-RQ";
|
|
case QDF_PROTO_ARP_RES:
|
|
return "ARP-RS";
|
|
case QDF_PROTO_DNS_QUERY:
|
|
return "DNS_Q";
|
|
case QDF_PROTO_DNS_RES:
|
|
return "DNS_RS";
|
|
case QDF_PROTO_EAP_REQUEST:
|
|
return "EAP_REQ";
|
|
case QDF_PROTO_EAP_RESPONSE:
|
|
return "EAP-RSP";
|
|
case QDF_PROTO_EAP_SUCCESS:
|
|
return "EAP-SUCCESS";
|
|
case QDF_PROTO_EAP_FAILURE:
|
|
return "EAP-FAIL";
|
|
case QDF_PROTO_EAP_INITIATE:
|
|
return "EAP-INIT";
|
|
case QDF_PROTO_EAP_FINISH:
|
|
return "EAP-FINISH";
|
|
case QDF_PROTO_EAPOL_START:
|
|
return "EAPOL-START";
|
|
case QDF_PROTO_EAPOL_LOGOFF:
|
|
return "EAPOL-LOGOFF";
|
|
case QDF_PROTO_EAPOL_ASF:
|
|
return "EAPOL-ASF";
|
|
case QDF_PROTO_EAP_REQ_ID:
|
|
return "EAP-REQ-ID";
|
|
case QDF_PROTO_EAP_RSP_ID:
|
|
return "EAP-RSP-ID";
|
|
case QDF_PROTO_EAP_M1:
|
|
return "EAP-M1";
|
|
case QDF_PROTO_EAP_M2:
|
|
return "EAP-M2";
|
|
case QDF_PROTO_EAP_M3:
|
|
return "EAP-M3";
|
|
case QDF_PROTO_EAP_M4:
|
|
return "EAP-M4";
|
|
case QDF_PROTO_EAP_M5:
|
|
return "EAP-M5";
|
|
case QDF_PROTO_EAP_M6:
|
|
return "EAP-M6";
|
|
case QDF_PROTO_EAP_M7:
|
|
return "EAP-M7";
|
|
case QDF_PROTO_EAP_M8:
|
|
return "EAP-M8";
|
|
case QDF_PROTO_EAP_WSC_START:
|
|
return "EAP-WSC-START";
|
|
case QDF_PROTO_EAP_WSC_DONE:
|
|
return "EAP-WSC-DONE";
|
|
case QDF_PROTO_EAP_WSC_ACK:
|
|
return "EAP-WSC-ACK";
|
|
case QDF_PROTO_EAP_WSC_NACK:
|
|
return "EAP-WSC-NACK";
|
|
case QDF_PROTO_EAP_WSC_FRAG_ACK:
|
|
return "EAP-WSC-FRAG-ACK";
|
|
default:
|
|
switch (type) {
|
|
case QDF_PROTO_TYPE_EAPOL:
|
|
return "EAP";
|
|
case QDF_PROTO_TYPE_DHCP:
|
|
return "DHCP";
|
|
case QDF_PROTO_TYPE_ARP:
|
|
return "ARP";
|
|
case QDF_PROTO_TYPE_DNS:
|
|
return "DNS";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* qdf_get_pkt_status_string() - Get the string based on pkt status
|
|
* @status: packet status
|
|
*
|
|
* Return: String based on pkt status
|
|
*/
|
|
static
|
|
uint8_t *qdf_get_pkt_status_string(uint8_t status)
|
|
{
|
|
switch (status) {
|
|
case QDF_TX_RX_STATUS_INVALID:
|
|
return "inv";
|
|
case QDF_TX_RX_STATUS_OK:
|
|
return "succ";
|
|
case QDF_TX_RX_STATUS_FW_DISCARD:
|
|
return "disc";
|
|
case QDF_TX_RX_STATUS_NO_ACK:
|
|
return "nack";
|
|
case QDF_TX_RX_STATUS_DROP:
|
|
return "drop";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
void qdf_dp_log_proto_pkt_info(uint8_t *sa, uint8_t *da, uint8_t type,
|
|
uint8_t subtype, uint8_t dir, uint16_t msdu_id,
|
|
uint8_t status)
|
|
{
|
|
uint8_t pkt_rate_limit;
|
|
static ulong last_ticks_tx[QDF_PROTO_SUBTYPE_MAX] = {0};
|
|
static ulong last_ticks_rx[QDF_PROTO_SUBTYPE_MAX] = {0};
|
|
ulong curr_ticks = jiffies;
|
|
|
|
pkt_rate_limit = qdf_get_rate_limit_by_type(type);
|
|
|
|
if ((dir == QDF_TX &&
|
|
!time_after(curr_ticks,
|
|
last_ticks_tx[subtype] + HZ / pkt_rate_limit)) ||
|
|
(dir == QDF_RX &&
|
|
!time_after(curr_ticks,
|
|
last_ticks_rx[subtype] + HZ / pkt_rate_limit)))
|
|
return;
|
|
|
|
if (dir == QDF_TX)
|
|
last_ticks_tx[subtype] = curr_ticks;
|
|
else
|
|
last_ticks_rx[subtype] = curr_ticks;
|
|
|
|
if (status == QDF_TX_RX_STATUS_INVALID)
|
|
qdf_nofl_info("%s %s: SA:" QDF_MAC_ADDR_FMT " DA:" QDF_MAC_ADDR_FMT,
|
|
qdf_get_pkt_type_string(type, subtype),
|
|
dir ? "RX" : "TX", QDF_MAC_ADDR_REF(sa),
|
|
QDF_MAC_ADDR_REF(da));
|
|
else
|
|
qdf_nofl_info("%s %s: SA:" QDF_MAC_ADDR_FMT " DA:" QDF_MAC_ADDR_FMT " msdu_id:%d status: %s",
|
|
qdf_get_pkt_type_string(type, subtype),
|
|
dir ? "RX" : "TX", QDF_MAC_ADDR_REF(sa),
|
|
QDF_MAC_ADDR_REF(da), msdu_id,
|
|
qdf_get_pkt_status_string(status));
|
|
}
|
|
|
|
qdf_export_symbol(qdf_dp_log_proto_pkt_info);
|
|
|
|
/**
|
|
* qdf_log_icmpv6_pkt() - log ICMPv6 packet
|
|
* @vdev_id: ID of the vdev
|
|
* @skb: skb pointer
|
|
* @dir: direction
|
|
* @pdev_id: ID of the pdev
|
|
*
|
|
* Return: true/false
|
|
*/
|
|
static bool qdf_log_icmpv6_pkt(uint8_t vdev_id, struct sk_buff *skb,
|
|
enum qdf_proto_dir dir, uint8_t pdev_id)
|
|
{
|
|
enum qdf_proto_subtype subtype;
|
|
|
|
if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ICMPv6) &&
|
|
((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_ICMPv6 ==
|
|
QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
|
|
(dir == QDF_RX && qdf_nbuf_is_icmpv6_pkt(skb) == true))) {
|
|
|
|
subtype = qdf_nbuf_get_icmpv6_subtype(skb);
|
|
|
|
QDF_NBUF_CB_DP_TRACE_PRINT(skb) = false;
|
|
if (dir == QDF_TX)
|
|
QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
|
|
else if (dir == QDF_RX)
|
|
QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
|
|
|
|
DPTRACE(qdf_dp_trace_proto_pkt(
|
|
QDF_DP_TRACE_ICMPv6_PACKET_RECORD,
|
|
vdev_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET),
|
|
(skb->data + QDF_NBUF_DEST_MAC_OFFSET),
|
|
QDF_PROTO_TYPE_ICMPv6, subtype, dir, pdev_id, false, 0));
|
|
|
|
switch (subtype) {
|
|
case QDF_PROTO_ICMPV6_REQ:
|
|
g_qdf_dp_trace_data.icmpv6_req++;
|
|
break;
|
|
case QDF_PROTO_ICMPV6_RES:
|
|
g_qdf_dp_trace_data.icmpv6_resp++;
|
|
break;
|
|
case QDF_PROTO_ICMPV6_RS:
|
|
g_qdf_dp_trace_data.icmpv6_rs++;
|
|
break;
|
|
case QDF_PROTO_ICMPV6_RA:
|
|
g_qdf_dp_trace_data.icmpv6_ra++;
|
|
break;
|
|
case QDF_PROTO_ICMPV6_NS:
|
|
g_qdf_dp_trace_data.icmpv6_ns++;
|
|
break;
|
|
case QDF_PROTO_ICMPV6_NA:
|
|
g_qdf_dp_trace_data.icmpv6_na++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* qdf_log_icmp_pkt() - log ICMP packet
|
|
* @vdev_id: ID of the vdev
|
|
* @skb: skb pointer
|
|
* @dir: direction
|
|
* @pdev_id: ID of the pdev
|
|
*
|
|
* Return: true/false
|
|
*/
|
|
static bool qdf_log_icmp_pkt(uint8_t vdev_id, struct sk_buff *skb,
|
|
enum qdf_proto_dir dir, uint8_t pdev_id)
|
|
{
|
|
enum qdf_proto_subtype proto_subtype;
|
|
uint8_t *data = NULL;
|
|
uint16_t seq_num = 0;
|
|
uint16_t icmp_id = 0;
|
|
uint32_t proto_priv_data = 0;
|
|
|
|
if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ICMP) &&
|
|
(qdf_nbuf_is_icmp_pkt(skb) == true)) {
|
|
|
|
QDF_NBUF_CB_DP_TRACE_PRINT(skb) = false;
|
|
proto_subtype = qdf_nbuf_get_icmp_subtype(skb);
|
|
|
|
data = qdf_nbuf_data(skb);
|
|
icmp_id = qdf_cpu_to_be16(*(uint16_t *)(data + ICMP_ID_OFFSET));
|
|
seq_num = qdf_cpu_to_be16(*(uint16_t *)(data + ICMP_SEQ_NUM_OFFSET));
|
|
|
|
proto_priv_data |= ((proto_priv_data | ((uint32_t)icmp_id)) << 16);
|
|
proto_priv_data |= (uint32_t)seq_num;
|
|
|
|
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;
|
|
|
|
DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ICMP_PACKET_RECORD,
|
|
vdev_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, proto_priv_data));
|
|
|
|
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;
|
|
}
|
|
|
|
#ifdef CONNECTIVITY_DIAG_EVENT
|
|
enum diag_tx_status wlan_get_diag_tx_status(enum qdf_dp_tx_rx_status tx_status)
|
|
{
|
|
switch (tx_status) {
|
|
case DIAG_TX_RX_STATUS_FW_DISCARD:
|
|
case DIAG_TX_RX_STATUS_INVALID:
|
|
case DIAG_TX_RX_STATUS_DROP:
|
|
case DIAG_TX_RX_STATUS_DOWNLOAD_SUCC:
|
|
case DIAG_TX_RX_STATUS_DEFAULT:
|
|
default:
|
|
return DIAG_TX_STATUS_FAIL;
|
|
case DIAG_TX_RX_STATUS_NO_ACK:
|
|
return DIAG_TX_STATUS_NO_ACK;
|
|
case DIAG_TX_RX_STATUS_OK:
|
|
return DIAG_TX_STATUS_ACK;
|
|
}
|
|
|
|
return DIAG_TX_STATUS_FAIL;
|
|
}
|
|
|
|
/**
|
|
* qdf_subtype_to_wlan_main_tag() - Convert qdf subtype to wlan main tag
|
|
* @subtype: EAPoL key subtype
|
|
*
|
|
* Return: Wlan main tag subtype
|
|
*/
|
|
static int qdf_subtype_to_wlan_main_tag(enum qdf_proto_subtype subtype)
|
|
{
|
|
switch (subtype) {
|
|
case QDF_PROTO_DHCP_DISCOVER:
|
|
return WLAN_CONN_DIAG_DHCP_DISC_EVENT;
|
|
case QDF_PROTO_DHCP_REQUEST:
|
|
return WLAN_CONN_DIAG_DHCP_REQUEST_EVENT;
|
|
case QDF_PROTO_DHCP_OFFER:
|
|
return WLAN_CONN_DIAG_DHCP_OFFER_EVENT;
|
|
case QDF_PROTO_DHCP_ACK:
|
|
return WLAN_CONN_DIAG_DHCP_ACK_EVENT;
|
|
case QDF_PROTO_DHCP_NACK:
|
|
return WLAN_CONN_DIAG_DHCP_NACK_EVENT;
|
|
case QDF_PROTO_EAPOL_M1:
|
|
return WLAN_CONN_DIAG_EAPOL_M1_EVENT;
|
|
case QDF_PROTO_EAPOL_M2:
|
|
return WLAN_CONN_DIAG_EAPOL_M2_EVENT;
|
|
case QDF_PROTO_EAPOL_M3:
|
|
return WLAN_CONN_DIAG_EAPOL_M3_EVENT;
|
|
case QDF_PROTO_EAPOL_M4:
|
|
return WLAN_CONN_DIAG_EAPOL_M4_EVENT;
|
|
case QDF_PROTO_EAP_REQUEST:
|
|
return WLAN_CONN_DIAG_EAP_REQ_EVENT;
|
|
case QDF_PROTO_EAP_RESPONSE:
|
|
return WLAN_CONN_DIAG_EAP_RESP_EVENT;
|
|
case QDF_PROTO_EAP_SUCCESS:
|
|
return WLAN_CONN_DIAG_EAP_SUCC_EVENT;
|
|
case QDF_PROTO_EAP_FAILURE:
|
|
return WLAN_CONN_DIAG_EAP_FAIL_EVENT;
|
|
case QDF_PROTO_EAPOL_START:
|
|
return WLAN_CONN_DIAG_EAP_START_EVENT;
|
|
default:
|
|
return WLAN_CONN_DIAG_MAX;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* qdf_get_wlan_eap_code() - Get EAP code
|
|
* @data: skb data pointer
|
|
*
|
|
* Return: EAP code value
|
|
*/
|
|
static int qdf_get_wlan_eap_code(uint8_t *data)
|
|
{
|
|
uint8_t code = *(data + EAP_CODE_OFFSET);
|
|
|
|
switch (code) {
|
|
case QDF_EAP_REQUEST:
|
|
return WLAN_CONN_DIAG_EAP_REQ_EVENT;
|
|
case QDF_EAP_RESPONSE:
|
|
return WLAN_CONN_DIAG_EAP_RESP_EVENT;
|
|
case QDF_EAP_SUCCESS:
|
|
return WLAN_CONN_DIAG_EAP_SUCC_EVENT;
|
|
case QDF_EAP_FAILURE:
|
|
return WLAN_CONN_DIAG_EAP_FAIL_EVENT;
|
|
default:
|
|
return WLAN_CONN_DIAG_MAX;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* qdf_eapol_get_key_type() - Get EAPOL key type
|
|
* @data: skb data pointer
|
|
* @subtype: EAPoL key subtype
|
|
*
|
|
* Return: EAPOL key type
|
|
*/
|
|
static
|
|
uint8_t qdf_eapol_get_key_type(uint8_t *data, enum qdf_proto_subtype subtype)
|
|
{
|
|
uint16_t key_info = *(uint16_t *)(data + EAPOL_KEY_INFO_OFFSET);
|
|
|
|
/* If key type is PTK, key type will be set in EAPOL Key info */
|
|
if (key_info & EAPOL_KEY_TYPE_MASK)
|
|
return qdf_subtype_to_wlan_main_tag(subtype);
|
|
else if (key_info & EAPOL_KEY_ENCRYPTED_MASK)
|
|
return WLAN_CONN_DIAG_GTK_M1_EVENT;
|
|
else
|
|
return WLAN_CONN_DIAG_GTK_M2_EVENT;
|
|
}
|
|
|
|
/**
|
|
* qdf_skip_wlan_connectivity_log() - Check if connectivity log need to skip
|
|
* @type: Protocol type
|
|
* @subtype: Protocol subtype
|
|
* @dir: Rx or Tx
|
|
* @op_mode: Vdev Operation mode
|
|
*
|
|
* Return: true or false
|
|
*/
|
|
static inline
|
|
bool qdf_skip_wlan_connectivity_log(enum qdf_proto_type type,
|
|
enum qdf_proto_subtype subtype,
|
|
enum qdf_proto_dir dir,
|
|
enum QDF_OPMODE op_mode)
|
|
{
|
|
if (op_mode != QDF_STA_MODE)
|
|
return true;
|
|
|
|
if (dir == QDF_RX && type == QDF_PROTO_TYPE_DHCP &&
|
|
(subtype == QDF_PROTO_DHCP_DISCOVER ||
|
|
subtype == QDF_PROTO_DHCP_REQUEST))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* qdf_fill_wlan_connectivity_log() - Fill and queue protocol packet to logging
|
|
* the logging queue
|
|
* @type: Protocol type
|
|
* @subtype: Protocol subtype
|
|
* @dir: Rx or Tx
|
|
* @qdf_tx_status: Tx completion status
|
|
* @op_mode: Vdev Operation mode
|
|
* @vdev_id: DP vdev ID
|
|
* @data: skb data pointer
|
|
*
|
|
* Return: None
|
|
*/
|
|
static
|
|
void qdf_fill_wlan_connectivity_log(enum qdf_proto_type type,
|
|
enum qdf_proto_subtype subtype,
|
|
enum qdf_proto_dir dir,
|
|
enum qdf_dp_tx_rx_status qdf_tx_status,
|
|
enum QDF_OPMODE op_mode,
|
|
uint8_t vdev_id, uint8_t *data)
|
|
{
|
|
uint8_t pkt_type;
|
|
|
|
WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_packet_info);
|
|
|
|
if (qdf_skip_wlan_connectivity_log(type, subtype, dir, op_mode))
|
|
return;
|
|
|
|
qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event));
|
|
|
|
wlan_diag_event.diag_cmn.timestamp_us =
|
|
qdf_get_time_of_the_day_ms() * 1000;
|
|
wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get());
|
|
wlan_diag_event.diag_cmn.vdev_id = vdev_id;
|
|
|
|
wlan_diag_event.version = DIAG_MGMT_VERSION;
|
|
|
|
if (type == QDF_PROTO_TYPE_DHCP) {
|
|
wlan_diag_event.subtype =
|
|
qdf_subtype_to_wlan_main_tag(subtype);
|
|
} else if (type == QDF_PROTO_TYPE_EAPOL) {
|
|
pkt_type = *(data + EAPOL_PACKET_TYPE_OFFSET);
|
|
if (pkt_type == EAPOL_PACKET_TYPE_EAP) {
|
|
wlan_diag_event.subtype =
|
|
qdf_get_wlan_eap_code(data);
|
|
wlan_diag_event.eap_type =
|
|
*(data + EAP_TYPE_OFFSET);
|
|
wlan_diag_event.eap_len =
|
|
qdf_ntohs(*(uint16_t *)(data + EAP_LENGTH_OFFSET));
|
|
} else if (pkt_type == EAPOL_PACKET_TYPE_KEY) {
|
|
wlan_diag_event.subtype =
|
|
qdf_eapol_get_key_type(data, subtype);
|
|
} else if (pkt_type == EAPOL_PACKET_TYPE_START) {
|
|
wlan_diag_event.subtype =
|
|
WLAN_CONN_DIAG_EAP_START_EVENT;
|
|
wlan_diag_event.eap_len =
|
|
qdf_ntohs(*(uint16_t *)(data + EAPOL_PKT_LEN_OFFSET));
|
|
} else {
|
|
return;
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
/*Tx completion status needs to be logged*/
|
|
if (dir == QDF_TX)
|
|
wlan_diag_event.tx_status =
|
|
wlan_get_diag_tx_status(qdf_tx_status);
|
|
|
|
WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_CONN_DP);
|
|
}
|
|
|
|
#else
|
|
static inline
|
|
void qdf_fill_wlan_connectivity_log(enum qdf_proto_type type,
|
|
enum qdf_proto_subtype subtype,
|
|
enum qdf_proto_dir dir,
|
|
enum qdf_dp_tx_rx_status qdf_tx_status,
|
|
enum QDF_OPMODE op_mode,
|
|
uint8_t vdev_id, uint8_t *data)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* qdf_log_eapol_pkt() - log EAPOL packet
|
|
* @vdev_id: ID of the vdev
|
|
* @skb: skb pointer
|
|
* @dir: direction
|
|
* @pdev_id: ID of the pdev
|
|
* @op_mode: Vdev Operation mode
|
|
*
|
|
* Return: true/false
|
|
*/
|
|
static bool qdf_log_eapol_pkt(uint8_t vdev_id, struct sk_buff *skb,
|
|
enum qdf_proto_dir dir, uint8_t pdev_id,
|
|
enum QDF_OPMODE op_mode)
|
|
{
|
|
enum qdf_proto_subtype subtype;
|
|
uint32_t dp_eap_trace;
|
|
uint32_t dp_eap_event;
|
|
|
|
dp_eap_trace = qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_EAPOL;
|
|
dp_eap_event = qdf_dp_get_proto_event_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_EAPOL;
|
|
|
|
if (!dp_eap_trace && !dp_eap_event)
|
|
return false;
|
|
|
|
if (!((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_EAPOL ==
|
|
QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
|
|
(dir == QDF_RX && qdf_nbuf_is_ipv4_eapol_pkt(skb) == true)))
|
|
return false;
|
|
|
|
subtype = qdf_nbuf_get_eapol_subtype(skb);
|
|
|
|
if (dp_eap_event && dir == QDF_RX) {
|
|
qdf_dp_log_proto_pkt_info(skb->data + QDF_NBUF_SRC_MAC_OFFSET,
|
|
skb->data + QDF_NBUF_DEST_MAC_OFFSET,
|
|
QDF_PROTO_TYPE_EAPOL, subtype, dir,
|
|
QDF_TRACE_DEFAULT_MSDU_ID,
|
|
QDF_TX_RX_STATUS_INVALID);
|
|
qdf_fill_wlan_connectivity_log(QDF_PROTO_TYPE_EAPOL, subtype,
|
|
QDF_RX, 0, op_mode,
|
|
vdev_id, skb->data);
|
|
}
|
|
|
|
if (dp_eap_trace) {
|
|
QDF_NBUF_CB_DP_TRACE_PRINT(skb) = 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;
|
|
|
|
DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_EAPOL_PACKET_RECORD,
|
|
vdev_id,
|
|
skb->data +
|
|
QDF_NBUF_SRC_MAC_OFFSET,
|
|
skb->data +
|
|
QDF_NBUF_DEST_MAC_OFFSET,
|
|
QDF_PROTO_TYPE_EAPOL, subtype,
|
|
dir, pdev_id, true, 0));
|
|
|
|
switch (subtype) {
|
|
case QDF_PROTO_EAPOL_M1:
|
|
g_qdf_dp_trace_data.eapol_m1++;
|
|
break;
|
|
case QDF_PROTO_EAPOL_M2:
|
|
g_qdf_dp_trace_data.eapol_m2++;
|
|
break;
|
|
case QDF_PROTO_EAPOL_M3:
|
|
g_qdf_dp_trace_data.eapol_m3++;
|
|
break;
|
|
case QDF_PROTO_EAPOL_M4:
|
|
g_qdf_dp_trace_data.eapol_m4++;
|
|
break;
|
|
default:
|
|
g_qdf_dp_trace_data.eapol_others++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* qdf_log_dhcp_pkt() - log DHCP packet
|
|
* @vdev_id: ID of the vdev
|
|
* @skb: skb pointer
|
|
* @dir: direction
|
|
* @pdev_id: ID of the pdev
|
|
* @op_mode: Vdev Operation mode
|
|
*
|
|
* Return: true/false
|
|
*/
|
|
static bool qdf_log_dhcp_pkt(uint8_t vdev_id, struct sk_buff *skb,
|
|
enum qdf_proto_dir dir, uint8_t pdev_id,
|
|
enum QDF_OPMODE op_mode)
|
|
{
|
|
enum qdf_proto_subtype subtype = QDF_PROTO_INVALID;
|
|
uint32_t dp_dhcp_trace;
|
|
uint32_t dp_dhcp_event;
|
|
|
|
dp_dhcp_trace = qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_DHCP;
|
|
dp_dhcp_event = qdf_dp_get_proto_event_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_DHCP;
|
|
|
|
if (!dp_dhcp_trace && !dp_dhcp_event)
|
|
return false;
|
|
|
|
if (!((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP ==
|
|
QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
|
|
(dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(skb) == true)))
|
|
return false;
|
|
|
|
subtype = qdf_nbuf_get_dhcp_subtype(skb);
|
|
|
|
if (dp_dhcp_event && dir == QDF_RX) {
|
|
qdf_dp_log_proto_pkt_info(skb->data + QDF_NBUF_SRC_MAC_OFFSET,
|
|
skb->data + QDF_NBUF_DEST_MAC_OFFSET,
|
|
QDF_PROTO_TYPE_DHCP, subtype, dir,
|
|
QDF_TRACE_DEFAULT_MSDU_ID,
|
|
QDF_TX_RX_STATUS_INVALID);
|
|
qdf_fill_wlan_connectivity_log(QDF_PROTO_TYPE_DHCP, subtype,
|
|
QDF_RX, 0, op_mode, vdev_id, 0);
|
|
}
|
|
|
|
if (dp_dhcp_trace) {
|
|
QDF_NBUF_CB_DP_TRACE_PRINT(skb) = 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;
|
|
|
|
DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_DHCP_PACKET_RECORD,
|
|
vdev_id,
|
|
skb->data +
|
|
QDF_NBUF_SRC_MAC_OFFSET,
|
|
skb->data +
|
|
QDF_NBUF_DEST_MAC_OFFSET,
|
|
QDF_PROTO_TYPE_DHCP, subtype,
|
|
dir, pdev_id, true, 0));
|
|
|
|
switch (subtype) {
|
|
case QDF_PROTO_DHCP_DISCOVER:
|
|
g_qdf_dp_trace_data.dhcp_disc++;
|
|
break;
|
|
case QDF_PROTO_DHCP_OFFER:
|
|
g_qdf_dp_trace_data.dhcp_off++;
|
|
break;
|
|
case QDF_PROTO_DHCP_REQUEST:
|
|
g_qdf_dp_trace_data.dhcp_req++;
|
|
break;
|
|
case QDF_PROTO_DHCP_ACK:
|
|
g_qdf_dp_trace_data.dhcp_ack++;
|
|
break;
|
|
case QDF_PROTO_DHCP_NACK:
|
|
g_qdf_dp_trace_data.dhcp_nack++;
|
|
break;
|
|
default:
|
|
g_qdf_dp_trace_data.eapol_others++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* qdf_log_arp_pkt() - log ARP packet
|
|
* @vdev_id: ID of the vdev
|
|
* @skb: skb pointer
|
|
* @dir: direction
|
|
* @pdev_id: ID of the pdev
|
|
*
|
|
* Return: true/false
|
|
*/
|
|
static bool qdf_log_arp_pkt(uint8_t vdev_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_ARP) &&
|
|
((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_ARP ==
|
|
QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
|
|
(dir == QDF_RX && qdf_nbuf_is_ipv4_arp_pkt(skb) == true))) {
|
|
|
|
proto_subtype = qdf_nbuf_get_arp_subtype(skb);
|
|
QDF_NBUF_CB_DP_TRACE_PRINT(skb) = 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;
|
|
|
|
DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ARP_PACKET_RECORD,
|
|
vdev_id,
|
|
skb->data +
|
|
QDF_NBUF_SRC_MAC_OFFSET,
|
|
skb->data +
|
|
QDF_NBUF_DEST_MAC_OFFSET,
|
|
QDF_PROTO_TYPE_ARP,
|
|
proto_subtype, dir, pdev_id,
|
|
true, 0));
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
bool qdf_dp_trace_log_pkt(uint8_t vdev_id, struct sk_buff *skb,
|
|
enum qdf_proto_dir dir, uint8_t pdev_id,
|
|
enum QDF_OPMODE op_mode)
|
|
{
|
|
if (!qdf_dp_get_proto_bitmap() && !qdf_dp_get_proto_event_bitmap())
|
|
return false;
|
|
if (qdf_log_arp_pkt(vdev_id, skb, dir, pdev_id))
|
|
return true;
|
|
if (qdf_log_dhcp_pkt(vdev_id, skb, dir, pdev_id, op_mode))
|
|
return true;
|
|
if (qdf_log_eapol_pkt(vdev_id, skb, dir, pdev_id, op_mode))
|
|
return true;
|
|
if (qdf_log_icmp_pkt(vdev_id, skb, dir, pdev_id))
|
|
return true;
|
|
if (qdf_log_icmpv6_pkt(vdev_id, skb, dir, pdev_id))
|
|
return true;
|
|
return false;
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_log_pkt);
|
|
|
|
void qdf_dp_display_mgmt_pkt(struct qdf_dp_trace_record_s *record,
|
|
uint16_t index, uint8_t pdev_id, uint8_t info)
|
|
{
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_mgmt_buf *buf =
|
|
(struct qdf_dp_trace_mgmt_buf *)record->data;
|
|
|
|
qdf_mem_zero(prepend_str, sizeof(prepend_str));
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, info, record);
|
|
|
|
DPTRACE_PRINT("%s [%d] [%s %s]",
|
|
prepend_str,
|
|
buf->vdev_id,
|
|
qdf_dp_type_to_str(buf->type),
|
|
qdf_dp_subtype_to_str(buf->subtype));
|
|
}
|
|
qdf_export_symbol(qdf_dp_display_mgmt_pkt);
|
|
|
|
|
|
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)
|
|
{
|
|
struct qdf_dp_trace_mgmt_buf buf;
|
|
int buf_size = sizeof(struct qdf_dp_trace_mgmt_buf);
|
|
|
|
if (qdf_dp_enable_check(NULL, code, QDF_NA) == false)
|
|
return;
|
|
|
|
if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
|
|
QDF_BUG(0);
|
|
|
|
buf.type = type;
|
|
buf.subtype = subtype;
|
|
buf.vdev_id = vdev_id;
|
|
qdf_dp_add_record(code, pdev_id, (uint8_t *)&buf, buf_size,
|
|
NULL, 0, true);
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_mgmt_pkt);
|
|
|
|
static void
|
|
qdf_dpt_display_credit_record_debugfs(qdf_debugfs_file_t file,
|
|
struct qdf_dp_trace_record_s *record,
|
|
uint32_t index)
|
|
{
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_credit_record *buf =
|
|
(struct qdf_dp_trace_credit_record *)record->data;
|
|
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, 0, record);
|
|
if (buf->operation == QDF_OP_NA)
|
|
qdf_debugfs_printf(file, "%s [%s] [T: %d G0: %d G1: %d]\n",
|
|
prepend_str,
|
|
qdf_dp_credit_source_to_str(buf->source),
|
|
buf->total_credits, buf->g0_credit,
|
|
buf->g1_credit);
|
|
else
|
|
qdf_debugfs_printf(file,
|
|
"%s [%s] [T: %d G0: %d G1: %d] [%s %d]\n",
|
|
prepend_str,
|
|
qdf_dp_credit_source_to_str(buf->source),
|
|
buf->total_credits, buf->g0_credit,
|
|
buf->g1_credit,
|
|
qdf_dp_operation_to_str(buf->operation),
|
|
buf->delta);
|
|
}
|
|
|
|
void qdf_dp_display_credit_record(struct qdf_dp_trace_record_s *record,
|
|
uint16_t index, uint8_t pdev_id, uint8_t info)
|
|
{
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_credit_record *buf =
|
|
(struct qdf_dp_trace_credit_record *)record->data;
|
|
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, info, record);
|
|
if (buf->operation == QDF_OP_NA)
|
|
DPTRACE_PRINT("%s [%s] [T: %d G0: %d G1: %d]",
|
|
prepend_str,
|
|
qdf_dp_credit_source_to_str(buf->source),
|
|
buf->total_credits, buf->g0_credit,
|
|
buf->g1_credit);
|
|
else
|
|
DPTRACE_PRINT("%s [%s] [T: %d G0: %d G1: %d] [%s %d]",
|
|
prepend_str,
|
|
qdf_dp_credit_source_to_str(buf->source),
|
|
buf->total_credits, buf->g0_credit,
|
|
buf->g1_credit,
|
|
qdf_dp_operation_to_str(buf->operation),
|
|
buf->delta);
|
|
}
|
|
|
|
void qdf_dp_trace_credit_record(enum QDF_CREDIT_UPDATE_SOURCE source,
|
|
enum QDF_CREDIT_OPERATION operation,
|
|
int delta, int total_credits,
|
|
int g0_credit, int g1_credit)
|
|
{
|
|
struct qdf_dp_trace_credit_record buf;
|
|
int buf_size = sizeof(struct qdf_dp_trace_credit_record);
|
|
enum QDF_DP_TRACE_ID code = QDF_DP_TRACE_TX_CREDIT_RECORD;
|
|
|
|
if (qdf_dp_enable_check(NULL, code, QDF_NA) == false)
|
|
return;
|
|
|
|
if (!(qdf_dp_get_proto_bitmap() & QDF_HL_CREDIT_TRACKING))
|
|
return;
|
|
|
|
if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
|
|
QDF_BUG(0);
|
|
|
|
buf.source = source;
|
|
buf.operation = operation;
|
|
buf.delta = delta;
|
|
buf.total_credits = total_credits;
|
|
buf.g0_credit = g0_credit;
|
|
buf.g1_credit = g1_credit;
|
|
|
|
qdf_dp_add_record(code, QDF_TRACE_DEFAULT_PDEV_ID, (uint8_t *)&buf,
|
|
buf_size, NULL, 0, false);
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_credit_record);
|
|
|
|
void qdf_dp_display_event_record(struct qdf_dp_trace_record_s *record,
|
|
uint16_t index, uint8_t pdev_id, uint8_t info)
|
|
{
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_event_buf *buf =
|
|
(struct qdf_dp_trace_event_buf *)record->data;
|
|
|
|
qdf_mem_zero(prepend_str, sizeof(prepend_str));
|
|
qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, info, record);
|
|
|
|
DPTRACE_PRINT("%s [%d] [%s %s]",
|
|
prepend_str,
|
|
buf->vdev_id,
|
|
qdf_dp_type_to_str(buf->type),
|
|
qdf_dp_subtype_to_str(buf->subtype));
|
|
}
|
|
qdf_export_symbol(qdf_dp_display_event_record);
|
|
|
|
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)
|
|
{
|
|
struct qdf_dp_trace_event_buf buf;
|
|
int buf_size = sizeof(struct qdf_dp_trace_event_buf);
|
|
|
|
if (qdf_dp_enable_check(NULL, code, QDF_NA) == false)
|
|
return;
|
|
|
|
if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
|
|
QDF_BUG(0);
|
|
|
|
buf.type = type;
|
|
buf.subtype = subtype;
|
|
buf.vdev_id = vdev_id;
|
|
qdf_dp_add_record(code, pdev_id,
|
|
(uint8_t *)&buf, buf_size, NULL, 0, true);
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_record_event);
|
|
|
|
|
|
void qdf_dp_display_proto_pkt(struct qdf_dp_trace_record_s *record,
|
|
uint16_t index, uint8_t pdev_id, uint8_t info)
|
|
{
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_proto_buf *buf =
|
|
(struct qdf_dp_trace_proto_buf *)record->data;
|
|
|
|
qdf_mem_zero(prepend_str, sizeof(prepend_str));
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, info, record);
|
|
DPTRACE_PRINT("%s [%d] [%s] SA: "
|
|
QDF_MAC_ADDR_FMT " %s DA:"
|
|
QDF_MAC_ADDR_FMT " proto priv data = %08x",
|
|
prepend_str,
|
|
buf->vdev_id,
|
|
qdf_dp_subtype_to_str(buf->subtype),
|
|
QDF_MAC_ADDR_REF(buf->sa.bytes),
|
|
qdf_dp_dir_to_str(buf->dir),
|
|
QDF_MAC_ADDR_REF(buf->da.bytes),
|
|
buf->proto_priv_data);
|
|
}
|
|
qdf_export_symbol(qdf_dp_display_proto_pkt);
|
|
|
|
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, bool print, uint32_t proto_priv_data)
|
|
{
|
|
struct qdf_dp_trace_proto_buf buf;
|
|
int buf_size = sizeof(struct qdf_dp_trace_proto_buf);
|
|
|
|
if (qdf_dp_enable_check(NULL, code, dir) == false)
|
|
return;
|
|
|
|
if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
|
|
QDF_BUG(0);
|
|
|
|
memcpy(&buf.sa, sa, QDF_NET_ETH_LEN);
|
|
memcpy(&buf.da, da, QDF_NET_ETH_LEN);
|
|
buf.dir = dir;
|
|
buf.type = type;
|
|
buf.subtype = subtype;
|
|
buf.vdev_id = vdev_id;
|
|
buf.proto_priv_data = proto_priv_data;
|
|
qdf_dp_add_record(code, pdev_id,
|
|
(uint8_t *)&buf, buf_size, NULL, 0, print);
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_proto_pkt);
|
|
|
|
void qdf_dp_display_ptr_record(struct qdf_dp_trace_record_s *record,
|
|
uint16_t index, uint8_t pdev_id, uint8_t info)
|
|
{
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_ptr_buf *buf =
|
|
(struct qdf_dp_trace_ptr_buf *)record->data;
|
|
bool is_free_pkt_ptr_record = false;
|
|
|
|
if ((record->code == QDF_DP_TRACE_FREE_PACKET_PTR_RECORD) ||
|
|
(record->code == QDF_DP_TRACE_LI_DP_FREE_PACKET_PTR_RECORD))
|
|
is_free_pkt_ptr_record = true;
|
|
|
|
qdf_mem_zero(prepend_str, sizeof(prepend_str));
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, info, record);
|
|
|
|
if (loc < sizeof(prepend_str))
|
|
scnprintf(&prepend_str[loc], sizeof(prepend_str) - loc,
|
|
"[msdu id %d %s %d]",
|
|
buf->msdu_id,
|
|
is_free_pkt_ptr_record ? "status" : "vdev_id",
|
|
buf->status);
|
|
|
|
if (info & QDF_DP_TRACE_RECORD_INFO_LIVE) {
|
|
/* In live mode donot dump the contents of the cookie */
|
|
DPTRACE_PRINT("%s", prepend_str);
|
|
} else {
|
|
dump_dp_hex_trace(prepend_str, (uint8_t *)&buf->cookie,
|
|
sizeof(buf->cookie));
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_dp_display_ptr_record);
|
|
|
|
static
|
|
enum qdf_proto_type qdf_dp_get_pkt_proto_type(qdf_nbuf_t nbuf)
|
|
{
|
|
uint8_t pkt_type;
|
|
|
|
if (!nbuf)
|
|
return QDF_PROTO_TYPE_MAX;
|
|
|
|
if (qdf_nbuf_data_is_dns_query(nbuf) ||
|
|
qdf_nbuf_data_is_dns_response(nbuf))
|
|
return QDF_PROTO_TYPE_DNS;
|
|
|
|
pkt_type = QDF_NBUF_CB_GET_PACKET_TYPE(nbuf);
|
|
|
|
switch (pkt_type) {
|
|
case QDF_NBUF_CB_PACKET_TYPE_EAPOL:
|
|
return QDF_PROTO_TYPE_EAPOL;
|
|
case QDF_NBUF_CB_PACKET_TYPE_ARP:
|
|
return QDF_PROTO_TYPE_ARP;
|
|
case QDF_NBUF_CB_PACKET_TYPE_DHCP:
|
|
return QDF_PROTO_TYPE_DHCP;
|
|
default:
|
|
return QDF_PROTO_TYPE_MAX;
|
|
}
|
|
}
|
|
|
|
static
|
|
enum qdf_proto_subtype qdf_dp_get_pkt_subtype(qdf_nbuf_t nbuf,
|
|
enum qdf_proto_type pkt_type)
|
|
{
|
|
switch (pkt_type) {
|
|
case QDF_PROTO_TYPE_EAPOL:
|
|
return qdf_nbuf_get_eapol_subtype(nbuf);
|
|
case QDF_PROTO_TYPE_ARP:
|
|
return qdf_nbuf_get_arp_subtype(nbuf);
|
|
case QDF_PROTO_TYPE_DHCP:
|
|
return qdf_nbuf_get_dhcp_subtype(nbuf);
|
|
case QDF_PROTO_TYPE_DNS:
|
|
return (qdf_nbuf_data_is_dns_query(nbuf)) ?
|
|
QDF_PROTO_DNS_QUERY : QDF_PROTO_DNS_RES;
|
|
default:
|
|
return QDF_PROTO_INVALID;
|
|
}
|
|
}
|
|
|
|
static
|
|
bool qdf_dp_proto_log_enable_check(enum qdf_proto_type pkt_type,
|
|
uint16_t status)
|
|
{
|
|
if (pkt_type == QDF_PROTO_TYPE_MAX)
|
|
return false;
|
|
|
|
switch (pkt_type) {
|
|
case QDF_PROTO_TYPE_EAPOL:
|
|
return qdf_dp_get_proto_event_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_EAPOL;
|
|
case QDF_PROTO_TYPE_DHCP:
|
|
return qdf_dp_get_proto_event_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_DHCP;
|
|
case QDF_PROTO_TYPE_ARP:
|
|
if (status == QDF_TX_RX_STATUS_OK)
|
|
return false;
|
|
else
|
|
return qdf_dp_get_proto_event_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_ARP;
|
|
case QDF_PROTO_TYPE_DNS:
|
|
if (status == QDF_TX_RX_STATUS_OK)
|
|
return false;
|
|
else
|
|
return qdf_dp_get_proto_event_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_DNS;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void qdf_dp_track_noack_check(qdf_nbuf_t nbuf, enum qdf_proto_subtype *subtype)
|
|
{
|
|
enum qdf_proto_type pkt_type = qdf_dp_get_pkt_proto_type(nbuf);
|
|
uint16_t dp_track = 0;
|
|
|
|
switch (pkt_type) {
|
|
case QDF_PROTO_TYPE_EAPOL:
|
|
dp_track = qdf_dp_get_proto_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_EAPOL;
|
|
break;
|
|
case QDF_PROTO_TYPE_DHCP:
|
|
dp_track = qdf_dp_get_proto_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_DHCP;
|
|
break;
|
|
case QDF_PROTO_TYPE_ARP:
|
|
dp_track = qdf_dp_get_proto_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_ARP;
|
|
break;
|
|
case QDF_PROTO_TYPE_DNS:
|
|
dp_track = qdf_dp_get_proto_bitmap() &
|
|
QDF_NBUF_PKT_TRAC_TYPE_DNS;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!dp_track) {
|
|
*subtype = QDF_PROTO_INVALID;
|
|
return;
|
|
}
|
|
|
|
*subtype = qdf_dp_get_pkt_subtype(nbuf, pkt_type);
|
|
}
|
|
qdf_export_symbol(qdf_dp_track_noack_check);
|
|
|
|
enum qdf_dp_tx_rx_status qdf_dp_get_status_from_a_status(uint8_t status)
|
|
{
|
|
if (status == QDF_A_STATUS_ERROR)
|
|
return QDF_TX_RX_STATUS_INVALID;
|
|
else if (status == QDF_A_STATUS_OK)
|
|
return QDF_TX_RX_STATUS_OK;
|
|
else
|
|
return QDF_TX_RX_STATUS_MAX;
|
|
}
|
|
qdf_export_symbol(qdf_dp_get_status_from_a_status);
|
|
|
|
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 buf_arg_status,
|
|
enum qdf_dp_tx_rx_status qdf_tx_status,
|
|
enum QDF_OPMODE op_mode)
|
|
{
|
|
struct qdf_dp_trace_ptr_buf buf;
|
|
int buf_size = sizeof(struct qdf_dp_trace_ptr_buf);
|
|
enum qdf_proto_type pkt_type;
|
|
enum qdf_proto_subtype subtype;
|
|
|
|
pkt_type = qdf_dp_get_pkt_proto_type(nbuf);
|
|
if ((code == QDF_DP_TRACE_FREE_PACKET_PTR_RECORD ||
|
|
code == QDF_DP_TRACE_LI_DP_FREE_PACKET_PTR_RECORD) &&
|
|
qdf_dp_proto_log_enable_check(pkt_type, qdf_tx_status)) {
|
|
subtype = qdf_dp_get_pkt_subtype(nbuf, pkt_type);
|
|
qdf_dp_log_proto_pkt_info(nbuf->data + QDF_NBUF_SRC_MAC_OFFSET,
|
|
nbuf->data + QDF_NBUF_DEST_MAC_OFFSET,
|
|
pkt_type, subtype,
|
|
QDF_TX, msdu_id, qdf_tx_status);
|
|
qdf_fill_wlan_connectivity_log(pkt_type, subtype,
|
|
QDF_TX, qdf_tx_status, op_mode,
|
|
QDF_NBUF_CB_TX_VDEV_CTX(nbuf),
|
|
nbuf->data);
|
|
}
|
|
|
|
if (qdf_dp_enable_check(nbuf, code, QDF_TX) == false)
|
|
return;
|
|
|
|
if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
|
|
QDF_BUG(0);
|
|
|
|
qdf_mem_copy(&buf.cookie, data, size);
|
|
buf.msdu_id = msdu_id;
|
|
buf.status = buf_arg_status;
|
|
qdf_dp_add_record(code, pdev_id, (uint8_t *)&buf, buf_size, NULL, 0,
|
|
QDF_NBUF_CB_DP_TRACE_PRINT(nbuf));
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_ptr);
|
|
|
|
void qdf_dp_trace_data_pkt(qdf_nbuf_t nbuf, uint8_t pdev_id,
|
|
enum QDF_DP_TRACE_ID code, uint16_t msdu_id,
|
|
enum qdf_proto_dir dir)
|
|
{
|
|
struct qdf_dp_trace_data_buf buf;
|
|
enum qdf_proto_type pkt_type;
|
|
|
|
pkt_type = qdf_dp_get_pkt_proto_type(nbuf);
|
|
if (code == QDF_DP_TRACE_DROP_PACKET_RECORD &&
|
|
qdf_dp_proto_log_enable_check(pkt_type, QDF_TX_RX_STATUS_DROP))
|
|
qdf_dp_log_proto_pkt_info(nbuf->data + QDF_NBUF_SRC_MAC_OFFSET,
|
|
nbuf->data + QDF_NBUF_DEST_MAC_OFFSET,
|
|
pkt_type,
|
|
qdf_dp_get_pkt_subtype(nbuf, pkt_type),
|
|
QDF_TX, msdu_id,
|
|
QDF_TX_RX_STATUS_DROP);
|
|
|
|
buf.msdu_id = msdu_id;
|
|
if (!qdf_dp_enable_check(nbuf, code, dir))
|
|
return;
|
|
|
|
qdf_dp_add_record(code, pdev_id,
|
|
nbuf ? qdf_nbuf_data(nbuf) : NULL,
|
|
nbuf ? nbuf->len - nbuf->data_len : 0,
|
|
(uint8_t *)&buf, sizeof(struct qdf_dp_trace_data_buf),
|
|
(nbuf) ? QDF_NBUF_CB_DP_TRACE_PRINT(nbuf) : false);
|
|
}
|
|
|
|
qdf_export_symbol(qdf_dp_trace_data_pkt);
|
|
|
|
void qdf_dp_display_record(struct qdf_dp_trace_record_s *record,
|
|
uint16_t index, uint8_t pdev_id, uint8_t info)
|
|
{
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
|
|
if (!(pdev_id == QDF_TRACE_DEFAULT_PDEV_ID ||
|
|
pdev_id == record->pdev_id))
|
|
return;
|
|
|
|
qdf_mem_zero(prepend_str, sizeof(prepend_str));
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, info, record);
|
|
|
|
switch (record->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_CE_FAST_PACKET_ERR_RECORD:
|
|
DPTRACE_PRINT(" %s: CE Fast Packet Error", prepend_str);
|
|
break;
|
|
case QDF_DP_TRACE_LI_DP_NULL_RX_PACKET_RECORD:
|
|
default:
|
|
dump_dp_hex_trace(prepend_str, record->data, record->size);
|
|
break;
|
|
};
|
|
}
|
|
qdf_export_symbol(qdf_dp_display_record);
|
|
|
|
void
|
|
qdf_dp_display_data_pkt_record(struct qdf_dp_trace_record_s *record,
|
|
uint16_t rec_index, uint8_t pdev_id,
|
|
uint8_t info)
|
|
{
|
|
int loc;
|
|
char prepend_str[DP_TRACE_META_DATA_STRLEN + 10];
|
|
struct qdf_dp_trace_data_buf *buf =
|
|
(struct qdf_dp_trace_data_buf *)record->data;
|
|
|
|
qdf_mem_zero(prepend_str, sizeof(prepend_str));
|
|
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
rec_index, info, record);
|
|
if (loc < sizeof(prepend_str))
|
|
loc += snprintf(&prepend_str[loc], sizeof(prepend_str) - loc,
|
|
"[%d]", buf->msdu_id);
|
|
dump_dp_hex_trace(prepend_str,
|
|
&record->data[sizeof(struct qdf_dp_trace_data_buf)],
|
|
record->size);
|
|
}
|
|
|
|
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)
|
|
{
|
|
|
|
if (qdf_dp_enable_check(nbuf, code, dir) == false)
|
|
return;
|
|
|
|
qdf_dp_add_record(code, pdev_id, nbuf ? qdf_nbuf_data(nbuf) : NULL,
|
|
size, NULL, 0,
|
|
(nbuf) ? QDF_NBUF_CB_DP_TRACE_PRINT(nbuf) : false);
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace);
|
|
|
|
void qdf_dp_trace_spin_lock_init(void)
|
|
{
|
|
spin_lock_init(&l_dp_trace_lock);
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_spin_lock_init);
|
|
|
|
void qdf_dp_trace_disable_live_mode(void)
|
|
{
|
|
g_qdf_dp_trace_data.force_live_mode = 0;
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_disable_live_mode);
|
|
|
|
void qdf_dp_trace_enable_live_mode(void)
|
|
{
|
|
g_qdf_dp_trace_data.force_live_mode = 1;
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_enable_live_mode);
|
|
|
|
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.dump_counter = 0;
|
|
g_qdf_dp_trace_data.num_records_to_dump = MAX_QDF_DP_TRACE_RECORDS;
|
|
if (g_qdf_dp_trace_data.enable)
|
|
memset(g_qdf_dp_trace_tbl, 0,
|
|
MAX_QDF_DP_TRACE_RECORDS *
|
|
sizeof(struct qdf_dp_trace_record_s));
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_clear_buffer);
|
|
|
|
void qdf_dp_trace_dump_stats(void)
|
|
{
|
|
DPTRACE_PRINT("STATS |DPT: tx %u rx %u 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)",
|
|
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,
|
|
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_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, "%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)
|
|
{
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_proto_buf *buf =
|
|
(struct qdf_dp_trace_proto_buf *)record->data;
|
|
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, 0, record);
|
|
qdf_debugfs_printf(file, "%s [%d] [%s] SA: "
|
|
QDF_MAC_ADDR_FMT " %s DA: "
|
|
QDF_MAC_ADDR_FMT,
|
|
prepend_str,
|
|
buf->vdev_id,
|
|
qdf_dp_subtype_to_str(buf->subtype),
|
|
QDF_MAC_ADDR_REF(buf->sa.bytes),
|
|
qdf_dp_dir_to_str(buf->dir),
|
|
QDF_MAC_ADDR_REF(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)
|
|
{
|
|
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_mgmt_buf *buf =
|
|
(struct qdf_dp_trace_mgmt_buf *)record->data;
|
|
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, 0, record);
|
|
|
|
qdf_debugfs_printf(file, "%s [%d] [%s %s]\n",
|
|
prepend_str,
|
|
buf->vdev_id,
|
|
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)
|
|
{
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_event_buf *buf =
|
|
(struct qdf_dp_trace_event_buf *)record->data;
|
|
|
|
qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, 0, record);
|
|
qdf_debugfs_printf(file, "%s [%d] [%s %s]\n",
|
|
prepend_str,
|
|
buf->vdev_id,
|
|
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[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
int loc;
|
|
struct qdf_dp_trace_ptr_buf *buf =
|
|
(struct qdf_dp_trace_ptr_buf *)record->data;
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, 0, record);
|
|
|
|
if (loc < sizeof(prepend_str))
|
|
scnprintf(&prepend_str[loc], sizeof(prepend_str) - loc,
|
|
"[msdu id %d %s %d]",
|
|
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_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)
|
|
{
|
|
int loc;
|
|
char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE];
|
|
struct qdf_dp_trace_data_buf *buf =
|
|
(struct qdf_dp_trace_data_buf *)record->data;
|
|
|
|
loc = qdf_dp_trace_fill_meta_str(prepend_str, sizeof(prepend_str),
|
|
index, 0, record);
|
|
if (loc < sizeof(prepend_str))
|
|
loc += snprintf(&prepend_str[loc], sizeof(prepend_str) - loc,
|
|
"[%d]", buf->msdu_id);
|
|
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 rec_requested %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.num_records_to_dump,
|
|
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 g_qdf_dp_trace_data.saved_tail;
|
|
}
|
|
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;
|
|
uint16_t num_records_to_dump = g_qdf_dp_trace_data.num_records_to_dump;
|
|
|
|
if (!g_qdf_dp_trace_data.enable) {
|
|
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
|
|
"%s: Tracing Disabled", __func__);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
if (num_records_to_dump > g_qdf_dp_trace_data.num)
|
|
num_records_to_dump = g_qdf_dp_trace_data.num;
|
|
|
|
/*
|
|
* Max dp trace record size should always be less than
|
|
* QDF_DP_TRACE_PREPEND_STR_SIZE(100) + BUFFER_SIZE(121).
|
|
*/
|
|
if (WARN_ON(QDF_DP_TRACE_MAX_RECORD_SIZE <
|
|
QDF_DP_TRACE_PREPEND_STR_SIZE + BUFFER_SIZE))
|
|
return QDF_STATUS_E_FAILURE;
|
|
|
|
spin_lock_bh(&l_dp_trace_lock);
|
|
p_record = g_qdf_dp_trace_tbl[i];
|
|
spin_unlock_bh(&l_dp_trace_lock);
|
|
|
|
for (;; ) {
|
|
/*
|
|
* Initially we get file as 1 page size, and
|
|
* if remaining size in file is less than one record max size,
|
|
* then return so that it gets an extra page.
|
|
*/
|
|
if ((file->size - file->count) < QDF_DP_TRACE_MAX_RECORD_SIZE) {
|
|
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_TX_CREDIT_RECORD:
|
|
qdf_dpt_display_credit_record_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: %llu %s\n",
|
|
i, p_record.time,
|
|
qdf_dp_code_to_string(p_record.code));
|
|
qdf_debugfs_printf(file, "HDD TX Timeout\n");
|
|
break;
|
|
|
|
case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
|
|
qdf_debugfs_printf(
|
|
file, "DPT: %04d: %llu %s\n",
|
|
i, p_record.time,
|
|
qdf_dp_code_to_string(p_record.code));
|
|
qdf_debugfs_printf(file, "HDD SoftAP TX Timeout\n");
|
|
break;
|
|
|
|
case QDF_DP_TRACE_CE_FAST_PACKET_ERR_RECORD:
|
|
qdf_debugfs_printf(
|
|
file, "DPT: %04d: %llu %s\n",
|
|
i, p_record.time,
|
|
qdf_dp_code_to_string(p_record.code));
|
|
qdf_debugfs_printf(file, "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:
|
|
case QDF_DP_TRACE_TX_PACKET_RECORD:
|
|
case QDF_DP_TRACE_RX_PACKET_RECORD:
|
|
case QDF_DP_TRACE_LI_DP_TX_PACKET_RECORD:
|
|
case QDF_DP_TRACE_LI_DP_RX_PACKET_RECORD:
|
|
|
|
default:
|
|
qdf_dpt_display_record_debugfs(file, &p_record, i);
|
|
break;
|
|
}
|
|
|
|
if (++g_qdf_dp_trace_data.dump_counter == num_records_to_dump)
|
|
break;
|
|
|
|
spin_lock_bh(&l_dp_trace_lock);
|
|
if (i == 0)
|
|
i = MAX_QDF_DP_TRACE_RECORDS;
|
|
|
|
i -= 1;
|
|
p_record = g_qdf_dp_trace_tbl[i];
|
|
spin_unlock_bh(&l_dp_trace_lock);
|
|
}
|
|
|
|
g_qdf_dp_trace_data.dump_counter = 0;
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
qdf_export_symbol(qdf_dpt_dump_stats_debugfs);
|
|
|
|
void qdf_dpt_set_value_debugfs(uint8_t proto_bitmap, uint8_t no_of_record,
|
|
uint8_t verbosity, uint16_t num_records_to_dump)
|
|
{
|
|
if (g_qdf_dp_trace_data.enable) {
|
|
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;
|
|
g_qdf_dp_trace_data.num_records_to_dump = num_records_to_dump;
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_dpt_set_value_debugfs);
|
|
|
|
|
|
void qdf_dp_trace_dump_all(uint32_t count, uint8_t pdev_id)
|
|
{
|
|
struct qdf_dp_trace_record_s p_record;
|
|
int32_t i, tail;
|
|
|
|
if (!g_qdf_dp_trace_data.enable) {
|
|
DPTRACE_PRINT("Tracing Disabled");
|
|
return;
|
|
}
|
|
|
|
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);
|
|
|
|
qdf_dp_trace_dump_stats();
|
|
|
|
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);
|
|
|
|
/* acquire the lock so that only one thread at a time can read
|
|
* the ring buffer
|
|
*/
|
|
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) {
|
|
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);
|
|
}
|
|
|
|
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, false);
|
|
if (i == tail)
|
|
break;
|
|
i += 1;
|
|
|
|
spin_lock_bh(&l_dp_trace_lock);
|
|
if (MAX_QDF_DP_TRACE_RECORDS == i)
|
|
i = 0;
|
|
|
|
p_record = g_qdf_dp_trace_tbl[i];
|
|
spin_unlock_bh(&l_dp_trace_lock);
|
|
}
|
|
} else {
|
|
spin_unlock_bh(&l_dp_trace_lock);
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_dump_all);
|
|
|
|
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);
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_dp_trace_throttle_live_mode);
|
|
|
|
void qdf_dp_trace_apply_tput_policy(bool is_data_traffic)
|
|
{
|
|
if (g_qdf_dp_trace_data.dynamic_verbosity_modify) {
|
|
goto check_live_mode;
|
|
return;
|
|
}
|
|
|
|
if (is_data_traffic) {
|
|
g_qdf_dp_trace_data.verbosity =
|
|
QDF_DP_TRACE_VERBOSITY_ULTRA_LOW;
|
|
} else {
|
|
g_qdf_dp_trace_data.verbosity =
|
|
g_qdf_dp_trace_data.ini_conf_verbosity;
|
|
}
|
|
check_live_mode:
|
|
qdf_dp_trace_throttle_live_mode(is_data_traffic);
|
|
}
|
|
#endif
|
|
|
|
struct qdf_print_ctrl print_ctrl_obj[MAX_PRINT_CONFIG_SUPPORTED];
|
|
|
|
struct category_name_info g_qdf_category_name[MAX_SUPPORTED_CATEGORY] = {
|
|
[QDF_MODULE_ID_TDLS] = {"tdls"},
|
|
[QDF_MODULE_ID_ACS] = {"ACS"},
|
|
[QDF_MODULE_ID_SCAN_SM] = {"scan state machine"},
|
|
[QDF_MODULE_ID_SCANENTRY] = {"scan entry"},
|
|
[QDF_MODULE_ID_WDS] = {"WDS"},
|
|
[QDF_MODULE_ID_ACTION] = {"action"},
|
|
[QDF_MODULE_ID_ROAM] = {"STA roaming"},
|
|
[QDF_MODULE_ID_INACT] = {"inactivity"},
|
|
[QDF_MODULE_ID_DOTH] = {"11h"},
|
|
[QDF_MODULE_ID_IQUE] = {"IQUE"},
|
|
[QDF_MODULE_ID_WME] = {"WME"},
|
|
[QDF_MODULE_ID_ACL] = {"ACL"},
|
|
[QDF_MODULE_ID_WPA] = {"WPA/RSN"},
|
|
[QDF_MODULE_ID_RADKEYS] = {"dump 802.1x keys"},
|
|
[QDF_MODULE_ID_RADDUMP] = {"dump radius packet"},
|
|
[QDF_MODULE_ID_RADIUS] = {"802.1x radius client"},
|
|
[QDF_MODULE_ID_DOT1XSM] = {"802.1x state machine"},
|
|
[QDF_MODULE_ID_DOT1X] = {"802.1x authenticator"},
|
|
[QDF_MODULE_ID_POWER] = {"power save"},
|
|
[QDF_MODULE_ID_STATE] = {"state"},
|
|
[QDF_MODULE_ID_OUTPUT] = {"output"},
|
|
[QDF_MODULE_ID_SCAN] = {"scan"},
|
|
[QDF_MODULE_ID_AUTH] = {"authentication"},
|
|
[QDF_MODULE_ID_ASSOC] = {"association"},
|
|
[QDF_MODULE_ID_NODE] = {"node"},
|
|
[QDF_MODULE_ID_ELEMID] = {"element ID"},
|
|
[QDF_MODULE_ID_XRATE] = {"rate"},
|
|
[QDF_MODULE_ID_INPUT] = {"input"},
|
|
[QDF_MODULE_ID_CRYPTO] = {"crypto"},
|
|
[QDF_MODULE_ID_DUMPPKTS] = {"dump packet"},
|
|
[QDF_MODULE_ID_DEBUG] = {"debug"},
|
|
[QDF_MODULE_ID_MLME] = {"mlme"},
|
|
[QDF_MODULE_ID_RRM] = {"rrm"},
|
|
[QDF_MODULE_ID_WNM] = {"wnm"},
|
|
[QDF_MODULE_ID_P2P_PROT] = {"p2p_prot"},
|
|
[QDF_MODULE_ID_PROXYARP] = {"proxyarp"},
|
|
[QDF_MODULE_ID_L2TIF] = {"l2tif"},
|
|
[QDF_MODULE_ID_WIFIPOS] = {"wifipos"},
|
|
[QDF_MODULE_ID_WRAP] = {"wrap"},
|
|
[QDF_MODULE_ID_DFS] = {"dfs"},
|
|
[QDF_MODULE_ID_ATF] = {"atf"},
|
|
[QDF_MODULE_ID_SPLITMAC] = {"splitmac"},
|
|
[QDF_MODULE_ID_IOCTL] = {"ioctl"},
|
|
[QDF_MODULE_ID_NAC] = {"nac"},
|
|
[QDF_MODULE_ID_MESH] = {"mesh"},
|
|
[QDF_MODULE_ID_MBO] = {"mbo"},
|
|
[QDF_MODULE_ID_EXTIOCTL_CHANSWITCH] = {"extchanswitch"},
|
|
[QDF_MODULE_ID_EXTIOCTL_CHANSSCAN] = {"extchanscan"},
|
|
[QDF_MODULE_ID_TLSHIM] = {"tlshim"},
|
|
[QDF_MODULE_ID_WMI] = {"WMI"},
|
|
[QDF_MODULE_ID_HTT] = {"HTT"},
|
|
[QDF_MODULE_ID_HDD] = {"HDD"},
|
|
[QDF_MODULE_ID_SME] = {"SME"},
|
|
[QDF_MODULE_ID_PE] = {"PE"},
|
|
[QDF_MODULE_ID_WMA] = {"WMA"},
|
|
[QDF_MODULE_ID_SYS] = {"SYS"},
|
|
[QDF_MODULE_ID_QDF] = {"QDF"},
|
|
[QDF_MODULE_ID_SAP] = {"SAP"},
|
|
[QDF_MODULE_ID_HDD_SOFTAP] = {"HDD_SAP"},
|
|
[QDF_MODULE_ID_HDD_DATA] = {"DATA"},
|
|
[QDF_MODULE_ID_HDD_SAP_DATA] = {"SAP_DATA"},
|
|
[QDF_MODULE_ID_HIF] = {"HIF"},
|
|
[QDF_MODULE_ID_HTC] = {"HTC"},
|
|
[QDF_MODULE_ID_TXRX] = {"TXRX"},
|
|
[QDF_MODULE_ID_QDF_DEVICE] = {"QDF_DEV"},
|
|
[QDF_MODULE_ID_CFG] = {"CFG"},
|
|
[QDF_MODULE_ID_BMI] = {"BMI"},
|
|
[QDF_MODULE_ID_EPPING] = {"EPPING"},
|
|
[QDF_MODULE_ID_QVIT] = {"QVIT"},
|
|
[QDF_MODULE_ID_DP] = {"DP"},
|
|
[QDF_MODULE_ID_HAL] = {"HAL"},
|
|
[QDF_MODULE_ID_SOC] = {"SOC"},
|
|
[QDF_MODULE_ID_OS_IF] = {"OSIF"},
|
|
[QDF_MODULE_ID_TARGET_IF] = {"TIF"},
|
|
[QDF_MODULE_ID_SCHEDULER] = {"SCH"},
|
|
[QDF_MODULE_ID_MGMT_TXRX] = {"MGMT_TXRX"},
|
|
[QDF_MODULE_ID_PMO] = {"PMO"},
|
|
[QDF_MODULE_ID_POLICY_MGR] = {"POLICY_MGR"},
|
|
[QDF_MODULE_ID_SA_API] = {"SA_API"},
|
|
[QDF_MODULE_ID_NAN] = {"NAN"},
|
|
[QDF_MODULE_ID_SPECTRAL] = {"SPECTRAL"},
|
|
[QDF_MODULE_ID_P2P] = {"P2P"},
|
|
[QDF_MODULE_ID_OFFCHAN_TXRX] = {"OFFCHAN"},
|
|
[QDF_MODULE_ID_REGULATORY] = {"REGULATORY"},
|
|
[QDF_MODULE_ID_OBJ_MGR] = {"OBJMGR"},
|
|
[QDF_MODULE_ID_SERIALIZATION] = {"SER"},
|
|
[QDF_MODULE_ID_NSS] = {"NSS"},
|
|
[QDF_MODULE_ID_ROAM_DEBUG] = {"roam debug"},
|
|
[QDF_MODULE_ID_DIRECT_BUF_RX] = {"DIRECT_BUF_RX"},
|
|
[QDF_MODULE_ID_DISA] = {"disa"},
|
|
[QDF_MODULE_ID_GREEN_AP] = {"GREEN_AP"},
|
|
[QDF_MODULE_ID_FD] = {"FILS discovery"},
|
|
[QDF_MODULE_ID_FTM] = {"FTM"},
|
|
[QDF_MODULE_ID_OCB] = {"OCB"},
|
|
[QDF_MODULE_ID_CONFIG] = {"CONFIG"},
|
|
[QDF_MODULE_ID_IPA] = {"IPA"},
|
|
[QDF_MODULE_ID_CP_STATS] = {"CP_STATS"},
|
|
[QDF_MODULE_ID_DCS] = {"DCS"},
|
|
[QDF_MODULE_ID_ACTION_OUI] = {"action_oui"},
|
|
[QDF_MODULE_ID_TARGET] = {"TARGET"},
|
|
[QDF_MODULE_ID_MBSSIE] = {"MBSSIE"},
|
|
[QDF_MODULE_ID_FWOL] = {"fwol"},
|
|
[QDF_MODULE_ID_SM_ENGINE] = {"SM_ENG"},
|
|
[QDF_MODULE_ID_CMN_MLME] = {"CMN_MLME"},
|
|
[QDF_MODULE_ID_BSSCOLOR] = {"BSSCOLOR"},
|
|
[QDF_MODULE_ID_CFR] = {"CFR"},
|
|
[QDF_MODULE_ID_DP_TX_CAPTURE] = {"TX_CAPTURE_ENHANCE"},
|
|
[QDF_MODULE_ID_INTEROP_ISSUES_AP] = {"INTEROP_ISSUES_AP"},
|
|
[QDF_MODULE_ID_DENYLIST_MGR] = {"dlm"},
|
|
[QDF_MODULE_ID_QLD] = {"QLD"},
|
|
[QDF_MODULE_ID_DYNAMIC_MODE_CHG] = {"Dynamic Mode Change"},
|
|
[QDF_MODULE_ID_COEX] = {"COEX"},
|
|
[QDF_MODULE_ID_MON_FILTER] = {"Monitor Filter"},
|
|
[QDF_MODULE_ID_PKT_CAPTURE] = {"pkt_capture"},
|
|
[QDF_MODULE_ID_RPTR] = {"RPTR"},
|
|
[QDF_MODULE_ID_6GHZ] = {"6GHZ"},
|
|
[QDF_MODULE_ID_IOT_SIM] = {"IOT_SIM"},
|
|
[QDF_MODULE_ID_MSCS] = {"MSCS"},
|
|
[QDF_MODULE_ID_GPIO] = {"GPIO_CFG"},
|
|
[QDF_MODULE_ID_IFMGR] = {"IF_MGR"},
|
|
[QDF_MODULE_ID_DIAG] = {"DIAG"},
|
|
[QDF_MODULE_ID_DP_INIT] = {"DP_INIT"},
|
|
[QDF_MODULE_ID_DP_TX] = {"DP_TX"},
|
|
[QDF_MODULE_ID_DP_RX] = {"DP_RX"},
|
|
[QDF_MODULE_ID_DP_STATS] = {"DP_STATS"},
|
|
[QDF_MODULE_ID_DP_HTT] = {"DP_HTT"},
|
|
[QDF_MODULE_ID_DP_PEER] = {"DP_PEER"},
|
|
[QDF_MODULE_ID_DP_RX_ERROR] = {"DP_RX_ERROR"},
|
|
[QDF_MODULE_ID_DP_HTT_TX_STATS] = {"DP_HTT_TX_STATS"},
|
|
[QDF_MODULE_ID_DP_RX_MON_STATUS] = {"DP_RX_MON_STATUS"},
|
|
[QDF_MODULE_ID_DP_RX_MON_DEST] = {"DP_RX_MON_DEST"},
|
|
[QDF_MODULE_ID_DP_REO] = {"DP_REO"},
|
|
[QDF_MODULE_ID_DP_TX_COMP] = {"DP_TX_COMP"},
|
|
[QDF_MODULE_ID_DP_VDEV] = {"DP_VDEV"},
|
|
[QDF_MODULE_ID_DP_CDP] = {"DP_CDP"},
|
|
[QDF_MODULE_ID_TSO] = {"TSO"},
|
|
[QDF_MODULE_ID_ME] = {"ME"},
|
|
[QDF_MODULE_ID_QWRAP] = {"QWRAP"},
|
|
[QDF_MODULE_ID_DBDC_REP] = {"DBDC_REP"},
|
|
[QDF_MODULE_ID_EXT_AP] = {"EXT_AP"},
|
|
[QDF_MODULE_ID_MLO] = {"MLO_MGR"},
|
|
[QDF_MODULE_ID_MGMT_RX_REO] = {"MGMT_RX_REO"},
|
|
[QDF_MODULE_ID_MLOIE] = {"MLOIE"},
|
|
[QDF_MODULE_ID_MBSS] = {"MBSS"},
|
|
[QDF_MODULE_ID_MON] = {"MONITOR"},
|
|
[QDF_MODULE_ID_AFC] = {"AFC"},
|
|
[QDF_MODULE_ID_TWT] = {"TWT"},
|
|
[QDF_MODULE_ID_SON] = {"SON"},
|
|
[QDF_MODULE_ID_WLAN_PRE_CAC] = {"PRE_CAC"},
|
|
[QDF_MODULE_ID_T2LM] = {"T2LM"},
|
|
[QDF_MODULE_ID_DP_SAWF] = {"DP_SAWF"},
|
|
[QDF_MODULE_ID_SCS] = {"SCS"},
|
|
[QDF_MODULE_ID_DP_UMAC_RESET] = {"UMAC_HW_RESET"},
|
|
[QDF_MODULE_ID_COAP] = {"COAP"},
|
|
[QDF_MODULE_ID_FTM_TIME_SYNC] = {"Time Sync"},
|
|
[QDF_MODULE_ID_WIFI_RADAR] = {"WIFI RADAR"},
|
|
[QDF_MODULE_ID_CDP] = {"CDP"},
|
|
[QDF_MODULE_ID_QMI] = {"QMI"},
|
|
[QDF_MODULE_ID_SOUNDING] = {"SOUNDING"},
|
|
[QDF_MODULE_ID_SAWF] = {"SAWF"},
|
|
[QDF_MODULE_ID_EPCS] = {"EPCS"},
|
|
[QDF_MODULE_ID_LL_SAP] = {"LL_SAP"},
|
|
[QDF_MODULE_ID_COHOSTED_BSS] = {"COHOSTED_BSS"},
|
|
[QDF_MODULE_ID_TELEMETRY_AGENT] = {"TELEMETRY_AGENT"},
|
|
[QDF_MODULE_ID_RF_PATH_SWITCH] = {"Dynamic RF Path Switch"},
|
|
[QDF_MODULE_ID_ANY] = {"ANY"},
|
|
};
|
|
qdf_export_symbol(g_qdf_category_name);
|
|
|
|
void qdf_trace_display(void)
|
|
{
|
|
QDF_MODULE_ID module_id;
|
|
|
|
pr_err(" 1)FATAL 2)ERROR 3)WARN 4)INFO 5)INFO_H 6)INFO_M 7)INFO_L 8)DEBUG\n");
|
|
for (module_id = 0; module_id < QDF_MODULE_ID_MAX; ++module_id) {
|
|
pr_err("%2d)%s %s %s %s %s %s %s %s %s\n",
|
|
(int)module_id,
|
|
g_qdf_category_name[module_id].category_name_str,
|
|
qdf_print_is_verbose_enabled(qdf_pidx, module_id,
|
|
QDF_TRACE_LEVEL_FATAL) ? "X" : " ",
|
|
qdf_print_is_verbose_enabled(qdf_pidx, module_id,
|
|
QDF_TRACE_LEVEL_ERROR) ? "X" : " ",
|
|
qdf_print_is_verbose_enabled(qdf_pidx, module_id,
|
|
QDF_TRACE_LEVEL_WARN) ? "X" : " ",
|
|
qdf_print_is_verbose_enabled(qdf_pidx, module_id,
|
|
QDF_TRACE_LEVEL_INFO) ? "X" : " ",
|
|
qdf_print_is_verbose_enabled(qdf_pidx, module_id,
|
|
QDF_TRACE_LEVEL_INFO_HIGH) ? "X" : " ",
|
|
qdf_print_is_verbose_enabled(qdf_pidx, module_id,
|
|
QDF_TRACE_LEVEL_INFO_MED) ? "X" : " ",
|
|
qdf_print_is_verbose_enabled(qdf_pidx, module_id,
|
|
QDF_TRACE_LEVEL_INFO_LOW) ? "X" : " ",
|
|
qdf_print_is_verbose_enabled(qdf_pidx, module_id,
|
|
QDF_TRACE_LEVEL_DEBUG) ? "X" : " ");
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_trace_display);
|
|
|
|
#ifdef WLAN_MAX_LOGS_PER_SEC
|
|
static qdf_time_t __log_window_end;
|
|
static qdf_atomic_t __log_window_count;
|
|
uint32_t qdf_rl_print_count = WLAN_MAX_LOGS_PER_SEC;
|
|
uint32_t qdf_rl_print_time = 1;
|
|
uint32_t qdf_rl_print_suppressed;
|
|
|
|
bool qdf_detected_excessive_logging(void)
|
|
{
|
|
qdf_time_t now = qdf_system_ticks();
|
|
bool excessive_prints = false;
|
|
|
|
/*
|
|
* If 'now' is more recent than the end of the window, reset.
|
|
*
|
|
* Note: This is not thread safe, and can result in more than one reset.
|
|
* For our purposes, this is fine.
|
|
*/
|
|
if (!qdf_atomic_read(&__log_window_count)) {
|
|
__log_window_end = now + (qdf_system_ticks_per_sec * qdf_rl_print_time);
|
|
} else if (qdf_system_time_after(now, __log_window_end)) {
|
|
__log_window_end = now + (qdf_system_ticks_per_sec * qdf_rl_print_time);
|
|
qdf_atomic_set(&__log_window_count, 0);
|
|
}
|
|
|
|
if (qdf_atomic_inc_return(&__log_window_count) > qdf_rl_print_count)
|
|
excessive_prints = true;
|
|
|
|
return excessive_prints;
|
|
}
|
|
|
|
void qdf_rl_print_count_set(uint32_t rl_print_count)
|
|
{
|
|
qdf_rl_print_count = rl_print_count;
|
|
}
|
|
|
|
qdf_export_symbol(qdf_rl_print_count_set);
|
|
|
|
void qdf_rl_print_time_set(uint32_t rl_print_time)
|
|
{
|
|
qdf_rl_print_time = rl_print_time;
|
|
}
|
|
|
|
qdf_export_symbol(qdf_rl_print_time_set);
|
|
|
|
void qdf_rl_print_suppressed_log(void)
|
|
{
|
|
if (qdf_rl_print_suppressed) {
|
|
pr_err("QDF Ratelimiting: %d prints suppressed",
|
|
qdf_rl_print_suppressed);
|
|
qdf_rl_print_suppressed = 0;
|
|
}
|
|
}
|
|
|
|
void qdf_rl_print_suppressed_inc(void)
|
|
{
|
|
qdf_rl_print_suppressed++;
|
|
}
|
|
#else
|
|
#define qdf_rl_print_suppressed_log()
|
|
#define qdf_rl_print_suppressed_inc()
|
|
#endif /* WLAN_MAX_LOGS_PER_SEC */
|
|
|
|
#ifdef QDF_TRACE_PRINT_ENABLE
|
|
static inline void print_to_console(char *str_buffer)
|
|
{
|
|
if (qdf_in_interrupt() && qdf_detected_excessive_logging()) {
|
|
qdf_rl_print_suppressed_inc();
|
|
return;
|
|
}
|
|
qdf_rl_print_suppressed_log();
|
|
pr_err("%s\n", str_buffer);
|
|
}
|
|
#else
|
|
|
|
#define print_to_console(str)
|
|
#endif
|
|
|
|
#ifdef MULTI_IF_NAME
|
|
static const char *qdf_trace_wlan_modname(void)
|
|
{
|
|
return MULTI_IF_NAME;
|
|
}
|
|
#else
|
|
static const char *qdf_trace_wlan_modname(void)
|
|
{
|
|
return "wlan";
|
|
}
|
|
#endif
|
|
|
|
void qdf_trace_msg_cmn(unsigned int idx,
|
|
QDF_MODULE_ID category,
|
|
QDF_TRACE_LEVEL verbose,
|
|
const char *str_format, va_list val)
|
|
{
|
|
char str_buffer[QDF_TRACE_BUFFER_SIZE];
|
|
int n;
|
|
|
|
/* Check if index passed is valid */
|
|
if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
|
|
pr_info("%s: Invalid index - %d\n", __func__, idx);
|
|
return;
|
|
}
|
|
|
|
/* Check if print control object is in use */
|
|
if (!print_ctrl_obj[idx].in_use) {
|
|
pr_info("%s: Invalid print control object\n", __func__);
|
|
return;
|
|
}
|
|
|
|
/* Check if category passed is valid */
|
|
if (category < 0 || category >= MAX_SUPPORTED_CATEGORY) {
|
|
vscnprintf(str_buffer, QDF_TRACE_BUFFER_SIZE, str_format, val);
|
|
pr_info("%s: Invalid category: %d, log: %s\n",
|
|
__func__, category, str_buffer);
|
|
return;
|
|
}
|
|
|
|
/* Check if verbose mask is valid */
|
|
if (verbose < 0 || verbose >= QDF_TRACE_LEVEL_MAX) {
|
|
vscnprintf(str_buffer, QDF_TRACE_BUFFER_SIZE, str_format, val);
|
|
pr_info("%s: Invalid verbose level %d, log: %s\n",
|
|
__func__, verbose, str_buffer);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Print the trace message when the desired verbose level is set in
|
|
* the desired category for the print control object
|
|
*/
|
|
if (print_ctrl_obj[idx].cat_info[category].category_verbose_mask &
|
|
QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose)) {
|
|
static const char * const VERBOSE_STR[] = {
|
|
[QDF_TRACE_LEVEL_NONE] = "",
|
|
[QDF_TRACE_LEVEL_FATAL] = "F",
|
|
[QDF_TRACE_LEVEL_ERROR] = "E",
|
|
[QDF_TRACE_LEVEL_WARN] = "W",
|
|
[QDF_TRACE_LEVEL_INFO] = "I",
|
|
[QDF_TRACE_LEVEL_INFO_HIGH] = "IH",
|
|
[QDF_TRACE_LEVEL_INFO_MED] = "IM",
|
|
[QDF_TRACE_LEVEL_INFO_LOW] = "IL",
|
|
[QDF_TRACE_LEVEL_DEBUG] = "D",
|
|
[QDF_TRACE_LEVEL_TRACE] = "T",
|
|
[QDF_TRACE_LEVEL_ALL] = "" };
|
|
|
|
/* print the prefix string into the string buffer... */
|
|
n = scnprintf(str_buffer, QDF_TRACE_BUFFER_SIZE,
|
|
"%s: [%d:%s:%s] ", qdf_trace_wlan_modname(),
|
|
in_interrupt() ? 0 : current->pid,
|
|
VERBOSE_STR[verbose],
|
|
g_qdf_category_name[category].category_name_str);
|
|
|
|
/* print the formatted log message after the prefix string */
|
|
vscnprintf(str_buffer + n, QDF_TRACE_BUFFER_SIZE - n,
|
|
str_format, val);
|
|
#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE)
|
|
wlan_log_to_user(verbose, (char *)str_buffer,
|
|
strlen(str_buffer));
|
|
if (qdf_unlikely(qdf_log_dump_at_kernel_enable))
|
|
print_to_console(str_buffer);
|
|
#else
|
|
pr_err("%s\n", str_buffer);
|
|
#endif
|
|
}
|
|
}
|
|
qdf_export_symbol(qdf_trace_msg_cmn);
|
|
|
|
QDF_STATUS qdf_print_setup(void)
|
|
{
|
|
int i;
|
|
|
|
/* Loop through all print ctrl objects */
|
|
for (i = 0; i < MAX_PRINT_CONFIG_SUPPORTED; i++) {
|
|
if (qdf_print_ctrl_cleanup(i))
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
qdf_export_symbol(qdf_print_setup);
|
|
|
|
QDF_STATUS qdf_print_ctrl_cleanup(unsigned int idx)
|
|
{
|
|
int i = 0;
|
|
|
|
if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
|
|
pr_info("%s: Invalid index - %d\n", __func__, idx);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
/* Clean up the print control object corresponding to that index
|
|
* If success, callee to change print control index to -1
|
|
*/
|
|
|
|
for (i = 0; i < MAX_SUPPORTED_CATEGORY; i++) {
|
|
print_ctrl_obj[idx].cat_info[i].category_verbose_mask =
|
|
QDF_TRACE_LEVEL_NONE;
|
|
}
|
|
print_ctrl_obj[idx].custom_print = NULL;
|
|
print_ctrl_obj[idx].custom_ctxt = NULL;
|
|
qdf_print_clean_node_flag(idx);
|
|
print_ctrl_obj[idx].in_use = false;
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
qdf_export_symbol(qdf_print_ctrl_cleanup);
|
|
|
|
int qdf_print_ctrl_register(const struct category_info *cinfo,
|
|
void *custom_print_handler,
|
|
void *custom_ctx,
|
|
const char *pctrl_name)
|
|
{
|
|
int idx = -1;
|
|
int i = 0;
|
|
|
|
for (i = 0; i < MAX_PRINT_CONFIG_SUPPORTED; i++) {
|
|
if (!print_ctrl_obj[i].in_use) {
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Callee to handle idx -1 appropriately */
|
|
if (idx == -1) {
|
|
pr_info("%s: Allocation failed! No print control object free\n",
|
|
__func__);
|
|
return idx;
|
|
}
|
|
|
|
print_ctrl_obj[idx].in_use = true;
|
|
|
|
/*
|
|
* In case callee does not pass category info,
|
|
* custom print handler, custom context and print control name,
|
|
* we do not set any value here. Clean up for the print control
|
|
* getting allocated would have taken care of initializing
|
|
* default values.
|
|
*
|
|
* We need to only set in_use to 1 in such a case
|
|
*/
|
|
|
|
if (pctrl_name) {
|
|
qdf_str_lcopy(print_ctrl_obj[idx].name, pctrl_name,
|
|
sizeof(print_ctrl_obj[idx].name));
|
|
}
|
|
|
|
if (custom_print_handler)
|
|
print_ctrl_obj[idx].custom_print = custom_print_handler;
|
|
|
|
if (custom_ctx)
|
|
print_ctrl_obj[idx].custom_ctxt = custom_ctx;
|
|
|
|
if (cinfo) {
|
|
for (i = 0; i < MAX_SUPPORTED_CATEGORY; i++) {
|
|
if (cinfo[i].category_verbose_mask ==
|
|
QDF_TRACE_LEVEL_ALL) {
|
|
print_ctrl_obj[idx].cat_info[i]
|
|
.category_verbose_mask = 0xFFFF;
|
|
} else if ((cinfo[i].category_verbose_mask ==
|
|
QDF_TRACE_LEVEL_NONE) ||
|
|
(cinfo[i].category_verbose_mask ==
|
|
QDF_TRACE_LEVEL_TO_MODULE_BITMASK(
|
|
QDF_TRACE_LEVEL_NONE))) {
|
|
print_ctrl_obj[idx].cat_info[i]
|
|
.category_verbose_mask = 0;
|
|
} else {
|
|
print_ctrl_obj[idx].cat_info[i]
|
|
.category_verbose_mask =
|
|
cinfo[i].category_verbose_mask;
|
|
}
|
|
}
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
qdf_export_symbol(qdf_print_ctrl_register);
|
|
|
|
#ifdef QDF_TRACE_PRINT_ENABLE
|
|
void qdf_shared_print_ctrl_cleanup(void)
|
|
{
|
|
qdf_print_ctrl_cleanup(qdf_pidx);
|
|
}
|
|
qdf_export_symbol(qdf_shared_print_ctrl_cleanup);
|
|
|
|
/*
|
|
* Set this to invalid value to differentiate with user-provided
|
|
* value.
|
|
*/
|
|
int qdf_dbg_mask = QDF_TRACE_LEVEL_MAX;
|
|
qdf_export_symbol(qdf_dbg_mask);
|
|
qdf_declare_param(qdf_dbg_mask, int);
|
|
|
|
/*
|
|
* QDF can be passed parameters which indicate the
|
|
* debug level for each module.
|
|
* an array of string values are passed, each string hold the following form
|
|
*
|
|
* <module name string>=<integer debug level value>
|
|
*
|
|
* The array qdf_dbg_arr will hold these module-string=value strings
|
|
* The variable qdf_dbg_arr_cnt will have the count of how many such
|
|
* string values were passed.
|
|
*/
|
|
static char *qdf_dbg_arr[QDF_MODULE_ID_MAX];
|
|
static int qdf_dbg_arr_cnt;
|
|
qdf_declare_param_array(qdf_dbg_arr, charp, &qdf_dbg_arr_cnt);
|
|
|
|
static uint16_t set_cumulative_verbose_mask(QDF_TRACE_LEVEL max_level)
|
|
{
|
|
uint16_t category_verbose_mask = 0;
|
|
QDF_TRACE_LEVEL level;
|
|
|
|
for (level = QDF_TRACE_LEVEL_FATAL; level <= max_level; level++) {
|
|
category_verbose_mask |=
|
|
QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level);
|
|
}
|
|
return category_verbose_mask;
|
|
}
|
|
|
|
static QDF_MODULE_ID find_qdf_module_from_string(char *str)
|
|
{
|
|
QDF_MODULE_ID mod_id;
|
|
|
|
for (mod_id = 0; mod_id < QDF_MODULE_ID_MAX; mod_id++) {
|
|
if (strcasecmp(str,
|
|
g_qdf_category_name[mod_id].category_name_str)
|
|
== 0) {
|
|
break;
|
|
}
|
|
}
|
|
return mod_id;
|
|
}
|
|
|
|
static void process_qdf_dbg_arr_param(struct category_info *cinfo,
|
|
int array_index)
|
|
{
|
|
char *mod_val_str, *mod_str, *val_str;
|
|
unsigned long dbg_level;
|
|
QDF_MODULE_ID mod_id;
|
|
|
|
mod_val_str = qdf_dbg_arr[array_index];
|
|
mod_str = strsep(&mod_val_str, "=");
|
|
val_str = mod_val_str;
|
|
if (!val_str) {
|
|
pr_info("qdf_dbg_arr: %s not in the <mod>=<val> form\n",
|
|
mod_str);
|
|
return;
|
|
}
|
|
|
|
mod_id = find_qdf_module_from_string(mod_str);
|
|
if (mod_id >= QDF_MODULE_ID_MAX) {
|
|
pr_info("ERROR!!Module name %s not in the list of modules\n",
|
|
mod_str);
|
|
return;
|
|
}
|
|
|
|
if (kstrtol(val_str, 10, &dbg_level) < 0) {
|
|
pr_info("ERROR!!Invalid debug level for module: %s\n",
|
|
mod_str);
|
|
return;
|
|
}
|
|
|
|
if (dbg_level >= QDF_TRACE_LEVEL_MAX) {
|
|
pr_info("ERROR!!Debug level for %s too high", mod_str);
|
|
pr_info("max: %d given %lu\n", QDF_TRACE_LEVEL_MAX,
|
|
dbg_level);
|
|
return;
|
|
}
|
|
|
|
pr_info("User passed setting module %s(%d) to level %lu\n",
|
|
mod_str,
|
|
mod_id,
|
|
dbg_level);
|
|
cinfo[mod_id].category_verbose_mask =
|
|
set_cumulative_verbose_mask((QDF_TRACE_LEVEL)dbg_level);
|
|
}
|
|
|
|
static void set_default_trace_levels(struct category_info *cinfo)
|
|
{
|
|
int i;
|
|
static QDF_TRACE_LEVEL module_trace_default_level[QDF_MODULE_ID_MAX] = {
|
|
[QDF_MODULE_ID_TDLS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_ACS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SCAN_SM] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SCANENTRY] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WDS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_ACTION] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_ROAM] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_INACT] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DOTH] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_IQUE] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WME] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_ACL] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WPA] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_RADKEYS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_RADDUMP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_RADIUS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DOT1XSM] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DOT1X] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_POWER] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_STATE] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_OUTPUT] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SCAN] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_AUTH] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_ASSOC] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_NODE] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_ELEMID] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_XRATE] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_INPUT] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_CRYPTO] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DUMPPKTS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DEBUG] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_MLME] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_RRM] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WNM] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_P2P_PROT] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_PROXYARP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_L2TIF] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WIFIPOS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WRAP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DFS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_ATF] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_SPLITMAC] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_IOCTL] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_NAC] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_MESH] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_MBO] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_EXTIOCTL_CHANSWITCH] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_EXTIOCTL_CHANSSCAN] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_TLSHIM] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WMI] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_HTT] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_HDD] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SME] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_PE] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WMA] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SYS] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_QDF] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_SAP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_HDD_SOFTAP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_HDD_DATA] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_HDD_SAP_DATA] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_HIF] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_HTC] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_TXRX] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_QDF_DEVICE] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_CFG] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_BMI] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_EPPING] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_QVIT] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DP] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_HAL] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SOC] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_OS_IF] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_TARGET_IF] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_SCHEDULER] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_MGMT_TXRX] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SERIALIZATION] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_PMO] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_P2P] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_POLICY_MGR] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_CONFIG] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_REGULATORY] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SA_API] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_NAN] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_OFFCHAN_TXRX] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SON] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SPECTRAL] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_OBJ_MGR] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_NSS] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_ROAM_DEBUG] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_CDP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DIRECT_BUF_RX] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_DISA] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_GREEN_AP] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_FTM] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_FD] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_OCB] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_IPA] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_ACTION_OUI] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_CP_STATS] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_DCS] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_MBSSIE] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_FWOL] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_SM_ENGINE] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_CMN_MLME] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_BSSCOLOR] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_CFR] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_DP_TX_CAPTURE] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_INTEROP_ISSUES_AP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_DENYLIST_MGR] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_QLD] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_DYNAMIC_MODE_CHG] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_COEX] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_MON_FILTER] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_PKT_CAPTURE] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_RPTR] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_6GHZ] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_IOT_SIM] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_MSCS] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_GPIO] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_IFMGR] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_DIAG] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_DP_INIT] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_TX] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_RX] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_STATS] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_HTT] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_PEER] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_RX_ERROR] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_HTT_TX_STATS] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_RX_MON_STATUS] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_RX_MON_DEST] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_REO] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_TX_COMP] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_VDEV] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DP_CDP] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_TSO] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_ME] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_QWRAP] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_DBDC_REP] = QDF_TRACE_LEVEL_FATAL,
|
|
[QDF_MODULE_ID_EXT_AP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_MLO] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_MLOIE] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_MBSS] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_MON] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_MGMT_RX_REO] = QDF_TRACE_LEVEL_WARN,
|
|
[QDF_MODULE_ID_TWT] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_WLAN_PRE_CAC] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_T2LM] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_DP_SAWF] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_SCS] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_DP_UMAC_RESET] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_COAP] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_FTM_TIME_SYNC] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_AFC] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_WIFI_RADAR] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_TARGET] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_QMI] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_SOUNDING] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_SAWF] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_EPCS] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_LL_SAP] = QDF_TRACE_LEVEL_NONE,
|
|
[QDF_MODULE_ID_COHOSTED_BSS] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_TELEMETRY_AGENT] = QDF_TRACE_LEVEL_ERROR,
|
|
[QDF_MODULE_ID_RF_PATH_SWITCH] = QDF_TRACE_LEVEL_INFO,
|
|
[QDF_MODULE_ID_ANY] = QDF_TRACE_LEVEL_INFO,
|
|
};
|
|
|
|
for (i = 0; i < MAX_SUPPORTED_CATEGORY; i++) {
|
|
cinfo[i].category_verbose_mask = set_cumulative_verbose_mask(
|
|
module_trace_default_level[i]);
|
|
}
|
|
}
|
|
|
|
void qdf_shared_print_ctrl_init(void)
|
|
{
|
|
int i;
|
|
struct category_info cinfo[MAX_SUPPORTED_CATEGORY];
|
|
|
|
set_default_trace_levels(cinfo);
|
|
|
|
/*
|
|
* User specified across-module single debug level
|
|
*/
|
|
if ((qdf_dbg_mask >= 0) && (qdf_dbg_mask < QDF_TRACE_LEVEL_MAX)) {
|
|
pr_info("User specified module debug level of %d\n",
|
|
qdf_dbg_mask);
|
|
for (i = 0; i < MAX_SUPPORTED_CATEGORY; i++) {
|
|
cinfo[i].category_verbose_mask =
|
|
set_cumulative_verbose_mask(qdf_dbg_mask);
|
|
}
|
|
} else if (qdf_dbg_mask != QDF_TRACE_LEVEL_MAX) {
|
|
pr_info("qdf_dbg_mask value is invalid\n");
|
|
pr_info("Using the default module debug levels instead\n");
|
|
}
|
|
|
|
/*
|
|
* Module ID-Level specified as array during module load
|
|
*/
|
|
for (i = 0; i < qdf_dbg_arr_cnt; i++) {
|
|
process_qdf_dbg_arr_param(cinfo, i);
|
|
}
|
|
qdf_pidx = qdf_print_ctrl_register(cinfo, NULL, NULL,
|
|
"LOG_SHARED_OBJ");
|
|
}
|
|
qdf_export_symbol(qdf_shared_print_ctrl_init);
|
|
#endif
|
|
|
|
#ifdef QCA_WIFI_MODULE_PARAMS_FROM_INI
|
|
QDF_STATUS qdf_module_param_handler(void *context, const char *str_param,
|
|
const char *str)
|
|
{
|
|
QDF_STATUS status = QDF_STATUS_E_FAILURE;
|
|
uint16_t param = 0;
|
|
uint32_t flush_tmr_prd;
|
|
bool dump_flag;
|
|
|
|
while (param < QDF_PARAM_MAX) {
|
|
if (qdf_str_eq(qdf_module_param[param], str_param)) {
|
|
switch (param) {
|
|
case MEM_DEBUG_DISABLED:
|
|
status = qdf_mem_debug_disabled_config_set(str);
|
|
break;
|
|
case QDF_DBG_MASK:
|
|
status = qdf_int32_parse(str, &qdf_dbg_mask);
|
|
break;
|
|
case PREALLOC_DISABLED:
|
|
status = qdf_prealloc_disabled_config_set(str);
|
|
break;
|
|
case QDF_LOG_DUMP_AT_KERNEL_ENABLE:
|
|
status = qdf_bool_parse(str, &dump_flag);
|
|
qdf_log_dump_at_kernel_enable = dump_flag;
|
|
break;
|
|
case QDF_DBG_ARR:
|
|
qdf_dbg_arr[0] = (char *)str;
|
|
status = QDF_STATUS_SUCCESS;
|
|
break;
|
|
case QDF_LOG_FLUSH_TIMER_PERIOD:
|
|
status = qdf_uint32_parse(str, &flush_tmr_prd);
|
|
qdf_log_flush_timer_period = flush_tmr_prd;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return status;
|
|
}
|
|
param++;
|
|
}
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
void qdf_initialize_module_param_from_ini(void)
|
|
{
|
|
QDF_STATUS status;
|
|
char *path = QDF_WIFI_MODULE_PARAMS_FILE;
|
|
|
|
status = qdf_ini_parse(path, NULL, qdf_module_param_handler, NULL);
|
|
if (QDF_IS_STATUS_ERROR(status)) {
|
|
QDF_TRACE_ERROR(QDF_MODULE_ID_QDF,
|
|
"Failed to parse *.ini file @ %s; status:%d",
|
|
path, status);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
QDF_STATUS qdf_print_set_category_verbose(unsigned int idx,
|
|
QDF_MODULE_ID category,
|
|
QDF_TRACE_LEVEL verbose,
|
|
bool is_set)
|
|
{
|
|
/* Check if index passed is valid */
|
|
if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
|
|
pr_err("%s: Invalid index - %d\n", __func__, idx);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
/* Check if print control object is in use */
|
|
if (!print_ctrl_obj[idx].in_use) {
|
|
pr_err("%s: Invalid print control object\n", __func__);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
/* Check if category passed is valid */
|
|
if (category < 0 || category >= MAX_SUPPORTED_CATEGORY) {
|
|
pr_err("%s: Invalid category: %d\n", __func__, category);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
/* Check if verbose mask is valid */
|
|
if (verbose < 0 || verbose >= QDF_TRACE_LEVEL_MAX) {
|
|
pr_err("%s: Invalid verbose level %d\n", __func__, verbose);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
if (verbose == QDF_TRACE_LEVEL_ALL) {
|
|
print_ctrl_obj[idx].cat_info[category].category_verbose_mask =
|
|
0xFFFF;
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (verbose == QDF_TRACE_LEVEL_NONE) {
|
|
print_ctrl_obj[idx].cat_info[category].category_verbose_mask =
|
|
QDF_TRACE_LEVEL_NONE;
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!is_set) {
|
|
if (print_ctrl_obj[idx].cat_info[category].category_verbose_mask
|
|
& QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose)) {
|
|
print_ctrl_obj[idx].cat_info[category]
|
|
.category_verbose_mask &=
|
|
~QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose);
|
|
}
|
|
} else {
|
|
print_ctrl_obj[idx].cat_info[category].category_verbose_mask |=
|
|
QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose);
|
|
}
|
|
|
|
pr_debug("%s: Print control object %d, Category %d, Verbose level %d\n",
|
|
__func__,
|
|
idx,
|
|
category,
|
|
print_ctrl_obj[idx].cat_info[category].category_verbose_mask);
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
qdf_export_symbol(qdf_print_set_category_verbose);
|
|
|
|
void qdf_log_dump_at_kernel_level(bool enable)
|
|
{
|
|
if (qdf_log_dump_at_kernel_enable == enable) {
|
|
QDF_TRACE_INFO(QDF_MODULE_ID_QDF,
|
|
"qdf_log_dump_at_kernel_enable is already %d\n",
|
|
enable);
|
|
}
|
|
qdf_log_dump_at_kernel_enable = enable;
|
|
}
|
|
|
|
qdf_export_symbol(qdf_log_dump_at_kernel_level);
|
|
|
|
QDF_TRACE_LEVEL qdf_print_get_category_verbose(unsigned int idx,
|
|
QDF_MODULE_ID category)
|
|
{
|
|
/* Check if index passed is valid */
|
|
if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
|
|
pr_info("%s: Invalid index - %d\n", __func__, idx);
|
|
return false;
|
|
}
|
|
|
|
/* Check if print control object is in use */
|
|
if (!print_ctrl_obj[idx].in_use) {
|
|
pr_info("%s: Invalid print control object\n", __func__);
|
|
return false;
|
|
}
|
|
|
|
/* Check if category passed is valid */
|
|
if (category < 0 || category >= MAX_SUPPORTED_CATEGORY) {
|
|
pr_info("%s: Invalid category: %d\n", __func__, category);
|
|
return false;
|
|
}
|
|
|
|
return print_ctrl_obj[idx].cat_info[category].category_verbose_mask;
|
|
}
|
|
|
|
qdf_export_symbol(qdf_print_get_category_verbose);
|
|
|
|
bool qdf_print_is_category_enabled(unsigned int idx, QDF_MODULE_ID category)
|
|
{
|
|
QDF_TRACE_LEVEL verbose_mask;
|
|
|
|
verbose_mask = qdf_print_get_category_verbose(idx, category);
|
|
|
|
if (verbose_mask == QDF_TRACE_LEVEL_NONE)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
qdf_export_symbol(qdf_print_is_category_enabled);
|
|
|
|
bool qdf_print_is_verbose_enabled(unsigned int idx, QDF_MODULE_ID category,
|
|
QDF_TRACE_LEVEL verbose)
|
|
{
|
|
bool verbose_enabled = false;
|
|
|
|
/* Check if index passed is valid */
|
|
if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
|
|
pr_info("%s: Invalid index - %d\n", __func__, idx);
|
|
return verbose_enabled;
|
|
}
|
|
|
|
/* Check if print control object is in use */
|
|
if (!print_ctrl_obj[idx].in_use) {
|
|
pr_info("%s: Invalid print control object\n", __func__);
|
|
return verbose_enabled;
|
|
}
|
|
|
|
/* Check if category passed is valid */
|
|
if (category < 0 || category >= MAX_SUPPORTED_CATEGORY) {
|
|
pr_info("%s: Invalid category: %d\n", __func__, category);
|
|
return verbose_enabled;
|
|
}
|
|
|
|
if ((verbose == QDF_TRACE_LEVEL_NONE) ||
|
|
(verbose >= QDF_TRACE_LEVEL_MAX)) {
|
|
verbose_enabled = false;
|
|
} else if (verbose == QDF_TRACE_LEVEL_ALL) {
|
|
if (print_ctrl_obj[idx].cat_info[category]
|
|
.category_verbose_mask == 0xFFFF)
|
|
verbose_enabled = true;
|
|
} else {
|
|
verbose_enabled =
|
|
(print_ctrl_obj[idx].cat_info[category].category_verbose_mask &
|
|
QDF_TRACE_LEVEL_TO_MODULE_BITMASK(verbose)) ? true : false;
|
|
}
|
|
|
|
return verbose_enabled;
|
|
}
|
|
qdf_export_symbol(qdf_print_is_verbose_enabled);
|
|
|
|
#ifdef DBG_LVL_MAC_FILTERING
|
|
|
|
QDF_STATUS qdf_print_set_node_flag(unsigned int idx, uint8_t enable)
|
|
{
|
|
/* Check if index passed is valid */
|
|
if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
|
|
pr_info("%s: Invalid index - %d\n", __func__, idx);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
/* Check if print control object is in use */
|
|
if (!print_ctrl_obj[idx].in_use) {
|
|
pr_info("%s: Invalid print control object\n", __func__);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
if (enable > 1) {
|
|
pr_info("%s: Incorrect input: Use 1 or 0 to enable or disable\n",
|
|
__func__);
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
print_ctrl_obj[idx].dbglvlmac_on = enable;
|
|
pr_info("%s: DbgLVLmac feature %s\n",
|
|
__func__,
|
|
((enable) ? "enabled" : "disabled"));
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
qdf_export_symbol(qdf_print_set_node_flag);
|
|
|
|
bool qdf_print_get_node_flag(unsigned int idx)
|
|
{
|
|
bool node_flag = false;
|
|
|
|
/* Check if index passed is valid */
|
|
if (idx < 0 || idx >= MAX_PRINT_CONFIG_SUPPORTED) {
|
|
pr_info("%s: Invalid index - %d\n", __func__, idx);
|
|
return node_flag;
|
|
}
|
|
|
|
/* Check if print control object is in use */
|
|
if (!print_ctrl_obj[idx].in_use) {
|
|
pr_info("%s: Invalid print control object\n", __func__);
|
|
return node_flag;
|
|
}
|
|
|
|
if (print_ctrl_obj[idx].dbglvlmac_on)
|
|
node_flag = true;
|
|
|
|
return node_flag;
|
|
}
|
|
qdf_export_symbol(qdf_print_get_node_flag);
|
|
|
|
void qdf_print_clean_node_flag(unsigned int idx)
|
|
{
|
|
/* Disable dbglvlmac_on during cleanup */
|
|
print_ctrl_obj[idx].dbglvlmac_on = 0;
|
|
}
|
|
|
|
#else
|
|
|
|
void qdf_print_clean_node_flag(unsigned int idx)
|
|
{
|
|
/* No operation in case of no support for DBG_LVL_MAC_FILTERING */
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
void QDF_PRINT_INFO(unsigned int idx, QDF_MODULE_ID module,
|
|
QDF_TRACE_LEVEL level,
|
|
char *str_format, ...)
|
|
{
|
|
va_list args;
|
|
|
|
/* Generic wrapper API will compile qdf_vprint in order to
|
|
* log the message. Once QDF converged debug framework is in
|
|
* place, this will be changed to adapt to the framework, compiling
|
|
* call to converged tracing API
|
|
*/
|
|
va_start(args, str_format);
|
|
qdf_vprint(str_format, args);
|
|
va_end(args);
|
|
}
|
|
qdf_export_symbol(QDF_PRINT_INFO);
|
|
|
|
#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE
|
|
void qdf_logging_init(void)
|
|
{
|
|
wlan_logging_sock_init_svc();
|
|
nl_srv_init(NULL, WLAN_NLINK_PROTO_FAMILY);
|
|
wlan_logging_notifier_init(qdf_log_dump_at_kernel_enable);
|
|
wlan_logging_set_flush_timer(qdf_log_flush_timer_period);
|
|
}
|
|
|
|
void qdf_logging_exit(void)
|
|
{
|
|
wlan_logging_notifier_deinit(qdf_log_dump_at_kernel_enable);
|
|
nl_srv_exit();
|
|
wlan_logging_sock_deinit_svc();
|
|
}
|
|
|
|
int qdf_logging_set_flush_timer(uint32_t milliseconds)
|
|
{
|
|
if (wlan_logging_set_flush_timer(milliseconds) == 0)
|
|
return QDF_STATUS_SUCCESS;
|
|
else
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
void qdf_logging_flush_logs(void)
|
|
{
|
|
wlan_flush_host_logs_for_fatal();
|
|
}
|
|
|
|
#else
|
|
void qdf_logging_init(void)
|
|
{
|
|
nl_srv_init(NULL, WLAN_NLINK_PROTO_FAMILY);
|
|
}
|
|
|
|
void qdf_logging_exit(void)
|
|
{
|
|
nl_srv_exit();
|
|
}
|
|
|
|
int qdf_logging_set_flush_timer(uint32_t milliseconds)
|
|
{
|
|
return QDF_STATUS_E_FAILURE;
|
|
}
|
|
|
|
void qdf_logging_flush_logs(void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
qdf_export_symbol(qdf_logging_set_flush_timer);
|
|
qdf_export_symbol(qdf_logging_flush_logs);
|
|
|
|
#ifdef CONFIG_KALLSYMS
|
|
inline int qdf_sprint_symbol(char *buffer, void *addr)
|
|
{
|
|
return sprint_symbol(buffer, (unsigned long)addr);
|
|
}
|
|
#else
|
|
int qdf_sprint_symbol(char *buffer, void *addr)
|
|
{
|
|
if (!buffer)
|
|
return 0;
|
|
|
|
buffer[0] = '\0';
|
|
return 1;
|
|
}
|
|
#endif
|
|
qdf_export_symbol(qdf_sprint_symbol);
|
|
|
|
void qdf_set_pidx(int pidx)
|
|
{
|
|
qdf_pidx = pidx;
|
|
}
|
|
qdf_export_symbol(qdf_set_pidx);
|
|
|
|
int qdf_get_pidx(void)
|
|
{
|
|
return qdf_pidx;
|
|
}
|
|
qdf_export_symbol(qdf_get_pidx);
|
|
|
|
#ifdef PANIC_ON_BUG
|
|
#ifdef CONFIG_SLUB_DEBUG
|
|
void __qdf_bug(void)
|
|
{
|
|
BUG();
|
|
}
|
|
qdf_export_symbol(__qdf_bug);
|
|
#endif /* CONFIG_SLUB_DEBUG */
|
|
#endif /* PANIC_ON_BUG */
|
|
|
|
#ifdef WLAN_QCOM_VA_MINIDUMP
|
|
static bool qdf_va_md_initialized;
|
|
static qdf_list_t qdf_va_md_list;
|
|
static qdf_spinlock_t qdf_va_md_list_lock;
|
|
#define QDF_MINIDUMP_LIST_SIZE 128
|
|
|
|
struct qdf_va_md_entry {
|
|
qdf_list_node_t node;
|
|
struct va_md_entry data;
|
|
};
|
|
|
|
static int qdf_va_md_notif_handler(struct notifier_block *this,
|
|
unsigned long event, void *ptr)
|
|
{
|
|
struct qdf_va_md_entry *entry;
|
|
struct qdf_va_md_entry *next;
|
|
|
|
qdf_spin_lock_irqsave(&qdf_va_md_list_lock);
|
|
qdf_list_for_each_del(&qdf_va_md_list, entry, next, node) {
|
|
qcom_va_md_add_region(&entry->data);
|
|
}
|
|
|
|
qdf_spin_unlock_irqrestore(&qdf_va_md_list_lock);
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
static struct notifier_block qdf_va_md_notif_blk = {
|
|
.notifier_call = qdf_va_md_notif_handler,
|
|
.priority = INT_MAX,
|
|
};
|
|
|
|
void __qdf_minidump_init(void)
|
|
{
|
|
int ret;
|
|
|
|
if (qdf_va_md_initialized)
|
|
return;
|
|
|
|
qdf_spinlock_create(&qdf_va_md_list_lock);
|
|
qdf_list_create(&qdf_va_md_list, QDF_MINIDUMP_LIST_SIZE);
|
|
ret = qcom_va_md_register(qdf_trace_wlan_modname(),
|
|
&qdf_va_md_notif_blk);
|
|
qdf_va_md_initialized = !ret;
|
|
}
|
|
|
|
qdf_export_symbol(__qdf_minidump_init);
|
|
|
|
void __qdf_minidump_deinit(void)
|
|
{
|
|
struct qdf_va_md_entry *entry;
|
|
struct qdf_va_md_entry *next;
|
|
|
|
if (!qdf_va_md_initialized)
|
|
return;
|
|
|
|
qdf_va_md_initialized = false;
|
|
qcom_va_md_unregister(qdf_trace_wlan_modname(),
|
|
&qdf_va_md_notif_blk);
|
|
qdf_spin_lock_irqsave(&qdf_va_md_list_lock);
|
|
qdf_list_for_each_del(&qdf_va_md_list, entry, next, node) {
|
|
qdf_list_remove_node(&qdf_va_md_list, &entry->node);
|
|
qdf_mem_free(entry);
|
|
}
|
|
|
|
qdf_list_destroy(&qdf_va_md_list);
|
|
qdf_spin_unlock_irqrestore(&qdf_va_md_list_lock);
|
|
qdf_spinlock_destroy(&qdf_va_md_list_lock);
|
|
}
|
|
|
|
qdf_export_symbol(__qdf_minidump_deinit);
|
|
|
|
void __qdf_minidump_log(void *start_addr, size_t size, const char *name)
|
|
{
|
|
struct qdf_va_md_entry *entry;
|
|
QDF_STATUS status;
|
|
|
|
if (!qdf_va_md_initialized)
|
|
return;
|
|
|
|
entry = qdf_mem_malloc(sizeof(*entry));
|
|
if (!entry) {
|
|
qdf_err("malloc failed for %s: %pK, %zu",
|
|
name, start_addr, size);
|
|
return;
|
|
}
|
|
|
|
qdf_str_lcopy(entry->data.owner, name, sizeof(entry->data.owner));
|
|
entry->data.vaddr = (unsigned long)start_addr;
|
|
entry->data.size = size;
|
|
|
|
qdf_spin_lock_irqsave(&qdf_va_md_list_lock);
|
|
status = qdf_list_insert_front(&qdf_va_md_list, &entry->node);
|
|
qdf_spin_unlock_irqrestore(&qdf_va_md_list_lock);
|
|
if (QDF_IS_STATUS_ERROR(status)) {
|
|
qdf_err("Failed to insert qdf va md entry, status %d", status);
|
|
qdf_mem_free(entry);
|
|
}
|
|
}
|
|
|
|
qdf_export_symbol(__qdf_minidump_log);
|
|
|
|
void __qdf_minidump_remove(void *addr, size_t size, const char *name)
|
|
{
|
|
struct qdf_va_md_entry *entry;
|
|
struct qdf_va_md_entry *next;
|
|
|
|
if (!qdf_va_md_initialized)
|
|
return;
|
|
|
|
qdf_spin_lock_irqsave(&qdf_va_md_list_lock);
|
|
qdf_list_for_each_del(&qdf_va_md_list, entry, next, node) {
|
|
if (entry->data.vaddr == (unsigned long)addr &&
|
|
entry->data.size == size &&
|
|
!qdf_str_cmp(entry->data.owner, name)) {
|
|
qdf_list_remove_node(&qdf_va_md_list, &entry->node);
|
|
qdf_mem_free(entry);
|
|
break;
|
|
}
|
|
}
|
|
|
|
qdf_spin_unlock_irqrestore(&qdf_va_md_list_lock);
|
|
}
|
|
|
|
qdf_export_symbol(__qdf_minidump_remove);
|
|
#endif
|