blob: 3d59c53d272f7e2f7213518bf89988d2994adf3c [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
3 *
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: cdf_trace
30 *
31 * Connectivity driver framework (CDF) trace APIs
32 *
33 * Trace, logging, and debugging definitions and APIs
34 *
35 */
36
37/* Include Files */
38#include <cdf_trace.h>
39#include <ani_global.h>
40#include <wlan_logging_sock_svc.h>
41#include "cdf_time.h"
42/* Preprocessor definitions and constants */
43
44#define CDF_TRACE_BUFFER_SIZE (512)
45
46/* macro to map cdf trace levels into the bitmask */
47#define CDF_TRACE_LEVEL_TO_MODULE_BITMASK(_level) ((1 << (_level)))
48
49typedef struct {
50 /* Trace level for a module, as a bitmask. The bits in this mask
51 * are ordered by CDF_TRACE_LEVEL. For example, each bit represents
52 * one of the bits in CDF_TRACE_LEVEL that may be turned on to have
53 * traces at that level logged, i.e. if CDF_TRACE_LEVEL_ERROR is
54 * == 2, then if bit 2 (low order) is turned ON, then ERROR traces
55 * will be printed to the trace log.
56 * Note that all bits turned OFF means no traces
57 */
58 uint16_t moduleTraceLevel;
59
60 /* 3 character string name for the module */
61 unsigned char moduleNameStr[4]; /* 3 chars plus the NULL */
62} moduleTraceInfo;
63
64#define CDF_DEFAULT_TRACE_LEVEL \
65 ((1 << CDF_TRACE_LEVEL_FATAL) | (1 << CDF_TRACE_LEVEL_ERROR))
66
67/* Array of static data that contains all of the per module trace
68 * information. This includes the trace level for the module and
69 * the 3 character 'name' of the module for marking the trace logs
70 */
71moduleTraceInfo g_cdf_trace_info[CDF_MODULE_ID_MAX] = {
72 [CDF_MODULE_ID_TLSHIM] = {CDF_DEFAULT_TRACE_LEVEL, "DP"},
73 [CDF_MODULE_ID_WMI] = {CDF_DEFAULT_TRACE_LEVEL, "WMI"},
74 [CDF_MODULE_ID_HDD] = {CDF_DEFAULT_TRACE_LEVEL, "HDD"},
75 [CDF_MODULE_ID_SME] = {CDF_DEFAULT_TRACE_LEVEL, "SME"},
76 [CDF_MODULE_ID_PE] = {CDF_DEFAULT_TRACE_LEVEL, "PE "},
77 [CDF_MODULE_ID_WMA] = {CDF_DEFAULT_TRACE_LEVEL, "WMA"},
78 [CDF_MODULE_ID_SYS] = {CDF_DEFAULT_TRACE_LEVEL, "SYS"},
79 [CDF_MODULE_ID_CDF] = {CDF_DEFAULT_TRACE_LEVEL, "CDF"},
80 [CDF_MODULE_ID_SAP] = {CDF_DEFAULT_TRACE_LEVEL, "SAP"},
81 [CDF_MODULE_ID_HDD_SOFTAP] = {CDF_DEFAULT_TRACE_LEVEL, "HSP"},
82 [CDF_MODULE_ID_HDD_DATA] = {CDF_DEFAULT_TRACE_LEVEL, "HDP"},
83 [CDF_MODULE_ID_HDD_SAP_DATA] = {CDF_DEFAULT_TRACE_LEVEL, "SDP"},
84 [CDF_MODULE_ID_BMI] = {CDF_DEFAULT_TRACE_LEVEL, "BMI"},
85 [CDF_MODULE_ID_HIF] = {CDF_DEFAULT_TRACE_LEVEL, "HIF"},
86 [CDF_MODULE_ID_TXRX] = {CDF_DEFAULT_TRACE_LEVEL, "TRX"},
87 [CDF_MODULE_ID_HTT] = {CDF_DEFAULT_TRACE_LEVEL, "HTT"},
88};
89
90/* Static and Global variables */
91static spinlock_t ltrace_lock;
92
93static cdf_trace_record_t g_cdf_trace_tbl[MAX_CDF_TRACE_RECORDS];
94/* global cdf trace data */
95static t_cdf_trace_data g_cdf_trace_data;
96/*
97 * all the call back functions for dumping MTRACE messages from ring buffer
98 * are stored in cdf_trace_cb_table,these callbacks are initialized during init
99 * only so, we will make a copy of these call back functions and maintain in to
100 * cdf_trace_restore_cb_table. Incase if we make modifications to
101 * cdf_trace_cb_table, we can certainly retrieve all the call back functions
102 * back from Restore Table
103 */
104static tp_cdf_trace_cb cdf_trace_cb_table[CDF_MODULE_ID_MAX];
105static tp_cdf_trace_cb cdf_trace_restore_cb_table[CDF_MODULE_ID_MAX];
106
107/* Static and Global variables */
108static spinlock_t l_dp_trace_lock;
109
110static struct cdf_dp_trace_record_s
111 g_cdf_dp_trace_tbl[MAX_CDF_DP_TRACE_RECORDS];
112
113/*
114 * all the options to configure/control DP trace are
115 * defined in this structure
116 */
117static struct s_cdf_dp_trace_data g_cdf_dp_trace_data;
118/*
119 * all the call back functions for dumping DPTRACE messages from ring buffer
120 * are stored in cdf_dp_trace_cb_table, callbacks are initialized during init
121 */
122static tp_cdf_dp_trace_cb cdf_dp_trace_cb_table[CDF_DP_TRACE_MAX];
123
124/**
125 * cdf_trace_set_level() - Set the trace level for a particular module
126 * @level : trace level
127 *
128 * Trace level is a member of the CDF_TRACE_LEVEL enumeration indicating
129 * the severity of the condition causing the trace message to be issued.
130 * More severe conditions are more likely to be logged.
131 *
132 * This is an external API that allows trace levels to be set for each module.
133 *
134 * Return: nothing
135 */
136void cdf_trace_set_level(CDF_MODULE_ID module, CDF_TRACE_LEVEL level)
137{
138 /* make sure the caller is passing in a valid LEVEL */
139 if (level >= CDF_TRACE_LEVEL_MAX) {
140 pr_err("%s: Invalid trace level %d passed in!\n", __func__,
141 level);
142 return;
143 }
144
145 /* Treat 'none' differently. NONE means we have to run off all
146 * the bits in the bit mask so none of the traces appear. Anything
147 * other than 'none' means we need to turn ON a bit in the bitmask
148 */
149 if (CDF_TRACE_LEVEL_NONE == level)
150 g_cdf_trace_info[module].moduleTraceLevel =
151 CDF_TRACE_LEVEL_NONE;
152 else
153 /* set the desired bit in the bit mask for the module trace
154 * level */
155 g_cdf_trace_info[module].moduleTraceLevel |=
156 CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level);
157}
158
159/**
160 * cdf_trace_set_module_trace_level() - Set module trace level
161 * @module: Module id
162 * @level: Trace level for a module, as a bitmask as per 'moduleTraceInfo'
163 *
164 * Sets the module trace level where the trace level is given as a bit mask
165 *
166 * Return: None
167 */
168void cdf_trace_set_module_trace_level(CDF_MODULE_ID module, uint32_t level)
169{
170 if (module < 0 || module >= CDF_MODULE_ID_MAX) {
171 pr_err("%s: Invalid module id %d passed\n", __func__, module);
172 return;
173 }
174 g_cdf_trace_info[module].moduleTraceLevel = level;
175}
176
177void cdf_trace_set_value(CDF_MODULE_ID module, CDF_TRACE_LEVEL level,
178 uint8_t on)
179{
180 /* make sure the caller is passing in a valid LEVEL */
181 if (level < 0 || level >= CDF_TRACE_LEVEL_MAX) {
182 pr_err("%s: Invalid trace level %d passed in!\n", __func__,
183 level);
184 return;
185 }
186
187 /* make sure the caller is passing in a valid module */
188 if (module < 0 || module >= CDF_MODULE_ID_MAX) {
189 pr_err("%s: Invalid module id %d passed in!\n", __func__,
190 module);
191 return;
192 }
193
194 /* Treat 'none' differently. NONE means we have to turn off all
195 the bits in the bit mask so none of the traces appear */
196 if (CDF_TRACE_LEVEL_NONE == level) {
197 g_cdf_trace_info[module].moduleTraceLevel =
198 CDF_TRACE_LEVEL_NONE;
199 }
200 /* Treat 'All' differently. All means we have to turn on all
201 the bits in the bit mask so all of the traces appear */
202 else if (CDF_TRACE_LEVEL_ALL == level) {
203 g_cdf_trace_info[module].moduleTraceLevel = 0xFFFF;
204 } else {
205 if (on)
206 /* set the desired bit in the bit mask for the module
207 trace level */
208 g_cdf_trace_info[module].moduleTraceLevel |=
209 CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level);
210 else
211 /* clear the desired bit in the bit mask for the module
212 trace level */
213 g_cdf_trace_info[module].moduleTraceLevel &=
214 ~(CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level));
215 }
216}
217
218/**
219 * cdf_trace_get_level() - get the trace level
220 * @level : trace level
221 *
222 * This is an external API that returns a bool value to signify if a
223 * particular trace level is set for the specified module.
224 * A member of the CDF_TRACE_LEVEL enumeration indicating the severity
225 * of the condition causing the trace message to be issued.
226 *
227 * Note that individual trace levels are the only valid values
228 * for this API. CDF_TRACE_LEVEL_NONE and CDF_TRACE_LEVEL_ALL
229 * are not valid input and will return false
230 *
231 * Return:
232 * false - the specified trace level for the specified module is OFF
233 * true - the specified trace level for the specified module is ON
234 */
235bool cdf_trace_get_level(CDF_MODULE_ID module, CDF_TRACE_LEVEL level)
236{
237 bool traceOn = false;
238
239 if ((CDF_TRACE_LEVEL_NONE == level) ||
240 (CDF_TRACE_LEVEL_ALL == level) || (level >= CDF_TRACE_LEVEL_MAX)) {
241 traceOn = false;
242 } else {
243 traceOn = (level & g_cdf_trace_info[module].moduleTraceLevel)
244 ? true : false;
245 }
246
247 return traceOn;
248}
249
250void cdf_snprintf(char *strBuffer, unsigned int size, char *strFormat, ...)
251{
252 va_list val;
253
254 va_start(val, strFormat);
255 snprintf(strBuffer, size, strFormat, val);
256 va_end(val);
257}
258
259#ifdef CDF_ENABLE_TRACING
260
261/**
262 * cdf_trace_msg() - externally called trace function
263 * @module : Module identifier a member of the CDF_MODULE_ID
264 * enumeration that identifies the module issuing the trace message.
265 * @level : Trace level a member of the CDF_TRACE_LEVEL enumeration
266 * indicating the severity of the condition causing the trace message
267 * to be issued. More severe conditions are more likely to be logged.
268 * @strFormat : 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 * Checks the level of severity and accordingly prints the trace messages
273 *
274 * Return: nothing
275 *
276 */
277void cdf_trace_msg(CDF_MODULE_ID module, CDF_TRACE_LEVEL level,
278 char *strFormat, ...)
279{
280 char strBuffer[CDF_TRACE_BUFFER_SIZE];
281 int n;
282
283 /* Print the trace message when the desired level bit is set in
284 the module tracel level mask */
285 if (g_cdf_trace_info[module].moduleTraceLevel &
286 CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level)) {
287 /* the trace level strings in an array. these are ordered in
288 * the same order as the trace levels are defined in the enum
289 * (see CDF_TRACE_LEVEL) so we can index into this array with
290 * the level and get the right string. The cdf trace levels
291 * are... none, Fatal, Error, Warning, Info, InfoHigh, InfoMed,
292 * InfoLow, Debug
293 */
294 static const char *TRACE_LEVEL_STR[] = { " ", "F ", "E ", "W ",
295 "I ", "IH", "IM", "IL", "D" };
296 va_list val;
297 va_start(val, strFormat);
298
299 /* print the prefix string into the string buffer... */
300 n = snprintf(strBuffer, CDF_TRACE_BUFFER_SIZE,
301 "wlan: [%d:%2s:%3s] ",
302 in_interrupt() ? 0 : current->pid,
303 (char *)TRACE_LEVEL_STR[level],
304 (char *)g_cdf_trace_info[module].moduleNameStr);
305
306 /* print the formatted log message after the prefix string */
307 if ((n >= 0) && (n < CDF_TRACE_BUFFER_SIZE)) {
308 vsnprintf(strBuffer + n, CDF_TRACE_BUFFER_SIZE - n,
309 strFormat, val);
310#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE)
311 wlan_log_to_user(level, (char *)strBuffer,
312 strlen(strBuffer));
313#else
314 pr_err("%s\n", strBuffer);
315#endif
316 }
317 va_end(val);
318 }
319}
320
321void cdf_trace_display(void)
322{
323 CDF_MODULE_ID moduleId;
324
325 pr_err
326 (" 1)FATAL 2)ERROR 3)WARN 4)INFO 5)INFO_H 6)INFO_M 7)INFO_L 8)DEBUG\n");
327 for (moduleId = 0; moduleId < CDF_MODULE_ID_MAX; ++moduleId) {
328 pr_err
329 ("%2d)%s %s %s %s %s %s %s %s %s\n",
330 (int)moduleId, g_cdf_trace_info[moduleId].moduleNameStr,
331 (g_cdf_trace_info[moduleId].
332 moduleTraceLevel & (1 << CDF_TRACE_LEVEL_FATAL)) ? "X" :
333 " ",
334 (g_cdf_trace_info[moduleId].
335 moduleTraceLevel & (1 << CDF_TRACE_LEVEL_ERROR)) ? "X" :
336 " ",
337 (g_cdf_trace_info[moduleId].
338 moduleTraceLevel & (1 << CDF_TRACE_LEVEL_WARN)) ? "X" :
339 " ",
340 (g_cdf_trace_info[moduleId].
341 moduleTraceLevel & (1 << CDF_TRACE_LEVEL_INFO)) ? "X" :
342 " ",
343 (g_cdf_trace_info[moduleId].
344 moduleTraceLevel & (1 << CDF_TRACE_LEVEL_INFO_HIGH)) ? "X"
345 : " ",
346 (g_cdf_trace_info[moduleId].
347 moduleTraceLevel & (1 << CDF_TRACE_LEVEL_INFO_MED)) ? "X"
348 : " ",
349 (g_cdf_trace_info[moduleId].
350 moduleTraceLevel & (1 << CDF_TRACE_LEVEL_INFO_LOW)) ? "X"
351 : " ",
352 (g_cdf_trace_info[moduleId].
353 moduleTraceLevel & (1 << CDF_TRACE_LEVEL_DEBUG)) ? "X" :
354 " ");
355 }
356}
357
358/**
359 * cdf_trace_hex_dump() - externally called hex dump function
360 * @module : Module identifier a member of the CDF_MODULE_ID enumeration that
361 * identifies the module issuing the trace message.
362 * @level : Trace level a member of the CDF_TRACE_LEVEL enumeration indicating
363 * the severity of the condition causing the trace message to be
364 * issued. More severe conditions are more likely to be logged.
365 * @data : The base address of the buffer to be logged.
366 * @buf_len : The size of the buffer to be logged.
367 *
368 * Checks the level of severity and accordingly prints the trace messages
369 *
370 * Return : nothing
371 */
372void cdf_trace_hex_dump(CDF_MODULE_ID module, CDF_TRACE_LEVEL level,
373 void *data, int buf_len)
374{
375 char *buf = (char *)data;
376 int i;
377
378 if (!(g_cdf_trace_info[module].moduleTraceLevel &
379 CDF_TRACE_LEVEL_TO_MODULE_BITMASK(level)))
380 return;
381
382 for (i = 0; (i + 15) < buf_len; i += 16) {
383 cdf_trace_msg(module, level,
384 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
385 buf[i],
386 buf[i + 1],
387 buf[i + 2],
388 buf[i + 3],
389 buf[i + 4],
390 buf[i + 5],
391 buf[i + 6],
392 buf[i + 7],
393 buf[i + 8],
394 buf[i + 9],
395 buf[i + 10],
396 buf[i + 11],
397 buf[i + 12],
398 buf[i + 13], buf[i + 14], buf[i + 15]);
399 }
400
401 /* Dump the bytes in the last line */
402 for (; i < buf_len; i++)
403 cdf_trace_msg(module, level, "%02x ", buf[i]);
404}
405
406#endif
407
408/**
409 * cdf_trace_enable() - Enable MTRACE for specific modules
410 * @bitmask_of_moduleId : Bitmask according to enum of the modules.
411 * 32 [dec] = 0010 0000 [bin] <enum of HDD is 5>
412 * 64 [dec] = 0100 0000 [bin] <enum of SME is 6>
413 * 128 [dec] = 1000 0000 [bin] <enum of PE is 7>
414 * @enable : can be true or false true implies enabling MTRACE false implies
415 * disabling MTRACE.
416 *
417 * Enable MTRACE for specific modules whose bits are set in bitmask and enable
418 * is true. if enable is false it disables MTRACE for that module. set the
419 * bitmask according to enum value of the modules.
420 * This functions will be called when you issue ioctl as mentioned following
421 * [iwpriv wlan0 setdumplog <value> <enable>].
422 * <value> - Decimal number, i.e. 64 decimal value shows only SME module,
423 * 128 decimal value shows only PE module, 192 decimal value shows PE and SME.
424 *
425 *
426 * Return : nothing
427 */
428void cdf_trace_enable(uint32_t bitmask_of_moduleId, uint8_t enable)
429{
430 int i;
431 if (bitmask_of_moduleId) {
432 for (i = 0; i < CDF_MODULE_ID_MAX; i++) {
433 if (((bitmask_of_moduleId >> i) & 1)) {
434 if (enable) {
435 if (NULL !=
436 cdf_trace_restore_cb_table[i]) {
437 cdf_trace_cb_table[i] =
438 cdf_trace_restore_cb_table[i];
439 }
440 } else {
441 cdf_trace_restore_cb_table[i] =
442 cdf_trace_cb_table[i];
443 cdf_trace_cb_table[i] = NULL;
444 }
445 }
446 }
447 } else {
448 if (enable) {
449 for (i = 0; i < CDF_MODULE_ID_MAX; i++) {
450 if (NULL != cdf_trace_restore_cb_table[i]) {
451 cdf_trace_cb_table[i] =
452 cdf_trace_restore_cb_table[i];
453 }
454 }
455 } else {
456 for (i = 0; i < CDF_MODULE_ID_MAX; i++) {
457 cdf_trace_restore_cb_table[i] =
458 cdf_trace_cb_table[i];
459 cdf_trace_cb_table[i] = NULL;
460 }
461 }
462 }
463}
464
465/**
466 * cdf_trace_init() - initializes cdf trace structures and variables
467 *
468 * Called immediately after cds_preopen, so that we can start recording HDD
469 * events ASAP.
470 *
471 * Return : nothing
472 */
473void cdf_trace_init(void)
474{
475 uint8_t i;
476 g_cdf_trace_data.head = INVALID_CDF_TRACE_ADDR;
477 g_cdf_trace_data.tail = INVALID_CDF_TRACE_ADDR;
478 g_cdf_trace_data.num = 0;
479 g_cdf_trace_data.enable = true;
480 g_cdf_trace_data.dumpCount = DEFAULT_CDF_TRACE_DUMP_COUNT;
481 g_cdf_trace_data.numSinceLastDump = 0;
482
483 for (i = 0; i < CDF_MODULE_ID_MAX; i++) {
484 cdf_trace_cb_table[i] = NULL;
485 cdf_trace_restore_cb_table[i] = NULL;
486 }
487}
488
489/**
490 * cdf_trace() - puts the messages in to ring-buffer
491 * @module : Enum of module, basically module id.
492 * @param : Code to be recorded
493 * @session : Session ID of the log
494 * @data : Actual message contents
495 *
496 * This function will be called from each module who wants record the messages
497 * in circular queue. Before calling this functions make sure you have
498 * registered your module with cdf through cdf_trace_register function.
499 *
500 *
501 * Return : nothing
502 */
503void cdf_trace(uint8_t module, uint8_t code, uint16_t session, uint32_t data)
504{
505 tp_cdf_trace_record rec = NULL;
506 unsigned long flags;
507
508 if (!g_cdf_trace_data.enable)
509 return;
510
511 /* if module is not registered, don't record for that module */
512 if (NULL == cdf_trace_cb_table[module])
513 return;
514
515 /* Aquire the lock so that only one thread at a time can fill the ring
516 * buffer
517 */
518 spin_lock_irqsave(&ltrace_lock, flags);
519
520 g_cdf_trace_data.num++;
521
522 if (g_cdf_trace_data.num > MAX_CDF_TRACE_RECORDS)
523 g_cdf_trace_data.num = MAX_CDF_TRACE_RECORDS;
524
525 if (INVALID_CDF_TRACE_ADDR == g_cdf_trace_data.head) {
526 /* first record */
527 g_cdf_trace_data.head = 0;
528 g_cdf_trace_data.tail = 0;
529 } else {
530 /* queue is not empty */
531 uint32_t tail = g_cdf_trace_data.tail + 1;
532
533 if (MAX_CDF_TRACE_RECORDS == tail)
534 tail = 0;
535
536 if (g_cdf_trace_data.head == tail) {
537 /* full */
538 if (MAX_CDF_TRACE_RECORDS == ++g_cdf_trace_data.head)
539 g_cdf_trace_data.head = 0;
540 }
541 g_cdf_trace_data.tail = tail;
542 }
543
544 rec = &g_cdf_trace_tbl[g_cdf_trace_data.tail];
545 rec->code = code;
546 rec->session = session;
547 rec->data = data;
548 rec->time = cdf_get_log_timestamp();
549 rec->module = module;
550 rec->pid = (in_interrupt() ? 0 : current->pid);
551 g_cdf_trace_data.numSinceLastDump++;
552 spin_unlock_irqrestore(&ltrace_lock, flags);
553}
554
555/**
556 * cdf_trace_spin_lock_init() - initializes the lock variable before use
557 *
558 * This function will be called from cds_alloc_global_context, we will have lock
559 * available to use ASAP
560 *
561 * Return : nothing
562 */
563CDF_STATUS cdf_trace_spin_lock_init(void)
564{
565 spin_lock_init(&ltrace_lock);
566
567 return CDF_STATUS_SUCCESS;
568}
569
570/**
571 * cdf_trace_register() - registers the call back functions
572 * @moduleID - enum value of module
573 * @cdf_trace_callback - call back functions to display the messages in
574 * particular format.
575 *
576 * Registers the call back functions to display the messages in particular
577 * format mentioned in these call back functions. This functions should be
578 * called by interested module in their init part as we will be ready to
579 * register as soon as modules are up.
580 *
581 * Return : nothing
582 */
583void cdf_trace_register(CDF_MODULE_ID moduleID,
584 tp_cdf_trace_cb cdf_trace_callback)
585{
586 cdf_trace_cb_table[moduleID] = cdf_trace_callback;
587}
588
589/**
590 * cdf_trace_dump_all() - Dump data from ring buffer via call back functions
591 * registered with CDF
592 * @pMac : Context of particular module
593 * @code : Reason code
594 * @session : Session id of log
595 * @count : Number of lines to dump starting from tail to head
596 *
597 * This function will be called up on issueing ioctl call as mentioned following
598 * [iwpriv wlan0 dumplog 0 0 <n> <bitmask_of_module>]
599 *
600 * <n> - number lines to dump starting from tail to head.
601 *
602 * <bitmask_of_module> - if anybody wants to know how many messages were
603 * recorded for particular module/s mentioned by setbit in bitmask from last
604 * <n> messages. It is optional, if you don't provide then it will dump
605 * everything from buffer.
606 *
607 * Return : nothing
608 */
609void cdf_trace_dump_all(void *pMac, uint8_t code, uint8_t session,
610 uint32_t count, uint32_t bitmask_of_module)
611{
612 cdf_trace_record_t pRecord;
613 int32_t i, tail;
614
615 if (!g_cdf_trace_data.enable) {
616 CDF_TRACE(CDF_MODULE_ID_SYS,
617 CDF_TRACE_LEVEL_ERROR, "Tracing Disabled");
618 return;
619 }
620
621 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR,
622 "Total Records: %d, Head: %d, Tail: %d",
623 g_cdf_trace_data.num, g_cdf_trace_data.head,
624 g_cdf_trace_data.tail);
625
626 /* aquire the lock so that only one thread at a time can read
627 * the ring buffer
628 */
629 spin_lock(&ltrace_lock);
630
631 if (g_cdf_trace_data.head != INVALID_CDF_TRACE_ADDR) {
632 i = g_cdf_trace_data.head;
633 tail = g_cdf_trace_data.tail;
634
635 if (count) {
636 if (count > g_cdf_trace_data.num)
637 count = g_cdf_trace_data.num;
638 if (tail >= (count - 1))
639 i = tail - count + 1;
640 else if (count != MAX_CDF_TRACE_RECORDS)
641 i = MAX_CDF_TRACE_RECORDS - ((count - 1) -
642 tail);
643 }
644
645 pRecord = g_cdf_trace_tbl[i];
646 /* right now we are not using numSinceLastDump member but
647 * in future we might re-visit and use this member to track
648 * how many latest messages got added while we were dumping
649 * from ring buffer
650 */
651 g_cdf_trace_data.numSinceLastDump = 0;
652 spin_unlock(&ltrace_lock);
653 for (;; ) {
654 if ((code == 0 || (code == pRecord.code)) &&
655 (cdf_trace_cb_table[pRecord.module] != NULL)) {
656 if (0 == bitmask_of_module) {
657 cdf_trace_cb_table[pRecord.
658 module] (pMac,
659 &pRecord,
660 (uint16_t)
661 i);
662 } else {
663 if (bitmask_of_module &
664 (1 << pRecord.module)) {
665 cdf_trace_cb_table[pRecord.
666 module]
667 (pMac, &pRecord,
668 (uint16_t) i);
669 }
670 }
671 }
672
673 if (i == tail)
674 break;
675 i += 1;
676
677 spin_lock(&ltrace_lock);
678 if (MAX_CDF_TRACE_RECORDS == i) {
679 i = 0;
680 pRecord = g_cdf_trace_tbl[0];
681 } else {
682 pRecord = g_cdf_trace_tbl[i];
683 }
684 spin_unlock(&ltrace_lock);
685 }
686 } else {
687 spin_unlock(&ltrace_lock);
688 }
689}
690
691/**
692 * cdf_dp_trace_init() - enables the DP trace
693 * Called during driver load and it enables DP trace
694 *
695 * Return: None
696 */
697void cdf_dp_trace_init(void)
698{
699 uint8_t i;
700
701 cdf_dp_trace_spin_lock_init();
702 g_cdf_dp_trace_data.head = INVALID_CDF_DP_TRACE_ADDR;
703 g_cdf_dp_trace_data.tail = INVALID_CDF_DP_TRACE_ADDR;
704 g_cdf_dp_trace_data.num = 0;
705 g_cdf_dp_trace_data.proto_bitmap = 0;
706 g_cdf_dp_trace_data.no_of_record = 0;
707 g_cdf_dp_trace_data.verbosity = CDF_DP_TRACE_VERBOSITY_DEFAULT;
708 g_cdf_dp_trace_data.enable = true;
709
710 for (i = 0; i < CDF_DP_TRACE_MAX; i++)
711 cdf_dp_trace_cb_table[i] = cdf_dp_display_record;
712}
713
714/**
715 * cdf_dp_trace_set_value() - Configure the value to control DP trace
716 * @proto_bitmap : defines the protocol to be tracked
717 * @no_of_records : defines the nth packet which is traced
718 * @verbosity : defines the verbosity level
719 *
720 * Return: None
721 */
722void cdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_record,
723 uint8_t verbosity)
724{
725 g_cdf_dp_trace_data.proto_bitmap = proto_bitmap;
726 g_cdf_dp_trace_data.no_of_record = no_of_record;
727 g_cdf_dp_trace_data.verbosity = verbosity;
728 return;
729}
730
731/**
732 * cdf_dp_trace_enable_track() - enable the tracing for netbuf
733 * @code : defines the event
734 *
735 * Return: true or false depends on whether tracing enabled
736 */
737static bool cdf_dp_trace_enable_track(enum CDF_DP_TRACE_ID code)
738{
739 if (g_cdf_dp_trace_data.verbosity == CDF_DP_TRACE_VERBOSITY_HIGH)
740 return true;
741 if (g_cdf_dp_trace_data.verbosity == CDF_DP_TRACE_VERBOSITY_MEDIUM
742 && (code <= CDF_DP_TRACE_HIF_PACKET_PTR_RECORD))
743 return true;
744 if (g_cdf_dp_trace_data.verbosity == CDF_DP_TRACE_VERBOSITY_LOW
745 && (code <= CDF_DP_TRACE_CE_PACKET_RECORD))
746 return true;
747 if (g_cdf_dp_trace_data.verbosity == CDF_DP_TRACE_VERBOSITY_DEFAULT
748 && (code == CDF_DP_TRACE_DROP_PACKET_RECORD))
749 return true;
750 return false;
751}
752
753/**
754 * cdf_dp_trace_set_track() - Marks whether the packet needs to be traced
755 * @nbuf : defines the netbuf
756 *
757 * Return: None
758 */
759void cdf_dp_trace_set_track(cdf_nbuf_t nbuf)
760{
761 spin_lock_bh(&l_dp_trace_lock);
762 g_cdf_dp_trace_data.count++;
763 if (g_cdf_dp_trace_data.proto_bitmap != 0) {
764 if (cds_pkt_get_proto_type(nbuf,
765 g_cdf_dp_trace_data.proto_bitmap, 0)) {
766 CDF_NBUF_SET_DP_TRACE(nbuf, 1);
767 }
768 }
769 if ((g_cdf_dp_trace_data.no_of_record != 0) &&
770 (g_cdf_dp_trace_data.count %
771 g_cdf_dp_trace_data.no_of_record == 0)) {
772 CDF_NBUF_SET_DP_TRACE(nbuf, 1);
773 }
774 spin_unlock_bh(&l_dp_trace_lock);
775 return;
776}
777
778/**
779 * dump_hex_trace() - Display the data in buffer
780 * @buf: buffer which contains data to be displayed
781 * @buf_len: defines the size of the data to be displayed
782 *
783 * Return: None
784 */
785static void dump_hex_trace(uint8_t *buf, uint8_t buf_len)
786{
787 uint8_t i = 0;
788 /* Dump the bytes in the last line */
789 cdf_print("DATA: ");
790 for (i = 0; i < buf_len; i++)
791 cdf_print("%02x ", buf[i]);
792 cdf_print("\n");
793}
794
795/**
796 * cdf_dp_display_trace() - Displays a record in DP trace
797 * @pRecord : pointer to a record in DP trace
798 * @recIndex : record index
799 *
800 * Return: None
801 */
802void cdf_dp_display_record(struct cdf_dp_trace_record_s *pRecord ,
803 uint16_t recIndex)
804{
805 cdf_print("INDEX: %04d TIME: %012llu CODE: %02d\n", recIndex,
806 pRecord->time, pRecord->code);
807 switch (pRecord->code) {
808 case CDF_DP_TRACE_HDD_TX_TIMEOUT:
809 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
810 "HDD TX Timeout\n");
811 break;
812 case CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
813 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
814 "HDD SoftAP TX Timeout\n");
815 break;
816 case CDF_DP_TRACE_VDEV_PAUSE:
817 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
818 "VDEV Pause\n");
819 break;
820 case CDF_DP_TRACE_VDEV_UNPAUSE:
821 CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
822 "VDEV UnPause\n");
823 break;
824 default:
825 dump_hex_trace(pRecord->data, pRecord->size);
826 }
827 return;
828}
829
830/**
831 * cdf_dp_trace() - Stores the data in buffer
832 * @nbuf : defines the netbuf
833 * @code : defines the event
834 * @data : defines the data to be stored
835 * @size : defines the size of the data record
836 *
837 * Return: None
838 */
839void cdf_dp_trace(cdf_nbuf_t nbuf, enum CDF_DP_TRACE_ID code,
840 uint8_t *data, uint8_t size)
841{
842 struct cdf_dp_trace_record_s *rec = NULL;
843
844 /* Return when Dp trace is not enabled */
845 if (!g_cdf_dp_trace_data.enable)
846 return;
847
848 /* If nbuf is NULL, check for VDEV PAUSE, UNPAUSE, TIMEOUT */
849 if (!nbuf) {
850 switch (code) {
851 case CDF_DP_TRACE_HDD_TX_TIMEOUT:
852 case CDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT:
853 case CDF_DP_TRACE_VDEV_PAUSE:
854 case CDF_DP_TRACE_VDEV_UNPAUSE:
855 if (cdf_dp_trace_enable_track(code))
856 goto register_record;
857 else
858 return;
859
860 default:
861 return;
862 }
863 }
864
865 /* Return when the packet is not a data packet */
866 if (NBUF_GET_PACKET_TRACK(nbuf) != NBUF_TX_PKT_DATA_TRACK)
867 return;
868
869 /* Return when nbuf is not marked for dp tracing or
870 * verbosity does not allow
871 */
872 if (cdf_dp_trace_enable_track(code) == false ||
873 !CDF_NBUF_GET_DP_TRACE(nbuf))
874 return;
875
876 /* Acquire the lock so that only one thread at a time can fill the ring
877 * buffer
878 */
879
880register_record:
881
882 spin_lock_bh(&l_dp_trace_lock);
883
884 g_cdf_dp_trace_data.num++;
885
886 if (g_cdf_dp_trace_data.num > MAX_CDF_DP_TRACE_RECORDS)
887 g_cdf_dp_trace_data.num = MAX_CDF_DP_TRACE_RECORDS;
888
889 if (INVALID_CDF_DP_TRACE_ADDR == g_cdf_dp_trace_data.head) {
890 /* first record */
891 g_cdf_dp_trace_data.head = 0;
892 g_cdf_dp_trace_data.tail = 0;
893 } else {
894 /* queue is not empty */
895 g_cdf_dp_trace_data.tail++;
896
897 if (MAX_CDF_DP_TRACE_RECORDS == g_cdf_dp_trace_data.tail)
898 g_cdf_dp_trace_data.tail = 0;
899
900 if (g_cdf_dp_trace_data.head == g_cdf_dp_trace_data.tail) {
901 /* full */
902 if (MAX_CDF_DP_TRACE_RECORDS ==
903 ++g_cdf_dp_trace_data.head)
904 g_cdf_dp_trace_data.head = 0;
905 }
906 }
907
908 rec = &g_cdf_dp_trace_tbl[g_cdf_dp_trace_data.tail];
909 rec->code = code;
910 rec->size = 0;
911 if (data != NULL && size > 0) {
912 if (size > CDF_DP_TRACE_RECORD_SIZE)
913 size = CDF_DP_TRACE_RECORD_SIZE;
914
915 rec->size = size;
916 switch (code) {
917 case CDF_DP_TRACE_HDD_PACKET_PTR_RECORD:
918 case CDF_DP_TRACE_CE_PACKET_PTR_RECORD:
919 case CDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD:
920 case CDF_DP_TRACE_TXRX_PACKET_PTR_RECORD:
921 case CDF_DP_TRACE_HTT_PACKET_PTR_RECORD:
922 case CDF_DP_TRACE_HTC_PACKET_PTR_RECORD:
923 case CDF_DP_TRACE_HIF_PACKET_PTR_RECORD:
924 cdf_mem_copy(rec->data, (uint8_t *)(&data), size);
925 break;
926
927 case CDF_DP_TRACE_DROP_PACKET_RECORD:
928 case CDF_DP_TRACE_HDD_PACKET_RECORD:
929 case CDF_DP_TRACE_CE_PACKET_RECORD:
930 cdf_mem_copy(rec->data, data, size);
931 break;
932 default:
933 break;
934 }
935 }
936 rec->time = cdf_get_log_timestamp();
937 rec->pid = (in_interrupt() ? 0 : current->pid);
938 spin_unlock_bh(&l_dp_trace_lock);
939}
940
941/**
942 * cdf_dp_trace_spin_lock_init() - initializes the lock variable before use
943 * This function will be called from cds_alloc_global_context, we will have lock
944 * available to use ASAP
945 *
946 * Return : nothing
947 */
948void cdf_dp_trace_spin_lock_init(void)
949{
950 spin_lock_init(&l_dp_trace_lock);
951
952 return;
953}
954
955/**
956 * cdf_dp_trace_dump_all() - Dump data from ring buffer via call back functions
957 * registered with CDF
958 * @code : Reason code
959 * @count : Number of lines to dump starting from tail to head
960 *
961 * Return : nothing
962 */
963void cdf_dp_trace_dump_all(uint32_t count)
964{
965 struct cdf_dp_trace_record_s pRecord;
966 int32_t i, tail;
967
968 if (!g_cdf_dp_trace_data.enable) {
969 CDF_TRACE(CDF_MODULE_ID_SYS,
970 CDF_TRACE_LEVEL_ERROR, "Tracing Disabled");
971 return;
972 }
973
974 CDF_TRACE(CDF_MODULE_ID_SYS, CDF_TRACE_LEVEL_ERROR,
975 "Total Records: %d, Head: %d, Tail: %d",
976 g_cdf_dp_trace_data.num, g_cdf_dp_trace_data.head,
977 g_cdf_dp_trace_data.tail);
978
979 /* aquire the lock so that only one thread at a time can read
980 * the ring buffer
981 */
982 spin_lock_bh(&l_dp_trace_lock);
983
984 if (g_cdf_dp_trace_data.head != INVALID_CDF_DP_TRACE_ADDR) {
985 i = g_cdf_dp_trace_data.head;
986 tail = g_cdf_dp_trace_data.tail;
987
988 if (count) {
989 if (count > g_cdf_dp_trace_data.num)
990 count = g_cdf_dp_trace_data.num;
991 if (tail >= (count - 1))
992 i = tail - count + 1;
993 else if (count != MAX_CDF_DP_TRACE_RECORDS)
994 i = MAX_CDF_DP_TRACE_RECORDS - ((count - 1) -
995 tail);
996 }
997
998 pRecord = g_cdf_dp_trace_tbl[i];
999 spin_unlock_bh(&l_dp_trace_lock);
1000 for (;; ) {
1001
1002 cdf_dp_trace_cb_table[pRecord.
1003 code] (&pRecord, (uint16_t)i);
1004 if (i == tail)
1005 break;
1006 i += 1;
1007
1008 spin_lock_bh(&l_dp_trace_lock);
1009 if (MAX_CDF_DP_TRACE_RECORDS == i)
1010 i = 0;
1011
1012 pRecord = g_cdf_dp_trace_tbl[i];
1013 spin_unlock_bh(&l_dp_trace_lock);
1014 }
1015 } else {
1016 spin_unlock_bh(&l_dp_trace_lock);
1017 }
1018}