RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / arch / arm / plat-brcm / buzzz.c
blobf7be641b847e02ff4f8b8ff7cbbadb7807bf8ffa
1 /*
2 * Broadcom BCM47xx Buzzz based Kernel Profiling and Debugging
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
5 *
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.
9 *
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.
18 * $Id$
20 * -----------------------------------------------------------------------------
22 * Filename : buzzz.c
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>
50 #include <linux/fs.h>
51 #include <linux/proc_fs.h>
52 #include <linux/seq_file.h>
53 #include <linux/in.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 */
77 /* defines */
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);
129 * #undef IP4DOTQ
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 */
141 #undef BUZZZ_ENUM
142 #define BUZZZ_ENUM(val) #val,
144 static const char * _str_INV = "INVALID";
146 static const char * _str_buzzz_tool[BUZZZ_TOOL_MAXIMUM] =
148 BUZZZ_ENUM(UNDEF)
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] =
162 BUZZZ_ENUM(DISABLED)
163 BUZZZ_ENUM(ENABLED)
164 BUZZZ_ENUM(PAUSED)
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] =
175 BUZZZ_ENUM(UNDEF)
176 BUZZZ_ENUM(WRAPOVER)
177 BUZZZ_ENUM(LIMITED)
178 BUZZZ_ENUM(TRANSMIT)
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] =
188 BUZZZ_ENUM(KCALL)
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)
198 BUZZZ_ENUM(SHOW)
199 BUZZZ_ENUM(START)
200 BUZZZ_ENUM(STOP)
201 BUZZZ_ENUM(PAUSE)
202 BUZZZ_ENUM(PLAY)
203 BUZZZ_ENUM(AUDIT)
204 BUZZZ_ENUM(DUMP)
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] =
217 BUZZZ_ENUM(RESET)
218 BUZZZ_ENUM(GENERAL)
219 BUZZZ_ENUM(ICACHE)
220 BUZZZ_ENUM(DCACHE)
221 BUZZZ_ENUM(TLB)
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] =
234 /* group 0: RESET */
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 */
246 /* group 2 ICACHE */
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 */
252 /* group 3 DCACHE */
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 */
258 /* group 4 TLB */
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] =
317 BUZZZ_ENUM(RESET)
318 BUZZZ_ENUM(GENERAL)
319 BUZZZ_ENUM(ICACHE)
320 BUZZZ_ENUM(DCACHE)
321 BUZZZ_ENUM(TLB)
322 BUZZZ_ENUM(DATA)
323 BUZZZ_ENUM(SPURIOUS)
324 BUZZZ_ENUM(BRANCHES)
325 BUZZZ_ENUM(MISCELLANEOUS)
328 static const char * _str_buzzz_pmon_event[BUZZZ_PMON_EVENT_MAXIMUM] =
330 /* group 0: RESET */
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 */
354 /* group 4: TLB */
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 */
360 /* group 5: DATA */
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] =
401 BUZZZ_ENUM(RESET)
402 BUZZZ_ENUM(GENERAL)
403 BUZZZ_ENUM(ICACHE)
404 BUZZZ_ENUM(DCACHE)
405 BUZZZ_ENUM(TLB)
406 BUZZZ_ENUM(BRANCH)
409 static const char * _str_buzzz_kevt_event[BUZZZ_KEVT_EVENT_MAXIMUM] =
411 /* group 0: RESET */
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 */
427 /* group 4: TLB */
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 */
459 typedef
460 struct buzzz_pmon_ctl
462 uint8_t u8[BUZZZ_PMON_COUNTERS];
463 } buzzz_pmon_ctl_t;
465 typedef
466 struct buzzz_pmon_ctr
468 uint32_t u32[4];
469 } buzzz_pmon_ctr_t;
471 typedef
472 struct buzzz_pmonst
474 buzzz_pmon_ctr_t min, max, sum;
475 } buzzz_pmonst_t;
477 #if defined(BUZZZ_CONFIG_PMON_USR)
478 unsigned int buzzz_pmon_usr_g;
480 typedef
481 struct buzzz_pmon_usr
483 unsigned int min, max, sum;
484 } buzzz_pmon_usr_t;
486 typedef
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 */
495 struct buzzz_priv
497 union
499 struct
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 */
508 } func;
510 struct
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;
529 } pmon;
531 struct
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 */
539 bool skip;
540 } kevt;
543 } buzzz_priv_t;
546 typedef /* Buzzz global structure */
547 struct buzzz
549 #if defined(CONFIG_SMP)
550 spinlock_t lock;
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 */
560 void * log;
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];
571 char page[4096];
572 } buzzz_t;
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,
582 .wrap = BUZZZ_FALSE,
583 .run = 0U,
584 .cur = (void *)NULL,
585 .end = (void *)NULL,
586 .log = (void*)NULL,
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;
604 buzzz_g.run += 1U;
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)
633 uint32_t total;
634 void * log;
636 if (buzzz_g.wrap == BUZZZ_TRUE)
637 total = (BUZZZ_AVAIL_BUFSIZE / log_size);
638 else
639 total = count;
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);
647 if (total > limit)
648 total = limit;
650 printk(CLRbold "BUZZZ_DUMP BGN total<%u>" CLRnl, total);
652 if (total == 0U) {
653 printk(CLRbold "BUZZZ_DUMP END" CLRnl);
654 return;
657 if (limit != BUZZZ_INVALID) { /* dump limited last few logs */
658 uint32_t part1;
660 part1 = ((uint32_t)buzzz_g.cur - (uint32_t)buzzz_g.log) / log_size;
662 if (total > part1) { /* some events prior to wrap */
663 uint32_t part2;
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));
672 total -= part2;
674 BUZZZ_PRINT("log<%p> part2<%u>", log, part2);
675 while (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);
685 while (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)
739 typedef
740 struct buzzz_func_log
742 union {
743 uint32_t u32;
744 void * func;
745 struct {
746 uint32_t rsvd : 1;
747 uint32_t is_klog : 1; /* BUZZZ_FUNC_LOGISEVT: 0:func, 1=evt */
748 uint32_t args : 14; /* number of arguments logged */
749 uint32_t id : 16;
750 } klog;
752 struct {
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 */
756 } site;
757 } arg0;
759 uint32_t arg1;
760 uint32_t arg2;
761 uint32_t arg3;
763 } buzzz_func_log_t;
765 static BUZZZ_INLINE int BUZZZ_NOINSTR_FUNC
766 _buzzz_symbol(char *p, unsigned long address)
768 int bytes = 0;
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);
777 else {
778 *eos = '\0';
779 sscanf(eos+1, "0x%lx", &offset);
780 bytes += sprintf(p + bytes, " %s" CLRnorm, symbol_buf);
781 if (offset)
782 bytes += sprintf(p + bytes, " +0x%lx", offset);
783 bytes += sprintf(p + bytes, "\n");
785 return bytes;
788 static BUZZZ_INLINE int BUZZZ_NOINSTR_FUNC
789 _buzzz_func_indent(char *p)
791 int bytes = 0;
792 if (buzzz_g.priv.func.config_exit) {
793 uint32_t indent;
794 for (indent = 0U; indent < buzzz_g.priv.func.indent; indent++)
795 bytes += sprintf(p + bytes, BUZZZ_FUNC_INDENT_STRING);
797 return bytes;
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;
804 int bytes = 0;
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) {
812 case 0:
813 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id]);
814 break;
815 case 1:
816 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id],
817 log->arg1);
818 break;
819 case 2:
820 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id],
821 log->arg1, log->arg2);
822 break;
823 case 3:
824 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id],
825 log->arg1, log->arg2, log->arg3);
826 break;
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 "=>");
841 else
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);
852 return bytes;
855 #define _BUZZZ_FUNC_BGN(flags) \
856 if (buzzz_g.tool != BUZZZ_TOOL_FUNC) return; \
857 if (buzzz_g.status != BUZZZ_STATUS_ENABLED) return; \
858 BUZZZ_LOCK(flags); \
859 if (buzzz_g.config_mode == BUZZZ_MODE_LIMITED) { \
860 if (buzzz_g.priv.func.limit == 0U) { \
861 _buzzz_pre_stop(); \
862 BUZZZ_UNLOCK(flags); \
863 return; \
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; \
875 BUZZZ_UNLOCK(flags);
878 void BUZZZ_NOINSTR_FUNC /* -finstrument compiler stub on function entry */
879 __cyg_profile_func_enter(void * called, void * caller)
881 unsigned long flags;
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)
890 unsigned long flags;
891 if (buzzz_g.priv.func.config_exit == BUZZZ_DISABLE)
892 return;
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)
902 unsigned long flags;
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)
912 unsigned long flags;
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)
924 unsigned long flags;
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)
937 unsigned long flags;
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);
953 return;
956 _buzzz_pre_start();
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;
965 _buzzz_post_start();
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);
977 _buzzz_pre_stop();
979 if (buzzz_g.wrap == BUZZZ_TRUE)
980 buzzz_g.priv.func.log_count
981 = (BUZZZ_AVAIL_BUFSIZE / sizeof(buzzz_func_log_t));
982 else
983 buzzz_g.priv.func.log_count = buzzz_g.priv.func.count;
984 buzzz_g.priv.func.log_index = 0U;
986 _buzzz_post_stop();
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)
994 return;
996 if (buzzz_g.status != BUZZZ_STATUS_DISABLED) {
997 buzzz_func_stop();
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));
1021 printk("\n");
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);
1030 return BUZZZ_ERROR;
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)
1061 return BUZZZ_ERROR;
1063 if (sizeof(buzzz_func_log_t) != 16)
1064 return BUZZZ_ERROR;
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.
1096 static
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))
1120 static
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)
1137 union cp15_c9_REG {
1138 uint32_t u32;
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 {
1152 uint32_t u32;
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 {
1168 uint32_t u32;
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 {
1176 uint32_t u32;
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 {
1184 uint32_t u32;
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,
1199 pmcr.enable);
1200 return pmcr.u32;
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)
1228 uint32_t u32 = 1;
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();
1241 pmcr.enable = 1;
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)
1272 uint32_t v32;
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));
1277 return 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)
1360 uint32_t log, ctr;
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]);
1370 else
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)
1394 uint32_t log, ctr;
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)
1421 uint32_t mode;
1422 uint32_t log, ctr;
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;
1442 /* Event values */
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 */
1477 } else
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 */
1494 return;
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)
1506 return;
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);
1511 buzzz_pmon_stop();
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();
1522 return;
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;
1540 else
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;
1558 else
1559 buzzz_g.priv.pmon.groupid++;
1561 if (buzzz_g.priv.pmon.groupid >= BUZZZ_PMON_GROUPS)
1562 buzzz_pmon_stop();
1563 else
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;
1582 else
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++)
1589 tot.u32[ctr] = 0U;
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),
1597 "NANO_SECONDS",
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));
1601 } else {
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);
1618 #else
1619 printk(CLRnl);
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",
1632 log->sum.u32[1],
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]);
1636 } else {
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");
1654 } else {
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++)
1660 tot.u32[ctr] = 0U;
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);
1669 #else
1670 printk(CLRnl);
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",
1678 log->min.u32[1],
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]);
1682 } else {
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");
1697 } else {
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++)
1703 tot.u32[ctr] = 0U;
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);
1712 #else
1713 printk(CLRnl);
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",
1721 log->max.u32[1],
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]);
1725 } else {
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");
1740 } else {
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)
1746 break;
1750 void BUZZZ_NOINSTR_FUNC
1751 buzzz_pmon_start(void)
1753 _buzzz_pre_start();
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) {
1777 _buzzz_pre_stop();
1779 _buzzz_pmon_bind(BUZZZ_PMON_GROUP_RESET);
1781 _buzzz_pmon_disable();
1783 buzzz_pmon_dump();
1785 _buzzz_post_stop();
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));
1805 printk("\n");
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)
1814 uint32_t evt;
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);
1819 return BUZZZ_ERROR;
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);
1825 return BUZZZ_ERROR;
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);
1832 return BUZZZ_ERROR;
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 * -----------------------------------------------------------------------------
1875 typedef
1876 struct buzzz_kevt_log
1878 uint32_t ctr[BUZZZ_KEVT_COUNTERS];
1879 union {
1880 uint32_t u32;
1881 struct {
1882 uint32_t core : 1;
1883 uint32_t rsvd : 7;
1884 uint32_t args : 8;
1885 uint32_t id : 16;
1886 } klog;
1887 } arg0;
1888 uint32_t arg1;
1889 uint32_t arg2, arg3, arg4, arg5;
1890 } buzzz_kevt_log_t;
1892 typedef
1893 struct buzzz_kevt_ctl
1895 uint8_t u8[BUZZZ_KEVT_COUNTERS];
1896 } buzzz_kevt_ctl_t;
1898 #if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1899 static
1900 buzzz_kevt_ctl_t buzzz_kevtctl_g[BUZZZ_KEVT_GROUPS] =
1902 /* ctl0 ctl1 */
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;
1961 cur->arg1 = arg1;
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;
1980 cur->arg1 = arg1;
1981 cur->arg2 = arg2;
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;
2000 cur->arg1 = arg1;
2001 cur->arg2 = arg2;
2002 cur->arg3 = arg3;
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;
2022 cur->arg1 = arg1;
2023 cur->arg2 = arg2;
2024 cur->arg3 = arg3;
2025 cur->arg4 = arg4;
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)
2049 uint32_t mode, ctr;
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;
2066 else
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;
2078 int cpu;
2079 _buzzz_pre_start();
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,
2087 cpu);
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);
2106 _buzzz_pre_stop();
2108 on_each_cpu(_buzzz_kevt_bind, &group, 1);
2109 on_each_cpu(_buzzz_kevt_disable, NULL, 1);
2111 _buzzz_post_stop();
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);
2121 break;
2122 case BUZZZ_KEVT_ID_IRQ_ACK_BAD:
2123 bytes += sprintf(p + bytes, CLRerr "IRQ_ACK_BAD %u", log->arg1);
2124 break;
2125 case BUZZZ_KEVT_ID_IRQ_MISROUTED:
2126 bytes += sprintf(p + bytes, CLRerr "IRQ_MISROUTED %u", log->arg1);
2127 break;
2128 case BUZZZ_KEVT_ID_IRQ_RESEND:
2129 bytes += sprintf(p + bytes, CLRerr "IRQ_RESEND %u", log->arg1);
2130 break;
2131 case BUZZZ_KEVT_ID_IRQ_CHECK:
2132 bytes += sprintf(p + bytes, CLRerr "IRQ_CHECK %u", log->arg1);
2133 break;
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);
2137 return bytes;
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);
2141 return bytes;
2142 case BUZZZ_KEVT_ID_SIRQ_ENTRY:
2143 bytes += sprintf(p + bytes, CLRm ">>> SOFTIRQ ");
2144 bytes += _buzzz_symbol(p + bytes, log->arg1);
2145 return bytes;
2146 case BUZZZ_KEVT_ID_SIRQ_EXIT:
2147 bytes += sprintf(p + bytes, CLRm "<<< SOFTIRQ ");
2148 bytes += _buzzz_symbol(p + bytes, log->arg1);
2149 return bytes;
2150 case BUZZZ_KEVT_ID_WORKQ_ENTRY:
2151 bytes += sprintf(p + bytes, CLRb ">>>>> WORKQ ");
2152 bytes += _buzzz_symbol(p + bytes, log->arg1);
2153 return bytes;
2154 case BUZZZ_KEVT_ID_WORKQ_EXIT:
2155 bytes += sprintf(p + bytes, CLRb "<<<<< WORKQ ");
2156 bytes += _buzzz_symbol(p + bytes, log->arg1);
2157 return bytes;
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);
2167 break;
2169 case BUZZZ_KEVT_ID_SCHED_TICK:
2170 bytes += sprintf(p + bytes, CLRb "\tscheduler tick jiffies<%u>",
2171 log->arg1);
2172 break;
2173 case BUZZZ_KEVT_ID_SCHED_HRTICK:
2174 bytes += sprintf(p + bytes, CLRb "sched hrtick");
2175 break;
2176 case BUZZZ_KEVT_ID_GTIMER_EVENT:
2177 bytes += sprintf(p + bytes, CLRb "\tgtimer ");
2178 bytes += _buzzz_symbol(p + bytes, log->arg1);
2179 return bytes;
2180 case BUZZZ_KEVT_ID_GTIMER_NEXT:
2181 bytes += sprintf(p + bytes, CLRb "\tgtimer next<%u>", log->arg1);
2182 break;
2184 bytes += sprintf(p + bytes, "%s", CLRnl);
2185 return bytes;
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];
2194 int bytes = 0;
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]);
2206 else
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;
2214 return bytes;
2215 } else if ((delta[0] > 1000000000) || (delta[1] > 1000000000)) {
2216 bytes += sprintf(p + bytes, CLRerr "---skipping log bug? ---" CLRnl);
2217 return bytes;
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);
2232 } else {
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) {
2245 case 0:
2246 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id]);
2247 break;
2248 case 1:
2249 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id],
2250 log->arg1);
2251 break;
2252 case 2:
2253 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id],
2254 log->arg1, log->arg2);
2255 break;
2256 case 3:
2257 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id],
2258 log->arg1, log->arg2, log->arg3);
2259 break;
2260 case 4:
2261 bytes += sprintf(p + bytes, buzzz_g.klogs[log->arg0.klog.id],
2262 log->arg1, log->arg2, log->arg3, log->arg4);
2263 break;
2264 default:
2265 break;
2268 bytes += sprintf(p + bytes, "%s", CLRnl);
2269 return bytes;
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);
2281 } else {
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));
2310 printk("\n");
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);
2319 return BUZZZ_ERROR;
2320 #endif /* CONFIG_BUZZZ_FUNC */
2322 #if !defined(CONFIG_ARM)
2323 printk(CLRerr "BUZZZ::KEVT not ported to MIPS" CLRnl);
2324 return BUZZZ_ERROR;
2325 #else /* CONFIG_ARM */
2326 if (_armv7_pmcntenset_test() != 0U) {
2327 printk(CLRerr "PMU counters are in use" CLRnl);
2328 return BUZZZ_ERROR;
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);
2353 return BUZZZ_ERROR;
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)
2369 return BUZZZ_ERROR;
2371 if (sizeof(buzzz_kevt_log_t) != 32)
2372 return BUZZZ_ERROR;
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);
2392 buzzz_stop(0U);
2395 static void BUZZZ_NOINSTR_FUNC
2396 buzzz_pmon_unittest(void)
2398 int i;
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++) {
2423 buzzz_pmon_bgn();
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 */
2437 buzzz_pmon_log(11);
2438 buzzz_pmon_log(12);
2439 buzzz_pmon_log(13);
2440 buzzz_pmon_log(14);
2441 buzzz_pmon_log(15);
2442 buzzz_pmon_log(16);
2443 buzzz_pmon_log(17);
2444 buzzz_pmon_log(18);
2445 buzzz_pmon_log(19);
2446 buzzz_pmon_log(20);
2448 buzzz_pmon_end(20);
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)
2520 int bytes = 0;
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));
2540 else
2541 log = cur + index;
2542 } else {
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);
2555 goto done;
2559 bytes += buzzz_func_dump_log(page + bytes, log);
2561 buzzz_g.priv.func.log_index++;
2564 /* do not place any code here */
2566 done:
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,
2580 .read = seq_read,
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)
2597 switch (arg) {
2598 #if defined(BUZZZ_CONFIG_UNITTEST)
2599 case 0:
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 */
2606 default:
2607 break;
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)
2626 unsigned int hz;
2627 char cn[8];
2628 struct cpuinfo_mips *c = &current_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 */
2643 buzzz_show(void)
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;
2663 default:
2664 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;
2677 default:
2678 printk(CLRwarn "Unsupported start for tool %s" CLRnl,
2679 str_buzzz_tool(buzzz_g.tool));
2680 return BUZZZ_ERROR;
2683 buzzz_p->timer.function = NULL;
2685 return BUZZZ_SUCCESS;
2688 int BUZZZ_NOINSTR_FUNC
2689 buzzz_start(uint32_t after)
2691 if (after == 0U) {
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;
2715 default:
2716 printk(CLRwarn "Unsupported stop for tool %s" CLRnl,
2717 str_buzzz_tool(buzzz_g.tool));
2718 return BUZZZ_ERROR;
2720 buzzz_p->timer.function = NULL;
2722 return BUZZZ_SUCCESS;
2725 int BUZZZ_NOINSTR_FUNC
2726 buzzz_stop(uint32_t after)
2728 if (after == 0U) {
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
2746 buzzz_pause(void)
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
2759 buzzz_play(void)
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
2772 buzzz_audit(void)
2774 printk(CLRwarn "Unsupported audit capability" CLRnl);
2775 return BUZZZ_ERROR;
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;
2785 default:
2786 printk(CLRwarn "Unsupported dump for tool %s" CLRnl,
2787 str_buzzz_tool(buzzz_g.tool));
2788 return BUZZZ_ERROR;
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);
2799 return BUZZZ_ERROR;
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();
2810 default:
2811 printk(CLRerr "Unsupported mode for tool %s" CLRnl,
2812 str_buzzz_tool(buzzz_g.tool));
2813 return BUZZZ_ERROR;
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);
2824 return BUZZZ_ERROR;
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;
2834 break;
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;
2840 else {
2841 printk(CLRwarn "Unsupported mode %s for %s" CLRnl,
2842 str_buzzz_mode(mode), str_buzzz_tool(buzzz_g.tool));
2843 return BUZZZ_ERROR;
2845 break;
2846 default:
2847 printk(CLRerr "Unsupported mode for tool %s" CLRnl,
2848 str_buzzz_tool(buzzz_g.tool));
2849 return BUZZZ_ERROR;
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;
2866 break;
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,
2871 BUZZZ_PMON_GROUPS);
2872 return BUZZZ_ERROR;
2874 break;
2875 default:
2876 printk(CLRerr "Unsupported limit for tool %s" CLRnl,
2877 str_buzzz_tool(buzzz_g.tool));
2878 return BUZZZ_ERROR;
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);
2891 else
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; */
2904 return 0;
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));
2920 switch (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);
2929 else
2930 return BUZZZ_ERROR;
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);
2936 else
2937 return BUZZZ_ERROR;
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);
2985 default:
2986 return -EINVAL;
2989 return ret;
2992 static int BUZZZ_NOINSTR_FUNC /* post ioct handling in character driver */
2993 buzzz_release(struct inode *inodep, struct file *filep)
2995 return 0;
2998 static const struct file_operations buzzz_fops =
3000 .open = buzzz_open,
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,
3019 .name = BUZZZ_NAME,
3020 .fops = &buzzz_fops
3023 /* Initialization of Buzzz during loading time */
3024 static int BUZZZ_NOINSTR_FUNC
3025 __init __init_buzzz(void)
3027 int err, i;
3028 char event_str[64];
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));
3038 return err;
3039 } else {
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;
3052 } else {
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);
3064 if (ent_sys) {
3065 ent_sys->proc_fops = &buzzz_proc_sys_fops;
3066 } else {
3067 printk(CLRerr "ERROR: BUZZZ sys proc register %s" BUZZZ_VER_FMTS CLRnl,
3068 BUZZZ_NAME, BUZZZ_VER_FMT(BUZZZ_SYS_VERSION));
3069 goto fail_free_log;
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));
3077 goto fail_free_log;
3079 #endif /* CONFIG_PROC_FS */
3081 if (_init_buzzz_func() == BUZZZ_ERROR) {
3082 printk(CLRerr "ERROR: Initialize Func Tool" CLRnl);
3083 goto fail_free_log;
3086 if (_init_buzzz_pmon() == BUZZZ_ERROR) {
3087 printk(CLRerr "ERROR: Initialize PMon Tool" CLRnl);
3088 goto fail_free_log;
3091 if (_init_buzzz_kevt() == BUZZZ_ERROR) {
3092 printk(CLRerr "ERROR: Initialize KEvt Tool" CLRnl);
3093 goto fail_free_log;
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)
3106 fail_free_log:
3107 #endif /* CONFIG_PROC_FS */
3108 kfree(buzzz_g.log);
3110 fail_dev_dereg:
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);