• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/plat-brcm/
1/*
2 * Broadcom BCM47xx Buzzz based Kernel Profiling and Debugging
3 *
4 * Copyright (C) 2013, 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.
17 *
18 * $Id$
19 *
20 * -----------------------------------------------------------------------------
21 *
22 * Filename     : buzzz.c
23 * Description  : Implementation of buzzz.c.
24 *
25 * Buzzz, a work in progress, provides 4 capabilities, namely,
26 *
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.
40 *
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.
44 *
45 * -----------------------------------------------------------------------------
46 */
47
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>
71
72#if defined(CC_BUZZZ_DEBUG)
73unsigned int buzzz_debug = 0U;
74EXPORT_SYMBOL(buzzz_debug);
75#endif  /*  CC_BUZZZ_DEBUG */
76
77/* defines */
78
79/* Maximum length of a single log entry cannot exceed 64 bytes */
80#define BUZZZ_LOGENTRY_MAXSZ    (64)
81
82/* Length of the buffer available for logging */
83#define BUZZZ_AVAIL_BUFSIZE     (BUZZZ_LOG_BUFSIZE - BUZZZ_LOGENTRY_MAXSZ)
84
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 */
93
94/*
95 * Function Call Tracing Tool
96 */
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   "  "
101
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 */
105
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 */
109
110/*
111 * Performance Monitoring Tool
112 */
113#define BUZZZ_PMON_SAMPLESZ     (10U)
114
115typedef void (*timer_fn_t)(unsigned long);
116/*
117 * -----------------------------------------------------------------------------
118 * Buzzz debug display support.
119 *
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);
128 * }
129 * #undef  IP4DOTQ
130 * #define IP4DOTQ(addr, n)        (((addr) >> (24 - 8 * n)) & 0xFF)
131 * -----------------------------------------------------------------------------
132 */
133
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 */
140
141#undef  BUZZZ_ENUM
142#define BUZZZ_ENUM(val)         #val,
143
144static const char * _str_INV = "INVALID";
145
146static const char * _str_buzzz_tool[BUZZZ_TOOL_MAXIMUM] =
147{
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 */
152};
153static BUZZZ_INLINE const char * BUZZZ_NOINSTR_FUNC
154str_buzzz_tool(uint32_t tool)
155{
156	return (tool >= BUZZZ_TOOL_MAXIMUM) ? _str_INV :
157		_str_buzzz_tool[tool];
158}
159
160static const char * _str_buzzz_status[BUZZZ_STATUS_MAXIMUM] =
161{
162	BUZZZ_ENUM(DISABLED)
163	BUZZZ_ENUM(ENABLED)
164	BUZZZ_ENUM(PAUSED)
165};
166static BUZZZ_INLINE const char * BUZZZ_NOINSTR_FUNC
167str_buzzz_status(uint32_t status)
168{
169	return (status >= BUZZZ_STATUS_MAXIMUM) ? _str_INV :
170		_str_buzzz_status[status];
171}
172
173static const char * _str_buzzz_mode[BUZZZ_MODE_MAXIMUM] =
174{
175	BUZZZ_ENUM(UNDEF)
176	BUZZZ_ENUM(WRAPOVER)
177	BUZZZ_ENUM(LIMITED)
178	BUZZZ_ENUM(TRANSMIT)
179};
180static BUZZZ_INLINE const char * BUZZZ_NOINSTR_FUNC
181str_buzzz_mode(uint32_t mode)
182{
183	return (mode >= BUZZZ_MODE_MAXIMUM) ? _str_INV :
184		_str_buzzz_mode[mode];
185}
186static const char * _str_buzzz_ioctl[BUZZZ_IOCTL_MAXIMUM] =
187{
188	BUZZZ_ENUM(KCALL)
189
190	BUZZZ_ENUM(CONFIG_TOOL)
191	BUZZZ_ENUM(CONFIG_MODE)
192	BUZZZ_ENUM(CONFIG_LIMIT)
193
194	BUZZZ_ENUM(CONFIG_FUNC)
195	BUZZZ_ENUM(CONFIG_PMON)
196	BUZZZ_ENUM(CONFIG_KEVT)
197
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)
205};
206static BUZZZ_INLINE const char * BUZZZ_NOINSTR_FUNC
207str_buzzz_ioctl(uint32_t ioctl)
208{
209	ioctl -= BUZZZ_IOCTL_KCALL;
210	return (ioctl >= BUZZZ_IOCTL_MAXIMUM) ? _str_INV :
211		_str_buzzz_ioctl[ioctl];
212}
213
214#if defined(CONFIG_MIPS) && defined(BUZZZ_CONFIG_CPU_MIPS_74K)
215static const char * _str_buzzz_pmon_group[BUZZZ_PMON_GROUP_MAXIMUM] =
216{
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) */
230};
231
232static const char * _str_buzzz_pmon_event[BUZZZ_PMON_EVENT_MAXIMUM] =
233{
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 */
239
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 */
245
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 */
251
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 */
257
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 */
263
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 */
269
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 */
275
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 */
281
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 */
287
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 */
293
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 */
299
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 */
305
306	/* group 12 : L2_CACHE */
307	/* BUZZZ_ENUM(WBACK) */
308	/* BUZZZ_ENUM(ACCESS) */
309	/* BUZZZ_ENUM(MISSES) */
310	/* BUZZZ_ENUM(MISS_CYCLES) */
311};
312#endif	/*  CONFIG_MIPS && BUZZZ_CONFIG_CPU_MIPS_74K */
313
314#if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
315static const char * _str_buzzz_pmon_group[BUZZZ_PMON_GROUP_MAXIMUM] =
316{
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)
326};
327
328static const char * _str_buzzz_pmon_event[BUZZZ_PMON_EVENT_MAXIMUM] =
329{
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 */
335
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 */
341
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 */
347
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 */
353
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 */
359
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 */
365
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 */
371
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 */
377
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 */
383};
384#endif	/*  CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
385
386static BUZZZ_INLINE const char * BUZZZ_NOINSTR_FUNC
387str_buzzz_pmon_group(uint32_t group)
388{
389	return (group >= BUZZZ_PMON_GROUP_MAXIMUM) ? _str_INV :
390		_str_buzzz_pmon_group[group];
391}
392static BUZZZ_INLINE const char * BUZZZ_NOINSTR_FUNC
393str_buzzz_pmon_event(uint32_t event)
394{
395	return (event >= BUZZZ_PMON_EVENT_MAXIMUM) ? _str_INV :
396		_str_buzzz_pmon_event[event];
397}
398
399static const char * _str_buzzz_kevt_group[BUZZZ_KEVT_GROUP_MAXIMUM] =
400{
401	BUZZZ_ENUM(RESET)
402	BUZZZ_ENUM(GENERAL)
403	BUZZZ_ENUM(ICACHE)
404	BUZZZ_ENUM(DCACHE)
405	BUZZZ_ENUM(TLB)
406	BUZZZ_ENUM(BRANCH)
407};
408
409static const char * _str_buzzz_kevt_event[BUZZZ_KEVT_EVENT_MAXIMUM] =
410{
411	/* group  0: RESET */
412	BUZZZ_ENUM(CTR0_NONE)                   /* 0x00 */
413	BUZZZ_ENUM(CTR1_NONE)                   /* 0x00 */
414
415	/* group  1: GENERAL */
416	BUZZZ_ENUM(SPEC_INSTRCNT)               /* 0x68 */
417	BUZZZ_ENUM(CYCLES_ELAPSED)              /* 0x11 */
418
419	/* group  2: ICACHE */
420	BUZZZ_ENUM(INSTRUCTIONS)                /* 0x68 */
421	BUZZZ_ENUM(IC_REFILL)                   /* 0x01 */
422
423	/* group  3: DCACHE */
424	BUZZZ_ENUM(DC_ACCESS)                   /* 0x04 */
425	BUZZZ_ENUM(DC_REFILL)                   /* 0x03 */
426
427	/* group  4: TLB */
428	BUZZZ_ENUM(INSTR_REFILL)                /* 0x02 */
429	BUZZZ_ENUM(DATA_REFILL)                 /* 0x05 */
430
431	/* group  5: MISCELLANEOUS */
432	BUZZZ_ENUM(BRANCH_MISPRED)              /* 0x10 */
433	BUZZZ_ENUM(STREX_FAILED)                /* 0x64 */
434};
435
436static BUZZZ_INLINE const char * BUZZZ_NOINSTR_FUNC
437str_buzzz_kevt_group(uint32_t group)
438{
439	return (group >= BUZZZ_KEVT_GROUP_MAXIMUM) ? _str_INV :
440	        _str_buzzz_kevt_group[group];
441}
442static BUZZZ_INLINE const char * BUZZZ_NOINSTR_FUNC
443str_buzzz_kevt_event(uint32_t event)
444{
445	return (event >= BUZZZ_KEVT_EVENT_MAXIMUM) ? _str_INV :
446	        _str_buzzz_kevt_event[event];
447}
448
449
450/*
451 * -----------------------------------------------------------------------------
452 * BUZZZ Logging Infrastructure
453 * -----------------------------------------------------------------------------
454 */
455
456/* #define BUZZZ_PMON_LOGS 64-1  maximum number of buzzz_pmon_log() logs */
457
458/* Performance Monitoring Tool private definitions */
459typedef
460struct buzzz_pmon_ctl
461{
462	uint8_t u8[BUZZZ_PMON_COUNTERS];
463} buzzz_pmon_ctl_t;
464
465typedef
466struct buzzz_pmon_ctr
467{
468	uint32_t u32[4];
469} buzzz_pmon_ctr_t;
470
471typedef
472struct buzzz_pmonst
473{
474	buzzz_pmon_ctr_t min, max, sum;
475} buzzz_pmonst_t;
476
477#if defined(BUZZZ_CONFIG_PMON_USR)
478unsigned int buzzz_pmon_usr_g;
479
480typedef
481struct buzzz_pmon_usr
482{
483	unsigned int min, max, sum;
484} buzzz_pmon_usr_t;
485
486typedef
487struct buzzz_pmonst_usr
488{
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 */
493
494typedef /* Buzzz tool private configuration parameters and state */
495struct buzzz_priv
496{
497	union
498	{
499		struct
500		{
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 */
505
506			uint32_t log_count;         /* used by proc filesystem */
507			uint32_t log_index;         /* used by proc filesystem */
508		} func;
509
510		struct
511		{
512			uint32_t groupid;           /* current group */
513			buzzz_pmon_ctl_t control;   /* current groups configuration */
514
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 */
518
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];
522
523#if defined(BUZZZ_CONFIG_PMON_USR)
524			buzzz_pmonst_usr_t usr;
525#endif	/*  BUZZZ_CONFIG_PMON_USR */
526
527			uint32_t config_skip;
528			uint32_t config_samples;
529		} pmon;
530
531		struct
532		{
533			uint32_t count;             /* count of logs */
534			uint32_t limit;             /* limit functions logged @start */
535			uint32_t config_evt;        /* kevt logging perf event */
536
537			uint32_t log_count;         /* used by proc filesystem */
538			uint32_t log_index;         /* used by proc filesystem */
539			bool     skip;
540		} kevt;
541
542	};
543} buzzz_priv_t;
544
545
546typedef /* Buzzz global structure */
547struct buzzz
548{
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 */
557
558	void *          cur;        /* pointer to next log entry */
559	void *          end;        /* pointer to end of log entry */
560	void *          log;
561
562	buzzz_priv_t    priv;       /* tool specific private data */
563
564	struct timer_list timer;
565
566	buzzz_mode_t    config_mode;    /* limited, continuous wrapover */
567	uint32_t        config_limit;   /* configured limit */
568
569	buzzz_fmt_t     klogs[BUZZZ_KLOG_MAXIMUM];
570
571	char            page[4096];
572} buzzz_t;
573
574static buzzz_t buzzz_g =        /* Global Buzzz object, see __init_buzzz() */
575{
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,
581
582	.wrap   = BUZZZ_FALSE,
583	.run    = 0U,
584	.cur    = (void *)NULL,
585	.end    = (void *)NULL,
586	.log    = (void*)NULL,
587
588	.timer  = TIMER_INITIALIZER(NULL, 0, (int)&buzzz_g)
589};
590
591static DEFINE_PER_CPU(buzzz_status_t, kevt_status) = BUZZZ_STATUS_DISABLED;
592
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;                                                    \
597	}
598
599static void BUZZZ_NOINSTR_FUNC /* Preamble to start tracing in a tool */
600_buzzz_pre_start(void)
601{
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));
608}
609
610static void BUZZZ_NOINSTR_FUNC /* Postamble to start tracing in a tool */
611_buzzz_post_start(void)
612{
613	buzzz_g.status = BUZZZ_STATUS_ENABLED;
614}
615
616static void BUZZZ_NOINSTR_FUNC /* Preamble to stop tracing in a tool */
617_buzzz_pre_stop(void)
618{
619	buzzz_g.status = BUZZZ_STATUS_DISABLED;
620}
621
622static void BUZZZ_NOINSTR_FUNC /* Postamble to stop tracing in a tool */
623_buzzz_post_stop(void)
624{
625}
626
627typedef int (*buzzz_dump_log_fn_t)(char * page, void *log);
628
629void BUZZZ_NOINSTR_FUNC /* Dump the kevt trace to console */
630buzzz_log_dump(uint32_t limit, uint32_t count,
631               uint32_t log_size, buzzz_dump_log_fn_t dump_log_fn)
632{
633	uint32_t total;
634	void * log;
635
636	if (buzzz_g.wrap == BUZZZ_TRUE)
637		total = (BUZZZ_AVAIL_BUFSIZE / log_size);
638	else
639		total = count;
640
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);
646
647	if (total > limit)
648		total = limit;
649
650	printk(CLRbold "BUZZZ_DUMP BGN total<%u>" CLRnl, total);
651
652	if (total == 0U) {
653		printk(CLRbold "BUZZZ_DUMP END" CLRnl);
654		return;
655	}
656
657	if (limit != BUZZZ_INVALID) {   /* dump limited last few logs */
658		uint32_t part1;
659
660		part1 = ((uint32_t)buzzz_g.cur - (uint32_t)buzzz_g.log) / log_size;
661
662		if (total > part1) {        /* some events prior to wrap */
663			uint32_t part2;
664
665			part2 = total - part1;  /* number of events prior to wrap */
666
667			BUZZZ_PRINT("limit total<%u>: part2<%u> + part1<%u>",
668			            total, part2, part1);
669
670			log = (void*)((uint32_t)buzzz_g.end - (part2 * log_size));
671
672			total -= part2;
673
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);
679			}
680		}
681
682		log = (void*)((uint32_t)buzzz_g.cur - (total * log_size));
683
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);
689		}
690
691	} else if (buzzz_g.wrap == BUZZZ_TRUE) {  /* all of ring buffer with wrap */
692
693		uint32_t part1, part2;
694
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;
697
698		BUZZZ_PRINT("Wrap part2<%u> part1<%u>", part2, part1);
699
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);
706		}
707
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);
714		}
715
716	} else {                      /* everything in ring buffer, no wrap */
717
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);
725		}
726
727	}
728
729	printk(CLRbold "BUZZZ_DUMP END" CLRnl);
730}
731/*
732 * -----------------------------------------------------------------------------
733 * Function Call Tracing subsystem
734 * -----------------------------------------------------------------------------
735 */
736
737#define BUZZZ_FUNC_LOGISEVT     (1 << 1)
738#define BUZZZ_FUNC_ADDRMASK     (~3U)
739typedef
740struct buzzz_func_log
741{
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;
751
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;
758
759	uint32_t arg1;
760	uint32_t arg2;
761	uint32_t arg3;
762
763} buzzz_func_log_t;
764
765static BUZZZ_INLINE int BUZZZ_NOINSTR_FUNC
766_buzzz_symbol(char *p, unsigned long address)
767{
768	int bytes = 0;
769	unsigned long offset = 0LU;
770	char * eos, symbol_buf[KSYM_NAME_LEN+1];
771
772	sprint_symbol(symbol_buf, address);
773	eos = strpbrk(symbol_buf, "+");
774
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");
784	}
785	return bytes;
786}
787
788static BUZZZ_INLINE int BUZZZ_NOINSTR_FUNC
789_buzzz_func_indent(char *p)
790{
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);
796	}
797	return bytes;
798}
799
800static int BUZZZ_NOINSTR_FUNC
801buzzz_func_dump_log(char * p, void * l)
802{
803	buzzz_func_log_t * log = (buzzz_func_log_t *)l;
804	int bytes = 0;
805
806	if (log->arg0.klog.is_klog) {   /* print using registered log formats */
807
808		bytes += _buzzz_func_indent(p + bytes);   /* print indentation spaces */
809
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;
827		}
828		bytes += sprintf(p + bytes, "%s", CLRnl);
829
830	} else {                        /* print function call entry/exit */
831
832		unsigned long address;      /* instruction address */
833
834		if (log->arg0.site.is_ent)
835			buzzz_g.priv.func.indent++;
836
837		bytes += _buzzz_func_indent(p + bytes); /* print indentation spaces */
838
839		if (log->arg0.site.is_ent)
840			bytes += sprintf(p + bytes, "%s", CLRr "=>");
841		else
842			bytes += sprintf(p + bytes, "%s", CLRg "<=");
843
844		if (!log->arg0.site.is_ent && (buzzz_g.priv.func.indent > 0))
845			buzzz_g.priv.func.indent--;
846
847		address = (unsigned long)(log->arg0.u32 & BUZZZ_FUNC_ADDRMASK);
848		bytes += _buzzz_symbol(p + bytes, address);
849
850	}
851
852	return bytes;
853}
854
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;                                                            \
864		}                                                                      \
865		buzzz_g.priv.func.limit--;                                             \
866	}
867
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;                                             \
874	}                                                                          \
875	BUZZZ_UNLOCK(flags);
876
877
878void BUZZZ_NOINSTR_FUNC /* -finstrument compiler stub on function entry */
879__cyg_profile_func_enter(void * called, void * caller)
880{
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);
885}
886
887void BUZZZ_NOINSTR_FUNC /* -finstrument compiler stub on function exit */
888__cyg_profile_func_exit(void * called, void * caller)
889{
890	unsigned long flags;
891	if (buzzz_g.priv.func.config_exit == BUZZZ_DISABLE)
892		return;
893
894	_BUZZZ_FUNC_BGN(flags);
895	((buzzz_func_log_t*)buzzz_g.cur)->arg0.u32 = (uint32_t)called;
896	_BUZZZ_FUNC_END(flags);
897}
898
899void BUZZZ_NOINSTR_FUNC /* embed prints with zero args in log */
900buzzz_func_log0(uint32_t log_id)
901{
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);
907}
908
909void BUZZZ_NOINSTR_FUNC /* embed prints with one u32 arg in log */
910buzzz_func_log1(uint32_t log_id, uint32_t arg1)
911{
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);
919}
920
921void BUZZZ_NOINSTR_FUNC /* embed prints with two u32 args in log */
922buzzz_func_log2(uint32_t log_id, uint32_t arg1, uint32_t arg2)
923{
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);
932}
933
934void BUZZZ_NOINSTR_FUNC /* embed prints with three u32 args in log */
935buzzz_func_log3(uint32_t log_id, uint32_t arg1, uint32_t arg2, uint32_t arg3)
936{
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);
946}
947
948void BUZZZ_NOINSTR_FUNC /* Start function call entry (exit optional) tracing */
949buzzz_func_start(void)
950{
951	if (buzzz_g.log == (void*)NULL) {
952		printk(CLRerr "ERROR: Log not allocated" CLRnl);
953		return;
954	}
955
956	_buzzz_pre_start();
957
958	buzzz_g.priv.func.count = 0U;
959	buzzz_g.priv.func.indent = 0U;
960	buzzz_g.priv.func.limit = buzzz_g.config_limit;
961
962	buzzz_g.priv.func.log_count = 0U;
963	buzzz_g.priv.func.log_index = 0U;
964
965	_buzzz_post_start();
966}
967
968void BUZZZ_NOINSTR_FUNC /* Stop function call entry (exit optional) tracing */
969buzzz_func_stop(void)
970{
971	if (buzzz_g.status != BUZZZ_STATUS_DISABLED) {
972		buzzz_g.status = BUZZZ_STATUS_ENABLED;
973
974		BUZZZ_FUNC_LOG(BUZZZ_RET_IP);
975		BUZZZ_FUNC_LOG(buzzz_func_stop);
976
977		_buzzz_pre_stop();
978
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;
985
986		_buzzz_post_stop();
987	}
988}
989
990void BUZZZ_NOINSTR_FUNC /* On kernel panic, to dump N function call history */
991buzzz_func_panic(void)
992{
993	if (buzzz_g.tool != BUZZZ_TOOL_FUNC)
994		return;
995
996	if (buzzz_g.status != BUZZZ_STATUS_DISABLED) {
997		buzzz_func_stop();
998
999		if (buzzz_g.panic == BUZZZ_FALSE) {
1000			buzzz_g.panic = BUZZZ_TRUE;
1001			buzzz_func_dump(BUZZZ_FUNC_PANIC_LOGS);
1002		}
1003	}
1004}
1005
1006void BUZZZ_NOINSTR_FUNC /* Dump the function call trace to console */
1007buzzz_func_dump(uint32_t limit)
1008{
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);
1011}
1012
1013void BUZZZ_NOINSTR_FUNC /* Dump the function call trace to console */
1014buzzz_func_show(void)
1015{
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");
1022}
1023
1024int BUZZZ_NOINSTR_FUNC
1025buzzz_func_default(void)
1026{
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 */
1032
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;
1039
1040	buzzz_g.config_limit = BUZZZ_INVALID;
1041	buzzz_g.config_mode = BUZZZ_MODE_WRAPOVER;
1042
1043	return BUZZZ_SUCCESS;
1044}
1045
1046int BUZZZ_NOINSTR_FUNC /* API to config function exit tracing */
1047buzzz_func_config(uint32_t config_exit)
1048{
1049	BUZZZ_ASSERT_STATUS_DISABLED();
1050
1051	buzzz_g.priv.func.config_exit = config_exit;
1052
1053	return BUZZZ_SUCCESS;
1054}
1055
1056/* Initialization of Buzzz Function tool  during loading time */
1057static int BUZZZ_NOINSTR_FUNC
1058__init _init_buzzz_func(void)
1059{
1060	if ((BUZZZ_AVAIL_BUFSIZE % sizeof(buzzz_func_log_t)) != 0)
1061		return BUZZZ_ERROR;
1062
1063	if (sizeof(buzzz_func_log_t) != 16)
1064		return BUZZZ_ERROR;
1065
1066	return BUZZZ_SUCCESS;
1067}
1068
1069/*
1070 * -----------------------------------------------------------------------------
1071 * Performance Monitoring subsystem
1072 * -----------------------------------------------------------------------------
1073 */
1074
1075#if defined(CONFIG_MIPS) && defined(BUZZZ_CONFIG_CPU_MIPS_74K)
1076/*
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
1086 */
1087
1088#define BUZZZ_PMON_VAL(val, mode)   (((uint32_t)(val) << 5) | (mode))
1089
1090/*
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.
1095 */
1096static
1097buzzz_pmon_ctl_t buzzz_pmonctl_g[BUZZZ_PMON_GROUPS] =
1098{
1099	/*  ctl0  ctl1  ctl2  ctl3 */
1100	{{    0U,   0U,   0U,   0U }},      /* group  0 RESET            */
1101
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 */
1113};
1114#endif	/*  CONFIG_MIPS && BUZZZ_CONFIG_CPU_MIPS_74K */
1115
1116#if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1117
1118#define BUZZZ_PMON_VAL(val, mode)   ((uint32_t)(val))
1119
1120static
1121buzzz_pmon_ctl_t buzzz_pmonctl_g[BUZZZ_PMON_GROUPS] =
1122{
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    */
1133};
1134
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)
1137union 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                       */
1148	};
1149};
1150
1151union 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                      */
1164	};
1165};
1166
1167union 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                                   */
1172	};
1173};
1174
1175union 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                                   */
1180	};
1181};
1182
1183union 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                                   */
1188	};
1189};
1190
1191static BUZZZ_INLINE uint32_t BUZZZ_NOINSTR_FUNC
1192_armv7_pmcr_RD(void)
1193{
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;
1201}
1202
1203static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1204_armv7_pmcr_WR(const uint32_t v32)
1205{
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));
1212}
1213
1214static BUZZZ_INLINE uint32_t BUZZZ_NOINSTR_FUNC
1215_armv7_pmcntenset_test(void)
1216{
1217	/* Test whether PMU counters required by buzzz are in use */
1218	union cp15_c9_REG pmcntenset;
1219
1220	asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset.u32));
1221	return (pmcntenset.ctr2 || pmcntenset.ctr3 ||
1222		pmcntenset.ctr4 || pmcntenset.ctr5);
1223}
1224
1225static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1226_armv7_pmuserenr_enable(void)
1227{
1228	uint32_t u32 = 1;
1229	asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r"(u32));
1230}
1231
1232static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1233_armv7_pmcn_enable(void)
1234{
1235	union cp15_c9_c12_PMCR pmcr;
1236	union cp15_c9_REG pmcntenset;
1237	union cp15_c9_REG pmintenclr;
1238
1239	/* Set Enable bit in PMCR */
1240	pmcr.u32 = _armv7_pmcr_RD();
1241	pmcr.enable = 1;
1242	_armv7_pmcr_WR(pmcr.u32);
1243
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);
1249
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);
1255}
1256
1257static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1258_armv7_pmcn_disable(void)
1259{
1260	union cp15_c9_REG pmcntenclr;
1261
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);
1267}
1268
1269static BUZZZ_INLINE uint32_t BUZZZ_NOINSTR_FUNC
1270_armv7_pmcn_read_buzzz_ctr(const uint32_t idx)
1271{
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;
1278}
1279
1280static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1281_armv7_pmcn_config_buzzz_ctr(const uint32_t idx, const uint32_t evt_type)
1282{
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));
1288
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);
1294}
1295
1296#endif	/*  CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1297
1298
1299static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1300_buzzz_pmon_enable(void)
1301{
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 */
1307}
1308
1309static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1310_buzzz_pmon_disable(void)
1311{
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 */
1317}
1318
1319void buzzz_pmon_show(void);
1320
1321static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1322_buzzz_pmon_log(uint32_t log_id)
1323{
1324	buzzz_pmon_ctr_t * log = &buzzz_g.priv.pmon.log[log_id];
1325
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 */
1338
1339}
1340
1341static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1342_buzzz_pmon_iter_set_invalid(void)
1343{
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;
1349}
1350
1351static BUZZZ_INLINE uint32_t BUZZZ_NOINSTR_FUNC
1352_buzzz_pmon_iter_is_invalid(void)
1353{
1354	return (buzzz_g.priv.pmon.log[0].u32[0] == BUZZZ_INVALID);
1355}
1356
1357static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1358_buzzz_pmon_run(uint32_t last_log)
1359{
1360	uint32_t log, ctr;
1361	buzzz_pmon_ctr_t elapsed, prev, curr;
1362
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];
1367
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]);
1372
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];
1379		}
1380	}
1381
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 */
1389}
1390
1391static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1392_buzzz_pmon_tot(uint32_t last_log)
1393{
1394	uint32_t log, ctr;
1395
1396	buzzz_g.priv.pmon.mon[buzzz_g.priv.pmon.groupid][0].sum.u32[0] = ~0U;
1397
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];
1406		}
1407	}
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 */
1416}
1417
1418static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
1419_buzzz_pmon_bind(uint32_t group)
1420{
1421	uint32_t mode;
1422	uint32_t log, ctr;
1423	buzzz_pmon_ctl_t * ctl;
1424
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;
1431		}
1432	}
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 */
1438
1439	/* Monitoring mode */
1440	mode = (group == BUZZZ_PMON_GROUP_RESET) ? 0 : BUZZZ_PMON_CTRL;
1441
1442	/* Event values */
1443	ctl = &buzzz_pmonctl_g[group];
1444
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]);
1454	}
1455#endif	/*  CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1456
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));
1462
1463	buzzz_g.priv.pmon.sample = 0U;
1464	buzzz_g.priv.pmon.groupid = group;
1465}
1466
1467/* Start a new sample */
1468void BUZZZ_NOINSTR_FUNC
1469buzzz_pmon_bgn(void)
1470{
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();
1479}
1480
1481/* Invalidate this iteration */
1482void BUZZZ_NOINSTR_FUNC
1483buzzz_pmon_clr(void)
1484{
1485	_buzzz_pmon_iter_set_invalid();
1486}
1487
1488/* Record performance counters at this event point */
1489void BUZZZ_NOINSTR_FUNC
1490buzzz_pmon_log(uint32_t log_id)
1491{
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;
1495	}
1496
1497	_buzzz_pmon_log(log_id);                        /* record counter values */
1498
1499	buzzz_g.priv.pmon.next_log_id = log_id + 1U;    /* for log sequence check */
1500}
1501
1502void BUZZZ_NOINSTR_FUNC
1503buzzz_pmon_end(uint32_t last_log_id)
1504{
1505	if (buzzz_g.status == BUZZZ_STATUS_DISABLED)
1506		return;
1507
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();
1512	}
1513
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 */
1518	}
1519
1520	if (buzzz_g.status != BUZZZ_STATUS_ENABLED) {
1521		_buzzz_pmon_iter_set_invalid();
1522		return;
1523	}
1524
1525	buzzz_g.priv.pmon.last_log_id = last_log_id;
1526	buzzz_g.priv.pmon.sample++;
1527
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);
1531
1532	if (buzzz_g.priv.pmon.groupid == 0) {  /* RESET or skip group ID */
1533
1534		BUZZZ_PRINT("SKIP samples completed");
1535
1536		if (buzzz_g.priv.pmon.sample >= buzzz_g.priv.pmon.config_samples) {
1537
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++;
1542
1543			_buzzz_pmon_bind(buzzz_g.priv.pmon.groupid);
1544		}
1545		return; /* exit without summing all samples for RESET group */
1546	}
1547
1548	/* Accumulate into run, current iteration, and setup for next iteration */
1549	_buzzz_pmon_run(last_log_id);
1550
1551	if (buzzz_g.priv.pmon.sample >= buzzz_g.priv.pmon.config_samples) {
1552
1553		_buzzz_pmon_tot(last_log_id); /* record current groups sum total */
1554
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++;
1560
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);
1565	}
1566}
1567
1568void BUZZZ_NOINSTR_FUNC
1569buzzz_pmon_dump(void)
1570{
1571	uint32_t group, log_id, ctr;
1572	buzzz_pmonst_t * log;
1573	buzzz_pmon_ctr_t tot;
1574
1575	printk("\n\n+++++++++++++++\n+ PMON Report +\n+++++++++++++++\n\n");
1576
1577	if (buzzz_g.status != BUZZZ_STATUS_DISABLED)
1578		printk(CLRwarn "PMon not disabled" CLRnl);
1579
1580	if (buzzz_g.config_mode == BUZZZ_MODE_LIMITED)
1581		group = buzzz_g.config_limit;
1582	else
1583		group = BUZZZ_PMON_GROUP_GENERAL;
1584
1585	for (; group < BUZZZ_PMON_GROUP_MAXIMUM; group++) {
1586
1587		/* Zero out the total cummulation */
1588		for (ctr = 0U; ctr < BUZZZ_PMON_COUNTERS; ctr++)
1589			tot.u32[ctr] = 0U;
1590
1591		/* Print the table header */
1592		printk("\n\nGroup:\t" CLRb "%s\n" CLRnl, str_buzzz_pmon_group(group));
1593
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));
1607		}
1608
1609		/* -------------- */
1610		/* SUM STATISTICS */
1611		/* -------------- */
1612
1613		printk(CLRb "\n\nSamples %u Statistics",
1614			buzzz_g.priv.pmon.config_samples);
1615
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 */
1621
1622		for (log_id = 1; log_id <= buzzz_g.priv.pmon.last_log_id; log_id++) {
1623
1624			/* Print table row = per event entry */
1625			log = &buzzz_g.priv.pmon.mon[group][log_id];
1626
1627			for (ctr = 0U; ctr < BUZZZ_PMON_COUNTERS; ctr++)
1628				tot.u32[ctr] += log->sum.u32[ctr];
1629
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]);
1641			}
1642		}
1643
1644		/*
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.
1649		 */
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");
1657		}
1658
1659		for (ctr = 0U; ctr < BUZZZ_PMON_COUNTERS; ctr++)
1660				tot.u32[ctr] = 0U;
1661
1662		/* -------------- */
1663		/* MIN STATISTICS */
1664		/* -------------- */
1665
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 */
1672
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];
1675
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]);
1687			}
1688
1689			for (ctr = 0U; ctr < BUZZZ_PMON_COUNTERS; ctr++)
1690				tot.u32[ctr] += log->min.u32[ctr];
1691		}
1692
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");
1700		}
1701
1702		for (ctr = 0U; ctr < BUZZZ_PMON_COUNTERS; ctr++)
1703				tot.u32[ctr] = 0U;
1704
1705		/* -------------- */
1706		/* MAX STATISTICS */
1707		/* -------------- */
1708
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 */
1715
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];
1718
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]);
1730			}
1731
1732			for (ctr = 0U; ctr < BUZZZ_PMON_COUNTERS; ctr++)
1733				tot.u32[ctr] += log->max.u32[ctr];
1734		}
1735
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");
1743		}
1744
1745		if (buzzz_g.config_mode == BUZZZ_MODE_LIMITED)
1746			break;
1747	}
1748}
1749
1750void BUZZZ_NOINSTR_FUNC
1751buzzz_pmon_start(void)
1752{
1753	_buzzz_pre_start();
1754
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));
1758
1759	_buzzz_pmon_bind(BUZZZ_PMON_GROUP_RESET);
1760	_buzzz_pmon_iter_set_invalid();
1761
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;
1765
1766	_buzzz_pmon_enable();
1767
1768	_buzzz_post_start();
1769
1770	BUZZZ_PRINT("buzzz_pmon_start");
1771}
1772
1773void BUZZZ_NOINSTR_FUNC
1774buzzz_pmon_stop(void)
1775{
1776	if (buzzz_g.status != BUZZZ_STATUS_DISABLED) {
1777		_buzzz_pre_stop();
1778
1779		_buzzz_pmon_bind(BUZZZ_PMON_GROUP_RESET);
1780
1781		_buzzz_pmon_disable();
1782
1783		buzzz_pmon_dump();
1784
1785		_buzzz_post_stop();
1786	}
1787}
1788
1789void BUZZZ_NOINSTR_FUNC
1790buzzz_pmon_show(void)
1791{
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");
1806
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");
1809}
1810
1811int BUZZZ_NOINSTR_FUNC
1812buzzz_pmon_default(void)
1813{
1814	uint32_t evt;
1815
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 */
1821
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 */
1827
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;
1833	}
1834#endif	/*  CONFIG_ARM */
1835
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;
1845
1846	buzzz_g.config_mode = BUZZZ_MODE_LIMITED;
1847	buzzz_g.config_limit = BUZZZ_PMON_GROUP_GENERAL;
1848
1849	return BUZZZ_SUCCESS;
1850}
1851
1852int BUZZZ_NOINSTR_FUNC
1853buzzz_pmon_config(uint32_t config_samples, uint32_t config_skip)
1854{
1855	BUZZZ_ASSERT_STATUS_DISABLED();
1856
1857	buzzz_g.priv.pmon.config_samples = config_samples;
1858	buzzz_g.priv.pmon.config_skip = config_skip;
1859
1860	return BUZZZ_SUCCESS;
1861}
1862
1863/* Initialization of Buzzz PMon tool during loading time */
1864static int BUZZZ_NOINSTR_FUNC
1865__init _init_buzzz_pmon(void)
1866{
1867	return BUZZZ_SUCCESS;
1868}
1869
1870/*
1871 * -----------------------------------------------------------------------------
1872 * Kernel Event Logging subsystem
1873 * -----------------------------------------------------------------------------
1874 */
1875typedef
1876struct buzzz_kevt_log
1877{
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;
1891
1892typedef
1893struct buzzz_kevt_ctl
1894{
1895	uint8_t u8[BUZZZ_KEVT_COUNTERS];
1896} buzzz_kevt_ctl_t;
1897
1898#if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
1899static
1900buzzz_kevt_ctl_t buzzz_kevtctl_g[BUZZZ_KEVT_GROUPS] =
1901{
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    */
1909};
1910#endif  /*  CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
1911
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;
1919
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;                                             \
1926	}                                                                          \
1927	BUZZZ_UNLOCK(flags);
1928
1929void BUZZZ_NOINSTR_FUNC
1930buzzz_kevt_log0(uint32_t log_id)
1931{
1932	unsigned long flags;
1933	buzzz_kevt_log_t * cur;
1934
1935	_BUZZZ_KEVT_BGN(flags, cur);
1936
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 */
1941
1942	cur->arg0.klog.args = 0;
1943
1944	_BUZZZ_KEVT_END(flags);
1945}
1946
1947void BUZZZ_NOINSTR_FUNC
1948buzzz_kevt_log1(uint32_t log_id, uint32_t arg1)
1949{
1950	unsigned long flags;
1951	buzzz_kevt_log_t * cur;
1952
1953	_BUZZZ_KEVT_BGN(flags, cur);
1954
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 */
1959
1960	cur->arg0.klog.args = 1;
1961	cur->arg1 = arg1;
1962
1963	_BUZZZ_KEVT_END(flags);
1964}
1965
1966void BUZZZ_NOINSTR_FUNC
1967buzzz_kevt_log2(uint32_t log_id, uint32_t arg1, uint32_t arg2)
1968{
1969	unsigned long flags;
1970	buzzz_kevt_log_t * cur;
1971
1972	_BUZZZ_KEVT_BGN(flags, cur);
1973
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 */
1978
1979	cur->arg0.klog.args = 2;
1980	cur->arg1 = arg1;
1981	cur->arg2 = arg2;
1982
1983	_BUZZZ_KEVT_END(flags);
1984}
1985
1986void BUZZZ_NOINSTR_FUNC
1987buzzz_kevt_log3(uint32_t log_id, uint32_t arg1, uint32_t arg2, uint32_t arg3)
1988{
1989	unsigned long flags;
1990	buzzz_kevt_log_t * cur;
1991
1992	_BUZZZ_KEVT_BGN(flags, cur);
1993
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 */
1998
1999	cur->arg0.klog.args = 3;
2000	cur->arg1 = arg1;
2001	cur->arg2 = arg2;
2002	cur->arg3 = arg3;
2003
2004	_BUZZZ_KEVT_END(flags);
2005}
2006
2007void BUZZZ_NOINSTR_FUNC
2008buzzz_kevt_log4(uint32_t log_id, uint32_t arg1, uint32_t arg2,
2009                uint32_t arg3, uint32_t arg4)
2010{
2011	unsigned long flags;
2012	buzzz_kevt_log_t * cur;
2013
2014	_BUZZZ_KEVT_BGN(flags, cur);
2015
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 */
2020
2021	cur->arg0.klog.args = 4;
2022	cur->arg1 = arg1;
2023	cur->arg2 = arg2;
2024	cur->arg3 = arg3;
2025	cur->arg4 = arg4;
2026
2027	_BUZZZ_KEVT_END(flags);
2028}
2029
2030static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
2031_buzzz_kevt_enable(void * none)
2032{
2033#if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
2034	_armv7_pmcn_enable();
2035#endif  /*  CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
2036}
2037
2038static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
2039_buzzz_kevt_disable(void * none)
2040{
2041#if defined(CONFIG_ARM) && defined(BUZZZ_CONFIG_CPU_ARMV7_A9)
2042	_armv7_pmcn_disable();
2043#endif  /*  CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
2044}
2045
2046static BUZZZ_INLINE void BUZZZ_NOINSTR_FUNC
2047_buzzz_kevt_bind(void * info)
2048{
2049	uint32_t mode, ctr;
2050	buzzz_kevt_ctl_t * ctl;
2051	buzzz_status_t * status;
2052	uint32_t group = *((uint32_t*)info);
2053
2054	mode = (group == BUZZZ_PMON_GROUP_RESET) ? 0 : BUZZZ_PMON_CTRL;
2055	ctl = &buzzz_kevtctl_g[group];
2056
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]);
2060	}
2061#endif  /*  CONFIG_ARM && BUZZZ_CONFIG_CPU_ARMV7_A9 */
2062
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;
2068
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));
2072}
2073
2074void BUZZZ_NOINSTR_FUNC /* Start kevt tracing */
2075buzzz_kevt_start(void)
2076{
2077	buzzz_status_t * status;
2078	int cpu;
2079	_buzzz_pre_start();
2080
2081	on_each_cpu(_buzzz_kevt_bind, &buzzz_g.priv.kevt.config_evt, 1);
2082
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);
2088	}
2089
2090	on_each_cpu(_buzzz_kevt_enable, NULL, 1);
2091
2092	_buzzz_post_start();
2093
2094	BUZZZ_PRINT("buzzz_kevt_start");
2095}
2096
2097void BUZZZ_NOINSTR_FUNC /* Stop kevt tracing */
2098buzzz_kevt_stop(void)
2099{
2100	buzzz_kevt_group_t group = BUZZZ_KEVT_GROUP_RESET;
2101
2102	if (buzzz_g.status != BUZZZ_STATUS_DISABLED) {
2103
2104		buzzz_kevt_log0(BUZZZ_KEVT_ID_BUZZZ_TMR);
2105
2106		_buzzz_pre_stop();
2107
2108		on_each_cpu(_buzzz_kevt_bind, &group, 1);
2109		on_each_cpu(_buzzz_kevt_disable, NULL, 1);
2110
2111		_buzzz_post_stop();
2112	}
2113}
2114
2115int BUZZZ_NOINSTR_FUNC
2116buzzz_kevt_parse_log(char * p, int bytes, buzzz_kevt_log_t * log)
2117{
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:
2159		{
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;
2168		}
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;
2183	}
2184	bytes += sprintf(p + bytes, "%s", CLRnl);
2185	return bytes;
2186}
2187
2188int BUZZZ_NOINSTR_FUNC
2189buzzz_kevt_dump_log(char * p, buzzz_kevt_log_t * log)
2190{
2191	static uint32_t core_cnt[NR_CPUS][BUZZZ_KEVT_COUNTERS]; /* [core][cntr] */
2192	static uint32_t nsecs[NR_CPUS];
2193
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 */
2198
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];
2203
2204		if (curr[ctr] < prev[ctr])  /* rollover */
2205			delta[ctr] = curr[ctr] + (~0U - prev[ctr]);
2206		else
2207			delta[ctr] = (curr[ctr] - prev[ctr]);
2208	}
2209
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;
2218	}
2219
2220	nsecs[log->arg0.klog.core] += (delta[1] * 1000) / BUZZZ_CYCLES_PER_USEC;
2221
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;
2225
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]);
2237	}
2238
2239	if (log->arg0.klog.id < BUZZZ_KEVT_ID_MAXIMUM)
2240		return buzzz_kevt_parse_log(p, bytes, log);
2241
2242	bytes += sprintf(p + bytes, CLRg);
2243
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;
2266	}
2267
2268	bytes += sprintf(p + bytes, "%s", CLRnl);
2269	return bytes;
2270}
2271
2272void BUZZZ_NOINSTR_FUNC	/* Dump the format line */
2273buzzz_kevt_dump_format(void)
2274{
2275	uint32_t group = buzzz_g.priv.kevt.config_evt;
2276
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));
2285	}
2286}
2287
2288void BUZZZ_NOINSTR_FUNC	/* Dump the kevt trace to console */
2289buzzz_kevt_dump(uint32_t limit)
2290{
2291	buzzz_g.priv.kevt.skip = true;
2292
2293	buzzz_kevt_dump_format();
2294
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);
2297
2298	buzzz_kevt_dump_format();
2299}
2300
2301void BUZZZ_NOINSTR_FUNC /* Dump the kevt trace to console */
2302buzzz_kevt_show(void)
2303{
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");
2311}
2312
2313int BUZZZ_NOINSTR_FUNC
2314buzzz_kevt_default(void)
2315{
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 */
2321
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;
2329	}
2330#endif  /* !CONFIG_ARM */
2331
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;
2337
2338	buzzz_g.config_mode = BUZZZ_MODE_WRAPOVER;
2339	buzzz_g.config_limit = BUZZZ_INVALID;
2340
2341	return BUZZZ_SUCCESS;
2342}
2343
2344
2345int BUZZZ_NOINSTR_FUNC /* API to config kevt performance counter group */
2346buzzz_kevt_config(uint32_t config_evt)
2347{
2348	BUZZZ_ASSERT_STATUS_DISABLED();
2349
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;
2354	}
2355
2356	buzzz_g.priv.kevt.config_evt = config_evt;
2357
2358	printk("buzzz_kevt_config %s\n",
2359	       str_buzzz_kevt_group(buzzz_g.priv.kevt.config_evt));
2360
2361	return BUZZZ_SUCCESS;
2362}
2363
2364/* Initialization of Buzzz Kevt tool during loading time */
2365static int BUZZZ_NOINSTR_FUNC
2366__init _init_buzzz_kevt(void)
2367{
2368	if ((BUZZZ_AVAIL_BUFSIZE % sizeof(buzzz_kevt_log_t)) != 0)
2369		return BUZZZ_ERROR;
2370
2371	if (sizeof(buzzz_kevt_log_t) != 32)
2372		return BUZZZ_ERROR;
2373
2374	return BUZZZ_SUCCESS;
2375}
2376
2377#if defined(BUZZZ_CONFIG_UNITTEST)
2378static void BUZZZ_NOINSTR_FUNC
2379buzzz_func_unittest(void)
2380{
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>");
2386
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);
2393}
2394
2395static void BUZZZ_NOINSTR_FUNC
2396buzzz_pmon_unittest(void)
2397{
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");
2409
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");
2420
2421	for (i = 0; (i < buzzz_g.priv.pmon.config_samples * 16); i++) {
2422
2423		buzzz_pmon_bgn();
2424
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);
2435
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);
2447
2448		buzzz_pmon_end(20);
2449	}
2450}
2451
2452static void BUZZZ_NOINSTR_FUNC
2453buzzz_kevt_unittest(void)
2454{
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>");
2461
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);
2488}
2489#endif  /*  BUZZZ_CONFIG_UNITTEST */
2490
2491
2492#if defined(CONFIG_PROC_FS)
2493/*
2494 * -----------------------------------------------------------------------------
2495 * BUZZZ Proc Filesystem interface
2496 * -----------------------------------------------------------------------------
2497 */
2498static int BUZZZ_NOINSTR_FUNC /* Invoked on single-open, presently */
2499buzzz_proc_sys_show(struct seq_file *seq, void *v)
2500{
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);
2512
2513	return BUZZZ_SUCCESS;
2514}
2515
2516static int BUZZZ_NOINSTR_FUNC
2517buzzz_proc_log_show(char * page, char **start, off_t off, int count,
2518	int * eof, void * data)
2519{
2520	int bytes = 0;
2521
2522	*start = page;  /* prepare start of buffer for printing */
2523
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;
2532
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;
2537
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;
2544		}
2545
2546		if (index == 0U) {  /* Log the header */
2547			buzzz_g.priv.func.indent = 0U;
2548
2549			bytes += sprintf(page + bytes,
2550				CLRbold "BUZZZ_DUMP BGN total<%u>" CLRnl,
2551				buzzz_g.priv.func.log_count);
2552
2553			if (buzzz_g.priv.func.log_count == 0U) {
2554				bytes += sprintf(page + bytes, CLRbold "BUZZZ_DUMP END" CLRnl);
2555				goto done;
2556			}
2557		}
2558
2559		bytes += buzzz_func_dump_log(page + bytes, log);
2560
2561		buzzz_g.priv.func.log_index++;
2562	}
2563
2564	/* do not place any code here */
2565
2566done:
2567	*eof = 1;       /* end of entry */
2568	return bytes;   /* 0B implies end of proc fs */
2569}
2570
2571static int BUZZZ_NOINSTR_FUNC /* Proc file system open handler */
2572buzzz_proc_sys_open(struct inode *inode, struct file *file)
2573{
2574	return single_open(file, buzzz_proc_sys_show, NULL);
2575}
2576
2577static const struct file_operations buzzz_proc_sys_fops =
2578{
2579	.open       =   buzzz_proc_sys_open,
2580	.read       =   seq_read,
2581	.llseek     =   seq_lseek,
2582	.release    =   single_release
2583};
2584
2585#endif  /*  CONFIG_PROC_FS */
2586
2587
2588/*
2589 * -----------------------------------------------------------------------------
2590 * BUZZZ kernel space command line handling
2591 * -----------------------------------------------------------------------------
2592 */
2593
2594int BUZZZ_NOINSTR_FUNC
2595buzzz_kcall(uint32_t arg)
2596{
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 */
2605
2606		default:
2607			break;
2608	}
2609
2610	return BUZZZ_SUCCESS;
2611}
2612
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>
2618extern si_t *bcm947xx_sih;
2619#define sih bcm947xx_sih
2620#endif	/*  CONFIG_MIPS */
2621
2622void BUZZZ_NOINSTR_FUNC
2623buzzz_kernel_info(void)
2624{
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 */
2638
2639	printk("%s", linux_banner);
2640}
2641
2642int BUZZZ_NOINSTR_FUNC /* Display the runtime status */
2643buzzz_show(void)
2644{
2645	buzzz_kernel_info();
2646
2647	printk(CLRbold "%s" BUZZZ_VER_FMTS CLRnl,
2648		BUZZZ_NAME, BUZZZ_VER_FMT(BUZZZ_SYS_VERSION));
2649
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);
2656
2657	printk("\nTool:\t\t" CLRb "%s" CLRnl, str_buzzz_tool(buzzz_g.tool));
2658
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;
2665	}
2666
2667	return BUZZZ_SUCCESS;
2668}
2669
2670int BUZZZ_NOINSTR_FUNC
2671buzzz_start_now(buzzz_t * buzzz_p)
2672{
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;
2681	}
2682
2683	buzzz_p->timer.function = NULL;
2684
2685	return BUZZZ_SUCCESS;
2686}
2687
2688int BUZZZ_NOINSTR_FUNC
2689buzzz_start(uint32_t after)
2690{
2691	if (after == 0U) {
2692		return buzzz_start_now(&buzzz_g);
2693	}
2694
2695	if (buzzz_g.timer.function != NULL) {
2696		printk(CLRwarn "Timer already in use, overwriting" CLRnl);
2697		del_timer(&buzzz_g.timer);
2698	}
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);
2704
2705	return BUZZZ_SUCCESS;
2706}
2707
2708int BUZZZ_NOINSTR_FUNC
2709buzzz_stop_now(buzzz_t * buzzz_p)
2710{
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;
2719	}
2720	buzzz_p->timer.function = NULL;
2721
2722	return BUZZZ_SUCCESS;
2723}
2724
2725int BUZZZ_NOINSTR_FUNC
2726buzzz_stop(uint32_t after)
2727{
2728	if (after == 0U) {
2729		return buzzz_stop_now(&buzzz_g);
2730	}
2731	if (buzzz_g.timer.function != NULL) {
2732		printk(CLRwarn "Timer already in use, overwriting" CLRnl);
2733		del_timer(&buzzz_g.timer);
2734	}
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);
2740
2741	return BUZZZ_SUCCESS;
2742}
2743
2744
2745int BUZZZ_NOINSTR_FUNC
2746buzzz_pause(void)
2747{
2748	if (buzzz_g.status == BUZZZ_STATUS_ENABLED) {
2749		BUZZZ_FUNC_LOG(BUZZZ_RET_IP);
2750		BUZZZ_FUNC_LOG(buzzz_pause);
2751
2752		buzzz_g.status = BUZZZ_STATUS_PAUSED;
2753	}
2754
2755	return BUZZZ_SUCCESS;
2756}
2757
2758int BUZZZ_NOINSTR_FUNC
2759buzzz_play(void)
2760{
2761	if (buzzz_g.status == BUZZZ_STATUS_PAUSED) {
2762		buzzz_g.status = BUZZZ_STATUS_ENABLED;
2763
2764		BUZZZ_FUNC_LOG(BUZZZ_RET_IP);
2765		BUZZZ_FUNC_LOG(buzzz_play);
2766	}
2767
2768	return BUZZZ_SUCCESS;
2769}
2770
2771int BUZZZ_NOINSTR_FUNC
2772buzzz_audit(void)
2773{
2774	printk(CLRwarn "Unsupported audit capability" CLRnl);
2775	return BUZZZ_ERROR;
2776}
2777
2778int BUZZZ_NOINSTR_FUNC
2779buzzz_dump(uint32_t items)
2780{
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;
2789	}
2790
2791	return BUZZZ_SUCCESS;
2792}
2793
2794int BUZZZ_NOINSTR_FUNC /* Configure the tool that will use the logging system */
2795buzzz_config_tool(buzzz_tool_t tool)
2796{
2797	if (tool > BUZZZ_TOOL_MAXIMUM) {
2798		printk(CLRerr "ERROR: Invalid tool %u" CLRnl, tool);
2799		return BUZZZ_ERROR;
2800	}
2801
2802	BUZZZ_ASSERT_STATUS_DISABLED();
2803
2804	buzzz_g.tool = tool;
2805
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;
2814	}
2815
2816	return BUZZZ_SUCCESS;
2817}
2818
2819int BUZZZ_NOINSTR_FUNC /* Configure the mode of operation of the tool */
2820buzzz_config_mode(buzzz_mode_t mode)
2821{
2822	if ((mode == BUZZZ_MODE_UNDEF) || (mode >= BUZZZ_MODE_MAXIMUM)) {
2823		printk(CLRerr "ERROR: Invalid mode %u" CLRnl, mode);
2824		return BUZZZ_ERROR;
2825	}
2826
2827	BUZZZ_ASSERT_STATUS_DISABLED();
2828
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;
2844			}
2845			break;
2846		default:
2847			printk(CLRerr "Unsupported mode for tool %s" CLRnl,
2848				str_buzzz_tool(buzzz_g.tool));
2849			return BUZZZ_ERROR;
2850	}
2851
2852	buzzz_g.config_mode = mode;
2853
2854	return BUZZZ_SUCCESS;
2855}
2856
2857int BUZZZ_NOINSTR_FUNC /* Configure a limit parameter in the tool */
2858buzzz_config_limit(uint32_t limit)
2859{
2860	BUZZZ_ASSERT_STATUS_DISABLED();
2861
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;
2873			}
2874			break;
2875		default:
2876			printk(CLRerr "Unsupported limit for tool %s" CLRnl,
2877				str_buzzz_tool(buzzz_g.tool));
2878			return BUZZZ_ERROR;
2879	}
2880
2881	buzzz_g.config_limit = limit;
2882
2883	return BUZZZ_SUCCESS;
2884}
2885
2886void BUZZZ_NOINSTR_FUNC
2887buzzz_klog_reg(uint32_t klog_id, char * klog_fmt)
2888{
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);
2893}
2894
2895/*
2896 * -----------------------------------------------------------------------------
2897 * BUZZZ Character Driver Ioctl handlers
2898 * -----------------------------------------------------------------------------
2899 */
2900static int BUZZZ_NOINSTR_FUNC /* pre ioctl handling in character driver */
2901buzzz_open(struct inode *inodep, struct file *filep)
2902{
2903	/* int minor = MINOR(inodep->i_rdev) & 0xf; */
2904	return 0;
2905}
2906
2907#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
2908static long BUZZZ_NOINSTR_FUNC
2909buzzz_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2910#else	/* < linux-2.6.36 */
2911static int BUZZZ_NOINSTR_FUNC /* ioctl handler in character driver */
2912buzzz_ioctl(struct inode *inode, struct file *file,
2913	unsigned int cmd, unsigned long arg)
2914#endif  /* < linux-2.6.36 */
2915{
2916	int ret = BUZZZ_ERROR;
2917
2918	BUZZZ_PRINT("cmd<%s>", str_buzzz_ioctl(cmd));
2919
2920	switch (cmd) {
2921		case BUZZZ_IOCTL_KCALL:
2922			BUZZZ_PRINT("invoke buzzz_kcall %lu", arg);
2923			return buzzz_kcall(arg);
2924
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;
2931
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;
2938
2939		case BUZZZ_IOCTL_CONFIG_LIMIT:
2940			BUZZZ_PRINT("invoke buzzz_config_limit %lu", arg);
2941			return buzzz_config_limit(arg);
2942
2943		case BUZZZ_IOCTL_CONFIG_FUNC:
2944			BUZZZ_PRINT("invoke buzzz_func_config %lu", arg);
2945			return buzzz_func_config(arg);
2946
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));
2951
2952		case BUZZZ_IOCTL_CONFIG_KEVT:
2953			BUZZZ_PRINT("invoke buzzz_kevt_config %lu", arg);
2954			return buzzz_kevt_config(arg);
2955
2956		case BUZZZ_IOCTL_SHOW:
2957			BUZZZ_PRINT("invoke buzzz_show");
2958			return buzzz_show();
2959
2960		case BUZZZ_IOCTL_START:
2961			BUZZZ_PRINT("invoke buzzz_start %lu", arg);
2962			return buzzz_start(arg);
2963
2964		case BUZZZ_IOCTL_STOP:
2965			BUZZZ_PRINT("invoke buzzz_stop %lu", arg);
2966			return buzzz_stop(arg);
2967
2968
2969		case BUZZZ_IOCTL_PAUSE:
2970			BUZZZ_PRINT("invoke buzzz_pause");
2971			return buzzz_pause();
2972
2973		case BUZZZ_IOCTL_PLAY:
2974			BUZZZ_PRINT("invoke buzzz_play");
2975			return buzzz_play();
2976
2977		case BUZZZ_IOCTL_AUDIT:
2978			BUZZZ_PRINT("invoke buzzz_audit");
2979			return buzzz_audit();
2980
2981		case BUZZZ_IOCTL_DUMP:
2982			BUZZZ_PRINT("invoke buzzz_dump %lu", arg);
2983			return buzzz_dump(arg);
2984
2985		default:
2986			return -EINVAL;
2987	}
2988
2989	return ret;
2990}
2991
2992static int BUZZZ_NOINSTR_FUNC /* post ioct handling in character driver */
2993buzzz_release(struct inode *inodep, struct file *filep)
2994{
2995	return 0;
2996}
2997
2998static const struct file_operations buzzz_fops =
2999{
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 */
3008};
3009
3010/*
3011 * -----------------------------------------------------------------------------
3012 * BUZZZ (linked into kernel) initialization (late level)
3013 * Should BUZZZ be a dynamically loaded module ....?
3014 * -----------------------------------------------------------------------------
3015 */
3016static struct miscdevice buzzz_dev =
3017{
3018	.minor  = MISC_DYNAMIC_MINOR,
3019	.name   = BUZZZ_NAME,
3020	.fops   = &buzzz_fops
3021};
3022
3023/* Initialization of Buzzz during loading time */
3024static int BUZZZ_NOINSTR_FUNC
3025__init __init_buzzz(void)
3026{
3027	int err, i;
3028	char event_str[64];
3029
3030#if defined(CONFIG_PROC_FS)
3031	struct proc_dir_entry *ent_sys, *ent_log;
3032#endif  /*  CONFIG_PROC_FS */
3033
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);
3043	}
3044
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));
3050
3051		goto fail_dev_dereg;
3052	} else {
3053		memset(buzzz_g.log, 0, BUZZZ_LOG_BUFSIZE);
3054	}
3055	buzzz_g.cur = buzzz_g.log;
3056	buzzz_g.end = (void*)((char*)buzzz_g.log - BUZZZ_LOGENTRY_MAXSZ);
3057
3058#if defined(CONFIG_PROC_FS)
3059	/* Construct a Proc filesystem entry for Buzzz */
3060
3061	proc_mkdir(BUZZZ_NAME, NULL);
3062
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;
3070	}
3071
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;
3078	}
3079#endif  /*  CONFIG_PROC_FS */
3080
3081	if (_init_buzzz_func() == BUZZZ_ERROR) {
3082		printk(CLRerr "ERROR: Initialize Func Tool" CLRnl);
3083		goto fail_free_log;
3084	}
3085
3086	if (_init_buzzz_pmon() == BUZZZ_ERROR) {
3087		printk(CLRerr "ERROR: Initialize PMon Tool" CLRnl);
3088		goto fail_free_log;
3089	}
3090
3091	if (_init_buzzz_kevt() == BUZZZ_ERROR) {
3092		printk(CLRerr "ERROR: Initialize KEvt Tool" CLRnl);
3093		goto fail_free_log;
3094	}
3095
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);
3099	}
3100
3101	buzzz_g.status = BUZZZ_STATUS_DISABLED;
3102
3103	return BUZZZ_SUCCESS;   /* Successful initialization of Buzzz */
3104
3105#if defined(CONFIG_PROC_FS)
3106fail_free_log:
3107#endif  /*  CONFIG_PROC_FS */
3108	kfree(buzzz_g.log);
3109
3110fail_dev_dereg:
3111	misc_deregister(&buzzz_dev);
3112
3113	return BUZZZ_ERROR;     /* Failed initialization of Buzzz */
3114}
3115
3116late_initcall(__init_buzzz);    /* init level 7 */
3117
3118EXPORT_SYMBOL(buzzz_start);
3119EXPORT_SYMBOL(buzzz_stop);
3120EXPORT_SYMBOL(buzzz_pause);
3121EXPORT_SYMBOL(buzzz_play);
3122EXPORT_SYMBOL(buzzz_audit);
3123EXPORT_SYMBOL(buzzz_dump);
3124EXPORT_SYMBOL(buzzz_config_tool);
3125EXPORT_SYMBOL(buzzz_config_mode);
3126EXPORT_SYMBOL(buzzz_config_limit);
3127EXPORT_SYMBOL(buzzz_klog_reg);
3128EXPORT_SYMBOL(buzzz_kcall);
3129
3130EXPORT_SYMBOL(__cyg_profile_func_enter);
3131EXPORT_SYMBOL(__cyg_profile_func_exit);
3132
3133EXPORT_SYMBOL(buzzz_func_log0);
3134EXPORT_SYMBOL(buzzz_func_log1);
3135EXPORT_SYMBOL(buzzz_func_log2);
3136EXPORT_SYMBOL(buzzz_func_log3);
3137EXPORT_SYMBOL(buzzz_func_start);
3138EXPORT_SYMBOL(buzzz_func_stop);
3139EXPORT_SYMBOL(buzzz_func_panic);
3140EXPORT_SYMBOL(buzzz_func_dump);
3141EXPORT_SYMBOL(buzzz_func_config);
3142
3143EXPORT_SYMBOL(buzzz_pmon_bgn);
3144EXPORT_SYMBOL(buzzz_pmon_clr);
3145EXPORT_SYMBOL(buzzz_pmon_log);
3146EXPORT_SYMBOL(buzzz_pmon_end);
3147EXPORT_SYMBOL(buzzz_pmon_start);
3148EXPORT_SYMBOL(buzzz_pmon_stop);
3149EXPORT_SYMBOL(buzzz_pmon_config);
3150#if defined(BUZZZ_CONFIG_PMON_USR)
3151EXPORT_SYMBOL(buzzz_pmon_usr_g);
3152#endif	/*  BUZZZ_CONFIG_PMON_USR */
3153
3154EXPORT_SYMBOL(buzzz_kevt_log0);
3155EXPORT_SYMBOL(buzzz_kevt_log1);
3156EXPORT_SYMBOL(buzzz_kevt_log2);
3157EXPORT_SYMBOL(buzzz_kevt_log3);
3158EXPORT_SYMBOL(buzzz_kevt_log4);
3159EXPORT_SYMBOL(buzzz_kevt_start);
3160EXPORT_SYMBOL(buzzz_kevt_stop);
3161EXPORT_SYMBOL(buzzz_kevt_dump);
3162EXPORT_SYMBOL(buzzz_kevt_config);
3163