/* * EVENT_LOG system definitions * * Copyright (C) 1999-2017, Broadcom Corporation * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that * you also meet, for each linked independent module, the terms and conditions of * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * * * <> * * $Id: event_log.h 711908 2017-07-20 10:37:34Z $ */ #ifndef _EVENT_LOG_H_ #define _EVENT_LOG_H_ #include #include #include #include #include /* logstrs header */ #define LOGSTRS_MAGIC 0x4C4F4753 #define LOGSTRS_VERSION 0x1 /* We make sure that the block size will fit in a single packet * (allowing for a bit of overhead on each packet */ #define EVENT_LOG_MAX_BLOCK_SIZE 1400 #define EVENT_LOG_WL_BLOCK_SIZE 0x200 #define EVENT_LOG_PSM_BLOCK_SIZE 0x200 #define EVENT_LOG_BUS_BLOCK_SIZE 0x200 #define EVENT_LOG_ERROR_BLOCK_SIZE 0x200 /* Maximum event log record payload size = 1024 bytes or 256 words. */ #define EVENT_LOG_MAX_RECORD_PAYLOAD_SIZE 256 /* * There are multiple levels of objects define here: * event_log_set - a set of buffers * event log groups - every event log call is part of just one. All * event log calls in a group are handled the * same way. Each event log group is associated * with an event log set or is off. */ #ifndef __ASSEMBLER__ /* On the external system where the dumper is we need to make sure * that these types are the same size as they are on the ARM the * produced them */ #ifdef EVENT_LOG_DUMPER #define _EL_BLOCK_PTR uint32 #define _EL_TYPE_PTR uint32 #define _EL_SET_PTR uint32 #define _EL_TOP_PTR uint32 #else #define _EL_BLOCK_PTR struct event_log_block * #define _EL_TYPE_PTR uint32 * #define _EL_SET_PTR struct event_log_set ** #define _EL_TOP_PTR struct event_log_top * #endif /* EVENT_LOG_DUMPER */ /* Event log sets (a logical circurlar buffer) consist of one or more * event_log_blocks. The blocks themselves form a logical circular * list. The log entries are placed in each event_log_block until it * is full. Logging continues with the next event_log_block in the * event_set until the last event_log_block is reached and then * logging starts over with the first event_log_block in the * event_set. */ typedef struct event_log_block { _EL_BLOCK_PTR next_block; _EL_BLOCK_PTR prev_block; _EL_TYPE_PTR end_ptr; /* Start of packet sent for log tracing */ uint16 pktlen; /* Size of rest of block */ uint16 count; /* Logtrace counter */ uint32 extra_hdr_info; /* LSB: 6 bits set id. MSB 24 bits reserved */ uint32 event_logs; } event_log_block_t; #define EVENT_LOG_BLOCK_HDRLEN 8 /* pktlen 2 + count 2 + extra_hdr_info 4 */ #define NAN_EVENT_LOG_MIN_LENGTH 2 /* Minimum length of Nan event */ typedef enum { SET_DESTINATION_INVALID = -1, SET_DESTINATION_HOST = 0, SET_DESTINATION_NONE = 1, SET_DESTINATION_MAX } event_log_set_destination_t; /* There can be multiple event_sets with each logging a set of * associated events (i.e, "fast" and "slow" events). */ typedef struct event_log_set { _EL_BLOCK_PTR first_block; /* Pointer to first event_log block */ _EL_BLOCK_PTR last_block; /* Pointer to last event_log block */ _EL_BLOCK_PTR logtrace_block; /* next block traced */ _EL_BLOCK_PTR cur_block; /* Pointer to current event_log block */ _EL_TYPE_PTR cur_ptr; /* Current event_log pointer */ uint32 blockcount; /* Number of blocks */ uint16 logtrace_count; /* Last count for logtrace */ uint16 blockfill_count; /* Fill count for logtrace */ uint32 timestamp; /* Last timestamp event */ uint32 cyclecount; /* Cycles at last timestamp event */ event_log_set_destination_t destination; uint16 size; /* same size for all buffers in one set */ } event_log_set_t; /* Top data structure for access to everything else */ typedef struct event_log_top { uint32 magic; #define EVENT_LOG_TOP_MAGIC 0x474C8669 /* 'EVLG' */ uint32 version; #define EVENT_LOG_VERSION 1 uint32 num_sets; uint32 logstrs_size; /* Size of lognums + logstrs area */ uint32 timestamp; /* Last timestamp event */ uint32 cyclecount; /* Cycles at last timestamp event */ _EL_SET_PTR sets; /* Ptr to array of set ptrs */ } event_log_top_t; /* Data structure of Keeping the Header from logstrs.bin */ typedef struct { uint32 logstrs_size; /* Size of the file */ uint32 rom_lognums_offset; /* Offset to the ROM lognum */ uint32 ram_lognums_offset; /* Offset to the RAM lognum */ uint32 rom_logstrs_offset; /* Offset to the ROM logstr */ uint32 ram_logstrs_offset; /* Offset to the RAM logstr */ /* Keep version and magic last since "header" is appended to the end of logstrs file. */ uint32 version; /* Header version */ uint32 log_magic; /* MAGIC number for verification 'LOGS' */ } logstr_header_t; /* * Use the following macros for generating log events. * * The FAST versions check the enable of the tag before evaluating the arguments and calling the * event_log function. This adds 5 instructions. The COMPACT versions evaluate the arguments * and call the event_log function unconditionally. The event_log function will then skip logging * if this tag is disabled. * * To support easy usage of existing debugging (e.g. msglevel) via macro re-definition there are * two variants of these macros to help. * * First there are the CAST versions. The event_log function normally logs uint32 values or else * they have to be cast to uint32. The CAST versions blindly cast for you so you don't have to edit * any existing code. * * Second there are the PAREN_ARGS versions. These expect the logging format string and arguments * to be enclosed in parentheses. This allows us to make the following mapping of an existing * msglevel macro: * #define WL_ERROR(args) EVENT_LOG_CAST_PAREN_ARGS(EVENT_LOG_TAG_WL_ERROR, args) * * The versions of the macros without FAST or COMPACT in their name are just synonyms for the * COMPACT versions. * * You should use the COMPACT macro (or its synonym) in cases where there is some preceding logic * that prevents the execution of the macro, e.g. WL_ERROR by definition rarely gets executed. * Use the FAST macro in performance sensitive paths. The key concept here is that you should be * assuming that your macro usage is compiled into ROM and can't be changed ... so choose wisely. * */ #if !defined(EVENT_LOG_DUMPER) && !defined(DHD_EFI) #ifndef EVENT_LOG_COMPILE /* Null define if no tracing */ #define EVENT_LOG(format, ...) #define EVENT_LOG_FAST(tag, fmt, ...) #define EVENT_LOG_COMPACT(tag, fmt, ...) #define EVENT_LOG_CAST(tag, fmt, ...) #define EVENT_LOG_FAST_CAST(tag, fmt, ...) #define EVENT_LOG_COMPACT_CAST(tag, fmt, ...) #define EVENT_LOG_CAST_PAREN_ARGS(tag, pargs) #define EVENT_LOG_FAST_CAST_PAREN_ARGS(tag, pargs) #define EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, pargs) #define EVENT_LOG_IS_ON(tag) 0 #define EVENT_LOG_IS_LOG_ON(tag) 0 #define EVENT_LOG_BUFFER(tag, buf, size) #else /* EVENT_LOG_COMPILE */ /* The first few are special because they can be done more efficiently * this way and they are the common case. Once there are too many * parameters the code size starts to be an issue and a loop is better */ #define _EVENT_LOG0(tag, fmt_num) \ event_log0(tag, fmt_num) #define _EVENT_LOG1(tag, fmt_num, t1) \ event_log1(tag, fmt_num, t1) #define _EVENT_LOG2(tag, fmt_num, t1, t2) \ event_log2(tag, fmt_num, t1, t2) #define _EVENT_LOG3(tag, fmt_num, t1, t2, t3) \ event_log3(tag, fmt_num, t1, t2, t3) #define _EVENT_LOG4(tag, fmt_num, t1, t2, t3, t4) \ event_log4(tag, fmt_num, t1, t2, t3, t4) /* The rest call the generic routine that takes a count */ #define _EVENT_LOG5(tag, fmt_num, ...) event_logn(5, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG6(tag, fmt_num, ...) event_logn(6, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG7(tag, fmt_num, ...) event_logn(7, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG8(tag, fmt_num, ...) event_logn(8, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG9(tag, fmt_num, ...) event_logn(9, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOGA(tag, fmt_num, ...) event_logn(10, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOGB(tag, fmt_num, ...) event_logn(11, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOGC(tag, fmt_num, ...) event_logn(12, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOGD(tag, fmt_num, ...) event_logn(13, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOGE(tag, fmt_num, ...) event_logn(14, tag, fmt_num, __VA_ARGS__) #define _EVENT_LOGF(tag, fmt_num, ...) event_logn(15, tag, fmt_num, __VA_ARGS__) /* Casting low level macros */ #define _EVENT_LOG_CAST0(tag, fmt_num) \ event_log0(tag, fmt_num) #define _EVENT_LOG_CAST1(tag, fmt_num, t1) \ event_log1(tag, fmt_num, (uint32)(t1)) #define _EVENT_LOG_CAST2(tag, fmt_num, t1, t2) \ event_log2(tag, fmt_num, (uint32)(t1), (uint32)(t2)) #define _EVENT_LOG_CAST3(tag, fmt_num, t1, t2, t3) \ event_log3(tag, fmt_num, (uint32)(t1), (uint32)(t2), (uint32)(t3)) #define _EVENT_LOG_CAST4(tag, fmt_num, t1, t2, t3, t4) \ event_log4(tag, fmt_num, (uint32)(t1), (uint32)(t2), (uint32)(t3), (uint32)(t4)) /* The rest call the generic routine that takes a count */ #define _EVENT_LOG_CAST5(tag, fmt_num, ...) _EVENT_LOG5(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CAST6(tag, fmt_num, ...) _EVENT_LOG6(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CAST7(tag, fmt_num, ...) _EVENT_LOG7(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CAST8(tag, fmt_num, ...) _EVENT_LOG8(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CAST9(tag, fmt_num, ...) _EVENT_LOG9(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CASTA(tag, fmt_num, ...) _EVENT_LOGA(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CASTB(tag, fmt_num, ...) _EVENT_LOGB(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CASTC(tag, fmt_num, ...) _EVENT_LOGC(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CASTD(tag, fmt_num, ...) _EVENT_LOGD(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CASTE(tag, fmt_num, ...) _EVENT_LOGE(tag, fmt_num, __VA_ARGS__) #define _EVENT_LOG_CASTF(tag, fmt_num, ...) _EVENT_LOGF(tag, fmt_num, __VA_ARGS__) /* Hack to make the proper routine call when variadic macros get * passed. Note the max of 15 arguments. More than that can't be * handled by the event_log entries anyways so best to catch it at compile * time */ #define _EVENT_LOG_VA_NUM_ARGS(F, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ _A, _B, _C, _D, _E, _F, N, ...) F ## N /* cast = _EVENT_LOG for no casting * cast = _EVENT_LOG_CAST for casting of fmt arguments to uint32. * Only first 4 arguments are casted to uint32. event_logn() is called * if more than 4 arguments are present. This function internally assumes * all arguments are uint32 */ #define _EVENT_LOG(cast, tag, fmt, ...) \ static char logstr[] __attribute__ ((section(".logstrs"))) = fmt; \ static uint32 fmtnum __attribute__ ((section(".lognums"))) = (uint32) &logstr; \ _EVENT_LOG_VA_NUM_ARGS(cast, ##__VA_ARGS__, \ F, E, D, C, B, A, 9, 8, \ 7, 6, 5, 4, 3, 2, 1, 0) \ (tag, (int) &fmtnum , ## __VA_ARGS__) #define EVENT_LOG_FAST(tag, fmt, ...) \ do { \ if (event_log_tag_sets != NULL) { \ uint8 tag_flag = *(event_log_tag_sets + tag); \ if ((tag_flag & ~EVENT_LOG_TAG_FLAG_SET_MASK) != 0) { \ _EVENT_LOG(_EVENT_LOG, tag, fmt , ## __VA_ARGS__); \ } \ } \ } while (0) #define EVENT_LOG_COMPACT(tag, fmt, ...) \ do { \ _EVENT_LOG(_EVENT_LOG, tag, fmt , ## __VA_ARGS__); \ } while (0) /* Event log macro with casting to uint32 of arguments */ #define EVENT_LOG_FAST_CAST(tag, fmt, ...) \ do { \ if (event_log_tag_sets != NULL) { \ uint8 tag_flag = *(event_log_tag_sets + tag); \ if ((tag_flag & ~EVENT_LOG_TAG_FLAG_SET_MASK) != 0) { \ _EVENT_LOG(_EVENT_LOG_CAST, tag, fmt , ## __VA_ARGS__); \ } \ } \ } while (0) #define EVENT_LOG_COMPACT_CAST(tag, fmt, ...) \ do { \ _EVENT_LOG(_EVENT_LOG_CAST, tag, fmt , ## __VA_ARGS__); \ } while (0) #define EVENT_LOG(tag, fmt, ...) EVENT_LOG_COMPACT(tag, fmt , ## __VA_ARGS__) #define EVENT_LOG_CAST(tag, fmt, ...) EVENT_LOG_COMPACT_CAST(tag, fmt , ## __VA_ARGS__) #define _EVENT_LOG_REMOVE_PAREN(...) __VA_ARGS__ #define EVENT_LOG_REMOVE_PAREN(args) _EVENT_LOG_REMOVE_PAREN args #define EVENT_LOG_CAST_PAREN_ARGS(tag, pargs) \ EVENT_LOG_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs)) #define EVENT_LOG_FAST_CAST_PAREN_ARGS(tag, pargs) \ EVENT_LOG_FAST_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs)) #define EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, pargs) \ EVENT_LOG_COMPACT_CAST(tag, EVENT_LOG_REMOVE_PAREN(pargs)) /* Minimal event logging. Event log internally calls event_logx() * log return address in caller. * Note that the if(0){..} below is to avoid compiler warnings * due to unused variables caused by this macro */ #define EVENT_LOG_RA(tag, args) \ do { \ if (0) { \ EVENT_LOG_COMPACT_CAST_PAREN_ARGS(tag, args); \ } \ event_log_caller_return_address(tag); \ } while (0) #define EVENT_LOG_IS_LOG_ON(tag) (*(event_log_tag_sets + (tag)) & EVENT_LOG_TAG_FLAG_LOG) #define EVENT_DUMP event_log_buffer extern uint8 *event_log_tag_sets; extern int event_log_init(osl_t *osh); extern int event_log_set_init(osl_t *osh, int set_num, int size); extern int event_log_set_expand(osl_t *osh, int set_num, int size); extern int event_log_set_shrink(osl_t *osh, int set_num, int size); extern int event_log_tag_start(int tag, int set_num, int flags); extern int event_log_tag_stop(int tag); typedef void (*event_log_logtrace_trigger_fn_t)(void *ctx); void event_log_set_logtrace_trigger_fn(event_log_logtrace_trigger_fn_t fn, void *ctx); event_log_top_t *event_log_get_top(void); extern int event_log_get(int set_num, int buflen, void *buf); extern uint8 *event_log_next_logtrace(int set_num); extern void event_log0(int tag, int fmtNum); extern void event_log1(int tag, int fmtNum, uint32 t1); extern void event_log2(int tag, int fmtNum, uint32 t1, uint32 t2); extern void event_log3(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3); extern void event_log4(int tag, int fmtNum, uint32 t1, uint32 t2, uint32 t3, uint32 t4); extern void event_logn(int num_args, int tag, int fmtNum, ...); extern void event_log_time_sync(uint32 ms); extern void event_log_buffer(int tag, uint8 *buf, int size); extern void event_log_caller_return_address(int tag); extern int event_log_set_destination_set(int set, event_log_set_destination_t dest); extern event_log_set_destination_t event_log_set_destination_get(int set); #endif /* EVENT_LOG_DUMPER */ #endif /* EVENT_LOG_COMPILE */ #endif /* __ASSEMBLER__ */ #endif /* _EVENT_LOG_H_ */