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 = ¤t_cpu_data; 2629 bcm_chipname(sih->chip, cn, 8); 2630 hz = si_cpu_clock(sih); 2631 printk("CPU: BCM%s rev %d at %d MHz\n", cn, sih->chiprev, 2632 (hz + 500000) / 1000000); 2633 printk("I-Cache %dkB, %d-way, linesize %d bytes.\n", 2634 c->icache.waysize * c->icache.ways, c->icache.ways, c->icache.linesz); 2635 printk("D-Cache %dkB, %d-way, linesize %d bytes.\n\n", 2636 c->dcache.waysize * c->dcache.ways, c->dcache.ways, c->dcache.linesz); 2637#endif /* CONFIG_MIPS */ 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