|  | /* | 
|  | * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved. | 
|  | * | 
|  | * Previously licensed under the ISC license by Qualcomm Atheros, Inc. | 
|  | * | 
|  | * | 
|  | * Permission to use, copy, modify, and/or distribute this software for | 
|  | * any purpose with or without fee is hereby granted, provided that the | 
|  | * above copyright notice and this permission notice appear in all | 
|  | * copies. | 
|  | * | 
|  | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | 
|  | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | 
|  | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE | 
|  | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | 
|  | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | 
|  | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | 
|  | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | 
|  | * PERFORMANCE OF THIS SOFTWARE. | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * This file was originally distributed by Qualcomm Atheros, Inc. | 
|  | * under proprietary terms before Copyright ownership was assigned | 
|  | * to the Linux Foundation. | 
|  | */ | 
|  |  | 
|  | /**========================================================================= | 
|  |  | 
|  | \file  vos_trace.c | 
|  |  | 
|  | \brief virtual Operating System Servies (vOS) | 
|  |  | 
|  | Trace, logging, and debugging definitions and APIs | 
|  |  | 
|  | ========================================================================*/ | 
|  |  | 
|  | /*=========================================================================== | 
|  |  | 
|  | EDIT HISTORY FOR FILE | 
|  |  | 
|  |  | 
|  | This section contains comments describing changes made to the module. | 
|  | Notice that changes are listed in reverse chronological order. | 
|  |  | 
|  |  | 
|  | $Header:$ $DateTime: $ $Author: $ | 
|  |  | 
|  |  | 
|  | when        who    what, where, why | 
|  | --------    ---    -------------------------------------------------------- | 
|  | 09/16/08    hvm    Adding ability to set multiple trace levels per component | 
|  | 09/11/08    lac    Added trace levels per component.  Cleanup from review. | 
|  | 08/14/08    vpai   Particular modules and desired level can be selected | 
|  | 06/20/08    vpai   Created Module | 
|  | ===========================================================================*/ | 
|  |  | 
|  | /*-------------------------------------------------------------------------- | 
|  | Include Files | 
|  | ------------------------------------------------------------------------*/ | 
|  | #include <vos_trace.h> | 
|  | #include <aniGlobal.h> | 
|  | #include <wlan_logging_sock_svc.h> | 
|  | #include "adf_os_time.h" | 
|  | /*-------------------------------------------------------------------------- | 
|  | Preprocessor definitions and constants | 
|  | ------------------------------------------------------------------------*/ | 
|  |  | 
|  | #define VOS_TRACE_BUFFER_SIZE ( 512 ) | 
|  |  | 
|  | // macro to map vos trace levels into the bitmask | 
|  | #define VOS_TRACE_LEVEL_TO_MODULE_BITMASK( _level ) ( ( 1 << (_level) ) ) | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | // Trace level for a module, as a bitmask.  The bits in this mask | 
|  | // are ordered by VOS_TRACE_LEVEL.  For example, each bit represents | 
|  | // one of the bits in VOS_TRACE_LEVEL that may be turned on to have | 
|  | // traces at that level logged, i.e. if VOS_TRACE_LEVEL_ERROR is | 
|  | // == 2, then if bit 2 (low order) is turned ON, then ERROR traces | 
|  | // will be printed to the trace log. | 
|  | // | 
|  | // Note that all bits turned OFF means no traces. | 
|  | v_U16_t moduleTraceLevel; | 
|  |  | 
|  | // 3 character string name for the module | 
|  | unsigned char moduleNameStr[ 4 ];   // 3 chars plus the NULL | 
|  |  | 
|  | } moduleTraceInfo; | 
|  |  | 
|  | #define VOS_DEFAULT_TRACE_LEVEL \ | 
|  | ((1<<VOS_TRACE_LEVEL_FATAL)|(1<<VOS_TRACE_LEVEL_ERROR)) | 
|  |  | 
|  | // Array of static data that contains all of the per module trace | 
|  | // information.  This includes the trace level for the module and | 
|  | // the 3 character 'name' of the module for marking the trace logs. | 
|  | moduleTraceInfo gVosTraceInfo[ VOS_MODULE_ID_MAX ] = | 
|  | { | 
|  | [VOS_MODULE_ID_TL]         = { VOS_DEFAULT_TRACE_LEVEL, "TL " }, | 
|  | [VOS_MODULE_ID_WDI]        = { VOS_DEFAULT_TRACE_LEVEL, "WDI" }, | 
|  | [VOS_MODULE_ID_RSV3]       = { VOS_DEFAULT_TRACE_LEVEL, "RV3" }, | 
|  | [VOS_MODULE_ID_RSV4]       = { VOS_DEFAULT_TRACE_LEVEL, "RV4" }, | 
|  | [VOS_MODULE_ID_HDD]        = { VOS_DEFAULT_TRACE_LEVEL, "HDD" }, | 
|  | [VOS_MODULE_ID_SME]        = { VOS_DEFAULT_TRACE_LEVEL, "SME" }, | 
|  | [VOS_MODULE_ID_PE]         = { VOS_DEFAULT_TRACE_LEVEL, "PE " }, | 
|  | [VOS_MODULE_ID_WDA]        = { VOS_DEFAULT_TRACE_LEVEL, "WDA" }, | 
|  | [VOS_MODULE_ID_SYS]        = { VOS_DEFAULT_TRACE_LEVEL, "SYS" }, | 
|  | [VOS_MODULE_ID_VOSS]       = { VOS_DEFAULT_TRACE_LEVEL, "VOS" }, | 
|  | [VOS_MODULE_ID_HIF]        = { VOS_DEFAULT_TRACE_LEVEL, "HIF" }, | 
|  | [VOS_MODULE_ID_HTC]        = { VOS_DEFAULT_TRACE_LEVEL, "HTC" }, | 
|  | [VOS_MODULE_ID_SAP]        = { VOS_DEFAULT_TRACE_LEVEL, "SAP" }, | 
|  | [VOS_MODULE_ID_HDD_SOFTAP] = { VOS_DEFAULT_TRACE_LEVEL, "HSP" }, | 
|  | [VOS_MODULE_ID_PMC]        = { VOS_DEFAULT_TRACE_LEVEL, "PMC" }, | 
|  | [VOS_MODULE_ID_HDD_DATA]   = { VOS_DEFAULT_TRACE_LEVEL, "HDP" }, | 
|  | [VOS_MODULE_ID_HDD_SAP_DATA] = { VOS_DEFAULT_TRACE_LEVEL, "SDP" }, | 
|  | [VOS_MODULE_ID_TXRX]       = { VOS_DEFAULT_TRACE_LEVEL, "TRX" }, | 
|  | [VOS_MODULE_ID_ADF]        = { VOS_DEFAULT_TRACE_LEVEL, "ADF" }, | 
|  | [VOS_MODULE_ID_CFG]        = { VOS_DEFAULT_TRACE_LEVEL, "CFG" } | 
|  | }; | 
|  | /*------------------------------------------------------------------------- | 
|  | Static and Global variables | 
|  | ------------------------------------------------------------------------*/ | 
|  | static spinlock_t ltraceLock; | 
|  |  | 
|  | static tvosTraceRecord gvosTraceTbl[MAX_VOS_TRACE_RECORDS]; | 
|  | // Global vosTraceData | 
|  | static tvosTraceData gvosTraceData; | 
|  | /* | 
|  | * all the call back functions for dumping MTRACE messages from ring buffer | 
|  | * are stored in vostraceCBTable,these callbacks are initialized during init only | 
|  | * so, we will make a copy of these call back functions and maintain in to | 
|  | * vostraceRestoreCBTable. Incase if we make modifications to vostraceCBTable, | 
|  | * we can certainly retrieve all the call back functions back from Restore Table | 
|  | */ | 
|  | static tpvosTraceCb vostraceCBTable[VOS_MODULE_ID_MAX]; | 
|  | static tpvosTraceCb vostraceRestoreCBTable[VOS_MODULE_ID_MAX]; | 
|  | static tp_vos_state_info_cb vos_state_info_table[VOS_MODULE_ID_MAX]; | 
|  |  | 
|  | /*------------------------------------------------------------------------- | 
|  | Functions | 
|  | ------------------------------------------------------------------------*/ | 
|  | void vos_trace_setLevel( VOS_MODULE_ID module, VOS_TRACE_LEVEL level ) | 
|  | { | 
|  | // Make sure the caller is passing in a valid LEVEL. | 
|  | if ( level >= VOS_TRACE_LEVEL_MAX ) | 
|  | { | 
|  | pr_err("%s: Invalid trace level %d passed in!\n", __func__, level); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Treat 'none' differently.  NONE means we have to run off all | 
|  | // the bits in the bit mask so none of the traces appear.  Anything other | 
|  | // than 'none' means we need to turn ON a bit in the bitmask. | 
|  | if ( VOS_TRACE_LEVEL_NONE == level ) | 
|  | { | 
|  | gVosTraceInfo[ module ].moduleTraceLevel = VOS_TRACE_LEVEL_NONE; | 
|  | } | 
|  | else | 
|  | { | 
|  | // Set the desired bit in the bit mask for the module trace level. | 
|  | gVosTraceInfo[ module ].moduleTraceLevel |= VOS_TRACE_LEVEL_TO_MODULE_BITMASK( level ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * vos_trace_set_module_trace_level() - Set module trace level | 
|  | * @module: Module id | 
|  | * @level: Trace level for a module, as a bitmask as per 'moduleTraceInfo' | 
|  | * | 
|  | * Sets the module trace level where the trace level is given as a bit mask | 
|  | * | 
|  | * Return: None | 
|  | */ | 
|  | void vos_trace_set_module_trace_level(VOS_MODULE_ID module, uint32_t level) | 
|  | { | 
|  | if (module < 0 || module >= VOS_MODULE_ID_MAX) { | 
|  | pr_err("%s: Invalid module id %d passed\n", __func__, module); | 
|  | return; | 
|  | } | 
|  |  | 
|  | gVosTraceInfo[module].moduleTraceLevel = level; | 
|  | } | 
|  |  | 
|  | void vos_trace_setValue( VOS_MODULE_ID module, VOS_TRACE_LEVEL level, v_U8_t on) | 
|  | { | 
|  | // Make sure the caller is passing in a valid LEVEL. | 
|  | if ( level < 0  || level >= VOS_TRACE_LEVEL_MAX ) | 
|  | { | 
|  | pr_err("%s: Invalid trace level %d passed in!\n", __func__, level); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Make sure the caller is passing in a valid module. | 
|  | if ( module < 0 || module >= VOS_MODULE_ID_MAX ) | 
|  | { | 
|  | pr_err("%s: Invalid module id %d passed in!\n", __func__, module); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Treat 'none' differently.  NONE means we have to turn off all | 
|  | // the bits in the bit mask so none of the traces appear. | 
|  | if ( VOS_TRACE_LEVEL_NONE == level ) | 
|  | { | 
|  | gVosTraceInfo[ module ].moduleTraceLevel = VOS_TRACE_LEVEL_NONE; | 
|  | } | 
|  | // Treat 'All' differently.  All means we have to turn on all | 
|  | // the bits in the bit mask so all of the traces appear. | 
|  | else if ( VOS_TRACE_LEVEL_ALL == level ) | 
|  | { | 
|  | gVosTraceInfo[ module ].moduleTraceLevel = 0xFFFF; | 
|  | } | 
|  |  | 
|  | else | 
|  | { | 
|  | if (on) | 
|  | // Set the desired bit in the bit mask for the module trace level. | 
|  | gVosTraceInfo[ module ].moduleTraceLevel |= VOS_TRACE_LEVEL_TO_MODULE_BITMASK( level ); | 
|  | else | 
|  | // Clear the desired bit in the bit mask for the module trace level. | 
|  | gVosTraceInfo[ module ].moduleTraceLevel &= ~(VOS_TRACE_LEVEL_TO_MODULE_BITMASK( level )); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | v_BOOL_t vos_trace_getLevel( VOS_MODULE_ID module, VOS_TRACE_LEVEL level ) | 
|  | { | 
|  | v_BOOL_t traceOn = VOS_FALSE; | 
|  |  | 
|  | if ( ( VOS_TRACE_LEVEL_NONE == level ) || | 
|  | ( VOS_TRACE_LEVEL_ALL  == level ) || | 
|  | ( level >= VOS_TRACE_LEVEL_MAX  )    ) | 
|  | { | 
|  | traceOn = VOS_FALSE; | 
|  | } | 
|  | else | 
|  | { | 
|  | traceOn = ( level & gVosTraceInfo[ module ].moduleTraceLevel ) ? VOS_TRUE : VOS_FALSE; | 
|  | } | 
|  |  | 
|  | return( traceOn ); | 
|  | } | 
|  |  | 
|  | void vos_snprintf(char *strBuffer, unsigned  int size, char *strFormat, ...) | 
|  | { | 
|  | va_list val; | 
|  |  | 
|  | va_start( val, strFormat ); | 
|  | snprintf (strBuffer, size, strFormat, val); | 
|  | va_end( val ); | 
|  | } | 
|  |  | 
|  | #ifdef VOS_ENABLE_TRACING | 
|  |  | 
|  | /*---------------------------------------------------------------------------- | 
|  |  | 
|  | \brief vos_trace_msg() - Externally called trace function | 
|  |  | 
|  | Checks the level of severity and accordingly prints the trace messages | 
|  |  | 
|  | \param module - module identifier.   A member of the VOS_MODULE_ID | 
|  | enumeration that identifies the module issuing the trace message. | 
|  |  | 
|  | \param level - trace level.   A member of the VOS_TRACE_LEVEL | 
|  | enumeration indicating the severity of the condition causing the | 
|  | trace message to be issued.   More severe conditions are more | 
|  | likely to be logged. | 
|  |  | 
|  | \param strFormat - format string.  The message to be logged.  This format | 
|  | string contains printf-like replacement parameters, which follow | 
|  | this parameter in the variable argument list. | 
|  |  | 
|  | \return  nothing | 
|  |  | 
|  | \sa | 
|  |  | 
|  | --------------------------------------------------------------------------*/ | 
|  | void vos_trace_msg( VOS_MODULE_ID module, VOS_TRACE_LEVEL level, char *strFormat, ... ) | 
|  | { | 
|  | char strBuffer[VOS_TRACE_BUFFER_SIZE]; | 
|  | int n; | 
|  |  | 
|  | // Print the trace message when the desired level bit is set in the module | 
|  | // tracel level mask. | 
|  | if ( gVosTraceInfo[ module ].moduleTraceLevel & VOS_TRACE_LEVEL_TO_MODULE_BITMASK( level ) ) | 
|  | { | 
|  | // the trace level strings in an array.  these are ordered in the same order | 
|  | // as the trace levels are defined in the enum (see VOS_TRACE_LEVEL) so we | 
|  | // can index into this array with the level and get the right string.  The | 
|  | // vos trace levels are... | 
|  | // none, Fatal, Error, Warning, Info, InfoHigh, InfoMed, InfoLow, Debug | 
|  | static const char * TRACE_LEVEL_STR[] = { "  ", "F ", "E ", "W ", "I ", "IH", "IM", "IL", "D" }; | 
|  | va_list val; | 
|  | va_start(val, strFormat); | 
|  |  | 
|  | // print the prefix string into the string buffer... | 
|  | n = snprintf(strBuffer, VOS_TRACE_BUFFER_SIZE, "wlan: [%d:%2s:%3s] ", | 
|  | in_interrupt() ? 0 : current->pid, | 
|  | (char *) TRACE_LEVEL_STR[ level ], | 
|  | (char *) gVosTraceInfo[ module ].moduleNameStr ); | 
|  |  | 
|  | // print the formatted log message after the prefix string. | 
|  | if ((n >= 0) && (n < VOS_TRACE_BUFFER_SIZE)) | 
|  | { | 
|  | vsnprintf(strBuffer + n, VOS_TRACE_BUFFER_SIZE - n, strFormat, val ); | 
|  |  | 
|  | #ifdef WLAN_LOGGING_SOCK_SVC_ENABLE | 
|  | wlan_log_to_user(level, (char *)strBuffer, strlen(strBuffer)); | 
|  | #else | 
|  | pr_err("%s\n", strBuffer); | 
|  | #endif | 
|  | } | 
|  | va_end(val); | 
|  | } | 
|  | } | 
|  |  | 
|  | void vos_trace_display(void) | 
|  | { | 
|  | VOS_MODULE_ID moduleId; | 
|  |  | 
|  | pr_err("     1)FATAL  2)ERROR  3)WARN  4)INFO  5)INFO_H  6)INFO_M  7)INFO_L 8)DEBUG\n"); | 
|  | for (moduleId = 0; moduleId < VOS_MODULE_ID_MAX; ++moduleId) | 
|  | { | 
|  | pr_err("%2d)%s    %s        %s       %s       %s        %s         %s         %s        %s\n", | 
|  | (int)moduleId, | 
|  | gVosTraceInfo[moduleId].moduleNameStr, | 
|  | (gVosTraceInfo[moduleId].moduleTraceLevel & (1 << VOS_TRACE_LEVEL_FATAL)) ? "X":" ", | 
|  | (gVosTraceInfo[moduleId].moduleTraceLevel & (1 << VOS_TRACE_LEVEL_ERROR)) ? "X":" ", | 
|  | (gVosTraceInfo[moduleId].moduleTraceLevel & (1 << VOS_TRACE_LEVEL_WARN)) ? "X":" ", | 
|  | (gVosTraceInfo[moduleId].moduleTraceLevel & (1 << VOS_TRACE_LEVEL_INFO)) ? "X":" ", | 
|  | (gVosTraceInfo[moduleId].moduleTraceLevel & (1 << VOS_TRACE_LEVEL_INFO_HIGH)) ? "X":" ", | 
|  | (gVosTraceInfo[moduleId].moduleTraceLevel & (1 << VOS_TRACE_LEVEL_INFO_MED)) ? "X":" ", | 
|  | (gVosTraceInfo[moduleId].moduleTraceLevel & (1 << VOS_TRACE_LEVEL_INFO_LOW)) ? "X":" ", | 
|  | (gVosTraceInfo[moduleId].moduleTraceLevel & (1 << VOS_TRACE_LEVEL_DEBUG)) ? "X":" " | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------- | 
|  |  | 
|  | \brief vos_trace_hex_dump() - Externally called hex dump function | 
|  |  | 
|  | Checks the level of severity and accordingly prints the trace messages | 
|  |  | 
|  | \param module - module identifier.   A member of the VOS_MODULE_ID | 
|  | enumeration that identifies the module issuing the trace message. | 
|  |  | 
|  | \param level - trace level.   A member of the VOS_TRACE_LEVEL | 
|  | enumeration indicating the severity of the condition causing the | 
|  | trace message to be issued.   More severe conditions are more | 
|  | likely to be logged. | 
|  |  | 
|  | \param data - .  The base address of the buffer to be logged. | 
|  |  | 
|  | \param buf_len - .  The size of the buffer to be logged. | 
|  |  | 
|  | \return  nothing | 
|  |  | 
|  | \sa | 
|  | --------------------------------------------------------------------------*/ | 
|  | void vos_trace_hex_dump( VOS_MODULE_ID module, VOS_TRACE_LEVEL level, | 
|  | void *data, int buf_len ) | 
|  | { | 
|  | const u8 *ptr = data; | 
|  | int i, linelen, remaining = buf_len; | 
|  | unsigned char linebuf[BUFFER_SIZE]; | 
|  |  | 
|  | if (!(gVosTraceInfo[module].moduleTraceLevel & | 
|  | VOS_TRACE_LEVEL_TO_MODULE_BITMASK(level))) | 
|  | return; | 
|  |  | 
|  | for (i = 0; i < buf_len; i += ROW_SIZE) { | 
|  | linelen = min(remaining, ROW_SIZE); | 
|  | remaining -= ROW_SIZE; | 
|  |  | 
|  | hex_dump_to_buffer(ptr + i, linelen, ROW_SIZE, 1, | 
|  | linebuf, sizeof(linebuf), false); | 
|  |  | 
|  | vos_trace_msg(module, level, "%.8x: %s", i, linebuf); | 
|  | } | 
|  | } | 
|  |  | 
|  | #endif | 
|  |  | 
|  | /*----------------------------------------------------------------------------- | 
|  | \brief vosTraceEnable() - Enable MTRACE for specific modules whose bits are | 
|  | set in bitmask and enable is true. if enable is false it disables MTRACE for | 
|  | that module. set the bitmask according to enum value of the modules. | 
|  |  | 
|  | this functions will be called when you issue ioctl as mentioned following | 
|  | [iwpriv wlan0 setdumplog <value> <enable>]. | 
|  | <value> - Decimal number, i.e. 64 decimal value shows only SME module, | 
|  | 128 decimal value shows only PE module, 192 decimal value shows PE and SME. | 
|  |  | 
|  | \param - bitmask_of_moduleId - as explained above set bitmask according to | 
|  | enum of the modules. | 
|  | 32 [dec]  = 0010 0000 [bin] <enum of HDD is 5> | 
|  | 64 [dec]  = 0100 0000 [bin] <enum of SME is 6> | 
|  | 128 [dec] = 1000 0000 [bin] <enum of PE is 7> | 
|  | \param - enable - can be true or false. | 
|  | True implies enabling MTRACE, false implies disabling MTRACE. | 
|  | ---------------------------------------------------------------------------*/ | 
|  | void vosTraceEnable(v_U32_t bitmask_of_moduleId, v_U8_t enable) | 
|  | { | 
|  | int i; | 
|  | if (bitmask_of_moduleId) | 
|  | { | 
|  | for (i = 0; i < VOS_MODULE_ID_MAX; i++) | 
|  | { | 
|  | if (((bitmask_of_moduleId >> i) & 1 )) | 
|  | { | 
|  | if (enable) | 
|  | { | 
|  | if (NULL != vostraceRestoreCBTable[i]) | 
|  | { | 
|  | vostraceCBTable[i] = vostraceRestoreCBTable[i]; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | vostraceRestoreCBTable[i] = vostraceCBTable[i]; | 
|  | vostraceCBTable[i] = NULL; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | if (enable) | 
|  | { | 
|  | for (i = 0; i < VOS_MODULE_ID_MAX; i++) | 
|  | { | 
|  | if (NULL != vostraceRestoreCBTable[i]) | 
|  | { | 
|  | vostraceCBTable[i] = vostraceRestoreCBTable[i]; | 
|  | } | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | for (i = 0; i < VOS_MODULE_ID_MAX; i++) | 
|  | { | 
|  | vostraceRestoreCBTable[i] = vostraceCBTable[i]; | 
|  | vostraceCBTable[i] = NULL; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------- | 
|  | \brief vosTraceInit() - Initializes vos trace structures and variables. | 
|  |  | 
|  | Called immediately after vos_preopen, so that we can start recording HDD | 
|  | events ASAP. | 
|  | ----------------------------------------------------------------------------*/ | 
|  | void vosTraceInit() | 
|  | { | 
|  | v_U8_t i; | 
|  | gvosTraceData.head = INVALID_VOS_TRACE_ADDR; | 
|  | gvosTraceData.tail = INVALID_VOS_TRACE_ADDR; | 
|  | gvosTraceData.num = 0; | 
|  | gvosTraceData.enable = TRUE; | 
|  | gvosTraceData.dumpCount = DEFAULT_VOS_TRACE_DUMP_COUNT; | 
|  | gvosTraceData.numSinceLastDump = 0; | 
|  |  | 
|  | for (i=0; i<VOS_MODULE_ID_MAX; i++) | 
|  | { | 
|  | vostraceCBTable[i] = NULL; | 
|  | vostraceRestoreCBTable[i] = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * vos_register_debugcb_init() - initializes debug callbacks | 
|  | * to NULL | 
|  | * | 
|  | * Return: None | 
|  | */ | 
|  | void vos_register_debugcb_init(void) | 
|  | { | 
|  | uint8_t i; | 
|  |  | 
|  | for (i = 0; i < VOS_MODULE_ID_MAX; i++) | 
|  | vos_state_info_table[i] = NULL; | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------- | 
|  | \brief vos_trace() - puts the messages in to ring-buffer | 
|  |  | 
|  | This function will be called from each module who wants record the messages | 
|  | in circular queue. Before calling this functions make sure you have | 
|  | registered your module with voss through vosTraceRegister function. | 
|  |  | 
|  | \param module - enum of module, basically module id. | 
|  | \param code - | 
|  | \param session - | 
|  | \param data - actual message contents. | 
|  | ----------------------------------------------------------------------------*/ | 
|  | void vos_trace(v_U8_t module, v_U8_t code, v_U16_t session, v_U32_t data) | 
|  | { | 
|  | tpvosTraceRecord rec = NULL; | 
|  | unsigned long flags; | 
|  | char time[20]; | 
|  |  | 
|  | if (!gvosTraceData.enable) | 
|  | { | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* If module is not registered, don't record for that module */ | 
|  | if (NULL == vostraceCBTable[module]) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | vos_get_time_of_the_day_in_hr_min_sec_usec(time, sizeof(time)); | 
|  |  | 
|  | /* Aquire the lock so that only one thread at a time can fill the ring buffer */ | 
|  | spin_lock_irqsave(<raceLock, flags); | 
|  |  | 
|  | gvosTraceData.num++; | 
|  |  | 
|  | if (gvosTraceData.num > MAX_VOS_TRACE_RECORDS) | 
|  | { | 
|  | gvosTraceData.num = MAX_VOS_TRACE_RECORDS; | 
|  | } | 
|  |  | 
|  | if (INVALID_VOS_TRACE_ADDR == gvosTraceData.head) | 
|  | { | 
|  | /* first record */ | 
|  | gvosTraceData.head = 0; | 
|  | gvosTraceData.tail = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | /* queue is not empty */ | 
|  | v_U32_t tail = gvosTraceData.tail + 1; | 
|  |  | 
|  | if (MAX_VOS_TRACE_RECORDS == tail) | 
|  | { | 
|  | tail = 0; | 
|  | } | 
|  |  | 
|  | if (gvosTraceData.head == tail) | 
|  | { | 
|  | /* full */ | 
|  | if (MAX_VOS_TRACE_RECORDS == ++gvosTraceData.head) | 
|  | { | 
|  | gvosTraceData.head = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | gvosTraceData.tail = tail; | 
|  | } | 
|  | rec = &gvosTraceTbl[gvosTraceData.tail]; | 
|  | rec->code = code; | 
|  | rec->session = session; | 
|  | rec->data = data; | 
|  | snprintf(rec->time, sizeof(rec->time), "%s", time); | 
|  | rec->module = module; | 
|  | rec->pid = (in_interrupt() ? 0 : current->pid); | 
|  | gvosTraceData.numSinceLastDump ++; | 
|  | spin_unlock_irqrestore(<raceLock, flags); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*----------------------------------------------------------------------------- | 
|  | \brief vos_trace_spin_lock_init() - Initializes the lock variable before use | 
|  |  | 
|  | This function will be called from vos_preOpen, we will have lock available | 
|  | to use ASAP. | 
|  | ----------------------------------------------------------------------------*/ | 
|  | VOS_STATUS vos_trace_spin_lock_init() | 
|  | { | 
|  | spin_lock_init(<raceLock); | 
|  |  | 
|  | return VOS_STATUS_SUCCESS; | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------------- | 
|  | \brief vosTraceRegister() - Registers the call back functions to display the | 
|  | messages in particular format mentioned in these call back functions. | 
|  |  | 
|  | this functions should be called by interested module in their init part as | 
|  | we will be ready to register as soon as modules are up. | 
|  |  | 
|  | \param moduleID - enum value of module | 
|  | \param vostraceCb - call back functions to display the messages in particular | 
|  | format. | 
|  | ----------------------------------------------------------------------------*/ | 
|  | void vosTraceRegister(VOS_MODULE_ID moduleID, tpvosTraceCb vostraceCb) | 
|  | { | 
|  | vostraceCBTable[moduleID] = vostraceCb; | 
|  | } | 
|  |  | 
|  | /*------------------------------------------------------------------------------ | 
|  | \brief vosTraceDumpAll() - Dump data from ring buffer via call back functions | 
|  | registered with VOSS | 
|  |  | 
|  | This function will be called up on issueing ioctl call as mentioned following | 
|  | [iwpriv wlan0 dumplog 0 0 <n> <bitmask_of_module>] | 
|  |  | 
|  | <n> - number lines to dump starting from tail to head. | 
|  |  | 
|  | <bitmask_of_module> - if anybody wants to know how many messages were recorded | 
|  | for particular module/s mentioned by setbit in bitmask from last <n> messages. | 
|  | it is optional, if you don't provide then it will dump everything from buffer. | 
|  |  | 
|  | \param pMac - context of particular module | 
|  | \param code - | 
|  | \param session - | 
|  | \param count - number of lines to dump starting from tail to head | 
|  | ----------------------------------------------------------------------------*/ | 
|  | void vosTraceDumpAll(void *pMac, v_U8_t code, v_U8_t session, | 
|  | v_U32_t count, v_U32_t bitmask_of_module) | 
|  | { | 
|  | tvosTraceRecord pRecord; | 
|  | tANI_S32 i, tail; | 
|  |  | 
|  |  | 
|  | if (!gvosTraceData.enable) | 
|  | { | 
|  | VOS_TRACE( VOS_MODULE_ID_SYS, | 
|  | VOS_TRACE_LEVEL_ERROR, "Tracing Disabled"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | VOS_TRACE( VOS_MODULE_ID_SYS, VOS_TRACE_LEVEL_INFO, | 
|  | "Total Records: %d, Head: %d, Tail: %d", | 
|  | gvosTraceData.num, gvosTraceData.head, gvosTraceData.tail); | 
|  |  | 
|  | /* Aquire the lock so that only one thread at a time can read the ring buffer */ | 
|  | spin_lock(<raceLock); | 
|  |  | 
|  | if (gvosTraceData.head != INVALID_VOS_TRACE_ADDR) | 
|  | { | 
|  | i = gvosTraceData.head; | 
|  | tail = gvosTraceData.tail; | 
|  |  | 
|  | if (count) | 
|  | { | 
|  | if (count > gvosTraceData.num) | 
|  | { | 
|  | count = gvosTraceData.num; | 
|  | } | 
|  | if (tail >= (count - 1)) | 
|  | { | 
|  | i = tail - count + 1; | 
|  | } | 
|  | else if (count != MAX_VOS_TRACE_RECORDS) | 
|  | { | 
|  | i = MAX_VOS_TRACE_RECORDS - ((count - 1) - tail); | 
|  | } | 
|  | } | 
|  |  | 
|  | pRecord = gvosTraceTbl[i]; | 
|  | /* right now we are not using numSinceLastDump member but in future | 
|  | we might re-visit and use this member to track how many latest | 
|  | messages got added while we were dumping from ring buffer */ | 
|  | gvosTraceData.numSinceLastDump = 0; | 
|  | spin_unlock(<raceLock); | 
|  | for (;;) | 
|  | { | 
|  | if ((code == 0 || (code == pRecord.code)) && | 
|  | (vostraceCBTable[pRecord.module] != NULL)) | 
|  | { | 
|  | if (0 == bitmask_of_module) | 
|  | { | 
|  | vostraceCBTable[pRecord.module](pMac, &pRecord, (v_U16_t)i); | 
|  | } | 
|  | else | 
|  | { | 
|  | if (bitmask_of_module & (1 << pRecord.module)) | 
|  | { | 
|  | vostraceCBTable[pRecord.module](pMac, &pRecord, (v_U16_t)i); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (i == tail) | 
|  | { | 
|  | break; | 
|  | } | 
|  | i += 1; | 
|  |  | 
|  | spin_lock(<raceLock); | 
|  | if (MAX_VOS_TRACE_RECORDS == i) | 
|  | { | 
|  | i = 0; | 
|  | pRecord= gvosTraceTbl[0]; | 
|  | } | 
|  | else | 
|  | { | 
|  | pRecord = gvosTraceTbl[i]; | 
|  | } | 
|  | spin_unlock(<raceLock); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | spin_unlock(<raceLock); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * vos_register_debug_callback() - stores callback handlers to print | 
|  | * state information | 
|  | * @module_id: module id of layer | 
|  | * @vos_state_infocb: callback to be registered | 
|  | * | 
|  | * This function is used to store callback handlers to print | 
|  | * state information | 
|  | * | 
|  | * Return: None | 
|  | */ | 
|  | void vos_register_debug_callback(VOS_MODULE_ID module_id, | 
|  | tp_vos_state_info_cb vos_state_infocb) | 
|  | { | 
|  | vos_state_info_table[module_id] = vos_state_infocb; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * vos_state_info_dump_all() - it invokes callback of layer which registered | 
|  | * its callback to print its state information. | 
|  | * @buf:  buffer pointer to be passed | 
|  | * @size:  size of buffer to be filled | 
|  | * @driver_dump_size: actual size of buffer used | 
|  | * | 
|  | * Return: zero on success | 
|  | */ | 
|  | int vos_state_info_dump_all(char *buf, uint16_t size, | 
|  | uint16_t *driver_dump_size) | 
|  | { | 
|  | uint8_t module, ret = 0; | 
|  | uint16_t buf_len = size; | 
|  | char *buf_ptr = buf; | 
|  |  | 
|  | for (module = 0; module < VOS_MODULE_ID_MAX; module++) { | 
|  | if (NULL != vos_state_info_table[module]) { | 
|  | vos_state_info_table[module](&buf_ptr, &buf_len); | 
|  | if (!buf_len) { | 
|  | ret = 1; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | *driver_dump_size = size - buf_len; | 
|  | return ret; | 
|  | } |