]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-log.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-log.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are
8  *  met:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
12  *
13  *      * Redistributions in binary form must reproduce the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer in the documentation and/or other materials provided
16  *        with the distribution.
17  *
18  *      * Neither the name of Cavium Networks nor the names of
19  *        its contributors may be used to endorse or promote products
20  *        derived from this software without specific prior written
21  *        permission.
22  *
23  *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24  *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25  *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26  *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27  *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28  *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29  *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30  *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31  *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32  *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * cvmx-log supplies a fast log buffer implementation. Each core writes
48  * log data to a differnet buffer to avoid synchronization overhead. Function
49  * call logging can be turned on with the GCC option "-pg".
50  *
51  * <hr>$Revision: 41586 $<hr>
52  */
53 #include "cvmx.h"
54 #include "cvmx-log.h"
55
56 #define CVMX_LOG_BUFFER_SIZE (1<<15)
57 #define CVMX_LOG_NUM_BUFFERS 4
58
59 /**
60  * The possible types of log data that can be stored in the
61  * buffer.
62  */
63 typedef enum
64 {
65     CVMX_LOG_TYPE_PC = 0,   /**< Log of the program counter location. used for code profiling / tracing */
66     CVMX_LOG_TYPE_PRINTF,   /**< Constant printf format string with two 64bit arguments */
67     CVMX_LOG_TYPE_DATA,     /**< Arbitrary array of dwords. Max size is 31 dwords */
68     CVMX_LOG_TYPE_STRUCTURE,/**< Log a structured data element. Max size is 30 dwords */
69     CVMX_LOG_TYPE_PERF,     /**< Mips performance counters control registers followed by the data */
70 } cvmx_log_type_t;
71
72 /**
73  * Header definition for each log entry.
74  */
75 typedef union
76 {
77     uint64_t u64;
78     struct
79     {
80         cvmx_log_type_t     type    : 3; /* Data in the log entry */
81         uint64_t            size    : 8; /* Data size in 64bit words */
82         uint64_t            cycle   :53; /* Low bits of the cycle counter as a timestamp */
83     } s;
84 } cvmx_log_header_t;
85
86 /**
87  * Circular log buffer. Each processor gets a private one to
88  * write to. Log entries are added at the current write
89  * location, then the write location is incremented. The
90  * buffer may wrap in the middle of a log entry.
91  */
92 static uint64_t cvmx_log_buffers[CVMX_LOG_NUM_BUFFERS][CVMX_LOG_BUFFER_SIZE];
93
94 /**
95  * Current locations in the log.
96  */
97 uint64_t *cvmx_log_buffer_write_ptr             = NULL; /* The next write will occur here */
98 uint64_t *cvmx_log_buffer_end_ptr               = NULL; /* Write must move to the next buffer when it equals this */
99 uint64_t *cvmx_log_buffer_head_ptr              = NULL; /* Pointer to begin extracting log data from */
100 static uint64_t *cvmx_log_buffer_read_ptr       = NULL; /* Location cvmx_display is reading from */
101 static uint64_t *cvmx_log_buffer_read_end_ptr   = NULL; /* Location where read will need the next buffer */
102 uint64_t cvmx_log_mcd0_on_full                  = 0;    /* If this is set, cvm-log will assert MCD0 when the log
103                                                             is full. This is set by the remote logging utility through
104                                                             the debugger interface. */
105
106
107 /**
108  * @INTERNAL
109  * Initialize the log for writing
110  */
111 static void __cvmx_log_initialize(void) CVMX_LOG_DISABLE_PC_LOGGING;
112 static void __cvmx_log_initialize(void)
113 {
114     int buf_num;
115
116     /* Link the buffers together using the last element in each buffer */
117     for (buf_num=0; buf_num<CVMX_LOG_NUM_BUFFERS-1; buf_num++)
118         cvmx_log_buffers[buf_num][CVMX_LOG_BUFFER_SIZE-1] = CAST64(cvmx_log_buffers[buf_num+1]);
119     cvmx_log_buffers[CVMX_LOG_NUM_BUFFERS-1][CVMX_LOG_BUFFER_SIZE-1] = CAST64(NULL);
120
121     cvmx_log_buffer_head_ptr = &cvmx_log_buffers[0][0];
122     cvmx_log_buffer_write_ptr = &cvmx_log_buffers[0][0];
123     cvmx_log_buffer_end_ptr = cvmx_log_buffer_write_ptr + CVMX_LOG_BUFFER_SIZE-1;
124 }
125
126
127 /**
128  * @INTERNAL
129  * Called when the log is full of data. This function must
130  * make room for more log data before returning.
131  */
132 static void __cvmx_log_full_process(void) CVMX_LOG_DISABLE_PC_LOGGING;
133 static void __cvmx_log_full_process(void)
134 {
135     if (cvmx_log_mcd0_on_full)
136     {
137         register uint64_t tmp;
138         /* Pulse MCD0 signal so a remote utility can extract the data */
139         asm volatile (
140             "dmfc0 %0, $22\n"
141                 "ori   %0, %0, 0x1110\n"
142             "dmtc0 %0, $22\n"
143             "nop\n"
144             "nop\n"
145             "nop\n"
146             "nop\n"
147             "nop\n"
148             "nop\n"
149             : "=r" (tmp));
150     }
151     /* The write ptr may have been modifed by the debugger, check it again */
152     if (!(volatile uint64_t)CAST64(cvmx_log_buffer_write_ptr))
153     {
154         #ifndef __KERNEL__
155             /* Disabled for the Linux kernel since printk is also profiled */
156             cvmx_dprintf("Log is full, reusing first buffer\n");
157         #endif
158         *cvmx_log_buffer_end_ptr = CAST64(cvmx_log_buffer_head_ptr);
159         cvmx_log_buffer_write_ptr = cvmx_log_buffer_head_ptr;
160         cvmx_log_buffer_end_ptr = cvmx_log_buffer_write_ptr + CVMX_LOG_BUFFER_SIZE-1;
161         cvmx_log_buffer_head_ptr = CASTPTR(uint64_t, *cvmx_log_buffer_end_ptr);
162         *cvmx_log_buffer_end_ptr = CAST64(NULL);
163     }
164 }
165
166
167 /**
168  * @INTERNAL
169  * Simple inline function to build a log header
170  *
171  * @param type   Type of header to build
172  * @param size   Amount of data that follows the header in dwords
173  * @return The header
174  */
175 static inline uint64_t __cvmx_log_build_header(cvmx_log_type_t type, uint64_t size) CVMX_LOG_DISABLE_PC_LOGGING;
176 static inline uint64_t __cvmx_log_build_header(cvmx_log_type_t type, uint64_t size)
177 {
178     cvmx_log_header_t header;
179     header.u64 = 0;
180     header.s.type = type;
181     header.s.size = size;
182     header.s.cycle = cvmx_get_cycle();
183     return header.u64;
184 }
185
186
187 /**
188  * @INTERNAL
189  * Function to write and increment the position. It rotates
190  * to the next log buffer as necessary.
191  *
192  * @param data   Data to write to the log
193  */
194 static inline void __cvmx_log_write(uint64_t data) CVMX_LOG_DISABLE_PC_LOGGING;
195 static inline void __cvmx_log_write(uint64_t data)
196 {
197     /* Check and see if we need to rotate the log */
198     if (cvmx_likely(cvmx_log_buffer_write_ptr != cvmx_log_buffer_end_ptr))
199     {
200         /* No rotate is necessary, just write the data */
201         *cvmx_log_buffer_write_ptr++ = data;
202     }
203     else
204     {
205         /* Initialize the log if necessary */
206         if (cvmx_unlikely(cvmx_log_buffer_head_ptr == NULL))
207             __cvmx_log_initialize();
208         else
209         {
210             cvmx_log_buffer_write_ptr = CASTPTR(uint64_t, *cvmx_log_buffer_end_ptr);
211             if (cvmx_likely(cvmx_log_buffer_write_ptr))
212             {
213                 /* Rotate the log. Might be a good time to send the old buffer
214                     somewhere */
215                 cvmx_log_buffer_end_ptr = cvmx_log_buffer_write_ptr + CVMX_LOG_BUFFER_SIZE-1;
216             }
217             else
218                 __cvmx_log_full_process();    /* After this function returns, the log must be ready for updates */
219         }
220         *cvmx_log_buffer_write_ptr++ = data;
221     }
222 }
223
224
225 /**
226  * Log a program counter address to the log. This is caused by
227  * the assembly code function mcount when writing the PC value
228  * is more complicated that the simple case support by it.
229  *
230  * @param pc     Program counter address to log
231  */
232 void cvmx_log_pc(uint64_t pc) CVMX_LOG_DISABLE_PC_LOGGING;
233 void cvmx_log_pc(uint64_t pc)
234 {
235     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PC, 1));
236     __cvmx_log_write(pc);
237 }
238
239
240 /**
241  * Log a constant printf style format string with 0 to 4
242  * arguments. The string must persist until the log is read,
243  * but the parameters are copied into the log.
244  *
245  * @param format  Constant printf style format string.
246  */
247 void cvmx_log_printf0(const char *format)
248 {
249     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 1));
250     __cvmx_log_write(CAST64(format));
251 }
252
253
254 /**
255  * Log a constant printf style format string with 0 to 4
256  * arguments. The string must persist until the log is read,
257  * but the parameters are copied into the log.
258  *
259  * @param format  Constant printf style format string.
260  * @param number1 64bit argument to the printf format string
261  */
262 void cvmx_log_printf1(const char *format, uint64_t number1)
263 {
264     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 2));
265     __cvmx_log_write(CAST64(format));
266     __cvmx_log_write(number1);
267 }
268
269
270 /**
271  * Log a constant printf style format string with 0 to 4
272  * arguments. The string must persist until the log is read,
273  * but the parameters are copied into the log.
274  *
275  * @param format  Constant printf style format string.
276  * @param number1 64bit argument to the printf format string
277  * @param number2 64bit argument to the printf format string
278  */
279 void cvmx_log_printf2(const char *format, uint64_t number1, uint64_t number2)
280 {
281     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 3));
282     __cvmx_log_write(CAST64(format));
283     __cvmx_log_write(number1);
284     __cvmx_log_write(number2);
285 }
286
287
288 /**
289  * Log a constant printf style format string with 0 to 4
290  * arguments. The string must persist until the log is read,
291  * but the parameters are copied into the log.
292  *
293  * @param format  Constant printf style format string.
294  * @param number1 64bit argument to the printf format string
295  * @param number2 64bit argument to the printf format string
296  * @param number3 64bit argument to the printf format string
297  */
298 void cvmx_log_printf3(const char *format, uint64_t number1, uint64_t number2, uint64_t number3)
299 {
300     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 4));
301     __cvmx_log_write(CAST64(format));
302     __cvmx_log_write(number1);
303     __cvmx_log_write(number2);
304     __cvmx_log_write(number3);
305 }
306
307
308 /**
309  * Log a constant printf style format string with 0 to 4
310  * arguments. The string must persist until the log is read,
311  * but the parameters are copied into the log.
312  *
313  * @param format  Constant printf style format string.
314  * @param number1 64bit argument to the printf format string
315  * @param number2 64bit argument to the printf format string
316  * @param number3 64bit argument to the printf format string
317  * @param number4 64bit argument to the printf format string
318  */
319 void cvmx_log_printf4(const char *format, uint64_t number1, uint64_t number2, uint64_t number3, uint64_t number4)
320 {
321     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PRINTF, 5));
322     __cvmx_log_write(CAST64(format));
323     __cvmx_log_write(number1);
324     __cvmx_log_write(number2);
325     __cvmx_log_write(number3);
326     __cvmx_log_write(number4);
327 }
328
329
330 /**
331  * Log an arbitrary block of 64bit words. At most 255 64bit
332  * words can be logged. The words are copied into the log.
333  *
334  * @param size_in_dwords
335  *               Number of 64bit dwords to copy into the log.
336  * @param data   Array of 64bit dwords to copy
337  */
338 void cvmx_log_data(uint64_t size_in_dwords, const uint64_t *data)
339 {
340     if (size_in_dwords > 255)
341         size_in_dwords = 255;
342
343     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_DATA, size_in_dwords));
344     while (size_in_dwords--)
345         __cvmx_log_write(*data++);
346 }
347
348
349 /**
350  * Log a structured data object. Post processing will use the
351  * debugging information in the ELF file to determine how to
352  * display the structure. Max of 2032 bytes.
353  *
354  * Example:
355  * cvmx_log_structure("cvmx_wqe_t", work, sizeof(*work));
356  *
357  * @param type   C typedef expressed as a string. This will be used to
358  *               lookup the structure in the debugging infirmation.
359  * @param data   Data to be written to the log.
360  * @param size_in_bytes
361  *               Size if the data in bytes. Normally you'll use the
362  *               sizeof() operator here.
363  */
364 void cvmx_log_structure(const char *type, void *data, int size_in_bytes)
365 {
366     uint64_t size_in_dwords = (size_in_bytes + 7) >> 3;
367     uint64_t *ptr = (uint64_t*)data;
368
369     if (size_in_dwords > 254)
370         size_in_dwords = 254;
371
372     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_STRUCTURE, size_in_dwords + 1));
373     __cvmx_log_write(CAST64(type));
374     while (size_in_dwords--)
375         __cvmx_log_write(*ptr++);
376 }
377
378
379 /**
380  * Setup the mips performance counters
381  *
382  * @param counter1 Event type for counter 1
383  * @param counter2 Event type for counter 2
384  */
385 void cvmx_log_perf_setup(cvmx_log_perf_event_t counter1, cvmx_log_perf_event_t counter2)
386 {
387     cvmx_log_perf_control_t control;
388
389     control.u32 = 0;
390     control.s.event = counter1;
391     control.s.U = 1;
392     control.s.S = 1;
393     control.s.K = 1;
394     control.s.EX = 1;
395     asm ("mtc0 %0, $25, 0\n" : : "r"(control.u32));
396     control.s.event = counter2;
397     asm ("mtc0 %0, $25, 2\n" : : "r"(control.u32));
398 }
399
400
401 /**
402  * Log the performance counters
403  */
404 void cvmx_log_perf(void)
405 {
406     uint64_t control1;
407     uint64_t control2;
408     uint64_t data1;
409     uint64_t data2;
410     asm ("dmfc0 %0, $25, 1\n" : "=r"(data1));
411     asm ("dmfc0 %0, $25, 3\n" : "=r"(data2));
412     asm ("mfc0 %0, $25, 0\n" : "=r"(control1));
413     asm ("mfc0 %0, $25, 2\n" : "=r"(control2));
414     __cvmx_log_write(__cvmx_log_build_header(CVMX_LOG_TYPE_PERF, 3));
415     __cvmx_log_write(((control1 & 0xffffffff) << 32) | (control2 & 0xffffffff));
416     __cvmx_log_write(data1);
417     __cvmx_log_write(data2);
418 }
419
420
421 /**
422  * @INTERNAL
423  * Read a dword from the log
424  *
425  * @return the dword
426  */
427 static uint64_t __cvmx_log_read(void) CVMX_LOG_DISABLE_PC_LOGGING;
428 static uint64_t __cvmx_log_read(void)
429 {
430     uint64_t data;
431
432     /* Check and see if we need to rotate the log */
433     if (cvmx_likely(cvmx_log_buffer_read_ptr != cvmx_log_buffer_read_end_ptr))
434     {
435         /* No rotate is necessary, just read the data */
436         data = *cvmx_log_buffer_read_ptr++;
437     }
438     else
439     {
440         cvmx_log_buffer_read_ptr = CASTPTR(uint64_t, *cvmx_log_buffer_read_end_ptr);
441         if (cvmx_likely(cvmx_log_buffer_read_ptr))
442         {
443             /* Rotate to the next log buffer */
444             cvmx_log_buffer_read_end_ptr = cvmx_log_buffer_read_ptr + CVMX_LOG_BUFFER_SIZE-1;
445             data = *cvmx_log_buffer_read_ptr++;
446         }
447         else
448         {
449             /* No more log buffers, return 0 */
450             cvmx_log_buffer_read_end_ptr = NULL;
451             data = 0;
452         }
453     }
454
455     return data;
456 }
457
458
459 /**
460  * Display the current log in a human readable format.
461  */
462 void cvmx_log_display(void)
463 {
464     unsigned int i;
465     cvmx_log_header_t header;
466
467     cvmx_log_buffer_read_ptr = cvmx_log_buffer_head_ptr;
468     cvmx_log_buffer_read_end_ptr = cvmx_log_buffer_read_ptr + CVMX_LOG_BUFFER_SIZE-1;
469
470     while (cvmx_log_buffer_read_ptr && (cvmx_log_buffer_read_ptr != cvmx_log_buffer_write_ptr))
471     {
472         header.u64 = __cvmx_log_read();
473         if (header.s.cycle == 0)
474             continue;
475         printf("%llu: ", (unsigned long long)header.s.cycle);
476         switch (header.s.type)
477         {
478             case CVMX_LOG_TYPE_PC:
479                 if (header.s.size == 1)
480                     printf("pc 0x%016llx\n", (unsigned long long)__cvmx_log_read());
481                 else
482                     printf("Illegal size (%d) for log entry: pc\n", header.s.size);
483                 break;
484             case CVMX_LOG_TYPE_PRINTF:
485                 switch (header.s.size)
486                 {
487                     case 1:
488                         printf(CASTPTR(const char, __cvmx_log_read()));
489                         break;
490                     case 2:
491                         printf(CASTPTR(const char, __cvmx_log_read()), __cvmx_log_read());
492                         break;
493                     case 3:
494                         printf(CASTPTR(const char, __cvmx_log_read()), __cvmx_log_read(), __cvmx_log_read());
495                         break;
496                     case 4:
497                         printf(CASTPTR(const char, __cvmx_log_read()), __cvmx_log_read(), __cvmx_log_read(), __cvmx_log_read());
498                         break;
499                     case 5:
500                         printf(CASTPTR(const char, __cvmx_log_read()), __cvmx_log_read(), __cvmx_log_read(), __cvmx_log_read(), __cvmx_log_read());
501                         break;
502                     default:
503                         printf("Illegal size (%d) for log entry: printf\n", header.s.size);
504                         break;
505                 }
506                 printf("\n");
507                 break;
508             case CVMX_LOG_TYPE_DATA:
509                 printf("data");
510                 for (i=0; i<header.s.size; i++)
511                     printf(" 0x%016llx", (unsigned long long)__cvmx_log_read());
512                 printf("\n");
513                 break;
514             case CVMX_LOG_TYPE_STRUCTURE:
515                 printf("struct %s", CASTPTR(const char, __cvmx_log_read()));
516                 for (i=1; i<header.s.size; i++)
517                     printf(" 0x%016llx", (unsigned long long)__cvmx_log_read());
518                 printf("\n");
519                 break;
520             case CVMX_LOG_TYPE_PERF:
521                 if (header.s.size == 3)
522                 {
523                     unsigned long long control = __cvmx_log_read();
524                     unsigned long long data1 = __cvmx_log_read();
525                     unsigned long long data2 = __cvmx_log_read();
526                     printf("perf control=0x%016llx data1=0x%016llx data2=0x%016llx\n", control, data1, data2);
527                 }
528                 else
529                     printf("Illegal size (%d) for log entry: perf\n", header.s.size);
530                 break;
531             default:
532                 break;
533         }
534     }
535 }
536