2 * Broadcom BCM47xx Buzzz based Kernel Profiling and Debugging
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * -----------------------------------------------------------------------------
23 * Description : Implementation of buzzz.c.
25 * Buzzz, a work in progress, provides 4 capabilities, namely,
27 * 1. A character device driver for userspace command line ioctl communication
28 * with proprietary Buzzz kernel debug tools.
29 * 2. A logging infrastructure that may be used for:
30 * - kernel event logging using pre-instrument kernel instrumentation,
31 * - MIPS 74K performance counter monitoring of code segments,
32 * - log of all functions calls using compiler -finstrument-function stubs.
33 * - logging a past history prior to an audit assert, or
34 * 3. An audit infrastucture allowing user defined audits to be invoked at
35 * some well known points within the system, e.g. periodic, context switch, a
36 * specific interrupt, queue overflow etc.
37 * 4. Transmission of logged data to an off-target host for post-processing and
38 * display, or recording into flash, etc.
39 * Currently a proc fs and netcat utility is used.
41 * Target: cat /proc/buzzz/log | nc 192.168.1.10 33333
42 * Host: nc -l 192.168.1.10 33333 > func_trace.txt
43 * BUG: use of netcat on target causes page fault.
45 * -----------------------------------------------------------------------------
48 #include <linux/init.h>
49 #include <linux/miscdevice.h>
51 #include <linux/proc_fs.h>
52 #include <linux/seq_file.h>
54 #include <linux/inet.h>
55 #include <linux/kallsyms.h>
56 #include <linux/kernel.h>
57 #include <linux/delay.h>
58 #include <linux/sched.h>
59 #include <linux/timer.h>
60 #include <linux/percpu.h>
61 #include <linux/cpu.h>
62 #include <linux/smp.h>
63 #if defined(CONFIG_MIPS)
64 #include <asm/mipsregs.h>
65 #include <asm/prefetch.h>
66 #endif /* CONFIG_MIPS */
67 #if defined(CONFIG_SMP)
68 #include <linux/spinlock_types.h>
69 #endif /* CONFIG_SMP */
70 #include <asm/buzzz.h>
72 #if defined(CC_BUZZZ_DEBUG)
73 unsigned int buzzz_debug
= 0U;
74 EXPORT_SYMBOL(buzzz_debug
);
75 #endif /* CC_BUZZZ_DEBUG */
79 /* Maximum length of a single log entry cannot exceed 64 bytes */
80 #define BUZZZ_LOGENTRY_MAXSZ (64)
82 /* Length of the buffer available for logging */
83 #define BUZZZ_AVAIL_BUFSIZE (BUZZZ_LOG_BUFSIZE - BUZZZ_LOGENTRY_MAXSZ)
85 /* Caution: BUZZZ may only be used on single core. Not SMP safe */
86 #if defined(CONFIG_SMP)
87 #define BUZZZ_LOCK(flags) spin_lock_irqsave(&buzzz_g.lock, flags)
88 #define BUZZZ_UNLOCK(flags) spin_unlock_irqrestore(&buzzz_g.lock, flags)
89 #else /* CONFIG_SMP */
90 #define BUZZZ_LOCK(flags) local_irq_save(flags)
91 #define BUZZZ_UNLOCK(flags) local_irq_restore(flags)
92 #endif /* !CONFIG_SMP */
95 * Function Call Tracing Tool
97 /* Number of logs prior to end of trace to be dumped on a kernel panic */
98 #define BUZZZ_FUNC_PANIC_LOGS (512)
99 #define BUZZZ_FUNC_LIMIT_LOGS (512)
100 #define BUZZZ_FUNC_INDENT_STRING " "
102 #if (BUZZZ_LOG_BUFSIZE < (4 * 4 * BUZZZ_FUNC_PANIC_LOGS))
103 #error "BUZZZ_FUNC_PANIC_LOGS is too large"
104 #endif /* test BUZZZ_LOG_BUFSIZE */
106 #if (BUZZZ_LOG_BUFSIZE < (4 * 4 * BUZZZ_FUNC_LIMIT_LOGS))
107 #error "BUZZZ_FUNC_LIMIT_LOGS is too large"
108 #endif /* test BUZZZ_LOG_BUFSIZE */
111 * Performance Monitoring Tool
113 #define BUZZZ_PMON_SAMPLESZ (10U)
115 typedef void (*timer_fn_t
)(unsigned long);
117 * -----------------------------------------------------------------------------
118 * Buzzz debug display support.
120 * KALLSYMS printk formats: %pf %pF mac(%pM %pm) (%pI4 %pi4)
121 * extern int sprint_symbol(char *buffer, unsigned long address);
122 * extern void __print_symbol(const char *fmt, unsigned long address);
123 * #define print_ip_sym(ip) printk("[<%016lx>]", ip); print_symbol(" %s\n", ip);
124 * __print_symbol(fmt, address) {
125 * char buffer[KSYM_SYMBOL_LEN = 127];
126 * sprint_symbol(buffer, address);
127 * printk(fmt, buffer);
130 * #define IP4DOTQ(addr, n) (((addr) >> (24 - 8 * n)) & 0xFF)
131 * -----------------------------------------------------------------------------
134 #if defined(BUZZZ_CONFIG_SYS_KDBG)
135 #define BUZZZ_PRINT(fmt, arg...) \
136 printk(CLRg "BUZZZ %s: " fmt CLRnl, __FUNCTION__, ##arg)
137 #else /* !BUZZZ_CONFIG_SYS_KDBG */
138 #define BUZZZ_PRINT(fmt, arg...) BUZZZ_NULL_STMT
139 #endif /* !BUZZZ_CONFIG_SYS_KDBG */
142 #define BUZZZ_ENUM(val) #val,
144 static const char * _str_INV
= "INVALID";
146 static const char * _str_buzzz_tool
[BUZZZ_TOOL_MAXIMUM
] =
149 BUZZZ_ENUM(FUNC
) /* Function call tracing */
150 BUZZZ_ENUM(PMON
) /* Algorithm performance monitoring */
151 BUZZZ_ENUM(KEVT
) /* Kernel space event tracing */
153 static BUZZZ_INLINE
const char * BUZZZ_NOINSTR_FUNC
154 str_buzzz_tool(uint32_t tool
)
156 return (tool
>= BUZZZ_TOOL_MAXIMUM
) ? _str_INV
:
157 _str_buzzz_tool
[tool
];
160 static const char * _str_buzzz_status
[BUZZZ_STATUS_MAXIMUM
] =
166 static BUZZZ_INLINE
const char * BUZZZ_NOINSTR_FUNC
167 str_buzzz_status(uint32_t status
)
169 return (status
>= BUZZZ_STATUS_MAXIMUM
) ? _str_INV
:
170 _str_buzzz_status
[status
];
173 static const char * _str_buzzz_mode
[BUZZZ_MODE_MAXIMUM
] =
180 static BUZZZ_INLINE
const char * BUZZZ_NOINSTR_FUNC
181 str_buzzz_mode(uint32_t mode
)
183 return (mode
>= BUZZZ_MODE_MAXIMUM
) ? _str_INV
:
184 _str_buzzz_mode
[mode
];
186 static const char * _str_buzzz_ioctl
[BUZZZ_IOCTL_MAXIMUM
] =
190 BUZZZ_ENUM(CONFIG_TOOL
)
191 BUZZZ_ENUM(CONFIG_MODE
)
192 BUZZZ_ENUM(CONFIG_LIMIT
)
194 BUZZZ_ENUM(CONFIG_FUNC
)
195 BUZZZ_ENUM(CONFIG_PMON
)
196 BUZZZ_ENUM(CONFIG_KEVT
)
206 static BUZZZ_INLINE
const char * BUZZZ_NOINSTR_FUNC
207 str_buzzz_ioctl(uint32_t ioctl
)
209 ioctl
-= BUZZZ_IOCTL_KCALL
;
210 return (ioctl
>= BUZZZ_IOCTL_MAXIMUM
) ? _str_INV
:
211 _str_buzzz_ioctl
[ioctl
];
214 #if defined(CONFIG_MIPS) && defined(BUZZZ_CONFIG_CPU_MIPS_74K)
215 static const char * _str_buzzz_pmon_group
[BUZZZ_PMON_GROUP_MAXIMUM
] =
222 BUZZZ_ENUM(CYCLES_COMPLETED
)
223 BUZZZ_ENUM(CYCLES_ISSUE_OOO
)
224 BUZZZ_ENUM(INSTR_GENERAL
)
225 BUZZZ_ENUM(INSTR_MISCELLANEOUS
)
226 BUZZZ_ENUM(INSTR_LOAD_STORE
)
227 BUZZZ_ENUM(CYCLES_IDLE_FULL
)
228 BUZZZ_ENUM(CYCLES_IDLE_WAIT
)
229 /* BUZZZ_ENUM(L2_CACHE) */
232 static const char * _str_buzzz_pmon_event
[BUZZZ_PMON_EVENT_MAXIMUM
] =
235 BUZZZ_ENUM(CTR0_NONE
) /* 127 */
236 BUZZZ_ENUM(CTR1_NONE
) /* 127 */
237 BUZZZ_ENUM(CTR2_NONE
) /* 127 */
238 BUZZZ_ENUM(CTR3_NONE
) /* 127 */
240 /* group 1 GENERAL */
241 BUZZZ_ENUM(COMPL0_MISPRED
) /* 56: 0, 2 */
242 BUZZZ_ENUM(CYCLES_ELAPSED
) /* 0: 0,1,2,3 */
243 BUZZZ_ENUM(EXCEPTIONS
) /* 58: 0, 2 */
244 BUZZZ_ENUM(COMPLETED
) /* 1: 0,1,2,3 */
247 BUZZZ_ENUM(IC_ACCESS
) /* 6: 0, 2 */
248 BUZZZ_ENUM(IC_REFILL
) /* 6: 1, 3 */
249 BUZZZ_ENUM(CYCLES_IC_MISS
) /* 7: 0, 2 */
250 BUZZZ_ENUM(CYCLES_L2_MISS
) /* 7: 1, 3 */
253 BUZZZ_ENUM(LOAD_DC_ACCESS
) /* 23: 0, 2 */
254 BUZZZ_ENUM(LSP_DC_ACCESS
) /* 23: 1, 3 */
255 BUZZZ_ENUM(WB_DC_ACCESS
) /* 24: 0, 2 */
256 BUZZZ_ENUM(LSP_DC_MISSES
) /* 24: 1, 3 */
259 BUZZZ_ENUM(ITLB_ACCESS
) /* 4: 0, 2 */
260 BUZZZ_ENUM(ITLB_MISS
) /* 4: 1, 3 */
261 BUZZZ_ENUM(JTLB_DACCESS
) /* 25: 0, 2 */
262 BUZZZ_ENUM(JTLB_XL_FAIL
) /* 25: 1, 3 */
264 /* group 5 CYCLES_COMPLETED */
265 BUZZZ_ENUM(COMPL0_INSTR
) /* 53: 0, 2 */
266 BUZZZ_ENUM(COMPL_LOAD_MISS
) /* 53: 1, 3 */
267 BUZZZ_ENUM(COMPL1_INSTR
) /* 54: 0, 2 */
268 BUZZZ_ENUM(COMPL2_INSTR
) /* 54: 1, 3 */
270 /* group 6 CYCLES_ISSUE_OOO */
271 BUZZZ_ENUM(ISS1_INSTR
) /* 20: 0, 2 */
272 BUZZZ_ENUM(ISS2_INSTR
) /* 20: 1, 3 */
273 BUZZZ_ENUM(OOO_ALU
) /* 21: 0, 2 */
274 BUZZZ_ENUM(OOO_AGEN
) /* 21: 1, 3 */
276 /* group 7 INSTR_GENERAL */
277 BUZZZ_ENUM(CONDITIONAL
) /* 39: 0, 2 */
278 BUZZZ_ENUM(MISPREDICTED
) /* 39: 1, 3 */
279 BUZZZ_ENUM(INTEGER
) /* 40: 0, 2 */
280 BUZZZ_ENUM(FLOAT
) /* 40: 1, 3 */
282 /* group 8 INSTR_MISCELLANEOUS */
283 BUZZZ_ENUM(JUMP
) /* 42: 0, 2 */
284 BUZZZ_ENUM(MULDIV
) /* 43: 1, 3 */
285 BUZZZ_ENUM(PREFETCH
) /* 52: 0, 2 */
286 BUZZZ_ENUM(PREFETCH_NULL
) /* 52: 1, 3 */
288 /* group 9 INSTR_LOAD_STORE */
289 BUZZZ_ENUM(LOAD
) /* 41: 0, 2 */
290 BUZZZ_ENUM(STORE
) /* 41: 1, 3 */
291 BUZZZ_ENUM(LOAD_UNCACHE
) /* 46: 0, 2 */
292 BUZZZ_ENUM(STORE_UNCACHE
) /* 46: 1, 3 */
294 /* group 10 CYCLES_IDLE_FULL */
295 BUZZZ_ENUM(ALU_CAND_POOL
) /* 13: 0, 2 */
296 BUZZZ_ENUM(AGEN_CAND_POOL
) /* 13: 1, 3 */
297 BUZZZ_ENUM(ALU_COMPL_BUF
) /* 14: 0, 2 */
298 BUZZZ_ENUM(AGEN_COMPL_BUF
) /* 14: 1, 3 */
300 /* group 11 CYCLES_IDLE_WAIT */
301 BUZZZ_ENUM(ALU_NO_INSTR
) /* 16: 0, 2 */
302 BUZZZ_ENUM(AGEN_NO_INSTR
) /* 16: 1, 3 */
303 BUZZZ_ENUM(ALU_NO_OPER
) /* 17: 0, 2 */
304 BUZZZ_ENUM(GEN_NO_OPER
) /* 17: 1, 3 */
306 /* group 12 : L2_CACHE */
307 /* BUZZZ_ENUM(WBACK) */
308 /* BUZZZ_ENUM(ACCESS) */
309 /* BUZZZ_ENUM(MISSES) */
310 /* BUZZZ_ENUM(MISS_CYCLES) */
312 #endif /* CONFIG_MIPS && BUZZZ_CONFIG_CPU_MIPS_74K */
314 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
315 static const char * _str_buzzz_pmon_group
[BUZZZ_PMON_GROUP_MAXIMUM
] =
325 BUZZZ_ENUM(MISCELLANEOUS
)
328 static const char * _str_buzzz_pmon_event
[BUZZZ_PMON_EVENT_MAXIMUM
] =
331 BUZZZ_ENUM(CTR0_SKIP
) /* 0x00 */
332 BUZZZ_ENUM(CTR1_SKIP
) /* 0x00 */
333 BUZZZ_ENUM(CTR2_SKIP
) /* 0x00 */
334 BUZZZ_ENUM(CTR3_SKIP
) /* 0x00 */
336 /* group 1: GENERAL */
337 BUZZZ_ENUM(BRANCH_MISPRED
) /* 0x10 */
338 BUZZZ_ENUM(CYCLES_ELAPSED
) /* 0x11 */
339 BUZZZ_ENUM(EXCEPTIONS
) /* 0x09 */
340 BUZZZ_ENUM(SPEC_INSTRCNT
) /* 0x68 */
342 /* group 2: ICACHE */
343 BUZZZ_ENUM(INSRTUCTIONS
) /* 0x68 */
344 BUZZZ_ENUM(IC_REFILL
) /* 0x01 */
345 BUZZZ_ENUM(CYCLES_IC_MISS
) /* 0x60 */
346 BUZZZ_ENUM(CYCLES_NOISSUE
) /* 0x66 */
348 /* group 3: DCACHE */
349 BUZZZ_ENUM(DC_ACCESS
) /* 0x04 */
350 BUZZZ_ENUM(DC_REFILL
) /* 0x03 */
351 BUZZZ_ENUM(CYCLES_DC_MISS
) /* 0x61 */
352 BUZZZ_ENUM(EVICTIONS
) /* 0x65 */
355 BUZZZ_ENUM(INSTR_REFILL
) /* 0x02 */
356 BUZZZ_ENUM(DATA_REFILL
) /* 0x05 */
357 BUZZZ_ENUM(CYCLES_ITLB_MISS
) /* 0x82 */
358 BUZZZ_ENUM(CYCLES_DTLB_MISS
) /* 0x83 */
361 BUZZZ_ENUM(READ_ACCESS
) /* 0x06 */
362 BUZZZ_ENUM(WRITE_ACCESS
) /* 0x07 */
363 BUZZZ_ENUM(CYCLES_WRITE
) /* 0x81 */
364 BUZZZ_ENUM(CYCLES_DMB
) /* 0x86 */
366 /* group 6: SPURIOUS */
367 BUZZZ_ENUM(INTERRUPTS
) /* 0x93 */
368 BUZZZ_ENUM(UNALIGNED
) /* 0x0F */
369 BUZZZ_ENUM(EXCEPTION_RTN
) /* 0x0A */
370 BUZZZ_ENUM(CYCLES_TLB_MISS
) /* 0x62 */
372 /* group 7: BRANCHES */
373 BUZZZ_ENUM(SW_PC_CHANGE
) /* 0x0C */
374 BUZZZ_ENUM(IMMED_BRANCHES
) /* 0x0D */
375 BUZZZ_ENUM(PROCEDURE_RTN
) /* 0x0E */
376 BUZZZ_ENUM(PRED_BRANCHES
) /* 0x12 */
378 /* group 8: MISCELLANEOUS */
379 BUZZZ_ENUM(STREX_PASSED
) /* 0x63 */
380 BUZZZ_ENUM(STREX_FAILED
) /* 0x64 */
381 BUZZZ_ENUM(DSB_INSTR
) /* 0x91 */
382 BUZZZ_ENUM(DMB_INSTR
) /* 0x92 */
384 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
386 static BUZZZ_INLINE
const char * BUZZZ_NOINSTR_FUNC
387 str_buzzz_pmon_group(uint32_t group
)
389 return (group
>= BUZZZ_PMON_GROUP_MAXIMUM
) ? _str_INV
:
390 _str_buzzz_pmon_group
[group
];
392 static BUZZZ_INLINE
const char * BUZZZ_NOINSTR_FUNC
393 str_buzzz_pmon_event(uint32_t event
)
395 return (event
>= BUZZZ_PMON_EVENT_MAXIMUM
) ? _str_INV
:
396 _str_buzzz_pmon_event
[event
];
399 static const char * _str_buzzz_kevt_group
[BUZZZ_KEVT_GROUP_MAXIMUM
] =
409 static const char * _str_buzzz_kevt_event
[BUZZZ_KEVT_EVENT_MAXIMUM
] =
412 BUZZZ_ENUM(CTR0_NONE
) /* 0x00 */
413 BUZZZ_ENUM(CTR1_NONE
) /* 0x00 */
415 /* group 1: GENERAL */
416 BUZZZ_ENUM(SPEC_INSTRCNT
) /* 0x68 */
417 BUZZZ_ENUM(CYCLES_ELAPSED
) /* 0x11 */
419 /* group 2: ICACHE */
420 BUZZZ_ENUM(INSTRUCTIONS
) /* 0x68 */
421 BUZZZ_ENUM(IC_REFILL
) /* 0x01 */
423 /* group 3: DCACHE */
424 BUZZZ_ENUM(DC_ACCESS
) /* 0x04 */
425 BUZZZ_ENUM(DC_REFILL
) /* 0x03 */
428 BUZZZ_ENUM(INSTR_REFILL
) /* 0x02 */
429 BUZZZ_ENUM(DATA_REFILL
) /* 0x05 */
431 /* group 5: MISCELLANEOUS */
432 BUZZZ_ENUM(BRANCH_MISPRED
) /* 0x10 */
433 BUZZZ_ENUM(STREX_FAILED
) /* 0x64 */
436 static BUZZZ_INLINE
const char * BUZZZ_NOINSTR_FUNC
437 str_buzzz_kevt_group(uint32_t group
)
439 return (group
>= BUZZZ_KEVT_GROUP_MAXIMUM
) ? _str_INV
:
440 _str_buzzz_kevt_group
[group
];
442 static BUZZZ_INLINE
const char * BUZZZ_NOINSTR_FUNC
443 str_buzzz_kevt_event(uint32_t event
)
445 return (event
>= BUZZZ_KEVT_EVENT_MAXIMUM
) ? _str_INV
:
446 _str_buzzz_kevt_event
[event
];
451 * -----------------------------------------------------------------------------
452 * BUZZZ Logging Infrastructure
453 * -----------------------------------------------------------------------------
456 /* #define BUZZZ_PMON_LOGS 64-1 maximum number of buzzz_pmon_log() logs */
458 /* Performance Monitoring Tool private definitions */
460 struct buzzz_pmon_ctl
462 uint8_t u8
[BUZZZ_PMON_COUNTERS
];
466 struct buzzz_pmon_ctr
474 buzzz_pmon_ctr_t min
, max
, sum
;
477 #if defined(BUZZZ_CONFIG_PMON_USR)
478 unsigned int buzzz_pmon_usr_g
;
481 struct buzzz_pmon_usr
483 unsigned int min
, max
, sum
;
487 struct buzzz_pmonst_usr
489 buzzz_pmon_usr_t run
;
490 buzzz_pmon_usr_t mon
[BUZZZ_PMON_GROUPS
];
491 } buzzz_pmonst_usr_t
;
492 #endif /* BUZZZ_CONFIG_PMON_USR */
494 typedef /* Buzzz tool private configuration parameters and state */
501 uint32_t count
; /* count of logs */
502 uint32_t limit
; /* limit functions logged @start */
503 uint32_t indent
; /* indented entry exit printing */
504 uint32_t config_exit
; /* function exit logging */
506 uint32_t log_count
; /* used by proc filesystem */
507 uint32_t log_index
; /* used by proc filesystem */
512 uint32_t groupid
; /* current group */
513 buzzz_pmon_ctl_t control
; /* current groups configuration */
515 uint32_t sample
; /* iteration for this group */
516 uint32_t next_log_id
; /* next log id */
517 uint32_t last_log_id
; /* last pmon log */
519 buzzz_pmon_ctr_t log
[BUZZZ_PMON_LOGS
+ 1];
520 buzzz_pmonst_t run
[BUZZZ_PMON_LOGS
+ 1];
521 buzzz_pmonst_t mon
[BUZZZ_PMON_GROUPS
][BUZZZ_PMON_LOGS
+ 1];
523 #if defined(BUZZZ_CONFIG_PMON_USR)
524 buzzz_pmonst_usr_t usr
;
525 #endif /* BUZZZ_CONFIG_PMON_USR */
527 uint32_t config_skip
;
528 uint32_t config_samples
;
533 uint32_t count
; /* count of logs */
534 uint32_t limit
; /* limit functions logged @start */
535 uint32_t config_evt
; /* kevt logging perf event */
537 uint32_t log_count
; /* used by proc filesystem */
538 uint32_t log_index
; /* used by proc filesystem */
546 typedef /* Buzzz global structure */
549 #if defined(CONFIG_SMP)
551 #endif /* CONFIG_SMP */
552 buzzz_status_t status
; /* current tool/user status */
553 buzzz_tool_t tool
; /* current tool/user of log buffer */
554 uint8_t panic
; /* auto dump on kernel panic */
555 uint8_t wrap
; /* log buffer wrapped */
556 uint16_t run
; /* tool/user incarnation number */
558 void * cur
; /* pointer to next log entry */
559 void * end
; /* pointer to end of log entry */
562 buzzz_priv_t priv
; /* tool specific private data */
564 struct timer_list timer
;
566 buzzz_mode_t config_mode
; /* limited, continuous wrapover */
567 uint32_t config_limit
; /* configured limit */
569 buzzz_fmt_t klogs
[BUZZZ_KLOG_MAXIMUM
];
574 static buzzz_t buzzz_g
= /* Global Buzzz object, see __init_buzzz() */
576 #if defined(CONFIG_SMP)
577 .lock
= __SPIN_LOCK_UNLOCKED(.lock
),
578 #endif /* CONFIG_SMP */
579 .tool
= BUZZZ_TOOL_UNDEF
,
580 .status
= BUZZZ_STATUS_DISABLED
,
588 .timer
= TIMER_INITIALIZER(NULL
, 0, (int)&buzzz_g
)
591 static DEFINE_PER_CPU(buzzz_status_t
, kevt_status
) = BUZZZ_STATUS_DISABLED
;
593 #define BUZZZ_ASSERT_STATUS_DISABLED() \
594 if (buzzz_g.status != BUZZZ_STATUS_DISABLED) { \
595 printk(CLRwarn "WARN: %s tool already enabled" CLRnl, __FUNCTION__); \
596 return BUZZZ_ERROR; \
599 static void BUZZZ_NOINSTR_FUNC
/* Preamble to start tracing in a tool */
600 _buzzz_pre_start(void)
602 buzzz_g
.panic
= BUZZZ_FALSE
;
603 buzzz_g
.wrap
= BUZZZ_FALSE
;
605 buzzz_g
.cur
= buzzz_g
.log
;
606 buzzz_g
.end
= (void*)((char*)buzzz_g
.log
607 + (BUZZZ_LOG_BUFSIZE
- BUZZZ_LOGENTRY_MAXSZ
));
610 static void BUZZZ_NOINSTR_FUNC
/* Postamble to start tracing in a tool */
611 _buzzz_post_start(void)
613 buzzz_g
.status
= BUZZZ_STATUS_ENABLED
;
616 static void BUZZZ_NOINSTR_FUNC
/* Preamble to stop tracing in a tool */
617 _buzzz_pre_stop(void)
619 buzzz_g
.status
= BUZZZ_STATUS_DISABLED
;
622 static void BUZZZ_NOINSTR_FUNC
/* Postamble to stop tracing in a tool */
623 _buzzz_post_stop(void)
627 typedef int (*buzzz_dump_log_fn_t
)(char * page
, void *log
);
629 void BUZZZ_NOINSTR_FUNC
/* Dump the kevt trace to console */
630 buzzz_log_dump(uint32_t limit
, uint32_t count
,
631 uint32_t log_size
, buzzz_dump_log_fn_t dump_log_fn
)
636 if (buzzz_g
.wrap
== BUZZZ_TRUE
)
637 total
= (BUZZZ_AVAIL_BUFSIZE
/ log_size
);
641 BUZZZ_PRINT("limit<%u> bufsz<%u> max<%u> count<%u> wrap<%u> total<%u>"
642 " log<%p> cur<%p> end<%p> log_size<%u>", limit
, BUZZZ_AVAIL_BUFSIZE
,
643 (BUZZZ_AVAIL_BUFSIZE
/ log_size
),
644 count
, buzzz_g
.wrap
, total
,
645 buzzz_g
.log
, buzzz_g
.cur
, buzzz_g
.end
, log_size
);
650 printk(CLRbold
"BUZZZ_DUMP BGN total<%u>" CLRnl
, total
);
653 printk(CLRbold
"BUZZZ_DUMP END" CLRnl
);
657 if (limit
!= BUZZZ_INVALID
) { /* dump limited last few logs */
660 part1
= ((uint32_t)buzzz_g
.cur
- (uint32_t)buzzz_g
.log
) / log_size
;
662 if (total
> part1
) { /* some events prior to wrap */
665 part2
= total
- part1
; /* number of events prior to wrap */
667 BUZZZ_PRINT("limit total<%u>: part2<%u> + part1<%u>",
668 total
, part2
, part1
);
670 log
= (void*)((uint32_t)buzzz_g
.end
- (part2
* log_size
));
674 BUZZZ_PRINT("log<%p> part2<%u>", log
, part2
);
676 dump_log_fn(buzzz_g
.page
, log
);
677 printk("%s", buzzz_g
.page
);
678 log
= (void*)((uint32_t)log
+ log_size
);
682 log
= (void*)((uint32_t)buzzz_g
.cur
- (total
* log_size
));
684 BUZZZ_PRINT("log<%p> total<%u>", log
, total
);
686 dump_log_fn(buzzz_g
.page
, log
);
687 printk("%s", buzzz_g
.page
);
688 log
= (void*)((uint32_t)log
+ log_size
);
691 } else if (buzzz_g
.wrap
== BUZZZ_TRUE
) { /* all of ring buffer with wrap */
693 uint32_t part1
, part2
;
695 part1
= ((uint32_t)buzzz_g
.cur
- (uint32_t)buzzz_g
.log
) / log_size
;
696 part2
= ((uint32_t)buzzz_g
.end
- (uint32_t)buzzz_g
.cur
) / log_size
;
698 BUZZZ_PRINT("Wrap part2<%u> part1<%u>", part2
, part1
);
700 log
= (void*)buzzz_g
.cur
;
701 BUZZZ_PRINT("log<%p> part2<%u>", log
, part2
);
702 while (part2
--) { /* from cur to end : part2 */
703 dump_log_fn(buzzz_g
.page
, log
);
704 printk("%s", buzzz_g
.page
);
705 log
= (void*)((uint32_t)log
+ log_size
);
708 log
= (void*)buzzz_g
.log
;
709 BUZZZ_PRINT("log<%p> part1<%u>", log
, part1
);
710 while (part1
--) { /* from log to cur : part1 */
711 dump_log_fn(buzzz_g
.page
, log
);
712 printk("%s", buzzz_g
.page
);
713 log
= (void*)((uint32_t)log
+ log_size
);
716 } else { /* everything in ring buffer, no wrap */
718 log
= (void*)buzzz_g
.log
; /* from log to cur */
719 BUZZZ_PRINT("No Wrap log to cur: log<%p:%p> <%u>",
720 log
, buzzz_g
.cur
, total
);
721 while (log
< (void*)buzzz_g
.cur
) {
722 dump_log_fn(buzzz_g
.page
, log
);
723 printk("%s", buzzz_g
.page
);
724 log
= (void*)((uint32_t)log
+ log_size
);
729 printk(CLRbold
"BUZZZ_DUMP END" CLRnl
);
732 * -----------------------------------------------------------------------------
733 * Function Call Tracing subsystem
734 * -----------------------------------------------------------------------------
737 #define BUZZZ_FUNC_LOGISEVT (1 << 1)
738 #define BUZZZ_FUNC_ADDRMASK (~3U)
740 struct buzzz_func_log
747 uint32_t is_klog
: 1; /* BUZZZ_FUNC_LOGISEVT: 0:func, 1=evt */
748 uint32_t args
: 14; /* number of arguments logged */
753 uint32_t is_ent
: 1; /* entry or exit of a function */
754 uint32_t is_klog
: 1; /* BUZZZ_FUNC_LOGISEVT: 0:func, 1=evt */
755 uint32_t addr
: 30; /* address of called function */
765 static BUZZZ_INLINE
int BUZZZ_NOINSTR_FUNC
766 _buzzz_symbol(char *p
, unsigned long address
)
769 unsigned long offset
= 0LU;
770 char * eos
, symbol_buf
[KSYM_NAME_LEN
+1];
772 sprint_symbol(symbol_buf
, address
);
773 eos
= strpbrk(symbol_buf
, "+");
775 if (eos
== (char*)NULL
)
776 bytes
+= sprintf(p
+ bytes
, " %s" CLRnl
, symbol_buf
);
779 sscanf(eos
+1, "0x%lx", &offset
);
780 bytes
+= sprintf(p
+ bytes
, " %s" CLRnorm
, symbol_buf
);
782 bytes
+= sprintf(p
+ bytes
, " +0x%lx", offset
);
783 bytes
+= sprintf(p
+ bytes
, "\n");
788 static BUZZZ_INLINE
int BUZZZ_NOINSTR_FUNC
789 _buzzz_func_indent(char *p
)
792 if (buzzz_g
.priv
.func
.config_exit
) {
794 for (indent
= 0U; indent
< buzzz_g
.priv
.func
.indent
; indent
++)
795 bytes
+= sprintf(p
+ bytes
, BUZZZ_FUNC_INDENT_STRING
);
800 static int BUZZZ_NOINSTR_FUNC
801 buzzz_func_dump_log(char * p
, void * l
)
803 buzzz_func_log_t
* log
= (buzzz_func_log_t
*)l
;
806 if (log
->arg0
.klog
.is_klog
) { /* print using registered log formats */
808 bytes
+= _buzzz_func_indent(p
+ bytes
); /* print indentation spaces */
810 bytes
+= sprintf(p
+ bytes
, "%s", CLRb
);
811 switch (log
->arg0
.klog
.args
) {
813 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
]);
816 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
],
820 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
],
821 log
->arg1
, log
->arg2
);
824 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
],
825 log
->arg1
, log
->arg2
, log
->arg3
);
828 bytes
+= sprintf(p
+ bytes
, "%s", CLRnl
);
830 } else { /* print function call entry/exit */
832 unsigned long address
; /* instruction address */
834 if (log
->arg0
.site
.is_ent
)
835 buzzz_g
.priv
.func
.indent
++;
837 bytes
+= _buzzz_func_indent(p
+ bytes
); /* print indentation spaces */
839 if (log
->arg0
.site
.is_ent
)
840 bytes
+= sprintf(p
+ bytes
, "%s", CLRr
"=>");
842 bytes
+= sprintf(p
+ bytes
, "%s", CLRg
"<=");
844 if (!log
->arg0
.site
.is_ent
&& (buzzz_g
.priv
.func
.indent
> 0))
845 buzzz_g
.priv
.func
.indent
--;
847 address
= (unsigned long)(log
->arg0
.u32
& BUZZZ_FUNC_ADDRMASK
);
848 bytes
+= _buzzz_symbol(p
+ bytes
, address
);
855 #define _BUZZZ_FUNC_BGN(flags) \
856 if (buzzz_g.tool != BUZZZ_TOOL_FUNC) return; \
857 if (buzzz_g.status != BUZZZ_STATUS_ENABLED) return; \
859 if (buzzz_g.config_mode == BUZZZ_MODE_LIMITED) { \
860 if (buzzz_g.priv.func.limit == 0U) { \
862 BUZZZ_UNLOCK(flags); \
865 buzzz_g.priv.func.limit--; \
868 #define _BUZZZ_FUNC_END(flags) \
869 buzzz_g.cur = (void*)(((buzzz_func_log_t*)buzzz_g.cur) + 1); \
870 buzzz_g.priv.func.count++; \
871 if (buzzz_g.cur >= buzzz_g.end) { \
872 buzzz_g.wrap = BUZZZ_TRUE; \
873 buzzz_g.cur = buzzz_g.log; \
878 void BUZZZ_NOINSTR_FUNC
/* -finstrument compiler stub on function entry */
879 __cyg_profile_func_enter(void * called
, void * caller
)
882 _BUZZZ_FUNC_BGN(flags
);
883 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg0
.u32
= (uint32_t)called
| 1U;
884 _BUZZZ_FUNC_END(flags
);
887 void BUZZZ_NOINSTR_FUNC
/* -finstrument compiler stub on function exit */
888 __cyg_profile_func_exit(void * called
, void * caller
)
891 if (buzzz_g
.priv
.func
.config_exit
== BUZZZ_DISABLE
)
894 _BUZZZ_FUNC_BGN(flags
);
895 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg0
.u32
= (uint32_t)called
;
896 _BUZZZ_FUNC_END(flags
);
899 void BUZZZ_NOINSTR_FUNC
/* embed prints with zero args in log */
900 buzzz_func_log0(uint32_t log_id
)
903 _BUZZZ_FUNC_BGN(flags
);
904 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg0
.u32
= (log_id
<< 16)
905 | BUZZZ_FUNC_LOGISEVT
;
906 _BUZZZ_FUNC_END(flags
);
909 void BUZZZ_NOINSTR_FUNC
/* embed prints with one u32 arg in log */
910 buzzz_func_log1(uint32_t log_id
, uint32_t arg1
)
913 _BUZZZ_FUNC_BGN(flags
);
914 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg0
.u32
= (log_id
<< 16)
915 | BUZZZ_FUNC_LOGISEVT
916 | (1U << 2); /* 1 arg */
917 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg1
= arg1
;
918 _BUZZZ_FUNC_END(flags
);
921 void BUZZZ_NOINSTR_FUNC
/* embed prints with two u32 args in log */
922 buzzz_func_log2(uint32_t log_id
, uint32_t arg1
, uint32_t arg2
)
925 _BUZZZ_FUNC_BGN(flags
);
926 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg0
.u32
= (log_id
<< 16)
927 | BUZZZ_FUNC_LOGISEVT
928 | (2U << 2); /* 2 args */
929 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg1
= arg1
;
930 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg2
= arg2
;
931 _BUZZZ_FUNC_END(flags
);
934 void BUZZZ_NOINSTR_FUNC
/* embed prints with three u32 args in log */
935 buzzz_func_log3(uint32_t log_id
, uint32_t arg1
, uint32_t arg2
, uint32_t arg3
)
938 _BUZZZ_FUNC_BGN(flags
);
939 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg0
.u32
= (log_id
<< 16)
940 | BUZZZ_FUNC_LOGISEVT
941 | (3U << 2); /* 3 args */
942 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg1
= arg1
;
943 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg2
= arg2
;
944 ((buzzz_func_log_t
*)buzzz_g
.cur
)->arg3
= arg3
;
945 _BUZZZ_FUNC_END(flags
);
948 void BUZZZ_NOINSTR_FUNC
/* Start function call entry (exit optional) tracing */
949 buzzz_func_start(void)
951 if (buzzz_g
.log
== (void*)NULL
) {
952 printk(CLRerr
"ERROR: Log not allocated" CLRnl
);
958 buzzz_g
.priv
.func
.count
= 0U;
959 buzzz_g
.priv
.func
.indent
= 0U;
960 buzzz_g
.priv
.func
.limit
= buzzz_g
.config_limit
;
962 buzzz_g
.priv
.func
.log_count
= 0U;
963 buzzz_g
.priv
.func
.log_index
= 0U;
968 void BUZZZ_NOINSTR_FUNC
/* Stop function call entry (exit optional) tracing */
969 buzzz_func_stop(void)
971 if (buzzz_g
.status
!= BUZZZ_STATUS_DISABLED
) {
972 buzzz_g
.status
= BUZZZ_STATUS_ENABLED
;
974 BUZZZ_FUNC_LOG(BUZZZ_RET_IP
);
975 BUZZZ_FUNC_LOG(buzzz_func_stop
);
979 if (buzzz_g
.wrap
== BUZZZ_TRUE
)
980 buzzz_g
.priv
.func
.log_count
981 = (BUZZZ_AVAIL_BUFSIZE
/ sizeof(buzzz_func_log_t
));
983 buzzz_g
.priv
.func
.log_count
= buzzz_g
.priv
.func
.count
;
984 buzzz_g
.priv
.func
.log_index
= 0U;
990 void BUZZZ_NOINSTR_FUNC
/* On kernel panic, to dump N function call history */
991 buzzz_func_panic(void)
993 if (buzzz_g
.tool
!= BUZZZ_TOOL_FUNC
)
996 if (buzzz_g
.status
!= BUZZZ_STATUS_DISABLED
) {
999 if (buzzz_g
.panic
== BUZZZ_FALSE
) {
1000 buzzz_g
.panic
= BUZZZ_TRUE
;
1001 buzzz_func_dump(BUZZZ_FUNC_PANIC_LOGS
);
1006 void BUZZZ_NOINSTR_FUNC
/* Dump the function call trace to console */
1007 buzzz_func_dump(uint32_t limit
)
1009 buzzz_log_dump(limit
, buzzz_g
.priv
.func
.count
, sizeof(buzzz_func_log_t
),
1010 (buzzz_dump_log_fn_t
)buzzz_func_dump_log
);
1013 void BUZZZ_NOINSTR_FUNC
/* Dump the function call trace to console */
1014 buzzz_func_show(void)
1016 printk("Count:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.func
.count
);
1017 printk("Limit:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.func
.limit
);
1018 printk("+Exit:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.func
.config_exit
);
1019 printk("+Limit:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.config_limit
);
1020 printk("+Mode:\t\t" CLRb
"%s" CLRnl
, str_buzzz_mode(buzzz_g
.config_mode
));
1024 int BUZZZ_NOINSTR_FUNC
1025 buzzz_func_default(void)
1027 #if defined(CONFIG_BUZZZ_KEVT)
1028 printk(CLRerr
"ERROR: BUZZZ Kernel Event Tracing Enabled" CLRnl
);
1029 printk(CLRerr
"Disable CONFIG_BUZZZ_KEVT for FUNC Tracing" CLRnl
);
1031 #endif /* CONFIG_BUZZZ_KEVT */
1033 buzzz_g
.priv
.func
.count
= 0U;
1034 buzzz_g
.priv
.func
.limit
= BUZZZ_INVALID
;
1035 buzzz_g
.priv
.func
.indent
= 0U;
1036 buzzz_g
.priv
.func
.config_exit
= BUZZZ_ENABLE
;
1037 buzzz_g
.priv
.func
.log_count
= 0U;
1038 buzzz_g
.priv
.func
.log_index
= 0U;
1040 buzzz_g
.config_limit
= BUZZZ_INVALID
;
1041 buzzz_g
.config_mode
= BUZZZ_MODE_WRAPOVER
;
1043 return BUZZZ_SUCCESS
;
1046 int BUZZZ_NOINSTR_FUNC
/* API to config function exit tracing */
1047 buzzz_func_config(uint32_t config_exit
)
1049 BUZZZ_ASSERT_STATUS_DISABLED();
1051 buzzz_g
.priv
.func
.config_exit
= config_exit
;
1053 return BUZZZ_SUCCESS
;
1056 /* Initialization of Buzzz Function tool during loading time */
1057 static int BUZZZ_NOINSTR_FUNC
1058 __init
_init_buzzz_func(void)
1060 if ((BUZZZ_AVAIL_BUFSIZE
% sizeof(buzzz_func_log_t
)) != 0)
1063 if (sizeof(buzzz_func_log_t
) != 16)
1066 return BUZZZ_SUCCESS
;
1070 * -----------------------------------------------------------------------------
1071 * Performance Monitoring subsystem
1072 * -----------------------------------------------------------------------------
1075 #if defined(CONFIG_MIPS) && defined(BUZZZ_CONFIG_CPU_MIPS_74K)
1077 * Field Descriptions for PerfCtl0-3 Register
1078 * b31 : M : Reads 1 if there is another PerfCtl register after this one.
1079 * b15 : PCTD : Disables counting when trace mode in PDTrace is enabled
1080 * b11:5 : Event: Determines which event to count.
1081 * b4 : IE : Set to cause interrupt when counter "overflows".
1082 * b3 : U : Counts events in User mode
1083 * b2 : S : Counts events when in Supervisor mode
1084 * b1 : K : Counts events when in Kernel mode
1085 * b0 : EXL : Counts when in Exception mode
1088 #define BUZZZ_PMON_VAL(val, mode) (((uint32_t)(val) << 5) | (mode))
1091 * 4 Events are grouped, allowing a single log to include 4 similar events.
1092 * The values to be used in each of the 4 performance counters per group are
1093 * listed below. These values need to be applied to the corresponding
1094 * performance control register in bit locations b5..b11.
1097 buzzz_pmon_ctl_t buzzz_pmonctl_g
[BUZZZ_PMON_GROUPS
] =
1099 /* ctl0 ctl1 ctl2 ctl3 */
1100 {{ 0U, 0U, 0U, 0U }}, /* group 0 RESET */
1102 {{ 56U, 0U, 58U, 1U }}, /* group 1 GENERAL */
1103 {{ 6U, 6U, 7U, 7U }}, /* group 2 ICACHE */
1104 {{ 23U, 23U, 24U, 24U }}, /* group 3 DCACHE */
1105 {{ 4U, 4U, 25U, 25U }}, /* group 4 TLB */
1106 {{ 53U, 53U, 54U, 54U }}, /* group 5 CYCLES_COMPLETED */
1107 {{ 20U, 20U, 21U, 21U }}, /* group 6 CYCLES_ISSUE_OOO */
1108 {{ 39U, 39U, 40U, 40U }}, /* group 7 INSTR_GENERAL */
1109 {{ 42U, 43U, 52U, 52U }}, /* group 8 INSTR_MISC */
1110 {{ 41U, 41U, 46U, 46U }}, /* group 9 INSTR_LOAD_STORE */
1111 {{ 13U, 13U, 14U, 14U }}, /* group 10 CYCLES_IDLE_FULL */
1112 {{ 16U, 16U, 17U, 17U }} /* group 11 CYCLES_IDLE_WAIT */
1114 #endif /* CONFIG_MIPS && BUZZZ_CONFIG_CPU_MIPS_74K */
1116 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1118 #define BUZZZ_PMON_VAL(val, mode) ((uint32_t)(val))
1121 buzzz_pmon_ctl_t buzzz_pmonctl_g
[BUZZZ_PMON_GROUPS
] =
1123 /* ctl0 ctl1 ctl2 ctl3 */
1124 {{ 0U, 0U, 0U, 0U }}, /* group 0 RESET */
1125 {{ 0x10, 0x11, 0x09, 0x68 }}, /* group 1 GENERAL */
1126 {{ 0x68, 0x01, 0x60, 0x66 }}, /* group 2 ICACHE */
1127 {{ 0x04, 0x03, 0x61, 0x65 }}, /* group 3 DCACHE */
1128 {{ 0x02, 0x05, 0x82, 0x83 }}, /* group 4 TLB */
1129 {{ 0x06, 0x07, 0x81, 0x86 }}, /* group 5 DATA */
1130 {{ 0x93, 0x0F, 0x0A, 0x62 }}, /* group 6 SPURIOUS */
1131 {{ 0x0C, 0x0D, 0x0E, 0x12 }}, /* group 7 BRANCHES */
1132 {{ 0x63, 0x64, 0x91, 0x92 }} /* group 8 MISCELLANEOUS */
1135 /* BUZZZ uses ARMv7 A9 counters #2,#3,#4,#5 as BUZZZ counters #0,#1,#2,#3 */
1136 #define BUZZZ_PMON_ARM_A9_CTR(idx) ((idx) + 2)
1139 struct { /* Little Endian */
1140 uint32_t ctr0
: 1; /* reserved for rest of the system */
1141 uint32_t ctr1
: 1; /* reserved for rest of the system */
1142 uint32_t ctr2
: 1; /* referred to as buzzz ctr 0 */
1143 uint32_t ctr3
: 1; /* referred to as buzzz ctr 1 */
1144 uint32_t ctr4
: 1; /* referred to as buzzz ctr 2 */
1145 uint32_t ctr5
: 1; /* referred to as buzzz ctr 3 */
1146 uint32_t ctr_none
: 25; /* unsupported for A9 */
1147 uint32_t cycle
: 1; /* cycle count register */
1151 union cp15_c9_c12_PMCR
{
1153 struct { /* Little Endian */
1154 uint32_t enable
: 1; /* E: enable all counters */
1155 uint32_t evt_reset
: 1; /* P: event counter reset (not incld PMCCNTR) */
1156 uint32_t clk_reset
: 1; /* C: clock counter reset */
1157 uint32_t clk_div
: 1; /* D: clock divider: 0=1cycle, 1=64cycle */
1158 uint32_t export_en
: 1; /* X: export enable */
1159 uint32_t prohibit
: 1; /* DP: disable in prohibited regions */
1160 uint32_t reserved
: 5; /* UNK/SBZP reserved/unknown */
1161 uint32_t counters
: 5; /* N: number of event counters */
1162 uint32_t id_code
: 8; /* IDCODE: identification code */
1163 uint32_t impl_code
: 8; /* IMP: implementer code */
1167 union cp15_c9_c12_PMSELR
{
1169 struct { /* Little Endian */
1170 uint32_t ctr_select
: 5; /* event counter selecter */
1171 uint32_t reserved
:25; /* reserved */
1175 union cp15_c9_c13_PMXEVTYPER
{
1177 struct { /* Little Endian */
1178 uint32_t evt_type
: 8; /* event type to count */
1179 uint32_t reserved
: 24; /* reserved */
1183 union cp15_c9_c14_PMUSERENR
{
1185 struct { /* Little Endian */
1186 uint32_t enable
: 1; /* user mode enable */
1187 uint32_t reserved
: 31; /* reserved */
1191 static BUZZZ_INLINE
uint32_t BUZZZ_NOINSTR_FUNC
1192 _armv7_pmcr_RD(void)
1194 union cp15_c9_c12_PMCR pmcr
;
1195 asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr
.u32
));
1196 BUZZZ_PRINT("RD PMCR IMP%u ID%u N[%u] DP[%u] X[%u] D[%u] C[%u] P[%u] E[%u]",
1197 pmcr
.impl_code
, pmcr
.id_code
, pmcr
.counters
, pmcr
.prohibit
,
1198 pmcr
.export_en
, pmcr
.clk_div
, pmcr
.clk_reset
, pmcr
.evt_reset
,
1203 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1204 _armv7_pmcr_WR(const uint32_t v32
)
1206 union cp15_c9_c12_PMCR pmcr
;
1207 pmcr
.u32
= v32
& 0x3F; /* write-able bits */
1208 BUZZZ_PRINT("WR PMCR: DP[%u] X[%u] D[%u] C[%u] P[%u] E[%u]",
1209 pmcr
.prohibit
, pmcr
.export_en
, pmcr
.clk_div
, pmcr
.clk_reset
,
1210 pmcr
.evt_reset
, pmcr
.enable
);
1211 asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(pmcr
.u32
));
1214 static BUZZZ_INLINE
uint32_t BUZZZ_NOINSTR_FUNC
1215 _armv7_pmcntenset_test(void)
1217 /* Test whether PMU counters required by buzzz are in use */
1218 union cp15_c9_REG pmcntenset
;
1220 asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset
.u32
));
1221 return (pmcntenset
.ctr2
|| pmcntenset
.ctr3
||
1222 pmcntenset
.ctr4
|| pmcntenset
.ctr5
);
1225 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1226 _armv7_pmuserenr_enable(void)
1229 asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r"(u32
));
1232 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1233 _armv7_pmcn_enable(void)
1235 union cp15_c9_c12_PMCR pmcr
;
1236 union cp15_c9_REG pmcntenset
;
1237 union cp15_c9_REG pmintenclr
;
1239 /* Set Enable bit in PMCR */
1240 pmcr
.u32
= _armv7_pmcr_RD();
1242 _armv7_pmcr_WR(pmcr
.u32
);
1244 /* Disable overflow interrupts on 4 buzzz counters: A9 ctr2 to ctr5 */
1245 pmintenclr
.u32
= 0U;
1246 pmintenclr
.ctr2
= pmintenclr
.ctr3
= pmintenclr
.ctr4
= pmintenclr
.ctr5
= 1;
1247 asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r"(pmintenclr
.u32
));
1248 BUZZZ_PRINT("Disable overflow interrupts PMINTENCLR[%08x]", pmintenclr
.u32
);
1250 /* Enable the 4 buzzz counters: A9 ctr2 to ctr5 */
1251 pmcntenset
.u32
= 0U;
1252 pmcntenset
.ctr2
= pmcntenset
.ctr3
= pmcntenset
.ctr4
= pmcntenset
.ctr5
= 1;
1253 asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(pmcntenset
.u32
));
1254 BUZZZ_PRINT("Enable CTR2-5 PMCNTENSET[%08x]", pmcntenset
.u32
);
1257 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1258 _armv7_pmcn_disable(void)
1260 union cp15_c9_REG pmcntenclr
;
1262 /* Disable the 4 buzzz counters: A9 ctr2 to ctr5 */
1263 pmcntenclr
.u32
= 0U;
1264 pmcntenclr
.ctr2
= pmcntenclr
.ctr3
= pmcntenclr
.ctr4
= pmcntenclr
.ctr5
= 1;
1265 asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(pmcntenclr
.u32
));
1266 BUZZZ_PRINT("Disable CTR2-5 PMCNTENCLR[%08x]", pmcntenclr
.u32
);
1269 static BUZZZ_INLINE
uint32_t BUZZZ_NOINSTR_FUNC
1270 _armv7_pmcn_read_buzzz_ctr(const uint32_t idx
)
1273 union cp15_c9_c12_PMSELR pmselr
;
1274 pmselr
.u32
= BUZZZ_PMON_ARM_A9_CTR(idx
);
1275 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(pmselr
.u32
));
1276 asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r"(v32
));
1280 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1281 _armv7_pmcn_config_buzzz_ctr(const uint32_t idx
, const uint32_t evt_type
)
1283 union cp15_c9_c13_PMXEVTYPER pmxevtyper
;
1284 union cp15_c9_c12_PMSELR pmselr
;
1285 pmselr
.u32
= 0U; /* Select the Counter using PMSELR */
1286 pmselr
.ctr_select
= BUZZZ_PMON_ARM_A9_CTR(idx
);
1287 asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(pmselr
.u32
));
1289 pmxevtyper
.u32
= 0U;
1290 pmxevtyper
.evt_type
= evt_type
; /* Configure the event type */
1291 asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r"(pmxevtyper
.u32
));
1292 BUZZZ_PRINT("Config Ctr<%u> PMSELR[%08x] PMXEVTYPER[%08x]",
1293 idx
, pmselr
.u32
, pmxevtyper
.u32
);
1296 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1299 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1300 _buzzz_pmon_enable(void)
1302 #if defined(CONFIG_MIPS) && defined(BUZZZ_CONFIG_CPU_MIPS_74K)
1303 #endif /* CONFIG_MIPS && BUZZZ_CONFIG_CPU_MIPS_74K */
1304 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1305 _armv7_pmcn_enable();
1306 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1309 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1310 _buzzz_pmon_disable(void)
1312 #if defined(CONFIG_MIPS) && defined(BUZZZ_CONFIG_CPU_MIPS_74K)
1313 #endif /* CONFIG_MIPS && BUZZZ_CONFIG_CPU_MIPS_74K */
1314 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1315 _armv7_pmcn_disable();
1316 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1319 void buzzz_pmon_show(void);
1321 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1322 _buzzz_pmon_log(uint32_t log_id
)
1324 buzzz_pmon_ctr_t
* log
= &buzzz_g
.priv
.pmon
.log
[log_id
];
1326 #if defined(CONFIG_MIPS) && defined(BUZZZ_CONFIG_CPU_MIPS_74K)
1327 log
->u32
[0] = read_c0_perf(1);
1328 log
->u32
[1] = read_c0_perf(3);
1329 log
->u32
[2] = read_c0_perf(5);
1330 log
->u32
[3] = read_c0_perf(7);
1331 #endif /* CONFIG_MIPS && BUZZZ_CONFIG_CPU_MIPS_74K */
1332 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1333 log
->u32
[0] = _armv7_pmcn_read_buzzz_ctr(0);
1334 log
->u32
[1] = _armv7_pmcn_read_buzzz_ctr(1);
1335 log
->u32
[2] = _armv7_pmcn_read_buzzz_ctr(2);
1336 log
->u32
[3] = _armv7_pmcn_read_buzzz_ctr(3);
1337 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1341 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1342 _buzzz_pmon_iter_set_invalid(void)
1344 #if defined(BUZZZ_CONFIG_PMON_USR)
1345 buzzz_pmon_usr_g
= 0U;
1346 #endif /* BUZZZ_CONFIG_PMON_USR */
1347 buzzz_g
.priv
.pmon
.log
[0].u32
[0] = BUZZZ_INVALID
;
1348 buzzz_g
.priv
.pmon
.next_log_id
= 0U;
1351 static BUZZZ_INLINE
uint32_t BUZZZ_NOINSTR_FUNC
1352 _buzzz_pmon_iter_is_invalid(void)
1354 return (buzzz_g
.priv
.pmon
.log
[0].u32
[0] == BUZZZ_INVALID
);
1357 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1358 _buzzz_pmon_run(uint32_t last_log
)
1361 buzzz_pmon_ctr_t elapsed
, prev
, curr
;
1363 for (log
= 1U; log
<= last_log
; log
++) {
1364 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++) {
1365 prev
.u32
[ctr
] = buzzz_g
.priv
.pmon
.log
[log
-1].u32
[ctr
];
1366 curr
.u32
[ctr
] = buzzz_g
.priv
.pmon
.log
[log
].u32
[ctr
];
1368 if (curr
.u32
[ctr
] < prev
.u32
[ctr
]) /* rollover */
1369 elapsed
.u32
[ctr
] = curr
.u32
[ctr
] + (~0U - prev
.u32
[ctr
]);
1371 elapsed
.u32
[ctr
] = (curr
.u32
[ctr
] - prev
.u32
[ctr
]);
1373 /* update min, max and sum statistics */
1374 if (elapsed
.u32
[ctr
] < buzzz_g
.priv
.pmon
.run
[log
].min
.u32
[ctr
])
1375 buzzz_g
.priv
.pmon
.run
[log
].min
.u32
[ctr
] = elapsed
.u32
[ctr
];
1376 if (elapsed
.u32
[ctr
] > buzzz_g
.priv
.pmon
.run
[log
].max
.u32
[ctr
])
1377 buzzz_g
.priv
.pmon
.run
[log
].max
.u32
[ctr
] = elapsed
.u32
[ctr
];
1378 buzzz_g
.priv
.pmon
.run
[log
].sum
.u32
[ctr
] += elapsed
.u32
[ctr
];
1382 #if defined(BUZZZ_CONFIG_PMON_USR)
1383 if (buzzz_pmon_usr_g
< buzzz_g
.priv
.pmon
.usr
.run
.min
)
1384 buzzz_g
.priv
.pmon
.usr
.run
.min
= buzzz_pmon_usr_g
;
1385 if (buzzz_pmon_usr_g
> buzzz_g
.priv
.pmon
.usr
.run
.max
)
1386 buzzz_g
.priv
.pmon
.usr
.run
.max
= buzzz_pmon_usr_g
;
1387 buzzz_g
.priv
.pmon
.usr
.run
.sum
+= buzzz_pmon_usr_g
;
1388 #endif /* BUZZZ_CONFIG_PMON_USR */
1391 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1392 _buzzz_pmon_tot(uint32_t last_log
)
1396 buzzz_g
.priv
.pmon
.mon
[buzzz_g
.priv
.pmon
.groupid
][0].sum
.u32
[0] = ~0U;
1398 for (log
= 1U; log
<= last_log
; log
++) {
1399 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++) {
1400 buzzz_g
.priv
.pmon
.mon
[buzzz_g
.priv
.pmon
.groupid
][log
].min
.u32
[ctr
]
1401 = buzzz_g
.priv
.pmon
.run
[log
].min
.u32
[ctr
];
1402 buzzz_g
.priv
.pmon
.mon
[buzzz_g
.priv
.pmon
.groupid
][log
].max
.u32
[ctr
]
1403 = buzzz_g
.priv
.pmon
.run
[log
].max
.u32
[ctr
];
1404 buzzz_g
.priv
.pmon
.mon
[buzzz_g
.priv
.pmon
.groupid
][log
].sum
.u32
[ctr
]
1405 = buzzz_g
.priv
.pmon
.run
[log
].sum
.u32
[ctr
];
1408 #if defined(BUZZZ_CONFIG_PMON_USR)
1409 buzzz_g
.priv
.pmon
.usr
.mon
[buzzz_g
.priv
.pmon
.groupid
].min
1410 = buzzz_g
.priv
.pmon
.usr
.run
.min
;
1411 buzzz_g
.priv
.pmon
.usr
.mon
[buzzz_g
.priv
.pmon
.groupid
].max
1412 = buzzz_g
.priv
.pmon
.usr
.run
.max
;
1413 buzzz_g
.priv
.pmon
.usr
.mon
[buzzz_g
.priv
.pmon
.groupid
].sum
1414 = buzzz_g
.priv
.pmon
.usr
.run
.sum
;
1415 #endif /* BUZZZ_CONFIG_PMON_USR */
1418 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
1419 _buzzz_pmon_bind(uint32_t group
)
1423 buzzz_pmon_ctl_t
* ctl
;
1425 /* Initialize storage for statistics */
1426 for (log
= 0U; log
<= BUZZZ_PMON_LOGS
; log
++) {
1427 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++) {
1428 buzzz_g
.priv
.pmon
.run
[log
].min
.u32
[ctr
] = ~0U;
1429 buzzz_g
.priv
.pmon
.run
[log
].max
.u32
[ctr
] = 0U;
1430 buzzz_g
.priv
.pmon
.run
[log
].sum
.u32
[ctr
] = 0U;
1433 #if defined(BUZZZ_CONFIG_PMON_USR)
1434 buzzz_g
.priv
.pmon
.usr
.run
.min
= ~0U;
1435 buzzz_g
.priv
.pmon
.usr
.run
.max
= 0U;
1436 buzzz_g
.priv
.pmon
.usr
.run
.sum
= 0U;
1437 #endif /* BUZZZ_CONFIG_PMON_USR */
1439 /* Monitoring mode */
1440 mode
= (group
== BUZZZ_PMON_GROUP_RESET
) ? 0 : BUZZZ_PMON_CTRL
;
1443 ctl
= &buzzz_pmonctl_g
[group
];
1445 #if defined(CONFIG_MIPS) && defined(BUZZZ_CONFIG_CPU_MIPS_74K)
1446 write_c0_perf(0, BUZZZ_PMON_VAL(ctl
->u8
[0], mode
));
1447 write_c0_perf(2, BUZZZ_PMON_VAL(ctl
->u8
[1], mode
));
1448 write_c0_perf(4, BUZZZ_PMON_VAL(ctl
->u8
[2], mode
));
1449 write_c0_perf(6, BUZZZ_PMON_VAL(ctl
->u8
[3], mode
));
1450 #endif /* CONFIG_MIPS && BUZZZ_CONFIG_CPU_MIPS_74K */
1451 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1452 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++) {
1453 _armv7_pmcn_config_buzzz_ctr(ctr
, ctl
->u8
[ctr
]);
1455 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1457 BUZZZ_PRINT("Bind next group<%u> <%u> <%u> <%u> <%u>", group
,
1458 BUZZZ_PMON_VAL(ctl
->u8
[0], mode
),
1459 BUZZZ_PMON_VAL(ctl
->u8
[1], mode
),
1460 BUZZZ_PMON_VAL(ctl
->u8
[2], mode
),
1461 BUZZZ_PMON_VAL(ctl
->u8
[3], mode
));
1463 buzzz_g
.priv
.pmon
.sample
= 0U;
1464 buzzz_g
.priv
.pmon
.groupid
= group
;
1467 /* Start a new sample */
1468 void BUZZZ_NOINSTR_FUNC
1469 buzzz_pmon_bgn(void)
1471 if (buzzz_g
.status
== BUZZZ_STATUS_ENABLED
) {
1472 #if defined(BUZZZ_CONFIG_PMON_USR)
1473 buzzz_pmon_usr_g
= 0U;
1474 #endif /* BUZZZ_CONFIG_PMON_USR */
1475 _buzzz_pmon_log(0U); /* record baseline values */
1476 buzzz_g
.priv
.pmon
.next_log_id
= 1U; /* for log sequence check */
1478 _buzzz_pmon_iter_set_invalid();
1481 /* Invalidate this iteration */
1482 void BUZZZ_NOINSTR_FUNC
1483 buzzz_pmon_clr(void)
1485 _buzzz_pmon_iter_set_invalid();
1488 /* Record performance counters at this event point */
1489 void BUZZZ_NOINSTR_FUNC
1490 buzzz_pmon_log(uint32_t log_id
)
1492 if (buzzz_g
.priv
.pmon
.next_log_id
!= log_id
) { /* check log sequence */
1493 _buzzz_pmon_iter_set_invalid(); /* tag sample as invalid */
1497 _buzzz_pmon_log(log_id
); /* record counter values */
1499 buzzz_g
.priv
.pmon
.next_log_id
= log_id
+ 1U; /* for log sequence check */
1502 void BUZZZ_NOINSTR_FUNC
1503 buzzz_pmon_end(uint32_t last_log_id
)
1505 if (buzzz_g
.status
== BUZZZ_STATUS_DISABLED
)
1508 if (last_log_id
>= BUZZZ_PMON_LOGS
) {
1509 printk(CLRerr
"Too many log points<%u>, only %u permitted" CLRnl
,
1510 last_log_id
, BUZZZ_PMON_LOGS
);
1514 /* Event 0, counter#0 log is used to track an invalid sample */
1515 if (_buzzz_pmon_iter_is_invalid()) {
1516 BUZZZ_PRINT("invalid iteration");
1517 return; /* invalid sample */
1520 if (buzzz_g
.status
!= BUZZZ_STATUS_ENABLED
) {
1521 _buzzz_pmon_iter_set_invalid();
1525 buzzz_g
.priv
.pmon
.last_log_id
= last_log_id
;
1526 buzzz_g
.priv
.pmon
.sample
++;
1528 BUZZZ_PRINT("group<%u> sample<%u> of <%u> last_log_id<%u>",
1529 buzzz_g
.priv
.pmon
.groupid
, buzzz_g
.priv
.pmon
.sample
,
1530 buzzz_g
.priv
.pmon
.config_samples
, last_log_id
);
1532 if (buzzz_g
.priv
.pmon
.groupid
== 0) { /* RESET or skip group ID */
1534 BUZZZ_PRINT("SKIP samples completed");
1536 if (buzzz_g
.priv
.pmon
.sample
>= buzzz_g
.priv
.pmon
.config_samples
) {
1538 if (buzzz_g
.config_mode
== BUZZZ_MODE_LIMITED
)
1539 buzzz_g
.priv
.pmon
.groupid
= buzzz_g
.config_limit
;
1541 buzzz_g
.priv
.pmon
.groupid
++;
1543 _buzzz_pmon_bind(buzzz_g
.priv
.pmon
.groupid
);
1545 return; /* exit without summing all samples for RESET group */
1548 /* Accumulate into run, current iteration, and setup for next iteration */
1549 _buzzz_pmon_run(last_log_id
);
1551 if (buzzz_g
.priv
.pmon
.sample
>= buzzz_g
.priv
.pmon
.config_samples
) {
1553 _buzzz_pmon_tot(last_log_id
); /* record current groups sum total */
1555 /* Move to next group, or end if limited to single group */
1556 if (buzzz_g
.config_mode
== BUZZZ_MODE_LIMITED
)
1557 buzzz_g
.priv
.pmon
.groupid
= BUZZZ_PMON_GROUPS
;
1559 buzzz_g
.priv
.pmon
.groupid
++;
1561 if (buzzz_g
.priv
.pmon
.groupid
>= BUZZZ_PMON_GROUPS
)
1564 _buzzz_pmon_bind(buzzz_g
.priv
.pmon
.groupid
);
1568 void BUZZZ_NOINSTR_FUNC
1569 buzzz_pmon_dump(void)
1571 uint32_t group
, log_id
, ctr
;
1572 buzzz_pmonst_t
* log
;
1573 buzzz_pmon_ctr_t tot
;
1575 printk("\n\n+++++++++++++++\n+ PMON Report +\n+++++++++++++++\n\n");
1577 if (buzzz_g
.status
!= BUZZZ_STATUS_DISABLED
)
1578 printk(CLRwarn
"PMon not disabled" CLRnl
);
1580 if (buzzz_g
.config_mode
== BUZZZ_MODE_LIMITED
)
1581 group
= buzzz_g
.config_limit
;
1583 group
= BUZZZ_PMON_GROUP_GENERAL
;
1585 for (; group
< BUZZZ_PMON_GROUP_MAXIMUM
; group
++) {
1587 /* Zero out the total cummulation */
1588 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++)
1591 /* Print the table header */
1592 printk("\n\nGroup:\t" CLRb
"%s\n" CLRnl
, str_buzzz_pmon_group(group
));
1594 if (group
== BUZZZ_PMON_GROUP_GENERAL
) {
1595 printk(CLRb
"%15s %12s %12s %15s %12s REGISTERED-EVENT" CLRnl
,
1596 str_buzzz_pmon_event((group
* BUZZZ_PMON_COUNTERS
) + 1),
1598 str_buzzz_pmon_event((group
* BUZZZ_PMON_COUNTERS
) + 3),
1599 str_buzzz_pmon_event((group
* BUZZZ_PMON_COUNTERS
) + 0),
1600 str_buzzz_pmon_event((group
* BUZZZ_PMON_COUNTERS
) + 2));
1602 printk(CLRb
"%15s %15s %15s %15s REGISTERED-EVENT" CLRnl
,
1603 str_buzzz_pmon_event((group
* BUZZZ_PMON_COUNTERS
) + 0),
1604 str_buzzz_pmon_event((group
* BUZZZ_PMON_COUNTERS
) + 1),
1605 str_buzzz_pmon_event((group
* BUZZZ_PMON_COUNTERS
) + 2),
1606 str_buzzz_pmon_event((group
* BUZZZ_PMON_COUNTERS
) + 3));
1609 /* -------------- */
1610 /* SUM STATISTICS */
1611 /* -------------- */
1613 printk(CLRb
"\n\nSamples %u Statistics",
1614 buzzz_g
.priv
.pmon
.config_samples
);
1616 #if defined(BUZZZ_CONFIG_PMON_USR)
1617 printk(": UserCtr[%u]" CLRnl
, buzzz_g
.priv
.pmon
.usr
.mon
[group
].sum
);
1620 #endif /* !BUZZZ_CONFIG_PMON_USR */
1622 for (log_id
= 1; log_id
<= buzzz_g
.priv
.pmon
.last_log_id
; log_id
++) {
1624 /* Print table row = per event entry */
1625 log
= &buzzz_g
.priv
.pmon
.mon
[group
][log_id
];
1627 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++)
1628 tot
.u32
[ctr
] += log
->sum
.u32
[ctr
];
1630 if (group
== BUZZZ_PMON_GROUP_GENERAL
) {
1631 printk("%15u %12u %12u %15u %12u %s\n",
1633 ((log
->sum
.u32
[1] * 1000) / BUZZZ_CYCLES_PER_USEC
),
1634 log
->sum
.u32
[3], log
->sum
.u32
[0], log
->sum
.u32
[2],
1635 buzzz_g
.klogs
[log_id
]);
1637 printk("%15u %15u %15u %15u %s\n",
1638 log
->sum
.u32
[0], log
->sum
.u32
[1],
1639 log
->sum
.u32
[2], log
->sum
.u32
[3],
1640 buzzz_g
.klogs
[log_id
]);
1645 * Print table summary total:
1646 * Total nanosecs is computed from total cycles/BUZZZ_CYCLES_PER_USEC.
1647 * The total nanosecs will not include any fractions of each event's
1648 * nanosec computed from cycles, and will be off by the fractions.
1650 if (group
== BUZZZ_PMON_GROUP_GENERAL
) {
1651 printk("\n%15u %12u %12u %15u %12u " CLRb
"%s" CLRnl
,
1652 tot
.u32
[1], ((tot
.u32
[1] * 1000) / BUZZZ_CYCLES_PER_USEC
),
1653 tot
.u32
[3], tot
.u32
[0], tot
.u32
[2], "Total");
1655 printk("\n%15u %15u %15u %15u " CLRb
"%s" CLRnl
,
1656 tot
.u32
[0], tot
.u32
[1], tot
.u32
[2], tot
.u32
[3], "Total");
1659 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++)
1662 /* -------------- */
1663 /* MIN STATISTICS */
1664 /* -------------- */
1666 printk(CLRb
"\nMIN statistics");
1667 #if defined(BUZZZ_CONFIG_PMON_USR)
1668 printk(": UserCtr[%u]" CLRnl
, buzzz_g
.priv
.pmon
.usr
.mon
[group
].min
);
1671 #endif /* !BUZZZ_CONFIG_PMON_USR */
1673 for (log_id
= 1; log_id
<= buzzz_g
.priv
.pmon
.last_log_id
; log_id
++) {
1674 log
= &buzzz_g
.priv
.pmon
.mon
[group
][log_id
];
1676 if (group
== BUZZZ_PMON_GROUP_GENERAL
) {
1677 printk("%15u %12u %12u %15u %12u %s\n",
1679 ((log
->min
.u32
[1] * 1000) / BUZZZ_CYCLES_PER_USEC
),
1680 log
->min
.u32
[3], log
->min
.u32
[0], log
->min
.u32
[2],
1681 buzzz_g
.klogs
[log_id
]);
1683 printk("%15u %15u %15u %15u %s\n",
1684 log
->min
.u32
[0], log
->min
.u32
[1],
1685 log
->min
.u32
[2], log
->min
.u32
[3],
1686 buzzz_g
.klogs
[log_id
]);
1689 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++)
1690 tot
.u32
[ctr
] += log
->min
.u32
[ctr
];
1693 if (group
== BUZZZ_PMON_GROUP_GENERAL
) {
1694 printk("\n%15u %12u %12u %15u %12u " CLRb
"%s" CLRnl
,
1695 tot
.u32
[1], ((tot
.u32
[1] * 1000) / BUZZZ_CYCLES_PER_USEC
),
1696 tot
.u32
[3], tot
.u32
[0], tot
.u32
[2], "Total");
1698 printk("\n%15u %15u %15u %15u " CLRb
"%s" CLRnl
,
1699 tot
.u32
[0], tot
.u32
[1], tot
.u32
[2], tot
.u32
[3], "Total");
1702 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++)
1705 /* -------------- */
1706 /* MAX STATISTICS */
1707 /* -------------- */
1709 printk(CLRb
"\nMAX statistics");
1710 #if defined(BUZZZ_CONFIG_PMON_USR)
1711 printk(": UserCtr[%u]" CLRnl
, buzzz_g
.priv
.pmon
.usr
.mon
[group
].max
);
1714 #endif /* !BUZZZ_CONFIG_PMON_USR */
1716 for (log_id
= 1; log_id
<= buzzz_g
.priv
.pmon
.last_log_id
; log_id
++) {
1717 log
= &buzzz_g
.priv
.pmon
.mon
[group
][log_id
];
1719 if (group
== BUZZZ_PMON_GROUP_GENERAL
) {
1720 printk("%15u %12u %12u %15u %12u %s\n",
1722 ((log
->max
.u32
[1] * 1000) / BUZZZ_CYCLES_PER_USEC
),
1723 log
->max
.u32
[3], log
->max
.u32
[0], log
->max
.u32
[2],
1724 buzzz_g
.klogs
[log_id
]);
1726 printk("%15u %15u %15u %15u %s\n",
1727 log
->max
.u32
[0], log
->max
.u32
[1],
1728 log
->max
.u32
[2], log
->max
.u32
[3],
1729 buzzz_g
.klogs
[log_id
]);
1732 for (ctr
= 0U; ctr
< BUZZZ_PMON_COUNTERS
; ctr
++)
1733 tot
.u32
[ctr
] += log
->max
.u32
[ctr
];
1736 if (group
== BUZZZ_PMON_GROUP_GENERAL
) {
1737 printk("\n%15u %12u %12u %15u %12u " CLRb
"%s" CLRnl
,
1738 tot
.u32
[1], ((tot
.u32
[1] * 1000) / BUZZZ_CYCLES_PER_USEC
),
1739 tot
.u32
[3], tot
.u32
[0], tot
.u32
[2], "Total");
1741 printk("\n%15u %15u %15u %15u " CLRb
"%s" CLRnl
,
1742 tot
.u32
[0], tot
.u32
[1], tot
.u32
[2], tot
.u32
[3], "Total");
1745 if (buzzz_g
.config_mode
== BUZZZ_MODE_LIMITED
)
1750 void BUZZZ_NOINSTR_FUNC
1751 buzzz_pmon_start(void)
1755 memset(buzzz_g
.priv
.pmon
.log
, 0, sizeof(buzzz_g
.priv
.pmon
.log
));
1756 memset(buzzz_g
.priv
.pmon
.run
, 0, sizeof(buzzz_g
.priv
.pmon
.run
));
1757 memset(buzzz_g
.priv
.pmon
.mon
, 0, sizeof(buzzz_g
.priv
.pmon
.mon
));
1759 _buzzz_pmon_bind(BUZZZ_PMON_GROUP_RESET
);
1760 _buzzz_pmon_iter_set_invalid();
1762 buzzz_g
.priv
.pmon
.sample
= 0U;
1763 buzzz_g
.priv
.pmon
.next_log_id
= 0U;
1764 buzzz_g
.priv
.pmon
.last_log_id
= 0U;
1766 _buzzz_pmon_enable();
1768 _buzzz_post_start();
1770 BUZZZ_PRINT("buzzz_pmon_start");
1773 void BUZZZ_NOINSTR_FUNC
1774 buzzz_pmon_stop(void)
1776 if (buzzz_g
.status
!= BUZZZ_STATUS_DISABLED
) {
1779 _buzzz_pmon_bind(BUZZZ_PMON_GROUP_RESET
);
1781 _buzzz_pmon_disable();
1789 void BUZZZ_NOINSTR_FUNC
1790 buzzz_pmon_show(void)
1792 printk("Group:\t\t" CLRb
"%s %d" CLRnl
,
1793 str_buzzz_pmon_group(buzzz_g
.priv
.pmon
.groupid
), buzzz_g
.priv
.pmon
.groupid
);
1794 printk("Control:\t" CLRb
"%u %u %u %u" CLRnl
,
1795 buzzz_g
.priv
.pmon
.control
.u8
[0], buzzz_g
.priv
.pmon
.control
.u8
[1],
1796 buzzz_g
.priv
.pmon
.control
.u8
[2], buzzz_g
.priv
.pmon
.control
.u8
[3]);
1797 printk("Sample:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.pmon
.sample
);
1798 printk("NextId:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.pmon
.next_log_id
);
1799 printk("LastId:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.pmon
.last_log_id
);
1800 printk("+Skip:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.pmon
.config_skip
);
1801 printk("+Sample:\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.pmon
.config_samples
);
1802 printk("+Group:\t\t" CLRb
"%s" CLRnl
,
1803 str_buzzz_pmon_group(buzzz_g
.config_limit
));
1804 printk("+Mode:\t\t" CLRb
"%s" CLRnl
, str_buzzz_mode(buzzz_g
.config_mode
));
1807 printk("Groups\n\t1: General\n\t2: I-Cache\n\t3: D-Cache\n\t4: TLB\n");
1808 printk("\t5: Data\n\t6: Spurious\n\t7: Branches\n\t8: Miscellaneous\n\n");
1811 int BUZZZ_NOINSTR_FUNC
1812 buzzz_pmon_default(void)
1816 #if defined(CONFIG_BUZZZ_FUNC)
1817 printk(CLRerr
"ERROR: BUZZZ Function Call Tracing Enabled" CLRnl
);
1818 printk(CLRerr
"Disable CONFIG_BUZZZ_FUNC for PMON tool" CLRnl
);
1820 #endif /* CONFIG_BUZZZ_FUNC */
1822 #if defined(CONFIG_BUZZZ_KEVT)
1823 printk(CLRerr
"ERROR: BUZZZ Kernel Event Tracing Enabled" CLRnl
);
1824 printk(CLRerr
"Disable CONFIG_BUZZZ_KEVT for PMON tool" CLRnl
);
1826 #endif /* CONFIG_BUZZZ_KEVT */
1828 #if defined(CONFIG_ARM)
1829 /* Ensure PMU is not being used by another subsystem */
1830 if (_armv7_pmcntenset_test() != 0U) {
1831 printk(CLRerr
"PMU counters are in use" CLRnl
);
1834 #endif /* CONFIG_ARM */
1836 buzzz_g
.priv
.pmon
.groupid
= BUZZZ_PMON_GROUP_RESET
;
1837 for (evt
= 0; evt
< BUZZZ_PMON_COUNTERS
; evt
++)
1838 buzzz_g
.priv
.pmon
.control
.u8
[evt
] =
1839 buzzz_pmonctl_g
[BUZZZ_PMON_GROUP_RESET
].u8
[evt
];
1840 buzzz_g
.priv
.pmon
.sample
= 0U;
1841 buzzz_g
.priv
.pmon
.next_log_id
= 0U;
1842 buzzz_g
.priv
.pmon
.last_log_id
= 0U;
1843 buzzz_g
.priv
.pmon
.config_skip
= BUZZZ_PMON_SAMPLESZ
;
1844 buzzz_g
.priv
.pmon
.config_samples
= BUZZZ_PMON_SAMPLESZ
;
1846 buzzz_g
.config_mode
= BUZZZ_MODE_LIMITED
;
1847 buzzz_g
.config_limit
= BUZZZ_PMON_GROUP_GENERAL
;
1849 return BUZZZ_SUCCESS
;
1852 int BUZZZ_NOINSTR_FUNC
1853 buzzz_pmon_config(uint32_t config_samples
, uint32_t config_skip
)
1855 BUZZZ_ASSERT_STATUS_DISABLED();
1857 buzzz_g
.priv
.pmon
.config_samples
= config_samples
;
1858 buzzz_g
.priv
.pmon
.config_skip
= config_skip
;
1860 return BUZZZ_SUCCESS
;
1863 /* Initialization of Buzzz PMon tool during loading time */
1864 static int BUZZZ_NOINSTR_FUNC
1865 __init
_init_buzzz_pmon(void)
1867 return BUZZZ_SUCCESS
;
1871 * -----------------------------------------------------------------------------
1872 * Kernel Event Logging subsystem
1873 * -----------------------------------------------------------------------------
1876 struct buzzz_kevt_log
1878 uint32_t ctr
[BUZZZ_KEVT_COUNTERS
];
1889 uint32_t arg2
, arg3
, arg4
, arg5
;
1893 struct buzzz_kevt_ctl
1895 uint8_t u8
[BUZZZ_KEVT_COUNTERS
];
1898 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1900 buzzz_kevt_ctl_t buzzz_kevtctl_g
[BUZZZ_KEVT_GROUPS
] =
1903 {{ 0U, 0U }}, /* group 0 RESET */
1904 {{ 0x68, 0x11 }}, /* group 1 GENERAL */
1905 {{ 0x68, 0x01 }}, /* group 2 ICACHE */
1906 {{ 0x04, 0x03 }}, /* group 3 DCACHE */
1907 {{ 0x02, 0x05 }}, /* group 4 TLB */
1908 {{ 0x10, 0x64 }} /* group 5 MISCELLANEOUS */
1910 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1912 /* embed prints with one args in log */
1913 #define _BUZZZ_KEVT_BGN(flags, cur) \
1914 if (buzzz_g.status != BUZZZ_STATUS_ENABLED) return; \
1915 BUZZZ_LOCK(flags); \
1916 cur = (buzzz_kevt_log_t*)buzzz_g.cur; \
1917 cur->arg0.klog.core = raw_smp_processor_id(); \
1918 cur->arg0.klog.id = log_id;
1920 #define _BUZZZ_KEVT_END(flags) \
1921 buzzz_g.cur = (void*)(((buzzz_kevt_log_t*)buzzz_g.cur) + 1); \
1922 buzzz_g.priv.kevt.count++; \
1923 if (buzzz_g.cur >= buzzz_g.end) { \
1924 buzzz_g.wrap = BUZZZ_TRUE; \
1925 buzzz_g.cur = buzzz_g.log; \
1927 BUZZZ_UNLOCK(flags);
1929 void BUZZZ_NOINSTR_FUNC
1930 buzzz_kevt_log0(uint32_t log_id
)
1932 unsigned long flags
;
1933 buzzz_kevt_log_t
* cur
;
1935 _BUZZZ_KEVT_BGN(flags
, cur
);
1937 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1938 cur
->ctr
[0] = _armv7_pmcn_read_buzzz_ctr(0);
1939 cur
->ctr
[1] = _armv7_pmcn_read_buzzz_ctr(1);
1940 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1942 cur
->arg0
.klog
.args
= 0;
1944 _BUZZZ_KEVT_END(flags
);
1947 void BUZZZ_NOINSTR_FUNC
1948 buzzz_kevt_log1(uint32_t log_id
, uint32_t arg1
)
1950 unsigned long flags
;
1951 buzzz_kevt_log_t
* cur
;
1953 _BUZZZ_KEVT_BGN(flags
, cur
);
1955 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1956 cur
->ctr
[0] = _armv7_pmcn_read_buzzz_ctr(0);
1957 cur
->ctr
[1] = _armv7_pmcn_read_buzzz_ctr(1);
1958 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1960 cur
->arg0
.klog
.args
= 1;
1963 _BUZZZ_KEVT_END(flags
);
1966 void BUZZZ_NOINSTR_FUNC
1967 buzzz_kevt_log2(uint32_t log_id
, uint32_t arg1
, uint32_t arg2
)
1969 unsigned long flags
;
1970 buzzz_kevt_log_t
* cur
;
1972 _BUZZZ_KEVT_BGN(flags
, cur
);
1974 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1975 cur
->ctr
[0] = _armv7_pmcn_read_buzzz_ctr(0);
1976 cur
->ctr
[1] = _armv7_pmcn_read_buzzz_ctr(1);
1977 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1979 cur
->arg0
.klog
.args
= 2;
1983 _BUZZZ_KEVT_END(flags
);
1986 void BUZZZ_NOINSTR_FUNC
1987 buzzz_kevt_log3(uint32_t log_id
, uint32_t arg1
, uint32_t arg2
, uint32_t arg3
)
1989 unsigned long flags
;
1990 buzzz_kevt_log_t
* cur
;
1992 _BUZZZ_KEVT_BGN(flags
, cur
);
1994 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1995 cur
->ctr
[0] = _armv7_pmcn_read_buzzz_ctr(0);
1996 cur
->ctr
[1] = _armv7_pmcn_read_buzzz_ctr(1);
1997 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1999 cur
->arg0
.klog
.args
= 3;
2004 _BUZZZ_KEVT_END(flags
);
2007 void BUZZZ_NOINSTR_FUNC
2008 buzzz_kevt_log4(uint32_t log_id
, uint32_t arg1
, uint32_t arg2
,
2009 uint32_t arg3
, uint32_t arg4
)
2011 unsigned long flags
;
2012 buzzz_kevt_log_t
* cur
;
2014 _BUZZZ_KEVT_BGN(flags
, cur
);
2016 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
2017 cur
->ctr
[0] = _armv7_pmcn_read_buzzz_ctr(0);
2018 cur
->ctr
[1] = _armv7_pmcn_read_buzzz_ctr(1);
2019 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
2021 cur
->arg0
.klog
.args
= 4;
2027 _BUZZZ_KEVT_END(flags
);
2030 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
2031 _buzzz_kevt_enable(void * none
)
2033 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
2034 _armv7_pmcn_enable();
2035 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
2038 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
2039 _buzzz_kevt_disable(void * none
)
2041 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
2042 _armv7_pmcn_disable();
2043 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
2046 static BUZZZ_INLINE
void BUZZZ_NOINSTR_FUNC
2047 _buzzz_kevt_bind(void * info
)
2050 buzzz_kevt_ctl_t
* ctl
;
2051 buzzz_status_t
* status
;
2052 uint32_t group
= *((uint32_t*)info
);
2054 mode
= (group
== BUZZZ_PMON_GROUP_RESET
) ? 0 : BUZZZ_PMON_CTRL
;
2055 ctl
= &buzzz_kevtctl_g
[group
];
2057 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
2058 for (ctr
= 0U; ctr
< BUZZZ_KEVT_COUNTERS
; ctr
++) {
2059 _armv7_pmcn_config_buzzz_ctr(ctr
, ctl
->u8
[ctr
]);
2061 #endif /* CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
2063 status
= &per_cpu(kevt_status
, raw_smp_processor_id());
2064 if (group
== BUZZZ_KEVT_GROUP_RESET
)
2065 *status
= BUZZZ_STATUS_DISABLED
;
2067 *status
= BUZZZ_STATUS_ENABLED
;
2069 BUZZZ_PRINT("Bind group<%u> <%u> <%u>", group
,
2070 BUZZZ_PMON_VAL(ctl
->u8
[0], mode
),
2071 BUZZZ_PMON_VAL(ctl
->u8
[1], mode
));
2074 void BUZZZ_NOINSTR_FUNC
/* Start kevt tracing */
2075 buzzz_kevt_start(void)
2077 buzzz_status_t
* status
;
2081 on_each_cpu(_buzzz_kevt_bind
, &buzzz_g
.priv
.kevt
.config_evt
, 1);
2083 for_each_online_cpu(cpu
) {
2084 status
= &per_cpu(kevt_status
, cpu
);
2085 if (*status
!= BUZZZ_STATUS_ENABLED
)
2086 printk(CLRerr
"buzzz_kevt_start failed to start on cpu<%d>" CLRnl
,
2090 on_each_cpu(_buzzz_kevt_enable
, NULL
, 1);
2092 _buzzz_post_start();
2094 BUZZZ_PRINT("buzzz_kevt_start");
2097 void BUZZZ_NOINSTR_FUNC
/* Stop kevt tracing */
2098 buzzz_kevt_stop(void)
2100 buzzz_kevt_group_t group
= BUZZZ_KEVT_GROUP_RESET
;
2102 if (buzzz_g
.status
!= BUZZZ_STATUS_DISABLED
) {
2104 buzzz_kevt_log0(BUZZZ_KEVT_ID_BUZZZ_TMR
);
2108 on_each_cpu(_buzzz_kevt_bind
, &group
, 1);
2109 on_each_cpu(_buzzz_kevt_disable
, NULL
, 1);
2115 int BUZZZ_NOINSTR_FUNC
2116 buzzz_kevt_parse_log(char * p
, int bytes
, buzzz_kevt_log_t
* log
)
2118 switch (log
->arg0
.klog
.id
) {
2119 case BUZZZ_KEVT_ID_IRQ_BAD
:
2120 bytes
+= sprintf(p
+ bytes
, CLRerr
"IRQ_BAD %u", log
->arg1
);
2122 case BUZZZ_KEVT_ID_IRQ_ACK_BAD
:
2123 bytes
+= sprintf(p
+ bytes
, CLRerr
"IRQ_ACK_BAD %u", log
->arg1
);
2125 case BUZZZ_KEVT_ID_IRQ_MISROUTED
:
2126 bytes
+= sprintf(p
+ bytes
, CLRerr
"IRQ_MISROUTED %u", log
->arg1
);
2128 case BUZZZ_KEVT_ID_IRQ_RESEND
:
2129 bytes
+= sprintf(p
+ bytes
, CLRerr
"IRQ_RESEND %u", log
->arg1
);
2131 case BUZZZ_KEVT_ID_IRQ_CHECK
:
2132 bytes
+= sprintf(p
+ bytes
, CLRerr
"IRQ_CHECK %u", log
->arg1
);
2134 case BUZZZ_KEVT_ID_IRQ_ENTRY
:
2135 bytes
+= sprintf(p
+ bytes
, CLRr
" >> IRQ %03u ", log
->arg1
);
2136 bytes
+= _buzzz_symbol(p
+ bytes
, log
->arg2
);
2138 case BUZZZ_KEVT_ID_IRQ_EXIT
:
2139 bytes
+= sprintf(p
+ bytes
, CLRr
" << IRQ %03u ", log
->arg1
);
2140 bytes
+= _buzzz_symbol(p
+ bytes
, log
->arg2
);
2142 case BUZZZ_KEVT_ID_SIRQ_ENTRY
:
2143 bytes
+= sprintf(p
+ bytes
, CLRm
">>> SOFTIRQ ");
2144 bytes
+= _buzzz_symbol(p
+ bytes
, log
->arg1
);
2146 case BUZZZ_KEVT_ID_SIRQ_EXIT
:
2147 bytes
+= sprintf(p
+ bytes
, CLRm
"<<< SOFTIRQ ");
2148 bytes
+= _buzzz_symbol(p
+ bytes
, log
->arg1
);
2150 case BUZZZ_KEVT_ID_WORKQ_ENTRY
:
2151 bytes
+= sprintf(p
+ bytes
, CLRb
">>>>> WORKQ ");
2152 bytes
+= _buzzz_symbol(p
+ bytes
, log
->arg1
);
2154 case BUZZZ_KEVT_ID_WORKQ_EXIT
:
2155 bytes
+= sprintf(p
+ bytes
, CLRb
"<<<<< WORKQ ");
2156 bytes
+= _buzzz_symbol(p
+ bytes
, log
->arg1
);
2158 case BUZZZ_KEVT_ID_SCHEDULE
:
2160 struct task_struct
* ptsk
, *ntsk
;
2161 ptsk
= (struct task_struct
*)log
->arg1
;
2162 ntsk
= (struct task_struct
*)log
->arg2
;
2163 bytes
+= sprintf(p
+ bytes
, CLRc
2164 "TASK_SWITCH from[%s %u:%u:%u] to[%s %u:%u:%u]",
2165 ptsk
->comm
, ptsk
->pid
, ptsk
->normal_prio
, ptsk
->prio
,
2166 ntsk
->comm
, ntsk
->pid
, ntsk
->normal_prio
, ntsk
->prio
);
2169 case BUZZZ_KEVT_ID_SCHED_TICK
:
2170 bytes
+= sprintf(p
+ bytes
, CLRb
"\tscheduler tick jiffies<%u>",
2173 case BUZZZ_KEVT_ID_SCHED_HRTICK
:
2174 bytes
+= sprintf(p
+ bytes
, CLRb
"sched hrtick");
2176 case BUZZZ_KEVT_ID_GTIMER_EVENT
:
2177 bytes
+= sprintf(p
+ bytes
, CLRb
"\tgtimer ");
2178 bytes
+= _buzzz_symbol(p
+ bytes
, log
->arg1
);
2180 case BUZZZ_KEVT_ID_GTIMER_NEXT
:
2181 bytes
+= sprintf(p
+ bytes
, CLRb
"\tgtimer next<%u>", log
->arg1
);
2184 bytes
+= sprintf(p
+ bytes
, "%s", CLRnl
);
2188 int BUZZZ_NOINSTR_FUNC
2189 buzzz_kevt_dump_log(char * p
, buzzz_kevt_log_t
* log
)
2191 static uint32_t core_cnt
[NR_CPUS
][BUZZZ_KEVT_COUNTERS
]; /* [core][cntr] */
2192 static uint32_t nsecs
[NR_CPUS
];
2195 uint32_t curr
[BUZZZ_KEVT_COUNTERS
], prev
[BUZZZ_KEVT_COUNTERS
];
2196 uint32_t delta
[BUZZZ_KEVT_COUNTERS
], ctr
;
2197 delta
[1] = 0U; /* compiler warning */
2199 for (ctr
= 0U; ctr
< BUZZZ_KEVT_COUNTERS
; ctr
++) {
2200 prev
[ctr
] = core_cnt
[log
->arg0
.klog
.core
][ctr
];
2201 curr
[ctr
] = log
->ctr
[ctr
];
2202 core_cnt
[log
->arg0
.klog
.core
][ctr
] = curr
[ctr
];
2204 if (curr
[ctr
] < prev
[ctr
]) /* rollover */
2205 delta
[ctr
] = curr
[ctr
] + (~0U - prev
[ctr
]);
2207 delta
[ctr
] = (curr
[ctr
] - prev
[ctr
]);
2210 /* HACK: skip first event that simply fills starting values into core_cnt */
2211 if (buzzz_g
.priv
.kevt
.skip
== true) {
2212 buzzz_g
.priv
.kevt
.skip
= false;
2213 nsecs
[0] = nsecs
[1] = 0U;
2215 } else if ((delta
[0] > 1000000000) || (delta
[1] > 1000000000)) {
2216 bytes
+= sprintf(p
+ bytes
, CLRerr
"---skipping log bug? ---" CLRnl
);
2220 nsecs
[log
->arg0
.klog
.core
] += (delta
[1] * 1000) / BUZZZ_CYCLES_PER_USEC
;
2222 if (buzzz_g
.priv
.kevt
.config_evt
== BUZZZ_KEVT_GROUP_GENERAL
) {
2223 uint32_t nanosecs
= ((delta
[1] * 1000) / BUZZZ_CYCLES_PER_USEC
)
2224 - BUZZZ_KEVT_NANOSECS
;
2226 bytes
+= sprintf(p
+ bytes
, "%s%3u%s %8u %5u.%03u %6u.%03u\t",
2227 (log
->arg0
.klog
.core
== 0)? CLRyk
: CLRck
,
2228 log
->arg0
.klog
.core
, CLRnorm
,
2229 delta
[0], nanosecs
/ 1000, (nanosecs
% 1000),
2230 nsecs
[log
->arg0
.klog
.core
] / 1000,
2231 nsecs
[log
->arg0
.klog
.core
] % 1000);
2233 bytes
+= sprintf(p
+ bytes
, "%s%3u%s %8u %8u\t",
2234 (log
->arg0
.klog
.core
== 0)? CLRyk
: CLRck
,
2235 log
->arg0
.klog
.core
, CLRnorm
,
2236 delta
[0], delta
[1]);
2239 if (log
->arg0
.klog
.id
< BUZZZ_KEVT_ID_MAXIMUM
)
2240 return buzzz_kevt_parse_log(p
, bytes
, log
);
2242 bytes
+= sprintf(p
+ bytes
, CLRg
);
2244 switch (log
->arg0
.klog
.args
) {
2246 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
]);
2249 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
],
2253 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
],
2254 log
->arg1
, log
->arg2
);
2257 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
],
2258 log
->arg1
, log
->arg2
, log
->arg3
);
2261 bytes
+= sprintf(p
+ bytes
, buzzz_g
.klogs
[log
->arg0
.klog
.id
],
2262 log
->arg1
, log
->arg2
, log
->arg3
, log
->arg4
);
2268 bytes
+= sprintf(p
+ bytes
, "%s", CLRnl
);
2272 void BUZZZ_NOINSTR_FUNC
/* Dump the format line */
2273 buzzz_kevt_dump_format(void)
2275 uint32_t group
= buzzz_g
.priv
.kevt
.config_evt
;
2277 if (buzzz_g
.priv
.kevt
.config_evt
== BUZZZ_KEVT_GROUP_GENERAL
) {
2278 printk("Format: CPU INSTR_CNT DELTA_MICROSECS* CUMM_MICROSECS* INFO\n");
2279 printk("*Overhead 45-55 nanosecs per row, subtracted %u\n",
2280 BUZZZ_KEVT_NANOSECS
);
2282 printk("Format: CPU %s %s INFO\n",
2283 str_buzzz_kevt_event((group
* BUZZZ_KEVT_COUNTERS
) + 0),
2284 str_buzzz_kevt_event((group
* BUZZZ_KEVT_COUNTERS
) + 1));
2288 void BUZZZ_NOINSTR_FUNC
/* Dump the kevt trace to console */
2289 buzzz_kevt_dump(uint32_t limit
)
2291 buzzz_g
.priv
.kevt
.skip
= true;
2293 buzzz_kevt_dump_format();
2295 buzzz_log_dump(limit
, buzzz_g
.priv
.kevt
.count
, sizeof(buzzz_kevt_log_t
),
2296 (buzzz_dump_log_fn_t
)buzzz_kevt_dump_log
);
2298 buzzz_kevt_dump_format();
2301 void BUZZZ_NOINSTR_FUNC
/* Dump the kevt trace to console */
2302 buzzz_kevt_show(void)
2304 printk("Count:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.kevt
.count
);
2305 printk("Limit:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.priv
.kevt
.limit
);
2306 printk("+Limit:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.config_limit
);
2307 printk("+Mode:\t\t" CLRb
"%s" CLRnl
, str_buzzz_mode(buzzz_g
.config_mode
));
2308 printk("Group:\t\t" CLRb
"%s" CLRnl
,
2309 str_buzzz_kevt_group(buzzz_g
.priv
.kevt
.config_evt
));
2313 int BUZZZ_NOINSTR_FUNC
2314 buzzz_kevt_default(void)
2316 #if defined(CONFIG_BUZZZ_FUNC)
2317 printk(CLRerr
"ERROR: BUZZZ Function Call Tracing Enabled" CLRnl
);
2318 printk(CLRerr
"Disable CONFIG_BUZZZ_FUNC for KEVT tracing" CLRnl
);
2320 #endif /* CONFIG_BUZZZ_FUNC */
2322 #if !defined(CONFIG_ARM)
2323 printk(CLRerr
"BUZZZ::KEVT not ported to MIPS" CLRnl
);
2325 #else /* CONFIG_ARM */
2326 if (_armv7_pmcntenset_test() != 0U) {
2327 printk(CLRerr
"PMU counters are in use" CLRnl
);
2330 #endif /* !CONFIG_ARM */
2332 buzzz_g
.priv
.kevt
.count
= 0U;
2333 buzzz_g
.priv
.kevt
.limit
= BUZZZ_INVALID
;
2334 buzzz_g
.priv
.kevt
.config_evt
= BUZZZ_KEVT_GROUP_GENERAL
;
2335 buzzz_g
.priv
.kevt
.log_count
= 0U;
2336 buzzz_g
.priv
.kevt
.log_index
= 0U;
2338 buzzz_g
.config_mode
= BUZZZ_MODE_WRAPOVER
;
2339 buzzz_g
.config_limit
= BUZZZ_INVALID
;
2341 return BUZZZ_SUCCESS
;
2345 int BUZZZ_NOINSTR_FUNC
/* API to config kevt performance counter group */
2346 buzzz_kevt_config(uint32_t config_evt
)
2348 BUZZZ_ASSERT_STATUS_DISABLED();
2350 if ((config_evt
== BUZZZ_KEVT_GROUP_RESET
) ||
2351 (config_evt
>= BUZZZ_KEVT_GROUP_MAXIMUM
)) {
2352 printk(CLRwarn
"Invalid event group<%u>" CLRnl
, config_evt
);
2356 buzzz_g
.priv
.kevt
.config_evt
= config_evt
;
2358 printk("buzzz_kevt_config %s\n",
2359 str_buzzz_kevt_group(buzzz_g
.priv
.kevt
.config_evt
));
2361 return BUZZZ_SUCCESS
;
2364 /* Initialization of Buzzz Kevt tool during loading time */
2365 static int BUZZZ_NOINSTR_FUNC
2366 __init
_init_buzzz_kevt(void)
2368 if ((BUZZZ_AVAIL_BUFSIZE
% sizeof(buzzz_kevt_log_t
)) != 0)
2371 if (sizeof(buzzz_kevt_log_t
) != 32)
2374 return BUZZZ_SUCCESS
;
2377 #if defined(BUZZZ_CONFIG_UNITTEST)
2378 static void BUZZZ_NOINSTR_FUNC
2379 buzzz_func_unittest(void)
2381 /* register events in _init function */
2382 buzzz_klog_reg(100, "Event 100 with no arguments");
2383 buzzz_klog_reg(101, "Event 101 with argument <%u>");
2384 buzzz_klog_reg(102, "Event 102 with argument <%u> <%u>");
2385 buzzz_klog_reg(103, "Event 103 with argument <%u> <%u> <%u>");
2387 /* invoke logging embedded in code */
2388 buzzz_func_log0(100);
2389 buzzz_func_log1(101, 1);
2390 buzzz_func_log2(102, 1, 2);
2391 buzzz_func_log3(103, 1, 2, 3);
2395 static void BUZZZ_NOINSTR_FUNC
2396 buzzz_pmon_unittest(void)
2399 buzzz_klog_reg(1, "udelay 1sec");
2400 buzzz_klog_reg(2, "udelay 2secs");
2401 buzzz_klog_reg(3, "udelay 3secs");
2402 buzzz_klog_reg(4, "udelay 4secs");
2403 buzzz_klog_reg(5, "udelay 5secs");
2404 buzzz_klog_reg(6, "udelay 6secs");
2405 buzzz_klog_reg(7, "udelay 7secs");
2406 buzzz_klog_reg(8, "udelay 8secs");
2407 buzzz_klog_reg(9, "udelay 9secs");
2408 buzzz_klog_reg(10, "udelay 10secs");
2410 buzzz_klog_reg(11, "Invoke PMON Log");
2411 buzzz_klog_reg(12, "Invoke PMON Log");
2412 buzzz_klog_reg(13, "Invoke PMON Log");
2413 buzzz_klog_reg(14, "Invoke PMON Log");
2414 buzzz_klog_reg(15, "Invoke PMON Log");
2415 buzzz_klog_reg(16, "Invoke PMON Log");
2416 buzzz_klog_reg(17, "Invoke PMON Log");
2417 buzzz_klog_reg(18, "Invoke PMON Log");
2418 buzzz_klog_reg(19, "Invoke PMON Log");
2419 buzzz_klog_reg(20, "Invoke PMON Log");
2421 for (i
= 0; (i
< buzzz_g
.priv
.pmon
.config_samples
* 16); i
++) {
2425 udelay(1); buzzz_pmon_log(1);
2426 udelay(2); buzzz_pmon_log(2);
2427 udelay(3); buzzz_pmon_log(3);
2428 udelay(4); buzzz_pmon_log(4);
2429 udelay(5); buzzz_pmon_log(5);
2430 udelay(6); buzzz_pmon_log(6);
2431 udelay(7); buzzz_pmon_log(7);
2432 udelay(8); buzzz_pmon_log(8);
2433 udelay(9); buzzz_pmon_log(9);
2434 udelay(10); buzzz_pmon_log(10);
2436 /* Measure cost of buzzz_pmon_log : do nothing between calls */
2452 static void BUZZZ_NOINSTR_FUNC
2453 buzzz_kevt_unittest(void)
2455 /* register events in _init function */
2456 buzzz_klog_reg(900, "Event argument");
2457 buzzz_klog_reg(901, "Event argument<%u>");
2458 buzzz_klog_reg(902, "Event argument<%u %u>");
2459 buzzz_klog_reg(903, "Event argument<%u %u %u>");
2460 buzzz_klog_reg(904, "Event argument<%u %u %u %u>");
2462 /* invoke logging embedded in code */
2463 buzzz_kevt_log0(900);
2464 buzzz_kevt_log0(900);
2465 buzzz_kevt_log0(900);
2466 buzzz_kevt_log0(900);
2467 buzzz_kevt_log0(900);
2468 buzzz_kevt_log1(901, 1);
2469 buzzz_kevt_log1(901, 1);
2470 buzzz_kevt_log1(901, 1);
2471 buzzz_kevt_log1(901, 1);
2472 buzzz_kevt_log1(901, 1);
2473 buzzz_kevt_log2(902, 1, 22);
2474 buzzz_kevt_log2(902, 1, 22);
2475 buzzz_kevt_log2(902, 1, 22);
2476 buzzz_kevt_log2(902, 1, 22);
2477 buzzz_kevt_log2(902, 1, 22);
2478 buzzz_kevt_log3(903, 1, 22, 333);
2479 buzzz_kevt_log3(903, 1, 22, 333);
2480 buzzz_kevt_log3(903, 1, 22, 333);
2481 buzzz_kevt_log3(903, 1, 22, 333);
2482 buzzz_kevt_log3(903, 1, 22, 333);
2483 buzzz_kevt_log4(904, 1, 22, 333, 4444);
2484 buzzz_kevt_log4(904, 1, 22, 333, 4444);
2485 buzzz_kevt_log4(904, 1, 22, 333, 4444);
2486 buzzz_kevt_log4(904, 1, 22, 333, 4444);
2487 buzzz_kevt_log4(904, 1, 22, 333, 4444);
2489 #endif /* BUZZZ_CONFIG_UNITTEST */
2492 #if defined(CONFIG_PROC_FS)
2494 * -----------------------------------------------------------------------------
2495 * BUZZZ Proc Filesystem interface
2496 * -----------------------------------------------------------------------------
2498 static int BUZZZ_NOINSTR_FUNC
/* Invoked on single-open, presently */
2499 buzzz_proc_sys_show(struct seq_file
*seq
, void *v
)
2501 seq_printf(seq
, CLRbold
"%s" BUZZZ_VER_FMTS CLRnl
,
2502 BUZZZ_NAME
, BUZZZ_VER_FMT(BUZZZ_SYS_VERSION
));
2503 seq_printf(seq
, "Status:\t\t" CLRb
"%s" CLRnl
,
2504 str_buzzz_status(buzzz_g
.status
));
2505 seq_printf(seq
, "Tool:\t\t" CLRb
"%s" CLRnl
,
2506 str_buzzz_tool(buzzz_g
.tool
));
2507 seq_printf(seq
, "Wrap:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.wrap
);
2508 seq_printf(seq
, "Run:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.run
);
2509 seq_printf(seq
, "Buf.log:\t" CLRb
"0x%p" CLRnl
, buzzz_g
.log
);
2510 seq_printf(seq
, "Buf.cur:\t" CLRb
"0x%p" CLRnl
, buzzz_g
.cur
);
2511 seq_printf(seq
, "Buf.end:\t" CLRb
"0x%p" CLRnl
, buzzz_g
.end
);
2513 return BUZZZ_SUCCESS
;
2516 static int BUZZZ_NOINSTR_FUNC
2517 buzzz_proc_log_show(char * page
, char **start
, off_t off
, int count
,
2518 int * eof
, void * data
)
2522 *start
= page
; /* prepare start of buffer for printing */
2524 if (buzzz_g
.priv
.func
.log_index
> buzzz_g
.priv
.func
.log_count
) {
2525 buzzz_g
.priv
.func
.log_index
= 0U; /* stop proc fs, return 0B */
2526 } else if (buzzz_g
.priv
.func
.log_index
== buzzz_g
.priv
.func
.log_count
) {
2527 bytes
+= sprintf(page
+ bytes
, CLRbold
"BUZZZ_DUMP END" CLRnl
);
2528 buzzz_g
.priv
.func
.log_index
++; /* stop proc fs on next call */
2529 } else { /* return a record */
2530 buzzz_func_log_t
*log
;
2531 uint32_t index
= buzzz_g
.priv
.func
.log_index
;
2533 if (buzzz_g
.wrap
== BUZZZ_TRUE
) {
2534 buzzz_func_log_t
*bgn
= (buzzz_func_log_t
*)buzzz_g
.log
;
2535 buzzz_func_log_t
*cur
= (buzzz_func_log_t
*)buzzz_g
.cur
;
2536 buzzz_func_log_t
*end
= (buzzz_func_log_t
*)buzzz_g
.end
;
2538 if ((cur
+ index
) >= end
) /* wrap: start from begining */
2539 log
= bgn
+ (index
- (end
- cur
));
2543 log
= (buzzz_func_log_t
*)buzzz_g
.log
+ index
;
2546 if (index
== 0U) { /* Log the header */
2547 buzzz_g
.priv
.func
.indent
= 0U;
2549 bytes
+= sprintf(page
+ bytes
,
2550 CLRbold
"BUZZZ_DUMP BGN total<%u>" CLRnl
,
2551 buzzz_g
.priv
.func
.log_count
);
2553 if (buzzz_g
.priv
.func
.log_count
== 0U) {
2554 bytes
+= sprintf(page
+ bytes
, CLRbold
"BUZZZ_DUMP END" CLRnl
);
2559 bytes
+= buzzz_func_dump_log(page
+ bytes
, log
);
2561 buzzz_g
.priv
.func
.log_index
++;
2564 /* do not place any code here */
2567 *eof
= 1; /* end of entry */
2568 return bytes
; /* 0B implies end of proc fs */
2571 static int BUZZZ_NOINSTR_FUNC
/* Proc file system open handler */
2572 buzzz_proc_sys_open(struct inode
*inode
, struct file
*file
)
2574 return single_open(file
, buzzz_proc_sys_show
, NULL
);
2577 static const struct file_operations buzzz_proc_sys_fops
=
2579 .open
= buzzz_proc_sys_open
,
2581 .llseek
= seq_lseek
,
2582 .release
= single_release
2585 #endif /* CONFIG_PROC_FS */
2589 * -----------------------------------------------------------------------------
2590 * BUZZZ kernel space command line handling
2591 * -----------------------------------------------------------------------------
2594 int BUZZZ_NOINSTR_FUNC
2595 buzzz_kcall(uint32_t arg
)
2598 #if defined(BUZZZ_CONFIG_UNITTEST)
2600 printk(" 1. func unit test\n 2. pmon unit test\n"); break;
2601 case 1: buzzz_func_unittest(); break;
2602 case 2: buzzz_pmon_unittest(); break;
2603 case 3: buzzz_kevt_unittest(); break;
2604 #endif /* BUZZZ_CONFIG_UNITTEST */
2610 return BUZZZ_SUCCESS
;
2613 #if defined(CONFIG_MIPS)
2614 #include <bcmutils.h> /* bcm_chipname */
2615 #include <siutils.h> /* typedef struct si_pub si_t */
2616 #include <hndcpu.h> /* si_cpu_clock */
2617 #include <asm/cpu-features.h>
2618 extern si_t
*bcm947xx_sih
;
2619 #define sih bcm947xx_sih
2620 #endif /* CONFIG_MIPS */
2622 void BUZZZ_NOINSTR_FUNC
2623 buzzz_kernel_info(void)
2625 #if defined(CONFIG_MIPS)
2628 struct cpuinfo_mips
*c
= ¤t_cpu_data
;
2629 bcm_chipname(sih
->chip
, cn
, 8);
2630 hz
= si_cpu_clock(sih
);
2631 printk("CPU: BCM%s rev %d at %d MHz\n", cn
, sih
->chiprev
,
2632 (hz
+ 500000) / 1000000);
2633 printk("I-Cache %dkB, %d-way, linesize %d bytes.\n",
2634 c
->icache
.waysize
* c
->icache
.ways
, c
->icache
.ways
, c
->icache
.linesz
);
2635 printk("D-Cache %dkB, %d-way, linesize %d bytes.\n\n",
2636 c
->dcache
.waysize
* c
->dcache
.ways
, c
->dcache
.ways
, c
->dcache
.linesz
);
2637 #endif /* CONFIG_MIPS */
2639 printk("%s", linux_banner
);
2642 int BUZZZ_NOINSTR_FUNC
/* Display the runtime status */
2645 buzzz_kernel_info();
2647 printk(CLRbold
"%s" BUZZZ_VER_FMTS CLRnl
,
2648 BUZZZ_NAME
, BUZZZ_VER_FMT(BUZZZ_SYS_VERSION
));
2650 printk("Status:\t\t" CLRb
"%s" CLRnl
, str_buzzz_status(buzzz_g
.status
));
2651 printk("Wrap:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.wrap
);
2652 printk("Run:\t\t" CLRb
"%u" CLRnl
, buzzz_g
.run
);
2653 printk("Buf.log:\t" CLRb
"0x%p" CLRnl
, buzzz_g
.log
);
2654 printk("Buf.cur:\t" CLRb
"0x%p" CLRnl
, buzzz_g
.cur
);
2655 printk("Buf.end:\t" CLRb
"0x%p" CLRnl
, buzzz_g
.end
);
2657 printk("\nTool:\t\t" CLRb
"%s" CLRnl
, str_buzzz_tool(buzzz_g
.tool
));
2659 switch (buzzz_g
.tool
) {
2660 case BUZZZ_TOOL_FUNC
: buzzz_func_show(); break;
2661 case BUZZZ_TOOL_PMON
: buzzz_pmon_show(); break;
2662 case BUZZZ_TOOL_KEVT
: buzzz_kevt_show(); break;
2667 return BUZZZ_SUCCESS
;
2670 int BUZZZ_NOINSTR_FUNC
2671 buzzz_start_now(buzzz_t
* buzzz_p
)
2673 switch (buzzz_g
.tool
) {
2674 case BUZZZ_TOOL_FUNC
: buzzz_func_start(); break;
2675 case BUZZZ_TOOL_PMON
: buzzz_pmon_start(); break;
2676 case BUZZZ_TOOL_KEVT
: buzzz_kevt_start(); break;
2678 printk(CLRwarn
"Unsupported start for tool %s" CLRnl
,
2679 str_buzzz_tool(buzzz_g
.tool
));
2683 buzzz_p
->timer
.function
= NULL
;
2685 return BUZZZ_SUCCESS
;
2688 int BUZZZ_NOINSTR_FUNC
2689 buzzz_start(uint32_t after
)
2692 return buzzz_start_now(&buzzz_g
);
2695 if (buzzz_g
.timer
.function
!= NULL
) {
2696 printk(CLRwarn
"Timer already in use, overwriting" CLRnl
);
2697 del_timer(&buzzz_g
.timer
);
2699 setup_timer(&buzzz_g
.timer
,
2700 (timer_fn_t
)buzzz_start_now
, (unsigned long)&buzzz_g
);
2701 buzzz_g
.timer
.expires
= jiffies
+ after
;
2702 add_timer(&buzzz_g
.timer
);
2703 printk("BUZZZ deferred start after %u\n", after
);
2705 return BUZZZ_SUCCESS
;
2708 int BUZZZ_NOINSTR_FUNC
2709 buzzz_stop_now(buzzz_t
* buzzz_p
)
2711 switch (buzzz_g
.tool
) {
2712 case BUZZZ_TOOL_FUNC
: buzzz_func_stop(); break;
2713 case BUZZZ_TOOL_PMON
: buzzz_pmon_stop(); break;
2714 case BUZZZ_TOOL_KEVT
: buzzz_kevt_stop(); break;
2716 printk(CLRwarn
"Unsupported stop for tool %s" CLRnl
,
2717 str_buzzz_tool(buzzz_g
.tool
));
2720 buzzz_p
->timer
.function
= NULL
;
2722 return BUZZZ_SUCCESS
;
2725 int BUZZZ_NOINSTR_FUNC
2726 buzzz_stop(uint32_t after
)
2729 return buzzz_stop_now(&buzzz_g
);
2731 if (buzzz_g
.timer
.function
!= NULL
) {
2732 printk(CLRwarn
"Timer already in use, overwriting" CLRnl
);
2733 del_timer(&buzzz_g
.timer
);
2735 setup_timer(&buzzz_g
.timer
,
2736 (timer_fn_t
)buzzz_stop_now
, (unsigned long)&buzzz_g
);
2737 buzzz_g
.timer
.expires
= jiffies
+ after
;
2738 add_timer(&buzzz_g
.timer
);
2739 printk("BUZZZ deferred stop %u\n", after
);
2741 return BUZZZ_SUCCESS
;
2745 int BUZZZ_NOINSTR_FUNC
2748 if (buzzz_g
.status
== BUZZZ_STATUS_ENABLED
) {
2749 BUZZZ_FUNC_LOG(BUZZZ_RET_IP
);
2750 BUZZZ_FUNC_LOG(buzzz_pause
);
2752 buzzz_g
.status
= BUZZZ_STATUS_PAUSED
;
2755 return BUZZZ_SUCCESS
;
2758 int BUZZZ_NOINSTR_FUNC
2761 if (buzzz_g
.status
== BUZZZ_STATUS_PAUSED
) {
2762 buzzz_g
.status
= BUZZZ_STATUS_ENABLED
;
2764 BUZZZ_FUNC_LOG(BUZZZ_RET_IP
);
2765 BUZZZ_FUNC_LOG(buzzz_play
);
2768 return BUZZZ_SUCCESS
;
2771 int BUZZZ_NOINSTR_FUNC
2774 printk(CLRwarn
"Unsupported audit capability" CLRnl
);
2778 int BUZZZ_NOINSTR_FUNC
2779 buzzz_dump(uint32_t items
)
2781 switch (buzzz_g
.tool
) {
2782 case BUZZZ_TOOL_FUNC
: buzzz_func_dump(items
); break;
2783 case BUZZZ_TOOL_PMON
: buzzz_pmon_dump(); break;
2784 case BUZZZ_TOOL_KEVT
: buzzz_kevt_dump(items
); break;
2786 printk(CLRwarn
"Unsupported dump for tool %s" CLRnl
,
2787 str_buzzz_tool(buzzz_g
.tool
));
2791 return BUZZZ_SUCCESS
;
2794 int BUZZZ_NOINSTR_FUNC
/* Configure the tool that will use the logging system */
2795 buzzz_config_tool(buzzz_tool_t tool
)
2797 if (tool
> BUZZZ_TOOL_MAXIMUM
) {
2798 printk(CLRerr
"ERROR: Invalid tool %u" CLRnl
, tool
);
2802 BUZZZ_ASSERT_STATUS_DISABLED();
2804 buzzz_g
.tool
= tool
;
2806 switch (buzzz_g
.tool
) {
2807 case BUZZZ_TOOL_FUNC
: return buzzz_func_default();
2808 case BUZZZ_TOOL_PMON
: return buzzz_pmon_default();
2809 case BUZZZ_TOOL_KEVT
: return buzzz_kevt_default();
2811 printk(CLRerr
"Unsupported mode for tool %s" CLRnl
,
2812 str_buzzz_tool(buzzz_g
.tool
));
2816 return BUZZZ_SUCCESS
;
2819 int BUZZZ_NOINSTR_FUNC
/* Configure the mode of operation of the tool */
2820 buzzz_config_mode(buzzz_mode_t mode
)
2822 if ((mode
== BUZZZ_MODE_UNDEF
) || (mode
>= BUZZZ_MODE_MAXIMUM
)) {
2823 printk(CLRerr
"ERROR: Invalid mode %u" CLRnl
, mode
);
2827 BUZZZ_ASSERT_STATUS_DISABLED();
2829 switch (buzzz_g
.tool
) {
2830 case BUZZZ_TOOL_FUNC
:
2831 case BUZZZ_TOOL_KEVT
:
2832 if (mode
== BUZZZ_MODE_LIMITED
)
2833 buzzz_g
.config_limit
= BUZZZ_FUNC_LIMIT_LOGS
;
2835 case BUZZZ_TOOL_PMON
:
2836 if (mode
== BUZZZ_MODE_WRAPOVER
)
2837 buzzz_g
.config_limit
= BUZZZ_INVALID
;
2838 else if (mode
== BUZZZ_MODE_LIMITED
)
2839 buzzz_g
.config_limit
= BUZZZ_PMON_GROUP_GENERAL
;
2841 printk(CLRwarn
"Unsupported mode %s for %s" CLRnl
,
2842 str_buzzz_mode(mode
), str_buzzz_tool(buzzz_g
.tool
));
2847 printk(CLRerr
"Unsupported mode for tool %s" CLRnl
,
2848 str_buzzz_tool(buzzz_g
.tool
));
2852 buzzz_g
.config_mode
= mode
;
2854 return BUZZZ_SUCCESS
;
2857 int BUZZZ_NOINSTR_FUNC
/* Configure a limit parameter in the tool */
2858 buzzz_config_limit(uint32_t limit
)
2860 BUZZZ_ASSERT_STATUS_DISABLED();
2862 switch (buzzz_g
.tool
) {
2863 case BUZZZ_TOOL_FUNC
: /* limit number events logged from start */
2864 case BUZZZ_TOOL_KEVT
:
2865 buzzz_g
.config_mode
= BUZZZ_MODE_LIMITED
;
2867 case BUZZZ_TOOL_PMON
: /* limit the pmon group */
2868 buzzz_g
.config_mode
= BUZZZ_MODE_LIMITED
;
2869 if (limit
> BUZZZ_PMON_GROUPS
) {
2870 printk(CLRerr
"Invalid limit. max<%u>" CLRnl
,
2876 printk(CLRerr
"Unsupported limit for tool %s" CLRnl
,
2877 str_buzzz_tool(buzzz_g
.tool
));
2881 buzzz_g
.config_limit
= limit
;
2883 return BUZZZ_SUCCESS
;
2886 void BUZZZ_NOINSTR_FUNC
2887 buzzz_klog_reg(uint32_t klog_id
, char * klog_fmt
)
2889 if (klog_id
< BUZZZ_KLOG_MAXIMUM
)
2890 strncpy(buzzz_g
.klogs
[klog_id
], klog_fmt
, BUZZZ_KLOG_FMT_LENGTH
-1);
2892 printk(CLRwarn
"WARN: Too many events id<%u>" CLRnl
, klog_id
);
2896 * -----------------------------------------------------------------------------
2897 * BUZZZ Character Driver Ioctl handlers
2898 * -----------------------------------------------------------------------------
2900 static int BUZZZ_NOINSTR_FUNC
/* pre ioctl handling in character driver */
2901 buzzz_open(struct inode
*inodep
, struct file
*filep
)
2903 /* int minor = MINOR(inodep->i_rdev) & 0xf; */
2907 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
2908 static long BUZZZ_NOINSTR_FUNC
2909 buzzz_ioctl(struct file
*file
, unsigned int cmd
, unsigned long arg
)
2910 #else /* < linux-2.6.36 */
2911 static int BUZZZ_NOINSTR_FUNC
/* ioctl handler in character driver */
2912 buzzz_ioctl(struct inode
*inode
, struct file
*file
,
2913 unsigned int cmd
, unsigned long arg
)
2914 #endif /* < linux-2.6.36 */
2916 int ret
= BUZZZ_ERROR
;
2918 BUZZZ_PRINT("cmd<%s>", str_buzzz_ioctl(cmd
));
2921 case BUZZZ_IOCTL_KCALL
:
2922 BUZZZ_PRINT("invoke buzzz_kcall %lu", arg
);
2923 return buzzz_kcall(arg
);
2925 case BUZZZ_IOCTL_CONFIG_TOOL
:
2926 BUZZZ_PRINT("invoke buzzz_config_tool %s", str_buzzz_tool(arg
));
2927 if ((buzzz_tool_t
)arg
< BUZZZ_TOOL_MAXIMUM
)
2928 return buzzz_config_tool((buzzz_tool_t
)arg
);
2932 case BUZZZ_IOCTL_CONFIG_MODE
:
2933 BUZZZ_PRINT("invoke buzzz_config_mode %s", str_buzzz_mode(arg
));
2934 if ((buzzz_mode_t
)arg
< BUZZZ_MODE_MAXIMUM
)
2935 return buzzz_config_mode((buzzz_mode_t
)arg
);
2939 case BUZZZ_IOCTL_CONFIG_LIMIT
:
2940 BUZZZ_PRINT("invoke buzzz_config_limit %lu", arg
);
2941 return buzzz_config_limit(arg
);
2943 case BUZZZ_IOCTL_CONFIG_FUNC
:
2944 BUZZZ_PRINT("invoke buzzz_func_config %lu", arg
);
2945 return buzzz_func_config(arg
);
2947 case BUZZZ_IOCTL_CONFIG_PMON
:
2948 BUZZZ_PRINT("invoke buzzz_pmon_config %lu %lu",
2949 (arg
& 0xFFFF), (arg
>> 16));
2950 return buzzz_pmon_config((arg
& 0xFFFF), (arg
>> 16));
2952 case BUZZZ_IOCTL_CONFIG_KEVT
:
2953 BUZZZ_PRINT("invoke buzzz_kevt_config %lu", arg
);
2954 return buzzz_kevt_config(arg
);
2956 case BUZZZ_IOCTL_SHOW
:
2957 BUZZZ_PRINT("invoke buzzz_show");
2958 return buzzz_show();
2960 case BUZZZ_IOCTL_START
:
2961 BUZZZ_PRINT("invoke buzzz_start %lu", arg
);
2962 return buzzz_start(arg
);
2964 case BUZZZ_IOCTL_STOP
:
2965 BUZZZ_PRINT("invoke buzzz_stop %lu", arg
);
2966 return buzzz_stop(arg
);
2969 case BUZZZ_IOCTL_PAUSE
:
2970 BUZZZ_PRINT("invoke buzzz_pause");
2971 return buzzz_pause();
2973 case BUZZZ_IOCTL_PLAY
:
2974 BUZZZ_PRINT("invoke buzzz_play");
2975 return buzzz_play();
2977 case BUZZZ_IOCTL_AUDIT
:
2978 BUZZZ_PRINT("invoke buzzz_audit");
2979 return buzzz_audit();
2981 case BUZZZ_IOCTL_DUMP
:
2982 BUZZZ_PRINT("invoke buzzz_dump %lu", arg
);
2983 return buzzz_dump(arg
);
2992 static int BUZZZ_NOINSTR_FUNC
/* post ioct handling in character driver */
2993 buzzz_release(struct inode
*inodep
, struct file
*filep
)
2998 static const struct file_operations buzzz_fops
=
3001 .release
= buzzz_release
,
3002 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
3003 .unlocked_ioctl
= buzzz_ioctl
,
3004 .compat_ioctl
= buzzz_ioctl
3005 #else /* < linux-2.6.36 */
3006 .ioctl
= buzzz_ioctl
3007 #endif /* < linux-2.6.36 */
3011 * -----------------------------------------------------------------------------
3012 * BUZZZ (linked into kernel) initialization (late level)
3013 * Should BUZZZ be a dynamically loaded module ....?
3014 * -----------------------------------------------------------------------------
3016 static struct miscdevice buzzz_dev
=
3018 .minor
= MISC_DYNAMIC_MINOR
,
3023 /* Initialization of Buzzz during loading time */
3024 static int BUZZZ_NOINSTR_FUNC
3025 __init
__init_buzzz(void)
3030 #if defined(CONFIG_PROC_FS)
3031 struct proc_dir_entry
*ent_sys
, *ent_log
;
3032 #endif /* CONFIG_PROC_FS */
3034 /* Create a 'miscelaneous' character driver and register with sysfs */
3035 if ((err
= misc_register(&buzzz_dev
)) != 0) {
3036 printk(CLRerr
"ERROR[%d] Register device %s" BUZZZ_VER_FMTS CLRnl
, err
,
3037 BUZZZ_DEV_PATH
, BUZZZ_VER_FMT(BUZZZ_DEV_VERSION
));
3040 printk(CLRb
"Registered device %s" BUZZZ_VER_FMTS
" <%d,%d>" CLRnl
,
3041 BUZZZ_DEV_PATH
, BUZZZ_VER_FMT(BUZZZ_DEV_VERSION
),
3042 MISC_MAJOR
, buzzz_dev
.minor
);
3045 /* Allocate Buzzz buffer */
3046 buzzz_g
.log
= (void *)kmalloc(BUZZZ_LOG_BUFSIZE
, GFP_KERNEL
);
3047 if (buzzz_g
.log
== (void*)NULL
) {
3048 printk(CLRerr
"ERROR: Log allocation %s" BUZZZ_VER_FMTS CLRnl
,
3049 BUZZZ_NAME
, BUZZZ_VER_FMT(BUZZZ_SYS_VERSION
));
3051 goto fail_dev_dereg
;
3053 memset(buzzz_g
.log
, 0, BUZZZ_LOG_BUFSIZE
);
3055 buzzz_g
.cur
= buzzz_g
.log
;
3056 buzzz_g
.end
= (void*)((char*)buzzz_g
.log
- BUZZZ_LOGENTRY_MAXSZ
);
3058 #if defined(CONFIG_PROC_FS)
3059 /* Construct a Proc filesystem entry for Buzzz */
3061 proc_mkdir(BUZZZ_NAME
, NULL
);
3063 ent_sys
= create_proc_entry(BUZZZ_NAME
"/sys", 0, NULL
);
3065 ent_sys
->proc_fops
= &buzzz_proc_sys_fops
;
3067 printk(CLRerr
"ERROR: BUZZZ sys proc register %s" BUZZZ_VER_FMTS CLRnl
,
3068 BUZZZ_NAME
, BUZZZ_VER_FMT(BUZZZ_SYS_VERSION
));
3072 ent_log
= create_proc_read_entry(BUZZZ_NAME
"/log", 0, NULL
,
3073 buzzz_proc_log_show
, (void*)&buzzz_g
);
3074 if (ent_log
== (struct proc_dir_entry
*)NULL
) {
3075 printk(CLRerr
"ERROR: BUZZZ log proc register %s" BUZZZ_VER_FMTS CLRnl
,
3076 BUZZZ_NAME
, BUZZZ_VER_FMT(BUZZZ_SYS_VERSION
));
3079 #endif /* CONFIG_PROC_FS */
3081 if (_init_buzzz_func() == BUZZZ_ERROR
) {
3082 printk(CLRerr
"ERROR: Initialize Func Tool" CLRnl
);
3086 if (_init_buzzz_pmon() == BUZZZ_ERROR
) {
3087 printk(CLRerr
"ERROR: Initialize PMon Tool" CLRnl
);
3091 if (_init_buzzz_kevt() == BUZZZ_ERROR
) {
3092 printk(CLRerr
"ERROR: Initialize KEvt Tool" CLRnl
);
3096 for (i
= 0; i
< BUZZZ_KLOG_MAXIMUM
; i
++) {
3097 sprintf(event_str
, "%sUNREGISTERED EVENT<%u>%s", CLRm
, i
, CLRnorm
);
3098 buzzz_klog_reg(i
, event_str
);
3101 buzzz_g
.status
= BUZZZ_STATUS_DISABLED
;
3103 return BUZZZ_SUCCESS
; /* Successful initialization of Buzzz */
3105 #if defined(CONFIG_PROC_FS)
3107 #endif /* CONFIG_PROC_FS */
3111 misc_deregister(&buzzz_dev
);
3113 return BUZZZ_ERROR
; /* Failed initialization of Buzzz */
3116 late_initcall(__init_buzzz
); /* init level 7 */
3118 EXPORT_SYMBOL(buzzz_start
);
3119 EXPORT_SYMBOL(buzzz_stop
);
3120 EXPORT_SYMBOL(buzzz_pause
);
3121 EXPORT_SYMBOL(buzzz_play
);
3122 EXPORT_SYMBOL(buzzz_audit
);
3123 EXPORT_SYMBOL(buzzz_dump
);
3124 EXPORT_SYMBOL(buzzz_config_tool
);
3125 EXPORT_SYMBOL(buzzz_config_mode
);
3126 EXPORT_SYMBOL(buzzz_config_limit
);
3127 EXPORT_SYMBOL(buzzz_klog_reg
);
3128 EXPORT_SYMBOL(buzzz_kcall
);
3130 EXPORT_SYMBOL(__cyg_profile_func_enter
);
3131 EXPORT_SYMBOL(__cyg_profile_func_exit
);
3133 EXPORT_SYMBOL(buzzz_func_log0
);
3134 EXPORT_SYMBOL(buzzz_func_log1
);
3135 EXPORT_SYMBOL(buzzz_func_log2
);
3136 EXPORT_SYMBOL(buzzz_func_log3
);
3137 EXPORT_SYMBOL(buzzz_func_start
);
3138 EXPORT_SYMBOL(buzzz_func_stop
);
3139 EXPORT_SYMBOL(buzzz_func_panic
);
3140 EXPORT_SYMBOL(buzzz_func_dump
);
3141 EXPORT_SYMBOL(buzzz_func_config
);
3143 EXPORT_SYMBOL(buzzz_pmon_bgn
);
3144 EXPORT_SYMBOL(buzzz_pmon_clr
);
3145 EXPORT_SYMBOL(buzzz_pmon_log
);
3146 EXPORT_SYMBOL(buzzz_pmon_end
);
3147 EXPORT_SYMBOL(buzzz_pmon_start
);
3148 EXPORT_SYMBOL(buzzz_pmon_stop
);
3149 EXPORT_SYMBOL(buzzz_pmon_config
);
3150 #if defined(BUZZZ_CONFIG_PMON_USR)
3151 EXPORT_SYMBOL(buzzz_pmon_usr_g
);
3152 #endif /* BUZZZ_CONFIG_PMON_USR */
3154 EXPORT_SYMBOL(buzzz_kevt_log0
);
3155 EXPORT_SYMBOL(buzzz_kevt_log1
);
3156 EXPORT_SYMBOL(buzzz_kevt_log2
);
3157 EXPORT_SYMBOL(buzzz_kevt_log3
);
3158 EXPORT_SYMBOL(buzzz_kevt_log4
);
3159 EXPORT_SYMBOL(buzzz_kevt_start
);
3160 EXPORT_SYMBOL(buzzz_kevt_stop
);
3161 EXPORT_SYMBOL(buzzz_kevt_dump
);
3162 EXPORT_SYMBOL(buzzz_kevt_config
);