blob: 445ffed20dd93800664f498fbd055cc98c870459 [file] [log] [blame]
Chouhan, Anurag57763182016-03-03 18:57:27 +05301/*
Nirav Shaheaa20d82016-04-25 18:01:05 +05302 * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
Chouhan, Anurag57763182016-03-03 18:57:27 +05303 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: qdf_trace
30 * QCA driver framework (QDF) trace APIs
31 * Trace, logging, and debugging definitions and APIs
32 */
33
34/* Include Files */
35#include <qdf_trace.h>
Chouhan, Anurag57763182016-03-03 18:57:27 +053036#include <wlan_logging_sock_svc.h>
37#include "qdf_time.h"
38/* Preprocessor definitions and constants */
39
40#define QDF_TRACE_BUFFER_SIZE (512)
41
42enum qdf_timestamp_unit qdf_log_timestamp_type = QDF_LOG_TIMESTAMP_UNIT;
43
44/* macro to map qdf trace levels into the bitmask */
45#define QDF_TRACE_LEVEL_TO_MODULE_BITMASK(_level) ((1 << (_level)))
46
47/**
48 * typedef struct module_trace_info - Trace level for a module, as a bitmask.
49 * The bits in this mask are ordered by QDF_TRACE_LEVEL. For example,
50 * each bit represents one of the bits in QDF_TRACE_LEVEL that may be turned
51 * on to have traces at that level logged, i.e. if QDF_TRACE_LEVEL_ERROR is
52 * == 2, then if bit 2 (low order) is turned ON, then ERROR traces will be
53 * printed to the trace log. Note that all bits turned OFF means no traces
54 * @module_trace_level: trace level
55 * @module_name_str: 3 character string name for the module
56 */
57typedef struct {
58 uint16_t module_trace_level;
59 unsigned char module_name_str[4];
60} module_trace_info;
61
62#define QDF_DEFAULT_TRACE_LEVEL \
63 ((1 << QDF_TRACE_LEVEL_FATAL) | (1 << QDF_TRACE_LEVEL_ERROR))
64
65/* Array of static data that contains all of the per module trace
66 * information. This includes the trace level for the module and
67 * the 3 character 'name' of the module for marking the trace logs
68 */
69module_trace_info g_qdf_trace_info[QDF_MODULE_ID_MAX] = {
70 [QDF_MODULE_ID_TLSHIM] = {QDF_DEFAULT_TRACE_LEVEL, "DP"},
71 [QDF_MODULE_ID_WMI] = {QDF_DEFAULT_TRACE_LEVEL, "WMI"},
72 [QDF_MODULE_ID_HDD] = {QDF_DEFAULT_TRACE_LEVEL, "HDD"},
73 [QDF_MODULE_ID_SME] = {QDF_DEFAULT_TRACE_LEVEL, "SME"},
74 [QDF_MODULE_ID_PE] = {QDF_DEFAULT_TRACE_LEVEL, "PE "},
75 [QDF_MODULE_ID_WMA] = {QDF_DEFAULT_TRACE_LEVEL, "WMA"},
76 [QDF_MODULE_ID_SYS] = {QDF_DEFAULT_TRACE_LEVEL, "SYS"},
77 [QDF_MODULE_ID_QDF] = {QDF_DEFAULT_TRACE_LEVEL, "QDF"},
78 [QDF_MODULE_ID_SAP] = {QDF_DEFAULT_TRACE_LEVEL, "SAP"},
79 [QDF_MODULE_ID_HDD_SOFTAP] = {QDF_DEFAULT_TRACE_LEVEL, "HSP"},
80 [QDF_MODULE_ID_HDD_DATA] = {QDF_DEFAULT_TRACE_LEVEL, "HDP"},
81 [QDF_MODULE_ID_HDD_SAP_DATA] = {QDF_DEFAULT_TRACE_LEVEL, "SDP"},
82 [QDF_MODULE_ID_BMI] = {QDF_DEFAULT_TRACE_LEVEL, "BMI"},
83 [QDF_MODULE_ID_HIF] = {QDF_DEFAULT_TRACE_LEVEL, "HIF"},
84 [QDF_MODULE_ID_TXRX] = {QDF_DEFAULT_TRACE_LEVEL, "TRX"},
85 [QDF_MODULE_ID_HTT] = {QDF_DEFAULT_TRACE_LEVEL, "HTT"},
86};
87
88/* Static and Global variables */
89static spinlock_t ltrace_lock;
90
91static qdf_trace_record_t g_qdf_trace_tbl[MAX_QDF_TRACE_RECORDS];
92/* global qdf trace data */
93static t_qdf_trace_data g_qdf_trace_data;
94/*
95 * all the call back functions for dumping MTRACE messages from ring buffer
96 * are stored in qdf_trace_cb_table,these callbacks are initialized during init
97 * only so, we will make a copy of these call back functions and maintain in to
98 * qdf_trace_restore_cb_table. Incase if we make modifications to
99 * qdf_trace_cb_table, we can certainly retrieve all the call back functions
100 * back from Restore Table
101 */
102static tp_qdf_trace_cb qdf_trace_cb_table[QDF_MODULE_ID_MAX];
103static tp_qdf_trace_cb qdf_trace_restore_cb_table[QDF_MODULE_ID_MAX];
Padma, Santhosh Kumar75394d62016-08-11 16:33:03 +0530104static tp_qdf_state_info_cb qdf_state_info_table[QDF_MODULE_ID_MAX];
Chouhan, Anurag57763182016-03-03 18:57:27 +0530105
Nirav Shahae6a0b32016-04-26 11:44:42 +0530106#ifdef FEATURE_DP_TRACE
Chouhan, Anurag57763182016-03-03 18:57:27 +0530107/* Static and Global variables */
108static spinlock_t l_dp_trace_lock;
109
110static struct qdf_dp_trace_record_s
111 g_qdf_dp_trace_tbl[MAX_QDF_DP_TRACE_RECORDS];
112
113/*
114 * all the options to configure/control DP trace are
115 * defined in this structure
116 */
117static struct s_qdf_dp_trace_data g_qdf_dp_trace_data;
118/*
119 * all the call back functions for dumping DPTRACE messages from ring buffer
120 * are stored in qdf_dp_trace_cb_table, callbacks are initialized during init
121 */
Houston Hoffman125423f2016-09-27 23:39:17 -0700122static tp_qdf_dp_trace_cb qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX+1];
Nirav Shahae6a0b32016-04-26 11:44:42 +0530123#endif
Chouhan, Anurag57763182016-03-03 18:57:27 +0530124/**
125 * qdf_trace_set_level() - Set the trace level for a particular module
126 * @module: Module id
127 * @level : trace level
128 *
129 * Trace level is a member of the QDF_TRACE_LEVEL enumeration indicating
130 * the severity of the condition causing the trace message to be issued.
131 * More severe conditions are more likely to be logged.
132 *
133 * This is an external API that allows trace levels to be set for each module.
134 *
135 * Return: None
136 */
137void qdf_trace_set_level(QDF_MODULE_ID module, QDF_TRACE_LEVEL level)
138{
139 /* make sure the caller is passing in a valid LEVEL */
140 if (level >= QDF_TRACE_LEVEL_MAX) {
141 pr_err("%s: Invalid trace level %d passed in!\n", __func__,
142 level);
143 return;
144 }
145
146 /* Treat 'none' differently. NONE means we have to run off all
147 * the bits in the bit mask so none of the traces appear. Anything
148 * other than 'none' means we need to turn ON a bit in the bitmask
149 */
150 if (QDF_TRACE_LEVEL_NONE == level)
151 g_qdf_trace_info[module].module_trace_level =
152 QDF_TRACE_LEVEL_NONE;
153 else
154 /* set the desired bit in the bit mask for the module trace
155 * level */
156 g_qdf_trace_info[module].module_trace_level |=
157 QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level);
158}
159EXPORT_SYMBOL(qdf_trace_set_level);
160
161/**
162 * qdf_trace_set_module_trace_level() - Set module trace level
163 * @module: Module id
164 * @level: Trace level for a module, as a bitmask as per 'module_trace_info'
165 *
166 * Sets the module trace level where the trace level is given as a bit mask
167 *
168 * Return: None
169 */
170void qdf_trace_set_module_trace_level(QDF_MODULE_ID module, uint32_t level)
171{
172 if (module < 0 || module >= QDF_MODULE_ID_MAX) {
173 pr_err("%s: Invalid module id %d passed\n", __func__, module);
174 return;
175 }
176 g_qdf_trace_info[module].module_trace_level = level;
177}
178EXPORT_SYMBOL(qdf_trace_set_module_trace_level);
179
180/**
181 * qdf_trace_set_value() - Set module trace value
182 * @module: Module id
183 * @level: Trace level for a module, as a bitmask as per 'module_trace_info'
184 * @on: set/clear the desired bit in the bit mask
185 *
186 * Return: None
187 */
188void qdf_trace_set_value(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
189 uint8_t on)
190{
191 /* make sure the caller is passing in a valid LEVEL */
192 if (level < 0 || level >= QDF_TRACE_LEVEL_MAX) {
193 pr_err("%s: Invalid trace level %d passed in!\n", __func__,
194 level);
195 return;
196 }
197
198 /* make sure the caller is passing in a valid module */
199 if (module < 0 || module >= QDF_MODULE_ID_MAX) {
200 pr_err("%s: Invalid module id %d passed in!\n", __func__,
201 module);
202 return;
203 }
204
205 /* Treat 'none' differently. NONE means we have to turn off all
206 the bits in the bit mask so none of the traces appear */
207 if (QDF_TRACE_LEVEL_NONE == level) {
208 g_qdf_trace_info[module].module_trace_level =
209 QDF_TRACE_LEVEL_NONE;
210 }
211 /* Treat 'All' differently. All means we have to turn on all
212 the bits in the bit mask so all of the traces appear */
213 else if (QDF_TRACE_LEVEL_ALL == level) {
214 g_qdf_trace_info[module].module_trace_level = 0xFFFF;
215 } else {
216 if (on)
217 /* set the desired bit in the bit mask for the module
218 trace level */
219 g_qdf_trace_info[module].module_trace_level |=
220 QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level);
221 else
222 /* clear the desired bit in the bit mask for the module
223 trace level */
224 g_qdf_trace_info[module].module_trace_level &=
225 ~(QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level));
226 }
227}
228EXPORT_SYMBOL(qdf_trace_set_value);
229
230/**
231 * qdf_trace_get_level() - get the trace level
232 * @module: module Id
233 * @level: trace level
234 *
235 * This is an external API that returns a bool value to signify if a
236 * particular trace level is set for the specified module.
237 * A member of the QDF_TRACE_LEVEL enumeration indicating the severity
238 * of the condition causing the trace message to be issued.
239 *
240 * Note that individual trace levels are the only valid values
241 * for this API. QDF_TRACE_LEVEL_NONE and QDF_TRACE_LEVEL_ALL
242 * are not valid input and will return false
243 *
244 * Return:
245 * false - the specified trace level for the specified module is OFF
246 * true - the specified trace level for the specified module is ON
247 */
248bool qdf_trace_get_level(QDF_MODULE_ID module, QDF_TRACE_LEVEL level)
249{
250 bool trace_on = false;
251
252 if ((QDF_TRACE_LEVEL_NONE == level) ||
253 (QDF_TRACE_LEVEL_ALL == level) || (level >= QDF_TRACE_LEVEL_MAX)) {
254 trace_on = false;
255 } else {
256 trace_on = (level & g_qdf_trace_info[module].module_trace_level)
257 ? true : false;
258 }
259
260 return trace_on;
261}
262EXPORT_SYMBOL(qdf_trace_get_level);
263
264/**
265 * qdf_snprintf() - wrapper function to snprintf
266 * @str_buffer: string Buffer
267 * @size: defines the size of the data record
268 * @str_format: Format string in which the message to be logged. This format
269 * string contains printf-like replacement parameters, which follow
270 * this parameter in the variable argument list.
271 *
272 * Return: None
273 */
274void qdf_snprintf(char *str_buffer, unsigned int size, char *str_format, ...)
275{
276 va_list val;
277
278 va_start(val, str_format);
279 snprintf(str_buffer, size, str_format, val);
280 va_end(val);
281}
282EXPORT_SYMBOL(qdf_snprintf);
283
284#ifdef QDF_ENABLE_TRACING
285
286/**
287 * qdf_trace_msg() - externally called trace function
288 * @module: Module identifier a member of the QDF_MODULE_ID
289 * enumeration that identifies the module issuing the trace message.
290 * @level: Trace level a member of the QDF_TRACE_LEVEL enumeration
291 * indicating the severity of the condition causing the trace message
292 * to be issued. More severe conditions are more likely to be logged.
293 * @str_format: Format string in which the message to be logged. This format
294 * string contains printf-like replacement parameters, which follow
295 * this parameter in the variable argument list.
296 *
297 * Checks the level of severity and accordingly prints the trace messages
298 *
299 * Return: None
300 */
301void qdf_trace_msg(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
302 char *str_format, ...)
303{
304 char str_buffer[QDF_TRACE_BUFFER_SIZE];
305 int n;
306
307 /* Print the trace message when the desired level bit is set in
308 the module tracel level mask */
309 if (g_qdf_trace_info[module].module_trace_level &
310 QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level)) {
311 /* the trace level strings in an array. these are ordered in
312 * the same order as the trace levels are defined in the enum
313 * (see QDF_TRACE_LEVEL) so we can index into this array with
314 * the level and get the right string. The qdf trace levels
315 * are... none, Fatal, Error, Warning, Info, info_high, info_med,
316 * info_low, Debug
317 */
318 static const char *TRACE_LEVEL_STR[] = { " ", "F ", "E ", "W ",
319 "I ", "IH", "IM", "IL", "D" };
320 va_list val;
321 va_start(val, str_format);
322
323 /* print the prefix string into the string buffer... */
324 n = snprintf(str_buffer, QDF_TRACE_BUFFER_SIZE,
325 "wlan: [%d:%2s:%3s] ",
326 in_interrupt() ? 0 : current->pid,
327 (char *)TRACE_LEVEL_STR[level],
328 (char *)g_qdf_trace_info[module].module_name_str);
329
330 /* print the formatted log message after the prefix string */
331 if ((n >= 0) && (n < QDF_TRACE_BUFFER_SIZE)) {
332 vsnprintf(str_buffer + n, QDF_TRACE_BUFFER_SIZE - n,
333 str_format, val);
334#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE)
335 wlan_log_to_user(level, (char *)str_buffer,
336 strlen(str_buffer));
337#else
338 pr_err("%s\n", str_buffer);
339#endif
340 }
341 va_end(val);
342 }
343}
344EXPORT_SYMBOL(qdf_trace_msg);
345
346/**
347 * qdf_trace_display() - Display trace
348 *
349 * Return: None
350 */
351void qdf_trace_display(void)
352{
353 QDF_MODULE_ID module_id;
354
355 pr_err
356 (" 1)FATAL 2)ERROR 3)WARN 4)INFO 5)INFO_H 6)INFO_M 7)INFO_L 8)DEBUG\n");
357 for (module_id = 0; module_id < QDF_MODULE_ID_MAX; ++module_id) {
358 pr_err
359 ("%2d)%s %s %s %s %s %s %s %s %s\n",
360 (int)module_id, g_qdf_trace_info[module_id].module_name_str,
361 (g_qdf_trace_info[module_id].
362 module_trace_level & (1 << QDF_TRACE_LEVEL_FATAL)) ? "X" :
363 " ",
364 (g_qdf_trace_info[module_id].
365 module_trace_level & (1 << QDF_TRACE_LEVEL_ERROR)) ? "X" :
366 " ",
367 (g_qdf_trace_info[module_id].
368 module_trace_level & (1 << QDF_TRACE_LEVEL_WARN)) ? "X" :
369 " ",
370 (g_qdf_trace_info[module_id].
371 module_trace_level & (1 << QDF_TRACE_LEVEL_INFO)) ? "X" :
372 " ",
373 (g_qdf_trace_info[module_id].
374 module_trace_level & (1 << QDF_TRACE_LEVEL_INFO_HIGH)) ? "X"
375 : " ",
376 (g_qdf_trace_info[module_id].
377 module_trace_level & (1 << QDF_TRACE_LEVEL_INFO_MED)) ? "X"
378 : " ",
379 (g_qdf_trace_info[module_id].
380 module_trace_level & (1 << QDF_TRACE_LEVEL_INFO_LOW)) ? "X"
381 : " ",
382 (g_qdf_trace_info[module_id].
383 module_trace_level & (1 << QDF_TRACE_LEVEL_DEBUG)) ? "X" :
384 " ");
385 }
386}
387EXPORT_SYMBOL(qdf_trace_display);
388
389#define ROW_SIZE 16
390/* Buffer size = data bytes(2 hex chars plus space) + NULL */
391#define BUFFER_SIZE ((ROW_SIZE * 3) + 1)
392
393/**
394 * qdf_trace_hex_dump() - externally called hex dump function
395 * @module: Module identifier a member of the QDF_MODULE_ID enumeration that
396 * identifies the module issuing the trace message.
397 * @level: Trace level a member of the QDF_TRACE_LEVEL enumeration indicating
398 * the severity of the condition causing the trace message to be
399 * issued. More severe conditions are more likely to be logged.
400 * @data: The base address of the buffer to be logged.
401 * @buf_len: The size of the buffer to be logged.
402 *
403 * Checks the level of severity and accordingly prints the trace messages
404 *
405 * Return: None
406 */
407void qdf_trace_hex_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level,
408 void *data, int buf_len)
409{
410 const u8 *ptr = data;
411 int i, linelen, remaining = buf_len;
412 unsigned char linebuf[BUFFER_SIZE];
413
414 if (!(g_qdf_trace_info[module].module_trace_level &
415 QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level)))
416 return;
417
418 for (i = 0; i < buf_len; i += ROW_SIZE) {
419 linelen = min(remaining, ROW_SIZE);
420 remaining -= ROW_SIZE;
421
422 hex_dump_to_buffer(ptr + i, linelen, ROW_SIZE, 1,
423 linebuf, sizeof(linebuf), false);
424
425 qdf_trace_msg(module, level, "%.8x: %s", i, linebuf);
426 }
427}
428EXPORT_SYMBOL(qdf_trace_hex_dump);
429
430#endif
431
432/**
433 * qdf_trace_enable() - Enable MTRACE for specific modules
434 * @bitmask_of_module_id: Bitmask according to enum of the modules.
435 * 32[dec] = 0010 0000 [bin] <enum of HDD is 5>
436 * 64[dec] = 0100 0000 [bin] <enum of SME is 6>
437 * 128[dec] = 1000 0000 [bin] <enum of PE is 7>
438 * @enable: can be true or false true implies enabling MTRACE false implies
439 * disabling MTRACE.
440 *
441 * Enable MTRACE for specific modules whose bits are set in bitmask and enable
442 * is true. if enable is false it disables MTRACE for that module. set the
443 * bitmask according to enum value of the modules.
444 * This functions will be called when you issue ioctl as mentioned following
445 * [iwpriv wlan0 setdumplog <value> <enable>].
446 * <value> - Decimal number, i.e. 64 decimal value shows only SME module,
447 * 128 decimal value shows only PE module, 192 decimal value shows PE and SME.
448 *
449 * Return: None
450 */
451void qdf_trace_enable(uint32_t bitmask_of_module_id, uint8_t enable)
452{
453 int i;
454 if (bitmask_of_module_id) {
455 for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
456 if (((bitmask_of_module_id >> i) & 1)) {
457 if (enable) {
458 if (NULL !=
459 qdf_trace_restore_cb_table[i]) {
460 qdf_trace_cb_table[i] =
461 qdf_trace_restore_cb_table[i];
462 }
463 } else {
464 qdf_trace_restore_cb_table[i] =
465 qdf_trace_cb_table[i];
466 qdf_trace_cb_table[i] = NULL;
467 }
468 }
469 }
470 } else {
471 if (enable) {
472 for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
473 if (NULL != qdf_trace_restore_cb_table[i]) {
474 qdf_trace_cb_table[i] =
475 qdf_trace_restore_cb_table[i];
476 }
477 }
478 } else {
479 for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
480 qdf_trace_restore_cb_table[i] =
481 qdf_trace_cb_table[i];
482 qdf_trace_cb_table[i] = NULL;
483 }
484 }
485 }
486}
487EXPORT_SYMBOL(qdf_trace_enable);
488
489/**
490 * qdf_trace_init() - initializes qdf trace structures and variables
491 *
492 * Called immediately after cds_preopen, so that we can start recording HDD
493 * events ASAP.
494 *
495 * Return: None
496 */
497void qdf_trace_init(void)
498{
499 uint8_t i;
500 g_qdf_trace_data.head = INVALID_QDF_TRACE_ADDR;
501 g_qdf_trace_data.tail = INVALID_QDF_TRACE_ADDR;
502 g_qdf_trace_data.num = 0;
503 g_qdf_trace_data.enable = true;
504 g_qdf_trace_data.dump_count = DEFAULT_QDF_TRACE_DUMP_COUNT;
505 g_qdf_trace_data.num_since_last_dump = 0;
506
507 for (i = 0; i < QDF_MODULE_ID_MAX; i++) {
508 qdf_trace_cb_table[i] = NULL;
509 qdf_trace_restore_cb_table[i] = NULL;
510 }
511}
512EXPORT_SYMBOL(qdf_trace_init);
513
514/**
515 * qdf_trace() - puts the messages in to ring-buffer
516 * @module: Enum of module, basically module id.
517 * @param: Code to be recorded
518 * @session: Session ID of the log
519 * @data: Actual message contents
520 *
521 * This function will be called from each module who wants record the messages
522 * in circular queue. Before calling this functions make sure you have
523 * registered your module with qdf through qdf_trace_register function.
524 *
525 * Return: None
526 */
527void qdf_trace(uint8_t module, uint8_t code, uint16_t session, uint32_t data)
528{
529 tp_qdf_trace_record rec = NULL;
530 unsigned long flags;
531
532 if (!g_qdf_trace_data.enable)
533 return;
534
535 /* if module is not registered, don't record for that module */
536 if (NULL == qdf_trace_cb_table[module])
537 return;
538
539 /* Aquire the lock so that only one thread at a time can fill the ring
540 * buffer
541 */
542 spin_lock_irqsave(&ltrace_lock, flags);
543
544 g_qdf_trace_data.num++;
545
546 if (g_qdf_trace_data.num > MAX_QDF_TRACE_RECORDS)
547 g_qdf_trace_data.num = MAX_QDF_TRACE_RECORDS;
548
549 if (INVALID_QDF_TRACE_ADDR == g_qdf_trace_data.head) {
550 /* first record */
551 g_qdf_trace_data.head = 0;
552 g_qdf_trace_data.tail = 0;
553 } else {
554 /* queue is not empty */
555 uint32_t tail = g_qdf_trace_data.tail + 1;
556
557 if (MAX_QDF_TRACE_RECORDS == tail)
558 tail = 0;
559
560 if (g_qdf_trace_data.head == tail) {
561 /* full */
562 if (MAX_QDF_TRACE_RECORDS == ++g_qdf_trace_data.head)
563 g_qdf_trace_data.head = 0;
564 }
565 g_qdf_trace_data.tail = tail;
566 }
567
568 rec = &g_qdf_trace_tbl[g_qdf_trace_data.tail];
569 rec->code = code;
570 rec->session = session;
571 rec->data = data;
572 rec->time = qdf_get_log_timestamp();
573 rec->module = module;
574 rec->pid = (in_interrupt() ? 0 : current->pid);
575 g_qdf_trace_data.num_since_last_dump++;
576 spin_unlock_irqrestore(&ltrace_lock, flags);
577}
578EXPORT_SYMBOL(qdf_trace);
579
580/**
581 * qdf_trace_spin_lock_init() - initializes the lock variable before use
582 *
583 * This function will be called from cds_alloc_global_context, we will have lock
584 * available to use ASAP
585 *
586 * Return: None
587 */
588QDF_STATUS qdf_trace_spin_lock_init(void)
589{
590 spin_lock_init(&ltrace_lock);
591
592 return QDF_STATUS_SUCCESS;
593}
594EXPORT_SYMBOL(qdf_trace_spin_lock_init);
595
596/**
597 * qdf_trace_register() - registers the call back functions
598 * @module_iD: enum value of module
599 * @qdf_trace_callback: call back functions to display the messages in
600 * particular format.
601 *
602 * Registers the call back functions to display the messages in particular
603 * format mentioned in these call back functions. This functions should be
604 * called by interested module in their init part as we will be ready to
605 * register as soon as modules are up.
606 *
607 * Return: None
608 */
609void qdf_trace_register(QDF_MODULE_ID module_iD,
610 tp_qdf_trace_cb qdf_trace_callback)
611{
612 qdf_trace_cb_table[module_iD] = qdf_trace_callback;
613}
614EXPORT_SYMBOL(qdf_trace_register);
615
616/**
617 * qdf_trace_dump_all() - Dump data from ring buffer via call back functions
618 * registered with QDF
619 * @p_mac: Context of particular module
620 * @code: Reason code
621 * @session: Session id of log
622 * @count: Number of lines to dump starting from tail to head
623 *
624 * This function will be called up on issueing ioctl call as mentioned following
625 * [iwpriv wlan0 dumplog 0 0 <n> <bitmask_of_module>]
626 *
627 * <n> - number lines to dump starting from tail to head.
628 *
629 * <bitmask_of_module> - if anybody wants to know how many messages were
630 * recorded for particular module/s mentioned by setbit in bitmask from last
631 * <n> messages. It is optional, if you don't provide then it will dump
632 * everything from buffer.
633 *
634 * Return: None
635 */
636void qdf_trace_dump_all(void *p_mac, uint8_t code, uint8_t session,
637 uint32_t count, uint32_t bitmask_of_module)
638{
639 qdf_trace_record_t p_record;
640 int32_t i, tail;
641
642 if (!g_qdf_trace_data.enable) {
643 QDF_TRACE(QDF_MODULE_ID_SYS,
644 QDF_TRACE_LEVEL_ERROR, "Tracing Disabled");
645 return;
646 }
647
648 QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO,
649 "Total Records: %d, Head: %d, Tail: %d",
650 g_qdf_trace_data.num, g_qdf_trace_data.head,
651 g_qdf_trace_data.tail);
652
653 /* aquire the lock so that only one thread at a time can read
654 * the ring buffer
655 */
656 spin_lock(&ltrace_lock);
657
658 if (g_qdf_trace_data.head != INVALID_QDF_TRACE_ADDR) {
659 i = g_qdf_trace_data.head;
660 tail = g_qdf_trace_data.tail;
661
662 if (count) {
663 if (count > g_qdf_trace_data.num)
664 count = g_qdf_trace_data.num;
665 if (tail >= (count - 1))
666 i = tail - count + 1;
667 else if (count != MAX_QDF_TRACE_RECORDS)
668 i = MAX_QDF_TRACE_RECORDS - ((count - 1) -
669 tail);
670 }
671
672 p_record = g_qdf_trace_tbl[i];
673 /* right now we are not using num_since_last_dump member but
674 * in future we might re-visit and use this member to track
675 * how many latest messages got added while we were dumping
676 * from ring buffer
677 */
678 g_qdf_trace_data.num_since_last_dump = 0;
679 spin_unlock(&ltrace_lock);
680 for (;; ) {
681 if ((code == 0 || (code == p_record.code)) &&
682 (qdf_trace_cb_table[p_record.module] != NULL)) {
683 if (0 == bitmask_of_module) {
684 qdf_trace_cb_table[p_record.
685 module] (p_mac,
686 &p_record,
687 (uint16_t)
688 i);
689 } else {
690 if (bitmask_of_module &
691 (1 << p_record.module)) {
692 qdf_trace_cb_table[p_record.
693 module]
694 (p_mac, &p_record,
695 (uint16_t) i);
696 }
697 }
698 }
699
700 if (i == tail)
701 break;
702 i += 1;
703
704 spin_lock(&ltrace_lock);
705 if (MAX_QDF_TRACE_RECORDS == i) {
706 i = 0;
707 p_record = g_qdf_trace_tbl[0];
708 } else {
709 p_record = g_qdf_trace_tbl[i];
710 }
711 spin_unlock(&ltrace_lock);
712 }
713 } else {
714 spin_unlock(&ltrace_lock);
715 }
716}
717EXPORT_SYMBOL(qdf_trace_dump_all);
718
Padma, Santhosh Kumar75394d62016-08-11 16:33:03 +0530719/**
720 * qdf_register_debugcb_init() - initializes debug callbacks
721 * to NULL
722 *
723 * Return: None
724 */
725void qdf_register_debugcb_init(void)
726{
727 uint8_t i;
728
729 for (i = 0; i < QDF_MODULE_ID_MAX; i++)
730 qdf_state_info_table[i] = NULL;
731}
732EXPORT_SYMBOL(qdf_register_debugcb_init);
733
734/**
735 * qdf_register_debug_callback() - stores callback handlers to print
736 * state information
737 * @module_id: module id of layer
738 * @qdf_state_infocb: callback to be registered
739 *
740 * This function is used to store callback handlers to print
741 * state information
742 *
743 * Return: None
744 */
745void qdf_register_debug_callback(QDF_MODULE_ID module_id,
746 tp_qdf_state_info_cb qdf_state_infocb)
747{
748 qdf_state_info_table[module_id] = qdf_state_infocb;
749}
750EXPORT_SYMBOL(qdf_register_debug_callback);
751
752/**
753 * qdf_state_info_dump_all() - it invokes callback of layer which registered
754 * its callback to print its state information.
755 * @buf: buffer pointer to be passed
756 * @size: size of buffer to be filled
757 * @driver_dump_size: actual size of buffer used
758 *
759 * Return: QDF_STATUS_SUCCESS on success
760 */
761QDF_STATUS qdf_state_info_dump_all(char *buf, uint16_t size,
762 uint16_t *driver_dump_size)
763{
764 uint8_t module, ret = QDF_STATUS_SUCCESS;
765 uint16_t buf_len = size;
766 char *buf_ptr = buf;
767
768 for (module = 0; module < QDF_MODULE_ID_MAX; module++) {
769 if (NULL != qdf_state_info_table[module]) {
770 qdf_state_info_table[module](&buf_ptr, &buf_len);
771 if (!buf_len) {
772 ret = QDF_STATUS_E_NOMEM;
773 break;
774 }
775 }
776 }
777
778 *driver_dump_size = size - buf_len;
779 return ret;
780}
781EXPORT_SYMBOL(qdf_state_info_dump_all);
782
Nirav Shahae6a0b32016-04-26 11:44:42 +0530783#ifdef FEATURE_DP_TRACE
Houston Hoffman125423f2016-09-27 23:39:17 -0700784static void qdf_dp_unused(struct qdf_dp_trace_record_s *record,
785 uint16_t index)
786{
787 qdf_print("%s: QDF_DP_TRACE_MAX event should not be generated",
788 __func__);
789}
790
Chouhan, Anurag57763182016-03-03 18:57:27 +0530791/**
792 * qdf_dp_trace_init() - enables the DP trace
793 * Called during driver load and it enables DP trace
794 *
795 * Return: None
796 */
797void qdf_dp_trace_init(void)
798{
799 uint8_t i;
800
801 qdf_dp_trace_spin_lock_init();
802 g_qdf_dp_trace_data.head = INVALID_QDF_DP_TRACE_ADDR;
803 g_qdf_dp_trace_data.tail = INVALID_QDF_DP_TRACE_ADDR;
804 g_qdf_dp_trace_data.num = 0;
Nirav Shah31d694b2016-05-03 20:18:22 +0530805 g_qdf_dp_trace_data.proto_bitmap = QDF_NBUF_PKT_TRAC_TYPE_EAPOL |
806 QDF_NBUF_PKT_TRAC_TYPE_DHCP | QDF_NBUF_PKT_TRAC_TYPE_MGMT_ACTION;
Chouhan, Anurag57763182016-03-03 18:57:27 +0530807 g_qdf_dp_trace_data.no_of_record = 0;
Nirav Shahcede2892016-05-19 12:41:15 +0530808 g_qdf_dp_trace_data.verbosity = QDF_DP_TRACE_VERBOSITY_LOW;
Chouhan, Anurag57763182016-03-03 18:57:27 +0530809 g_qdf_dp_trace_data.enable = true;
810
Houston Hoffman125423f2016-09-27 23:39:17 -0700811 for (i = 0; i < ARRAY_SIZE(qdf_dp_trace_cb_table); i++)
Chouhan, Anurag57763182016-03-03 18:57:27 +0530812 qdf_dp_trace_cb_table[i] = qdf_dp_display_record;
Nirav Shaheaa20d82016-04-25 18:01:05 +0530813
814 qdf_dp_trace_cb_table[QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD] =
815 qdf_dp_trace_cb_table[QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD] =
816 qdf_dp_trace_cb_table[QDF_DP_TRACE_FREE_PACKET_PTR_RECORD] =
817 qdf_dp_display_ptr_record;
818 qdf_dp_trace_cb_table[QDF_DP_TRACE_EAPOL_PACKET_RECORD] =
819 qdf_dp_trace_cb_table[QDF_DP_TRACE_DHCP_PACKET_RECORD] =
820 qdf_dp_trace_cb_table[QDF_DP_TRACE_ARP_PACKET_RECORD] =
821 qdf_dp_display_proto_pkt;
Nirav Shah31d694b2016-05-03 20:18:22 +0530822 qdf_dp_trace_cb_table[QDF_DP_TRACE_MGMT_PACKET_RECORD] =
823 qdf_dp_display_mgmt_pkt;
Nirav Shaheaa20d82016-04-25 18:01:05 +0530824
Houston Hoffman125423f2016-09-27 23:39:17 -0700825 qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX] = qdf_dp_unused;
Chouhan, Anurag57763182016-03-03 18:57:27 +0530826}
827EXPORT_SYMBOL(qdf_dp_trace_init);
828
829/**
830 * qdf_dp_trace_set_value() - Configure the value to control DP trace
831 * @proto_bitmap: defines the protocol to be tracked
832 * @no_of_records: defines the nth packet which is traced
833 * @verbosity: defines the verbosity level
834 *
835 * Return: None
836 */
837void qdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_record,
838 uint8_t verbosity)
839{
840 g_qdf_dp_trace_data.proto_bitmap = proto_bitmap;
841 g_qdf_dp_trace_data.no_of_record = no_of_record;
842 g_qdf_dp_trace_data.verbosity = verbosity;
843 return;
844}
845EXPORT_SYMBOL(qdf_dp_trace_set_value);
846
847/**
848 * qdf_dp_trace_enable_track() - enable the tracing for netbuf
849 * @code: defines the event
850 *
Nirav Shaheaa20d82016-04-25 18:01:05 +0530851 * In High verbosity all codes are logged.
852 * For Med/Low and Default case code which has
853 * less value than corresponding verbosity codes
854 * are logged.
855 *
Chouhan, Anurag57763182016-03-03 18:57:27 +0530856 * Return: true or false depends on whether tracing enabled
857 */
858static bool qdf_dp_trace_enable_track(enum QDF_DP_TRACE_ID code)
859{
Nirav Shaheaa20d82016-04-25 18:01:05 +0530860 switch (g_qdf_dp_trace_data.verbosity) {
861 case QDF_DP_TRACE_VERBOSITY_HIGH:
Chouhan, Anurag57763182016-03-03 18:57:27 +0530862 return true;
Nirav Shaheaa20d82016-04-25 18:01:05 +0530863 case QDF_DP_TRACE_VERBOSITY_MEDIUM:
864 if (code <= QDF_DP_TRACE_MED_VERBOSITY)
865 return true;
866 return false;
867 case QDF_DP_TRACE_VERBOSITY_LOW:
868 if (code <= QDF_DP_TRACE_LOW_VERBOSITY)
869 return true;
870 return false;
871 case QDF_DP_TRACE_VERBOSITY_DEFAULT:
872 if (code <= QDF_DP_TRACE_DEFAULT_VERBOSITY)
873 return true;
874 return false;
875 default:
876 return false;
877 }
Chouhan, Anurag57763182016-03-03 18:57:27 +0530878}
879EXPORT_SYMBOL(qdf_dp_trace_enable_track);
880
881/**
Nirav Shaheaa20d82016-04-25 18:01:05 +0530882 * qdf_dp_get_proto_bitmap() - get dp trace proto bitmap
883 *
884 * Return: proto bitmap
885 */
886uint8_t qdf_dp_get_proto_bitmap(void)
887{
888 if (g_qdf_dp_trace_data.enable)
889 return g_qdf_dp_trace_data.proto_bitmap;
890 else
891 return 0;
892}
893
894/**
Chouhan, Anurag57763182016-03-03 18:57:27 +0530895 * qdf_dp_trace_set_track() - Marks whether the packet needs to be traced
896 * @nbuf: defines the netbuf
Nirav Shah29beae02016-04-26 22:58:54 +0530897 * @dir: direction
Chouhan, Anurag57763182016-03-03 18:57:27 +0530898 *
899 * Return: None
900 */
Nirav Shah29beae02016-04-26 22:58:54 +0530901void qdf_dp_trace_set_track(qdf_nbuf_t nbuf, enum qdf_proto_dir dir)
Chouhan, Anurag57763182016-03-03 18:57:27 +0530902{
Nirav Shah29beae02016-04-26 22:58:54 +0530903 uint32_t count = 0;
904
Chouhan, Anurag57763182016-03-03 18:57:27 +0530905 spin_lock_bh(&l_dp_trace_lock);
Nirav Shah29beae02016-04-26 22:58:54 +0530906 if (QDF_TX == dir)
907 count = ++g_qdf_dp_trace_data.tx_count;
908 else if (QDF_RX == dir)
909 count = ++g_qdf_dp_trace_data.rx_count;
910
Chouhan, Anurag57763182016-03-03 18:57:27 +0530911 if ((g_qdf_dp_trace_data.no_of_record != 0) &&
Nirav Shah29beae02016-04-26 22:58:54 +0530912 (count % g_qdf_dp_trace_data.no_of_record == 0)) {
913 if (QDF_TX == dir)
914 QDF_NBUF_CB_TX_DP_TRACE(nbuf) = 1;
915 else if (QDF_RX == dir)
916 QDF_NBUF_CB_RX_DP_TRACE(nbuf) = 1;
Chouhan, Anurag57763182016-03-03 18:57:27 +0530917 }
918 spin_unlock_bh(&l_dp_trace_lock);
919 return;
920}
921EXPORT_SYMBOL(qdf_dp_trace_set_track);
922
923/**
924 * dump_hex_trace() - Display the data in buffer
925 * @buf: buffer which contains data to be displayed
926 * @buf_len: defines the size of the data to be displayed
927 *
928 * Return: None
929 */
Nirav Shaheaa20d82016-04-25 18:01:05 +0530930static void dump_hex_trace(char *str, uint8_t *buf, uint8_t buf_len)
Chouhan, Anurag57763182016-03-03 18:57:27 +0530931{
Nirav Shaheaa20d82016-04-25 18:01:05 +0530932 unsigned char linebuf[BUFFER_SIZE];
933 const u8 *ptr = buf;
934 int i, linelen, remaining = buf_len;
935
Chouhan, Anurag57763182016-03-03 18:57:27 +0530936 /* Dump the bytes in the last line */
Nirav Shaheaa20d82016-04-25 18:01:05 +0530937 for (i = 0; i < buf_len; i += ROW_SIZE) {
938 linelen = min(remaining, ROW_SIZE);
939 remaining -= ROW_SIZE;
940
941 hex_dump_to_buffer(ptr + i, linelen, ROW_SIZE, 1,
942 linebuf, sizeof(linebuf), false);
943
944 qdf_trace_msg(QDF_MODULE_ID_QDF,
Nirav Shah29beae02016-04-26 22:58:54 +0530945 QDF_TRACE_LEVEL_ERROR, "DPT: %s: %s", str, linebuf);
Nirav Shaheaa20d82016-04-25 18:01:05 +0530946 }
Chouhan, Anurag57763182016-03-03 18:57:27 +0530947}
948EXPORT_SYMBOL(dump_hex_trace);
949
950/**
Nirav Shaheaa20d82016-04-25 18:01:05 +0530951 * qdf_dp_code_to_string() - convert dptrace code to string
952 * @code: dptrace code
Chouhan, Anurag57763182016-03-03 18:57:27 +0530953 *
Nirav Shaheaa20d82016-04-25 18:01:05 +0530954 * Return: string version of code
Chouhan, Anurag57763182016-03-03 18:57:27 +0530955 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -0700956static
Nirav Shaheaa20d82016-04-25 18:01:05 +0530957const char *qdf_dp_code_to_string(enum QDF_DP_TRACE_ID code)
Chouhan, Anurag57763182016-03-03 18:57:27 +0530958{
Nirav Shaheaa20d82016-04-25 18:01:05 +0530959 switch (code) {
960 case QDF_DP_TRACE_DROP_PACKET_RECORD:
961 return "DROP:";
962 case QDF_DP_TRACE_EAPOL_PACKET_RECORD:
963 return "EAPOL:";
964 case QDF_DP_TRACE_DHCP_PACKET_RECORD:
965 return "DHCP:";
966 case QDF_DP_TRACE_ARP_PACKET_RECORD:
967 return "ARP:";
Nirav Shah31d694b2016-05-03 20:18:22 +0530968 case QDF_DP_TRACE_MGMT_PACKET_RECORD:
969 return "MGMT:";
Nirav Shah29beae02016-04-26 22:58:54 +0530970 case QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD:
971 return "HDD: TX: PTR:";
972 case QDF_DP_TRACE_HDD_TX_PACKET_RECORD:
973 return "HDD: TX: DATA:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530974 case QDF_DP_TRACE_CE_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530975 return "CE: TX: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530976 case QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530977 return "CE: TX: FAST: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530978 case QDF_DP_TRACE_FREE_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530979 return "FREE: TX: PTR:";
980 case QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD:
981 return "HTT: RX: PTR:";
982 case QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD:
983 return "HTT: RX: OF: PTR:";
984 case QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD:
985 return "HDD: RX: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530986 case QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530987 return "TXRX: TX: Q: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530988 case QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530989 return "TXRX: TX: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530990 case QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530991 return "TXRX: TX: FAST: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530992 case QDF_DP_TRACE_HTT_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530993 return "HTT: TX: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530994 case QDF_DP_TRACE_HTC_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530995 return "HTC: TX: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +0530996 case QDF_DP_TRACE_HIF_PACKET_PTR_RECORD:
Nirav Shah29beae02016-04-26 22:58:54 +0530997 return "HIF: TX: PTR:";
998 case QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD:
999 return "TXRX: RX: PTR:";
Nirav Shaheaa20d82016-04-25 18:01:05 +05301000 case QDF_DP_TRACE_HDD_TX_TIMEOUT:
Nirav Shah29beae02016-04-26 22:58:54 +05301001 return "HDD: STA: TO:";
Nirav Shaheaa20d82016-04-25 18:01:05 +05301002 case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
Nirav Shah29beae02016-04-26 22:58:54 +05301003 return "HDD: SAP: TO:";
Chouhan, Anurag57763182016-03-03 18:57:27 +05301004 default:
Nirav Shaheaa20d82016-04-25 18:01:05 +05301005 return "Invalid";
Chouhan, Anurag57763182016-03-03 18:57:27 +05301006 }
Chouhan, Anurag57763182016-03-03 18:57:27 +05301007}
Chouhan, Anurag57763182016-03-03 18:57:27 +05301008
1009/**
Nirav Shaheaa20d82016-04-25 18:01:05 +05301010 * qdf_dp_dir_to_str() - convert direction to string
1011 * @dir: direction
Chouhan, Anurag57763182016-03-03 18:57:27 +05301012 *
Nirav Shaheaa20d82016-04-25 18:01:05 +05301013 * Return: string version of direction
Chouhan, Anurag57763182016-03-03 18:57:27 +05301014 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -07001015static const char *qdf_dp_dir_to_str(enum qdf_proto_dir dir)
Chouhan, Anurag57763182016-03-03 18:57:27 +05301016{
Nirav Shaheaa20d82016-04-25 18:01:05 +05301017 switch (dir) {
1018 case QDF_TX:
Nirav Shah29beae02016-04-26 22:58:54 +05301019 return " --> ";
Nirav Shaheaa20d82016-04-25 18:01:05 +05301020 case QDF_RX:
Nirav Shah29beae02016-04-26 22:58:54 +05301021 return " <-- ";
Nirav Shaheaa20d82016-04-25 18:01:05 +05301022 default:
1023 return "invalid";
1024 }
1025}
Chouhan, Anurag57763182016-03-03 18:57:27 +05301026
Nirav Shaheaa20d82016-04-25 18:01:05 +05301027/**
1028 * qdf_dp_type_to_str() - convert packet type to string
1029 * @type: type
1030 *
1031 * Return: string version of packet type
1032 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -07001033static const char *qdf_dp_type_to_str(enum qdf_proto_type type)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301034{
1035 switch (type) {
1036 case QDF_PROTO_TYPE_DHCP:
1037 return "DHCP";
1038 case QDF_PROTO_TYPE_EAPOL:
1039 return "EAPOL";
1040 case QDF_PROTO_TYPE_ARP:
1041 return "ARP";
Nirav Shah31d694b2016-05-03 20:18:22 +05301042 case QDF_PROTO_TYPE_MGMT:
1043 return "MGMT";
Nirav Shaheaa20d82016-04-25 18:01:05 +05301044 default:
1045 return "invalid";
1046 }
1047}
Nirav Shaheaa20d82016-04-25 18:01:05 +05301048
1049/**
1050 * qdf_dp_subtype_to_str() - convert packet subtype to string
1051 * @type: type
1052 *
1053 * Return: string version of packet subtype
1054 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -07001055static const char *qdf_dp_subtype_to_str(enum qdf_proto_subtype subtype)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301056{
1057 switch (subtype) {
1058 case QDF_PROTO_EAPOL_M1:
1059 return "M1";
1060 case QDF_PROTO_EAPOL_M2:
1061 return "M2";
1062 case QDF_PROTO_EAPOL_M3:
1063 return "M3";
1064 case QDF_PROTO_EAPOL_M4:
1065 return "M4";
1066 case QDF_PROTO_DHCP_DISCOVER:
1067 return "DISCOVER";
1068 case QDF_PROTO_DHCP_REQUEST:
1069 return "REQUEST";
1070 case QDF_PROTO_DHCP_OFFER:
1071 return "OFFER";
1072 case QDF_PROTO_DHCP_ACK:
1073 return "ACK";
1074 case QDF_PROTO_DHCP_NACK:
1075 return "NACK";
1076 case QDF_PROTO_DHCP_RELEASE:
1077 return "RELEASE";
1078 case QDF_PROTO_DHCP_INFORM:
1079 return "INFORM";
1080 case QDF_PROTO_DHCP_DECLINE:
1081 return "DECLINE";
Nirav Shahcede2892016-05-19 12:41:15 +05301082 case QDF_PROTO_ARP_REQ:
1083 return "REQUEST";
1084 case QDF_PROTO_ARP_RES:
1085 return "RESPONSE";
Nirav Shah31d694b2016-05-03 20:18:22 +05301086 case QDF_PROTO_MGMT_ASSOC:
1087 return "ASSOC";
1088 case QDF_PROTO_MGMT_DISASSOC:
1089 return "DISASSOC";
1090 case QDF_PROTO_MGMT_AUTH:
1091 return "AUTH";
1092 case QDF_PROTO_MGMT_DEAUTH:
1093 return "DEAUTH";
Nirav Shaheaa20d82016-04-25 18:01:05 +05301094 default:
1095 return "invalid";
1096 }
1097}
Nirav Shaheaa20d82016-04-25 18:01:05 +05301098
1099/**
1100 * qdf_dp_enable_check() - check if dptrace is enable or not
1101 * @nbuf: nbuf
1102 * @code: dptrace code
1103 *
1104 * Return: true/false
1105 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -07001106static bool qdf_dp_enable_check(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code,
1107 enum qdf_proto_dir dir)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301108{
Chouhan, Anurag57763182016-03-03 18:57:27 +05301109 /* Return when Dp trace is not enabled */
1110 if (!g_qdf_dp_trace_data.enable)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301111 return false;
Chouhan, Anurag57763182016-03-03 18:57:27 +05301112
Nirav Shaheaa20d82016-04-25 18:01:05 +05301113 if (qdf_dp_trace_enable_track(code) == false)
1114 return false;
Chouhan, Anurag57763182016-03-03 18:57:27 +05301115
Nirav Shaheaa20d82016-04-25 18:01:05 +05301116 if ((nbuf) && ((QDF_NBUF_CB_TX_PACKET_TRACK(nbuf) !=
1117 QDF_NBUF_TX_PKT_DATA_TRACK) ||
Nirav Shah29beae02016-04-26 22:58:54 +05301118 ((dir == QDF_TX) && (QDF_NBUF_CB_TX_DP_TRACE(nbuf) == 0)) ||
1119 ((dir == QDF_RX) && (QDF_NBUF_CB_RX_DP_TRACE(nbuf) == 0))))
Nirav Shaheaa20d82016-04-25 18:01:05 +05301120 return false;
Chouhan, Anurag57763182016-03-03 18:57:27 +05301121
Nirav Shaheaa20d82016-04-25 18:01:05 +05301122 return true;
1123}
Chouhan, Anurag57763182016-03-03 18:57:27 +05301124
Nirav Shaheaa20d82016-04-25 18:01:05 +05301125/**
1126 * qdf_dp_add_record() - add dp trace record
1127 * @code: dptrace code
1128 * @data: data pointer
1129 * @size: size of buffer
Nirav Shahcede2892016-05-19 12:41:15 +05301130 * @print: true to print it in kmsg
Nirav Shaheaa20d82016-04-25 18:01:05 +05301131 *
1132 * Return: none
1133 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -07001134static void qdf_dp_add_record(enum QDF_DP_TRACE_ID code,
1135 uint8_t *data, uint8_t size, bool print)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301136{
1137 struct qdf_dp_trace_record_s *rec = NULL;
Nirav Shah29beae02016-04-26 22:58:54 +05301138 int index;
Chouhan, Anurag57763182016-03-03 18:57:27 +05301139 spin_lock_bh(&l_dp_trace_lock);
1140
1141 g_qdf_dp_trace_data.num++;
1142
1143 if (g_qdf_dp_trace_data.num > MAX_QDF_DP_TRACE_RECORDS)
1144 g_qdf_dp_trace_data.num = MAX_QDF_DP_TRACE_RECORDS;
1145
1146 if (INVALID_QDF_DP_TRACE_ADDR == g_qdf_dp_trace_data.head) {
1147 /* first record */
1148 g_qdf_dp_trace_data.head = 0;
1149 g_qdf_dp_trace_data.tail = 0;
1150 } else {
1151 /* queue is not empty */
1152 g_qdf_dp_trace_data.tail++;
1153
1154 if (MAX_QDF_DP_TRACE_RECORDS == g_qdf_dp_trace_data.tail)
1155 g_qdf_dp_trace_data.tail = 0;
1156
1157 if (g_qdf_dp_trace_data.head == g_qdf_dp_trace_data.tail) {
1158 /* full */
1159 if (MAX_QDF_DP_TRACE_RECORDS ==
1160 ++g_qdf_dp_trace_data.head)
1161 g_qdf_dp_trace_data.head = 0;
1162 }
1163 }
1164
1165 rec = &g_qdf_dp_trace_tbl[g_qdf_dp_trace_data.tail];
Nirav Shah29beae02016-04-26 22:58:54 +05301166 index = g_qdf_dp_trace_data.tail;
Chouhan, Anurag57763182016-03-03 18:57:27 +05301167 rec->code = code;
1168 rec->size = 0;
1169 if (data != NULL && size > 0) {
1170 if (size > QDF_DP_TRACE_RECORD_SIZE)
1171 size = QDF_DP_TRACE_RECORD_SIZE;
1172
1173 rec->size = size;
Nirav Shaheaa20d82016-04-25 18:01:05 +05301174 qdf_mem_copy(rec->data, data, size);
Chouhan, Anurag57763182016-03-03 18:57:27 +05301175 }
1176 rec->time = qdf_get_log_timestamp();
1177 rec->pid = (in_interrupt() ? 0 : current->pid);
1178 spin_unlock_bh(&l_dp_trace_lock);
Nirav Shaheaa20d82016-04-25 18:01:05 +05301179
Nirav Shahcede2892016-05-19 12:41:15 +05301180 if (g_qdf_dp_trace_data.live_mode || (print == true))
Nirav Shah29beae02016-04-26 22:58:54 +05301181 qdf_dp_trace_cb_table[rec->code] (rec, index);
Nirav Shaheaa20d82016-04-25 18:01:05 +05301182}
Nirav Shaheaa20d82016-04-25 18:01:05 +05301183
Nirav Shaheaa20d82016-04-25 18:01:05 +05301184
1185/**
1186 * qdf_log_eapol_pkt() - log EAPOL packet
1187 * @session_id: vdev_id
1188 * @skb: skb pointer
Nirav Shah29beae02016-04-26 22:58:54 +05301189 * @dir: direction
Nirav Shaheaa20d82016-04-25 18:01:05 +05301190 *
1191 * Return: true/false
1192 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -07001193static bool qdf_log_eapol_pkt(uint8_t session_id, struct sk_buff *skb,
1194 enum qdf_proto_dir dir)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301195{
Nirav Shaheaa20d82016-04-25 18:01:05 +05301196 enum qdf_proto_subtype subtype;
1197
1198 if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_EAPOL) &&
Nirav Shah9c3b3fe2016-07-20 16:05:06 +05301199 ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_EAPOL ==
1200 QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
1201 (dir == QDF_RX && qdf_nbuf_is_ipv4_eapol_pkt(skb) == true))) {
Nirav Shaheaa20d82016-04-25 18:01:05 +05301202
Himanshu Agarwalfcd64e92016-07-20 17:45:58 +05301203 subtype = qdf_nbuf_get_eapol_subtype(skb);
Nirav Shaheaa20d82016-04-25 18:01:05 +05301204 DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_EAPOL_PACKET_RECORD,
1205 session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET),
1206 (skb->data + QDF_NBUF_DEST_MAC_OFFSET),
Nirav Shah29beae02016-04-26 22:58:54 +05301207 QDF_PROTO_TYPE_EAPOL, subtype, dir));
Nirav Shah29beae02016-04-26 22:58:54 +05301208 if (QDF_TX == dir)
1209 QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
1210 else if (QDF_RX == dir)
1211 QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
Nirav Shaheaa20d82016-04-25 18:01:05 +05301212 return true;
1213 }
1214 return false;
1215}
Nirav Shaheaa20d82016-04-25 18:01:05 +05301216
1217/**
1218 * qdf_log_dhcp_pkt() - log DHCP packet
1219 * @session_id: vdev_id
1220 * @skb: skb pointer
Nirav Shah29beae02016-04-26 22:58:54 +05301221 * @dir: direction
Nirav Shaheaa20d82016-04-25 18:01:05 +05301222 *
1223 * Return: true/false
1224 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -07001225static bool qdf_log_dhcp_pkt(uint8_t session_id, struct sk_buff *skb,
1226 enum qdf_proto_dir dir)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301227{
1228 enum qdf_proto_subtype subtype = QDF_PROTO_INVALID;
1229
1230 if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_DHCP) &&
Nirav Shah9c3b3fe2016-07-20 16:05:06 +05301231 ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP ==
1232 QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
1233 (dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(skb) == true))) {
Nirav Shaheaa20d82016-04-25 18:01:05 +05301234
Himanshu Agarwalfcd64e92016-07-20 17:45:58 +05301235 subtype = qdf_nbuf_get_dhcp_subtype(skb);
Nirav Shaheaa20d82016-04-25 18:01:05 +05301236 DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_DHCP_PACKET_RECORD,
1237 session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET),
1238 (skb->data + QDF_NBUF_DEST_MAC_OFFSET),
Nirav Shah29beae02016-04-26 22:58:54 +05301239 QDF_PROTO_TYPE_DHCP, subtype, dir));
1240 if (QDF_TX == dir)
1241 QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
1242 else if (QDF_RX == dir)
1243 QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
Nirav Shaheaa20d82016-04-25 18:01:05 +05301244 return true;
1245 }
1246 return false;
1247}
Nirav Shaheaa20d82016-04-25 18:01:05 +05301248
1249/**
1250 * qdf_log_arp_pkt() - log ARP packet
1251 * @session_id: vdev_id
1252 * @skb: skb pointer
Nirav Shah29beae02016-04-26 22:58:54 +05301253 * @dir: direction
Nirav Shaheaa20d82016-04-25 18:01:05 +05301254 *
1255 * Return: true/false
1256 */
Jeff Johnson4729b6f2016-10-07 13:02:43 -07001257static bool qdf_log_arp_pkt(uint8_t session_id, struct sk_buff *skb,
1258 enum qdf_proto_dir dir)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301259{
Nirav Shahcede2892016-05-19 12:41:15 +05301260 enum qdf_proto_subtype proto_subtype;
1261
Nirav Shaheaa20d82016-04-25 18:01:05 +05301262 if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ARP) &&
Nirav Shah9c3b3fe2016-07-20 16:05:06 +05301263 ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_ARP ==
1264 QDF_NBUF_CB_GET_PACKET_TYPE(skb)) ||
1265 (dir == QDF_RX && qdf_nbuf_is_ipv4_arp_pkt(skb) == true))) {
Nirav Shahcede2892016-05-19 12:41:15 +05301266
Himanshu Agarwalfcd64e92016-07-20 17:45:58 +05301267 proto_subtype = qdf_nbuf_get_arp_subtype(skb);
Nirav Shaheaa20d82016-04-25 18:01:05 +05301268 DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ARP_PACKET_RECORD,
1269 session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET),
1270 (skb->data + QDF_NBUF_DEST_MAC_OFFSET),
Nirav Shahcede2892016-05-19 12:41:15 +05301271 QDF_PROTO_TYPE_ARP, proto_subtype, dir));
Nirav Shah29beae02016-04-26 22:58:54 +05301272 if (QDF_TX == dir)
1273 QDF_NBUF_CB_TX_DP_TRACE(skb) = 1;
1274 else if (QDF_RX == dir)
1275 QDF_NBUF_CB_RX_DP_TRACE(skb) = 1;
Nirav Shaheaa20d82016-04-25 18:01:05 +05301276 return true;
1277 }
1278 return false;
1279}
Nirav Shaheaa20d82016-04-25 18:01:05 +05301280
1281/**
1282 * qdf_dp_trace_log_pkt() - log packet type enabled through iwpriv
1283 * @session_id: vdev_id
1284 * @skb: skb pointer
Nirav Shah29beae02016-04-26 22:58:54 +05301285 * @dir: direction
Nirav Shaheaa20d82016-04-25 18:01:05 +05301286 *
1287 * Return: none
1288 */
1289void qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb,
Nirav Shah29beae02016-04-26 22:58:54 +05301290 enum qdf_proto_dir dir)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301291{
1292 if (qdf_dp_get_proto_bitmap()) {
1293 if (qdf_log_arp_pkt(session_id,
Nirav Shah29beae02016-04-26 22:58:54 +05301294 skb, dir) == false) {
Nirav Shaheaa20d82016-04-25 18:01:05 +05301295 if (qdf_log_dhcp_pkt(session_id,
Nirav Shah29beae02016-04-26 22:58:54 +05301296 skb, dir) == false) {
Nirav Shaheaa20d82016-04-25 18:01:05 +05301297 if (qdf_log_eapol_pkt(session_id,
Nirav Shah29beae02016-04-26 22:58:54 +05301298 skb, dir) == false) {
Nirav Shaheaa20d82016-04-25 18:01:05 +05301299 return;
1300 }
1301 }
1302 }
1303 }
1304}
1305EXPORT_SYMBOL(qdf_dp_trace_log_pkt);
1306
1307/**
Nirav Shah31d694b2016-05-03 20:18:22 +05301308 * qdf_dp_display_mgmt_pkt() - display proto packet
1309 * @record: dptrace record
1310 * @index: index
1311 *
1312 * Return: none
1313 */
1314void qdf_dp_display_mgmt_pkt(struct qdf_dp_trace_record_s *record,
1315 uint16_t index)
1316{
1317 struct qdf_dp_trace_mgmt_buf *buf =
1318 (struct qdf_dp_trace_mgmt_buf *)record->data;
1319
1320 qdf_print("DPT: %04d: %012llu: %s vdev_id %d", index,
1321 record->time, qdf_dp_code_to_string(record->code),
1322 buf->vdev_id);
1323 qdf_print("DPT: Type %s Subtype %s", qdf_dp_type_to_str(buf->type),
1324 qdf_dp_subtype_to_str(buf->subtype));
1325}
1326EXPORT_SYMBOL(qdf_dp_display_mgmt_pkt);
1327
1328/**
1329 * qdf_dp_trace_mgmt_pkt() - record mgmt packet
1330 * @code: dptrace code
1331 * @vdev_id: vdev id
1332 * @type: proto type
1333 * @subtype: proto subtype
1334 *
1335 * Return: none
1336 */
1337void qdf_dp_trace_mgmt_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id,
1338 enum qdf_proto_type type, enum qdf_proto_subtype subtype)
1339{
1340 struct qdf_dp_trace_mgmt_buf buf;
1341 int buf_size = sizeof(struct qdf_dp_trace_mgmt_buf);
1342
1343 if (qdf_dp_enable_check(NULL, code, QDF_NA) == false)
1344 return;
1345
1346 if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
1347 QDF_BUG(0);
1348
1349 buf.type = type;
1350 buf.subtype = subtype;
1351 buf.vdev_id = vdev_id;
Nirav Shahcede2892016-05-19 12:41:15 +05301352 qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, true);
Nirav Shah31d694b2016-05-03 20:18:22 +05301353}
1354EXPORT_SYMBOL(qdf_dp_trace_mgmt_pkt);
1355
1356
1357/**
Nirav Shaheaa20d82016-04-25 18:01:05 +05301358 * qdf_dp_display_proto_pkt() - display proto packet
1359 * @record: dptrace record
1360 * @index: index
1361 *
1362 * Return: none
1363 */
1364void qdf_dp_display_proto_pkt(struct qdf_dp_trace_record_s *record,
1365 uint16_t index)
1366{
1367 struct qdf_dp_trace_proto_buf *buf =
1368 (struct qdf_dp_trace_proto_buf *)record->data;
1369
Nirav Shah29beae02016-04-26 22:58:54 +05301370 qdf_print("DPT: %04d: %012llu: %s vdev_id %d", index,
Nirav Shaheaa20d82016-04-25 18:01:05 +05301371 record->time, qdf_dp_code_to_string(record->code),
1372 buf->vdev_id);
Anurag Chouhan61d118e2016-07-20 18:43:18 +05301373 qdf_print("DPT: SA: " QDF_MAC_ADDRESS_STR " %s DA: "
1374 QDF_MAC_ADDRESS_STR " Type %s Subtype %s",
1375 QDF_MAC_ADDR_ARRAY(buf->sa.bytes), qdf_dp_dir_to_str(buf->dir),
1376 QDF_MAC_ADDR_ARRAY(buf->da.bytes),
1377 qdf_dp_type_to_str(buf->type),
Nirav Shaheaa20d82016-04-25 18:01:05 +05301378 qdf_dp_subtype_to_str(buf->subtype));
1379}
1380EXPORT_SYMBOL(qdf_dp_display_proto_pkt);
1381
1382/**
1383 * qdf_dp_trace_proto_pkt() - record proto packet
1384 * @code: dptrace code
1385 * @vdev_id: vdev id
1386 * @sa: source mac address
1387 * @da: destination mac address
1388 * @type: proto type
1389 * @subtype: proto subtype
1390 * @dir: direction
1391 *
1392 * Return: none
1393 */
1394void qdf_dp_trace_proto_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id,
1395 uint8_t *sa, uint8_t *da, enum qdf_proto_type type,
1396 enum qdf_proto_subtype subtype, enum qdf_proto_dir dir)
1397{
1398 struct qdf_dp_trace_proto_buf buf;
1399 int buf_size = sizeof(struct qdf_dp_trace_ptr_buf);
1400
Nirav Shah29beae02016-04-26 22:58:54 +05301401 if (qdf_dp_enable_check(NULL, code, dir) == false)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301402 return;
1403
1404 if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
1405 QDF_BUG(0);
1406
1407 memcpy(&buf.sa, sa, QDF_NET_ETH_LEN);
1408 memcpy(&buf.da, da, QDF_NET_ETH_LEN);
1409 buf.dir = dir;
1410 buf.type = type;
1411 buf.subtype = subtype;
1412 buf.vdev_id = vdev_id;
Nirav Shahcede2892016-05-19 12:41:15 +05301413 qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, true);
Nirav Shaheaa20d82016-04-25 18:01:05 +05301414}
1415EXPORT_SYMBOL(qdf_dp_trace_proto_pkt);
1416
1417/**
1418 * qdf_dp_display_ptr_record() - display record
1419 * @record: dptrace record
1420 * @index: index
1421 *
1422 * Return: none
1423 */
1424void qdf_dp_display_ptr_record(struct qdf_dp_trace_record_s *record,
1425 uint16_t index)
1426{
1427 struct qdf_dp_trace_ptr_buf *buf =
1428 (struct qdf_dp_trace_ptr_buf *)record->data;
1429
Nirav Shah29beae02016-04-26 22:58:54 +05301430 if (record->code == QDF_DP_TRACE_FREE_PACKET_PTR_RECORD)
1431 qdf_print("DPT: %04d: %012llu: %s msdu_id: %d, status: %d",
1432 index, record->time,
1433 qdf_dp_code_to_string(record->code), buf->msdu_id,
1434 buf->status);
1435 else
1436 qdf_print("DPT: %04d: %012llu: %s msdu_id: %d, vdev_id: %d",
1437 index,
1438 record->time, qdf_dp_code_to_string(record->code),
1439 buf->msdu_id, buf->status);
Nirav Shaheaa20d82016-04-25 18:01:05 +05301440 dump_hex_trace("cookie", (uint8_t *)&buf->cookie, sizeof(buf->cookie));
1441}
1442EXPORT_SYMBOL(qdf_dp_display_ptr_record);
1443
1444/**
1445 * qdf_dp_trace_ptr() - record dptrace
1446 * @code: dptrace code
1447 * @data: data
1448 * @size: size of data
1449 * @msdu_id: msdu_id
1450 * @status: return status
1451 *
1452 * Return: none
1453 */
1454void qdf_dp_trace_ptr(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code,
1455 uint8_t *data, uint8_t size, uint16_t msdu_id, uint16_t status)
1456{
1457 struct qdf_dp_trace_ptr_buf buf;
1458 int buf_size = sizeof(struct qdf_dp_trace_ptr_buf);
1459
Nirav Shah29beae02016-04-26 22:58:54 +05301460 if (qdf_dp_enable_check(nbuf, code, QDF_TX) == false)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301461 return;
1462
1463 if (buf_size > QDF_DP_TRACE_RECORD_SIZE)
1464 QDF_BUG(0);
1465
1466 qdf_mem_copy(&buf.cookie, data, size);
1467 buf.msdu_id = msdu_id;
1468 buf.status = status;
Nirav Shahcede2892016-05-19 12:41:15 +05301469 qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, false);
Nirav Shaheaa20d82016-04-25 18:01:05 +05301470}
1471EXPORT_SYMBOL(qdf_dp_trace_ptr);
1472
1473/**
1474 * qdf_dp_display_trace() - Displays a record in DP trace
1475 * @pRecord : pointer to a record in DP trace
1476 * @recIndex : record index
1477 *
1478 * Return: None
1479 */
1480void qdf_dp_display_record(struct qdf_dp_trace_record_s *pRecord,
1481 uint16_t recIndex)
1482{
Nirav Shah29beae02016-04-26 22:58:54 +05301483 qdf_print("DPT: %04d: %012llu: %s", recIndex,
Nirav Shaheaa20d82016-04-25 18:01:05 +05301484 pRecord->time, qdf_dp_code_to_string(pRecord->code));
1485 switch (pRecord->code) {
1486 case QDF_DP_TRACE_HDD_TX_TIMEOUT:
1487 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
1488 "HDD TX Timeout\n");
1489 break;
1490 case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
1491 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
1492 "HDD SoftAP TX Timeout\n");
1493 break;
Nirav Shah29beae02016-04-26 22:58:54 +05301494 case QDF_DP_TRACE_HDD_TX_PACKET_RECORD:
Nirav Shaheaa20d82016-04-25 18:01:05 +05301495 dump_hex_trace("DATA", pRecord->data, pRecord->size);
1496 break;
1497 default:
1498 dump_hex_trace("cookie", pRecord->data, pRecord->size);
1499 }
1500}
1501EXPORT_SYMBOL(qdf_dp_display_record);
1502
1503
1504/**
1505 * qdf_dp_trace() - Stores the data in buffer
1506 * @nbuf : defines the netbuf
1507 * @code : defines the event
1508 * @data : defines the data to be stored
1509 * @size : defines the size of the data record
1510 *
1511 * Return: None
1512 */
1513void qdf_dp_trace(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code,
Nirav Shah29beae02016-04-26 22:58:54 +05301514 uint8_t *data, uint8_t size, enum qdf_proto_dir dir)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301515{
Nirav Shah29beae02016-04-26 22:58:54 +05301516
1517 if (qdf_dp_enable_check(nbuf, code, dir) == false)
Nirav Shaheaa20d82016-04-25 18:01:05 +05301518 return;
1519
Nirav Shahcede2892016-05-19 12:41:15 +05301520 qdf_dp_add_record(code, data, size, false);
Chouhan, Anurag57763182016-03-03 18:57:27 +05301521}
1522EXPORT_SYMBOL(qdf_dp_trace);
1523
1524/**
1525 * qdf_dp_trace_spin_lock_init() - initializes the lock variable before use
1526 * This function will be called from cds_alloc_global_context, we will have lock
1527 * available to use ASAP
1528 *
1529 * Return: None
1530 */
1531void qdf_dp_trace_spin_lock_init(void)
1532{
1533 spin_lock_init(&l_dp_trace_lock);
Chouhan, Anurag57763182016-03-03 18:57:27 +05301534}
1535EXPORT_SYMBOL(qdf_dp_trace_spin_lock_init);
1536
1537/**
Nirav Shah29beae02016-04-26 22:58:54 +05301538 * qdf_dp_trace_enable_live_mode() - enable live mode for dptrace
1539 *
1540 * Return: none
1541 */
1542void qdf_dp_trace_enable_live_mode(void)
1543{
1544 g_qdf_dp_trace_data.live_mode = 1;
1545
1546}
1547EXPORT_SYMBOL(qdf_dp_trace_enable_live_mode);
1548
1549
1550/**
Nirav Shahcede2892016-05-19 12:41:15 +05301551 * qdf_dp_trace_clear_buffer() - clear dp trace buffer
1552 *
1553 * Return: none
1554 */
1555void qdf_dp_trace_clear_buffer(void)
1556{
1557 g_qdf_dp_trace_data.head = INVALID_QDF_DP_TRACE_ADDR;
1558 g_qdf_dp_trace_data.tail = INVALID_QDF_DP_TRACE_ADDR;
1559 g_qdf_dp_trace_data.num = 0;
1560 g_qdf_dp_trace_data.proto_bitmap = QDF_NBUF_PKT_TRAC_TYPE_EAPOL |
1561 QDF_NBUF_PKT_TRAC_TYPE_DHCP | QDF_NBUF_PKT_TRAC_TYPE_MGMT_ACTION;
1562 g_qdf_dp_trace_data.no_of_record = 0;
1563 g_qdf_dp_trace_data.verbosity = QDF_DP_TRACE_VERBOSITY_LOW;
1564 g_qdf_dp_trace_data.enable = true;
1565
1566 memset(g_qdf_dp_trace_tbl, 0,
1567 MAX_QDF_DP_TRACE_RECORDS * sizeof(struct qdf_dp_trace_record_s));
1568}
1569EXPORT_SYMBOL(qdf_dp_trace_clear_buffer);
1570
1571/**
Chouhan, Anurag57763182016-03-03 18:57:27 +05301572 * qdf_dp_trace_dump_all() - Dump data from ring buffer via call back functions
1573 * registered with QDF
1574 * @code: Reason code
1575 * @count: Number of lines to dump starting from tail to head
1576 *
1577 * Return: None
1578 */
1579void qdf_dp_trace_dump_all(uint32_t count)
1580{
1581 struct qdf_dp_trace_record_s p_record;
1582 int32_t i, tail;
1583
1584 if (!g_qdf_dp_trace_data.enable) {
1585 QDF_TRACE(QDF_MODULE_ID_SYS,
1586 QDF_TRACE_LEVEL_ERROR, "Tracing Disabled");
1587 return;
1588 }
1589
1590 QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR,
1591 "Total Records: %d, Head: %d, Tail: %d",
1592 g_qdf_dp_trace_data.num, g_qdf_dp_trace_data.head,
1593 g_qdf_dp_trace_data.tail);
1594
1595 /* aquire the lock so that only one thread at a time can read
1596 * the ring buffer
1597 */
1598 spin_lock_bh(&l_dp_trace_lock);
1599
1600 if (g_qdf_dp_trace_data.head != INVALID_QDF_DP_TRACE_ADDR) {
1601 i = g_qdf_dp_trace_data.head;
1602 tail = g_qdf_dp_trace_data.tail;
1603
1604 if (count) {
1605 if (count > g_qdf_dp_trace_data.num)
1606 count = g_qdf_dp_trace_data.num;
1607 if (tail >= (count - 1))
1608 i = tail - count + 1;
1609 else if (count != MAX_QDF_DP_TRACE_RECORDS)
1610 i = MAX_QDF_DP_TRACE_RECORDS - ((count - 1) -
1611 tail);
1612 }
1613
1614 p_record = g_qdf_dp_trace_tbl[i];
1615 spin_unlock_bh(&l_dp_trace_lock);
1616 for (;; ) {
1617
1618 qdf_dp_trace_cb_table[p_record.
1619 code] (&p_record, (uint16_t)i);
1620 if (i == tail)
1621 break;
1622 i += 1;
1623
1624 spin_lock_bh(&l_dp_trace_lock);
1625 if (MAX_QDF_DP_TRACE_RECORDS == i)
1626 i = 0;
1627
1628 p_record = g_qdf_dp_trace_tbl[i];
1629 spin_unlock_bh(&l_dp_trace_lock);
1630 }
1631 } else {
1632 spin_unlock_bh(&l_dp_trace_lock);
1633 }
1634}
1635EXPORT_SYMBOL(qdf_dp_trace_dump_all);
Nirav Shahae6a0b32016-04-26 11:44:42 +05301636#endif