Prakash Dhavali | 7090c5f | 2015-11-02 17:55:19 -0800 | [diff] [blame^] | 1 | /* |
| 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 | |
| 49 | typedef 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 | */ |
| 71 | moduleTraceInfo 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 */ |
| 91 | static spinlock_t ltrace_lock; |
| 92 | |
| 93 | static cdf_trace_record_t g_cdf_trace_tbl[MAX_CDF_TRACE_RECORDS]; |
| 94 | /* global cdf trace data */ |
| 95 | static 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 | */ |
| 104 | static tp_cdf_trace_cb cdf_trace_cb_table[CDF_MODULE_ID_MAX]; |
| 105 | static tp_cdf_trace_cb cdf_trace_restore_cb_table[CDF_MODULE_ID_MAX]; |
| 106 | |
| 107 | /* Static and Global variables */ |
| 108 | static spinlock_t l_dp_trace_lock; |
| 109 | |
| 110 | static 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 | */ |
| 117 | static 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 | */ |
| 122 | static 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 | */ |
| 136 | void 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 | */ |
| 168 | void 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 | |
| 177 | void 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 | */ |
| 235 | bool 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 | |
| 250 | void 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 | */ |
| 277 | void 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 | |
| 321 | void 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 | */ |
| 372 | void 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 | */ |
| 428 | void 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 | */ |
| 473 | void 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 | */ |
| 503 | void 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(<race_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(<race_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 | */ |
| 563 | CDF_STATUS cdf_trace_spin_lock_init(void) |
| 564 | { |
| 565 | spin_lock_init(<race_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 | */ |
| 583 | void 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 | */ |
| 609 | void 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(<race_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(<race_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(<race_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(<race_lock); |
| 685 | } |
| 686 | } else { |
| 687 | spin_unlock(<race_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 | */ |
| 697 | void 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 | */ |
| 722 | void 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 | */ |
| 737 | static 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 | */ |
| 759 | void 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 | */ |
| 785 | static 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 | */ |
| 802 | void 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 | */ |
| 839 | void 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 | |
| 880 | register_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 | */ |
| 948 | void 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 | */ |
| 963 | void 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 | } |