1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17215990Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22215990Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27215990Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38210284Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett 41210284Sjmallett 42210284Sjmallett 43210284Sjmallett 44210284Sjmallett 45215990Sjmallett 46210284Sjmallett/** 47210284Sjmallett * @file 48210284Sjmallett * 49210284Sjmallett * cvmx-log supplies a fast log buffer implementation. Each core writes 50210284Sjmallett * log data to a differnet buffer to avoid synchronization overhead. Function 51210284Sjmallett * call logging can be turned on with the GCC option "-pg". 52210284Sjmallett * 53232812Sjmallett * <hr>$Revision: 70030 $<hr> 54210284Sjmallett */ 55210284Sjmallett#include "cvmx.h" 56215990Sjmallett#include "cvmx-core.h" 57210284Sjmallett#include "cvmx-log.h" 58210284Sjmallett 59210284Sjmallett#define CVMX_LOG_BUFFER_SIZE (1<<15) 60210284Sjmallett#define CVMX_LOG_NUM_BUFFERS 4 61210284Sjmallett 62210284Sjmallett/** 63210284Sjmallett * The possible types of log data that can be stored in the 64210284Sjmallett * buffer. 65210284Sjmallett */ 66210284Sjmalletttypedef enum 67210284Sjmallett{ 68210284Sjmallett CVMX_LOG_TYPE_PC = 0, /**< Log of the program counter location. used for code profiling / tracing */ 69210284Sjmallett CVMX_LOG_TYPE_PRINTF, /**< Constant printf format string with two 64bit arguments */ 70210284Sjmallett CVMX_LOG_TYPE_DATA, /**< Arbitrary array of dwords. Max size is 31 dwords */ 71210284Sjmallett CVMX_LOG_TYPE_STRUCTURE,/**< Log a structured data element. Max size is 30 dwords */ 72210284Sjmallett CVMX_LOG_TYPE_PERF, /**< Mips performance counters control registers followed by the data */ 73210284Sjmallett} cvmx_log_type_t; 74210284Sjmallett 75210284Sjmallett/** 76210284Sjmallett * Header definition for each log entry. 77210284Sjmallett */ 78210284Sjmalletttypedef union 79210284Sjmallett{ 80210284Sjmallett uint64_t u64; 81210284Sjmallett struct 82210284Sjmallett { 83210284Sjmallett cvmx_log_type_t type : 3; /* Data in the log entry */ 84210284Sjmallett uint64_t size : 8; /* Data size in 64bit words */ 85210284Sjmallett uint64_t cycle :53; /* Low bits of the cycle counter as a timestamp */ 86210284Sjmallett } s; 87210284Sjmallett} cvmx_log_header_t; 88210284Sjmallett 89210284Sjmallett/** 90210284Sjmallett * Circular log buffer. Each processor gets a private one to 91210284Sjmallett * write to. Log entries are added at the current write 92210284Sjmallett * location, then the write location is incremented. The 93210284Sjmallett * buffer may wrap in the middle of a log entry. 94210284Sjmallett */ 95210284Sjmallettstatic uint64_t cvmx_log_buffers[CVMX_LOG_NUM_BUFFERS][CVMX_LOG_BUFFER_SIZE]; 96210284Sjmallett 97210284Sjmallett/** 98210284Sjmallett * Current locations in the log. 99210284Sjmallett */ 100210284Sjmallettuint64_t *cvmx_log_buffer_write_ptr = NULL; /* The next write will occur here */ 101210284Sjmallettuint64_t *cvmx_log_buffer_end_ptr = NULL; /* Write must move to the next buffer when it equals this */ 102210284Sjmallettuint64_t *cvmx_log_buffer_head_ptr = NULL; /* Pointer to begin extracting log data from */ 103210284Sjmallettstatic uint64_t *cvmx_log_buffer_read_ptr = NULL; /* Location cvmx_display is reading from */ 104210284Sjmallettstatic uint64_t *cvmx_log_buffer_read_end_ptr = NULL; /* Location where read will need the next buffer */ 105210284Sjmallettuint64_t cvmx_log_mcd0_on_full = 0; /* If this is set, cvm-log will assert MCD0 when the log 106210284Sjmallett is full. This is set by the remote logging utility through 107210284Sjmallett the debugger interface. */ 108210284Sjmallett 109210284Sjmallett 110210284Sjmallett/** 111210284Sjmallett * @INTERNAL 112210284Sjmallett * Initialize the log for writing 113210284Sjmallett */ 114210284Sjmallettstatic void __cvmx_log_initialize(void) CVMX_LOG_DISABLE_PC_LOGGING; 115210284Sjmallettstatic void __cvmx_log_initialize(void) 116210284Sjmallett{ 117210284Sjmallett int buf_num; 118210284Sjmallett 119210284Sjmallett /* Link the buffers together using the last element in each buffer */ 120210284Sjmallett for (buf_num=0; buf_num<CVMX_LOG_NUM_BUFFERS-1; buf_num++) 121210284Sjmallett cvmx_log_buffers[buf_num][CVMX_LOG_BUFFER_SIZE-1] = CAST64(cvmx_log_buffers[buf_num+1]); 122210284Sjmallett cvmx_log_buffers[CVMX_LOG_NUM_BUFFERS-1][CVMX_LOG_BUFFER_SIZE-1] = CAST64(NULL); 123210284Sjmallett 124210284Sjmallett cvmx_log_buffer_head_ptr = &cvmx_log_buffers[0][0]; 125210284Sjmallett cvmx_log_buffer_write_ptr = &cvmx_log_buffers[0][0]; 126210284Sjmallett cvmx_log_buffer_end_ptr = cvmx_log_buffer_write_ptr + CVMX_LOG_BUFFER_SIZE-1; 127210284Sjmallett} 128210284Sjmallett 129210284Sjmallett 130210284Sjmallett/** 131210284Sjmallett * @INTERNAL 132210284Sjmallett * Called when the log is full of data. This function must 133210284Sjmallett * make room for more log data before returning. 134210284Sjmallett */ 135210284Sjmallettstatic void __cvmx_log_full_process(void) CVMX_LOG_DISABLE_PC_LOGGING; 136210284Sjmallettstatic void __cvmx_log_full_process(void) 137210284Sjmallett{ 138210284Sjmallett if (cvmx_log_mcd0_on_full) 139210284Sjmallett { 140210284Sjmallett register uint64_t tmp; 141210284Sjmallett /* Pulse MCD0 signal so a remote utility can extract the data */ 142210284Sjmallett asm volatile ( 143210284Sjmallett "dmfc0 %0, $22\n" 144210284Sjmallett "ori %0, %0, 0x1110\n" 145210284Sjmallett "dmtc0 %0, $22\n" 146210284Sjmallett "nop\n" 147210284Sjmallett "nop\n" 148210284Sjmallett "nop\n" 149210284Sjmallett "nop\n" 150210284Sjmallett "nop\n" 151210284Sjmallett "nop\n" 152210284Sjmallett : "=r" (tmp)); 153210284Sjmallett } 154210284Sjmallett /* The write ptr may have been modifed by the debugger, check it again */ 155210284Sjmallett if (!(volatile uint64_t)CAST64(cvmx_log_buffer_write_ptr)) 156210284Sjmallett { 157210284Sjmallett #ifndef __KERNEL__ 158210284Sjmallett /* Disabled for the Linux kernel since printk is also profiled */ 159210284Sjmallett cvmx_dprintf("Log is full, reusing first buffer\n"); 160210284Sjmallett #endif 161210284Sjmallett *cvmx_log_buffer_end_ptr = CAST64(cvmx_log_buffer_head_ptr); 162210284Sjmallett cvmx_log_buffer_write_ptr = cvmx_log_buffer_head_ptr; 163210284Sjmallett cvmx_log_buffer_end_ptr = cvmx_log_buffer_write_ptr + CVMX_LOG_BUFFER_SIZE-1; 164210284Sjmallett cvmx_log_buffer_head_ptr = CASTPTR(uint64_t, *cvmx_log_buffer_end_ptr); 165210284Sjmallett *cvmx_log_buffer_end_ptr = CAST64(NULL); 166210284Sjmallett } 167210284Sjmallett} 168210284Sjmallett 169210284Sjmallett 170210284Sjmallett/** 171210284Sjmallett * @INTERNAL 172210284Sjmallett * Simple inline function to build a log header 173210284Sjmallett * 174210284Sjmallett * @param type Type of header to build 175210284Sjmallett * @param size Amount of data that follows the header in dwords 176210284Sjmallett * @return The header 177210284Sjmallett */ 178210284Sjmallettstatic inline uint64_t __cvmx_log_build_header(cvmx_log_type_t type, uint64_t size) CVMX_LOG_DISABLE_PC_LOGGING; 179210284Sjmallettstatic inline uint64_t __cvmx_log_build_header(cvmx_log_type_t type, uint64_t size) 180210284Sjmallett{ 181210284Sjmallett cvmx_log_header_t header; 182210284Sjmallett header.u64 = 0; 183210284Sjmallett header.s.type = type; 184210284Sjmallett header.s.size = size; 185210284Sjmallett header.s.cycle = cvmx_get_cycle(); 186210284Sjmallett return header.u64; 187210284Sjmallett} 188210284Sjmallett 189210284Sjmallett 190210284Sjmallett/** 191210284Sjmallett * @INTERNAL 192210284Sjmallett * Function to write and increment the position. It rotates 193210284Sjmallett * to the next log buffer as necessary. 194210284Sjmallett * 195210284Sjmallett * @param data Data to write to the log 196210284Sjmallett */ 197210284Sjmallettstatic inline void __cvmx_log_write(uint64_t data) CVMX_LOG_DISABLE_PC_LOGGING; 198210284Sjmallettstatic inline void __cvmx_log_write(uint64_t data) 199210284Sjmallett{ 200210284Sjmallett /* Check and see if we need to rotate the log */ 201210284Sjmallett if (cvmx_likely(cvmx_log_buffer_write_ptr != cvmx_log_buffer_end_ptr)) 202210284Sjmallett { 203210284Sjmallett /* No rotate is necessary, just write the data */ 204210284Sjmallett *cvmx_log_buffer_write_ptr++ = data; 205210284Sjmallett } 206210284Sjmallett else 207210284Sjmallett { 208210284Sjmallett /* Initialize the log if necessary */ 209210284Sjmallett if (cvmx_unlikely(cvmx_log_buffer_head_ptr == NULL)) 210210284Sjmallett __cvmx_log_initialize(); 211210284Sjmallett else 212210284Sjmallett { 213210284Sjmallett cvmx_log_buffer_write_ptr = CASTPTR(uint64_t, *cvmx_log_buffer_end_ptr); 214210284Sjmallett if (cvmx_likely(cvmx_log_buffer_write_ptr)) 215210284Sjmallett { 216210284Sjmallett /* Rotate the log. Might be a good time to send the old buffer 217210284Sjmallett somewhere */ 218210284Sjmallett cvmx_log_buffer_end_ptr = cvmx_log_buffer_write_ptr + CVMX_LOG_BUFFER_SIZE-1; 219210284Sjmallett } 220210284Sjmallett else 221210284Sjmallett __cvmx_log_full_process(); /* After this function returns, the log must be ready for updates */ 222210284Sjmallett } 223210284Sjmallett *cvmx_log_buffer_write_ptr++ = data; 224210284Sjmallett } 225210284Sjmallett} 226210284Sjmallett 227210284Sjmallett 228210284Sjmallett/** 229210284Sjmallett * Log a program counter address to the log. This is caused by 230210284Sjmallett * the assembly code function mcount when writing the PC value 231210284Sjmallett * is more complicated that the simple case support by it. 232210284Sjmallett * 233210284Sjmallett * @param pc Program counter address to log 234210284Sjmallett */ 235210284Sjmallettvoid cvmx_log_pc(uint64_t pc) CVMX_LOG_DISABLE_PC_LOGGING; 236210284Sjmallettvoid cvmx_log_pc(uint64_t pc) 237210284Sjmallett{ 238210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PC, 1)); 239210284Sjmallett __cvmx_log_write(pc); 240210284Sjmallett} 241210284Sjmallett 242210284Sjmallett 243210284Sjmallett/** 244210284Sjmallett * Log a constant printf style format string with 0 to 4 245210284Sjmallett * arguments. The string must persist until the log is read, 246210284Sjmallett * but the parameters are copied into the log. 247210284Sjmallett * 248210284Sjmallett * @param format Constant printf style format string. 249210284Sjmallett */ 250210284Sjmallettvoid cvmx_log_printf0(const char *format) 251210284Sjmallett{ 252210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 1)); 253210284Sjmallett __cvmx_log_write(CAST64(format)); 254210284Sjmallett} 255210284Sjmallett 256210284Sjmallett 257210284Sjmallett/** 258210284Sjmallett * Log a constant printf style format string with 0 to 4 259210284Sjmallett * arguments. The string must persist until the log is read, 260210284Sjmallett * but the parameters are copied into the log. 261210284Sjmallett * 262210284Sjmallett * @param format Constant printf style format string. 263210284Sjmallett * @param number1 64bit argument to the printf format string 264210284Sjmallett */ 265210284Sjmallettvoid cvmx_log_printf1(const char *format, uint64_t number1) 266210284Sjmallett{ 267210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 2)); 268210284Sjmallett __cvmx_log_write(CAST64(format)); 269210284Sjmallett __cvmx_log_write(number1); 270210284Sjmallett} 271210284Sjmallett 272210284Sjmallett 273210284Sjmallett/** 274210284Sjmallett * Log a constant printf style format string with 0 to 4 275210284Sjmallett * arguments. The string must persist until the log is read, 276210284Sjmallett * but the parameters are copied into the log. 277210284Sjmallett * 278210284Sjmallett * @param format Constant printf style format string. 279210284Sjmallett * @param number1 64bit argument to the printf format string 280210284Sjmallett * @param number2 64bit argument to the printf format string 281210284Sjmallett */ 282210284Sjmallettvoid cvmx_log_printf2(const char *format, uint64_t number1, uint64_t number2) 283210284Sjmallett{ 284210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 3)); 285210284Sjmallett __cvmx_log_write(CAST64(format)); 286210284Sjmallett __cvmx_log_write(number1); 287210284Sjmallett __cvmx_log_write(number2); 288210284Sjmallett} 289210284Sjmallett 290210284Sjmallett 291210284Sjmallett/** 292210284Sjmallett * Log a constant printf style format string with 0 to 4 293210284Sjmallett * arguments. The string must persist until the log is read, 294210284Sjmallett * but the parameters are copied into the log. 295210284Sjmallett * 296210284Sjmallett * @param format Constant printf style format string. 297210284Sjmallett * @param number1 64bit argument to the printf format string 298210284Sjmallett * @param number2 64bit argument to the printf format string 299210284Sjmallett * @param number3 64bit argument to the printf format string 300210284Sjmallett */ 301210284Sjmallettvoid cvmx_log_printf3(const char *format, uint64_t number1, uint64_t number2, uint64_t number3) 302210284Sjmallett{ 303210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 4)); 304210284Sjmallett __cvmx_log_write(CAST64(format)); 305210284Sjmallett __cvmx_log_write(number1); 306210284Sjmallett __cvmx_log_write(number2); 307210284Sjmallett __cvmx_log_write(number3); 308210284Sjmallett} 309210284Sjmallett 310210284Sjmallett 311210284Sjmallett/** 312210284Sjmallett * Log a constant printf style format string with 0 to 4 313210284Sjmallett * arguments. The string must persist until the log is read, 314210284Sjmallett * but the parameters are copied into the log. 315210284Sjmallett * 316210284Sjmallett * @param format Constant printf style format string. 317210284Sjmallett * @param number1 64bit argument to the printf format string 318210284Sjmallett * @param number2 64bit argument to the printf format string 319210284Sjmallett * @param number3 64bit argument to the printf format string 320210284Sjmallett * @param number4 64bit argument to the printf format string 321210284Sjmallett */ 322210284Sjmallettvoid cvmx_log_printf4(const char *format, uint64_t number1, uint64_t number2, uint64_t number3, uint64_t number4) 323210284Sjmallett{ 324210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 5)); 325210284Sjmallett __cvmx_log_write(CAST64(format)); 326210284Sjmallett __cvmx_log_write(number1); 327210284Sjmallett __cvmx_log_write(number2); 328210284Sjmallett __cvmx_log_write(number3); 329210284Sjmallett __cvmx_log_write(number4); 330210284Sjmallett} 331210284Sjmallett 332210284Sjmallett 333210284Sjmallett/** 334210284Sjmallett * Log an arbitrary block of 64bit words. At most 255 64bit 335210284Sjmallett * words can be logged. The words are copied into the log. 336210284Sjmallett * 337210284Sjmallett * @param size_in_dwords 338210284Sjmallett * Number of 64bit dwords to copy into the log. 339210284Sjmallett * @param data Array of 64bit dwords to copy 340210284Sjmallett */ 341210284Sjmallettvoid cvmx_log_data(uint64_t size_in_dwords, const uint64_t *data) 342210284Sjmallett{ 343210284Sjmallett if (size_in_dwords > 255) 344210284Sjmallett size_in_dwords = 255; 345210284Sjmallett 346210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_DATA, size_in_dwords)); 347210284Sjmallett while (size_in_dwords--) 348210284Sjmallett __cvmx_log_write(*data++); 349210284Sjmallett} 350210284Sjmallett 351210284Sjmallett 352210284Sjmallett/** 353210284Sjmallett * Log a structured data object. Post processing will use the 354210284Sjmallett * debugging information in the ELF file to determine how to 355210284Sjmallett * display the structure. Max of 2032 bytes. 356210284Sjmallett * 357210284Sjmallett * Example: 358210284Sjmallett * cvmx_log_structure("cvmx_wqe_t", work, sizeof(*work)); 359210284Sjmallett * 360210284Sjmallett * @param type C typedef expressed as a string. This will be used to 361210284Sjmallett * lookup the structure in the debugging infirmation. 362210284Sjmallett * @param data Data to be written to the log. 363210284Sjmallett * @param size_in_bytes 364210284Sjmallett * Size if the data in bytes. Normally you'll use the 365210284Sjmallett * sizeof() operator here. 366210284Sjmallett */ 367210284Sjmallettvoid cvmx_log_structure(const char *type, void *data, int size_in_bytes) 368210284Sjmallett{ 369210284Sjmallett uint64_t size_in_dwords = (size_in_bytes + 7) >> 3; 370210284Sjmallett uint64_t *ptr = (uint64_t*)data; 371210284Sjmallett 372210284Sjmallett if (size_in_dwords > 254) 373210284Sjmallett size_in_dwords = 254; 374210284Sjmallett 375210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_STRUCTURE, size_in_dwords + 1)); 376210284Sjmallett __cvmx_log_write(CAST64(type)); 377210284Sjmallett while (size_in_dwords--) 378210284Sjmallett __cvmx_log_write(*ptr++); 379210284Sjmallett} 380210284Sjmallett 381210284Sjmallett 382210284Sjmallett/** 383210284Sjmallett * Setup the mips performance counters 384210284Sjmallett * 385210284Sjmallett * @param counter1 Event type for counter 1 386210284Sjmallett * @param counter2 Event type for counter 2 387210284Sjmallett */ 388215990Sjmallettvoid cvmx_log_perf_setup(cvmx_core_perf_t counter1, cvmx_core_perf_t counter2) 389210284Sjmallett{ 390215990Sjmallett cvmx_core_perf_control_t control; 391210284Sjmallett 392210284Sjmallett control.u32 = 0; 393210284Sjmallett control.s.event = counter1; 394215990Sjmallett control.s.u = 1; 395215990Sjmallett control.s.s = 1; 396215990Sjmallett control.s.k = 1; 397215990Sjmallett control.s.ex = 1; 398210284Sjmallett asm ("mtc0 %0, $25, 0\n" : : "r"(control.u32)); 399210284Sjmallett control.s.event = counter2; 400210284Sjmallett asm ("mtc0 %0, $25, 2\n" : : "r"(control.u32)); 401210284Sjmallett} 402210284Sjmallett 403210284Sjmallett 404210284Sjmallett/** 405210284Sjmallett * Log the performance counters 406210284Sjmallett */ 407210284Sjmallettvoid cvmx_log_perf(void) 408210284Sjmallett{ 409210284Sjmallett uint64_t control1; 410210284Sjmallett uint64_t control2; 411210284Sjmallett uint64_t data1; 412210284Sjmallett uint64_t data2; 413210284Sjmallett asm ("dmfc0 %0, $25, 1\n" : "=r"(data1)); 414210284Sjmallett asm ("dmfc0 %0, $25, 3\n" : "=r"(data2)); 415210284Sjmallett asm ("mfc0 %0, $25, 0\n" : "=r"(control1)); 416210284Sjmallett asm ("mfc0 %0, $25, 2\n" : "=r"(control2)); 417210284Sjmallett __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PERF, 3)); 418210284Sjmallett __cvmx_log_write(((control1 & 0xffffffff) << 32) | (control2 & 0xffffffff)); 419210284Sjmallett __cvmx_log_write(data1); 420210284Sjmallett __cvmx_log_write(data2); 421210284Sjmallett} 422210284Sjmallett 423210284Sjmallett 424210284Sjmallett/** 425210284Sjmallett * @INTERNAL 426210284Sjmallett * Read a dword from the log 427210284Sjmallett * 428210284Sjmallett * @return the dword 429210284Sjmallett */ 430210284Sjmallettstatic uint64_t __cvmx_log_read(void) CVMX_LOG_DISABLE_PC_LOGGING; 431210284Sjmallettstatic uint64_t __cvmx_log_read(void) 432210284Sjmallett{ 433210284Sjmallett uint64_t data; 434210284Sjmallett 435210284Sjmallett /* Check and see if we need to rotate the log */ 436210284Sjmallett if (cvmx_likely(cvmx_log_buffer_read_ptr != cvmx_log_buffer_read_end_ptr)) 437210284Sjmallett { 438210284Sjmallett /* No rotate is necessary, just read the data */ 439210284Sjmallett data = *cvmx_log_buffer_read_ptr++; 440210284Sjmallett } 441210284Sjmallett else 442210284Sjmallett { 443210284Sjmallett cvmx_log_buffer_read_ptr = CASTPTR(uint64_t, *cvmx_log_buffer_read_end_ptr); 444210284Sjmallett if (cvmx_likely(cvmx_log_buffer_read_ptr)) 445210284Sjmallett { 446210284Sjmallett /* Rotate to the next log buffer */ 447210284Sjmallett cvmx_log_buffer_read_end_ptr = cvmx_log_buffer_read_ptr + CVMX_LOG_BUFFER_SIZE-1; 448210284Sjmallett data = *cvmx_log_buffer_read_ptr++; 449210284Sjmallett } 450210284Sjmallett else 451210284Sjmallett { 452210284Sjmallett /* No more log buffers, return 0 */ 453210284Sjmallett cvmx_log_buffer_read_end_ptr = NULL; 454210284Sjmallett data = 0; 455210284Sjmallett } 456210284Sjmallett } 457210284Sjmallett 458210284Sjmallett return data; 459210284Sjmallett} 460210284Sjmallett 461210284Sjmallett 462210284Sjmallett/** 463210284Sjmallett * Display the current log in a human readable format. 464210284Sjmallett */ 465210284Sjmallettvoid cvmx_log_display(void) 466210284Sjmallett{ 467210284Sjmallett unsigned int i; 468210284Sjmallett cvmx_log_header_t header; 469210284Sjmallett 470210284Sjmallett cvmx_log_buffer_read_ptr = cvmx_log_buffer_head_ptr; 471210284Sjmallett cvmx_log_buffer_read_end_ptr = cvmx_log_buffer_read_ptr + CVMX_LOG_BUFFER_SIZE-1; 472210284Sjmallett 473210284Sjmallett while (cvmx_log_buffer_read_ptr && (cvmx_log_buffer_read_ptr != cvmx_log_buffer_write_ptr)) 474210284Sjmallett { 475210284Sjmallett header.u64 = __cvmx_log_read(); 476210284Sjmallett if (header.s.cycle == 0) 477210284Sjmallett continue; 478210284Sjmallett printf("%llu: ", (unsigned long long)header.s.cycle); 479210284Sjmallett switch (header.s.type) 480210284Sjmallett { 481210284Sjmallett case CVMX_LOG_TYPE_PC: 482210284Sjmallett if (header.s.size == 1) 483210284Sjmallett printf("pc 0x%016llx\n", (unsigned long long)__cvmx_log_read()); 484210284Sjmallett else 485210284Sjmallett printf("Illegal size (%d) for log entry: pc\n", header.s.size); 486210284Sjmallett break; 487210284Sjmallett case CVMX_LOG_TYPE_PRINTF: 488210284Sjmallett switch (header.s.size) 489210284Sjmallett { 490210284Sjmallett case 1: 491210284Sjmallett printf(CASTPTR(const char, __cvmx_log_read())); 492210284Sjmallett break; 493210284Sjmallett case 2: 494210284Sjmallett printf(CASTPTR(const char, __cvmx_log_read()), __cvmx_log_read()); 495210284Sjmallett break; 496210284Sjmallett case 3: 497210284Sjmallett printf(CASTPTR(const char, __cvmx_log_read()), __cvmx_log_read(), __cvmx_log_read()); 498210284Sjmallett break; 499210284Sjmallett case 4: 500210284Sjmallett printf(CASTPTR(const char, __cvmx_log_read()), __cvmx_log_read(), __cvmx_log_read(), __cvmx_log_read()); 501210284Sjmallett break; 502210284Sjmallett case 5: 503210284Sjmallett printf(CASTPTR(const char, __cvmx_log_read()), __cvmx_log_read(), __cvmx_log_read(), __cvmx_log_read(), __cvmx_log_read()); 504210284Sjmallett break; 505210284Sjmallett default: 506210284Sjmallett printf("Illegal size (%d) for log entry: printf\n", header.s.size); 507210284Sjmallett break; 508210284Sjmallett } 509210284Sjmallett printf("\n"); 510210284Sjmallett break; 511210284Sjmallett case CVMX_LOG_TYPE_DATA: 512210284Sjmallett printf("data"); 513210284Sjmallett for (i=0; i<header.s.size; i++) 514210284Sjmallett printf(" 0x%016llx", (unsigned long long)__cvmx_log_read()); 515210284Sjmallett printf("\n"); 516210284Sjmallett break; 517210284Sjmallett case CVMX_LOG_TYPE_STRUCTURE: 518210284Sjmallett printf("struct %s", CASTPTR(const char, __cvmx_log_read())); 519210284Sjmallett for (i=1; i<header.s.size; i++) 520210284Sjmallett printf(" 0x%016llx", (unsigned long long)__cvmx_log_read()); 521210284Sjmallett printf("\n"); 522210284Sjmallett break; 523210284Sjmallett case CVMX_LOG_TYPE_PERF: 524210284Sjmallett if (header.s.size == 3) 525210284Sjmallett { 526210284Sjmallett unsigned long long control = __cvmx_log_read(); 527210284Sjmallett unsigned long long data1 = __cvmx_log_read(); 528210284Sjmallett unsigned long long data2 = __cvmx_log_read(); 529210284Sjmallett printf("perf control=0x%016llx data1=0x%016llx data2=0x%016llx\n", control, data1, data2); 530210284Sjmallett } 531210284Sjmallett else 532210284Sjmallett printf("Illegal size (%d) for log entry: perf\n", header.s.size); 533210284Sjmallett break; 534210284Sjmallett default: 535210284Sjmallett break; 536210284Sjmallett } 537210284Sjmallett } 538210284Sjmallett} 539210284Sjmallett 540