bsltrace.c (6781B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * Broadcom System Log Trace Buffer Sink 8 */ 9 #include <soc/drv.h> 10 #include <sal/core/libc.h> 11 #include <sal/core/sync.h> 12 #include <sal/core/alloc.h> 13 #include <sal/appl/io.h> 14 #include <appl/diag/bslsink.h> 15 #include <appl/diag/bslenable.h> 16 #include <shared/bsl.h> 17 18 /* 19 * BSL copies the trace string to the buffer in two steps. 20 * First the prefix string is copied, then the log string. 21 * So each trace string uses two trace buffer entries. 22 * Using a short entry length and double the max entries. 23 */ 24 #define MAX_NUM_TRACE_ENTRIES 1000 25 #define MAX_TRACE_ENTRY_LEN 64 26 27 typedef struct bsl_trace_buf_s { 28 char * buffer_start; 29 int buffer_size; 30 int cur_num_entries; 31 int max_num_entries; 32 int entry_length; 33 char * head; 34 sal_mutex_t lock; 35 } bsl_trace_buf_t; 36 37 static bsl_trace_buf_t trace; 38 static bslsink_sink_t trace_sink; 39 40 /* 41 * Note that inserting trace messages during an interrupt is 42 * only allowed in cases where the interrupt handling is done 43 * at thread level. 44 */ 45 STATIC int bsltrace_add(const char *format, va_list args) 46 { 47 int str_len = 0; 48 49 /* Lock access to trace buf */ 50 sal_mutex_take(trace.lock, sal_mutex_FOREVER); 51 52 /* Add string to head of trace buffer */ 53 str_len = sal_vsprintf(trace.head, format, args); 54 55 if (str_len > trace.entry_length) { 56 /* Handle Error */ 57 } else if (str_len < 0) { 58 /* Handle Error */ 59 } else { 60 /* Increment head*/ 61 trace.head = (char *)(trace.head) + trace.entry_length; 62 63 /* Handle wrap */ 64 if (trace.head == (trace.buffer_start + trace.buffer_size) ) { 65 trace.head = trace.buffer_start; 66 } 67 68 /* Count up to max number of entries until full, 69 then simply overwrite the oldest */ 70 if (trace.cur_num_entries < trace.max_num_entries) { 71 trace.cur_num_entries++; 72 } 73 } 74 75 /* Unlock access to trace buf */ 76 sal_mutex_give(trace.lock); 77 78 return str_len; 79 } 80 81 STATIC int 82 bsltrace_vfprintf(void *file, const char *format, va_list args) 83 { 84 /* Need to print to circular trace buffer */ 85 return bsltrace_add(format, args); 86 } 87 88 STATIC int 89 bsltrace_cleanup(bslsink_sink_t * sink) 90 { 91 92 /* Free allocated trace buffer */ 93 if (trace.buffer_start) { 94 sal_free(trace.buffer_start); 95 } 96 97 return 0; 98 } 99 100 int bsltrace_clear(void) 101 { 102 if (!trace.lock) { 103 cli_out("Trace Buffer Not Initialized\n"); 104 return 0; 105 } 106 107 /* Lock access to trace buf */ 108 sal_mutex_take(trace.lock, sal_mutex_FOREVER); 109 110 trace.head = trace.buffer_start; 111 trace.cur_num_entries = 0; 112 113 /* Unlock access to trace buf */ 114 sal_mutex_give(trace.lock); 115 116 return 0; 117 } 118 119 /* Print the last "entries" entries. 120 * Print all entries if "entries" < 0 121 */ 122 int bsltrace_print(int entries) 123 { 124 char * entry = NULL; 125 int i, j; 126 127 if (!trace.lock) { 128 cli_out("Trace Buffer Not Initialized\n"); 129 return 0; 130 } 131 132 /* Lock access to trace buf */ 133 sal_mutex_take(trace.lock, sal_mutex_FOREVER); 134 135 if (trace.cur_num_entries == 0) { 136 cli_out("Empty Trace Buffer\n"); 137 138 /* Unlock access to trace buf */ 139 sal_mutex_give(trace.lock); 140 141 return 0; 142 } else if (trace.cur_num_entries < trace.max_num_entries) { 143 entry = trace.buffer_start; 144 } 145 else { 146 entry = trace.head; 147 } 148 149 /* Print trace oldest to newest */ 150 if ((entries < 0) || 151 (entries > (trace.cur_num_entries / 2))) { 152 j = 0; 153 } else { 154 j = (trace.cur_num_entries - (entries * 2)); 155 } 156 157 for (i = 0; i < trace.cur_num_entries; i++) { 158 if (i >= j) { 159 cli_out("%s", entry); 160 } 161 entry += trace.entry_length; 162 if (entry == (trace.buffer_start + trace.buffer_size)) { 163 entry = trace.buffer_start; 164 } 165 } 166 167 /* Unlock access to trace buf */ 168 sal_mutex_give(trace.lock); 169 170 return 0; 171 } 172 173 /* As each trace string uses two trace buffer entries, 174 * Adjust the number of entries accordingly.. 175 */ 176 int bsltrace_config_set(int nentry, int size) 177 { 178 int n, sz; 179 180 if (!trace.lock) { 181 cli_out("Trace Buffer Not Initialized\n"); 182 return 0; 183 } 184 185 if ((trace.max_num_entries == (nentry * 2)) && 186 (trace.entry_length == size)) { 187 /* No Changes */ 188 return 0; 189 } 190 n = (nentry > 0) ? (nentry * 2) : trace.max_num_entries; 191 sz = (size > 0) ? size : trace.entry_length; 192 193 /* Lock access to trace buf */ 194 sal_mutex_take(trace.lock, sal_mutex_FOREVER); 195 196 sal_free(trace.buffer_start); 197 198 trace.buffer_start = 199 sal_alloc(sz * n, "bsltrace"); 200 trace.head = trace.buffer_start; 201 trace.buffer_size = sz * n; 202 trace.cur_num_entries = 0; 203 trace.max_num_entries = n; 204 trace.entry_length = sz; 205 206 /* Unlock access to trace buf */ 207 sal_mutex_give(trace.lock); 208 209 return 0; 210 } 211 212 int bsltrace_config_get(int *nentry, int *size) 213 { 214 *nentry = trace.max_num_entries / 2; 215 *size = trace.entry_length; 216 return trace.cur_num_entries / 2; 217 } 218 219 int 220 bsltrace_init(void) 221 { 222 223 bslsink_sink_t *sink; 224 225 if (!soc_property_get(0, "tracesink", 1)) { 226 return 0; 227 } 228 229 /* Create mutex lock to protect buffer access */ 230 if (!trace.lock) { 231 trace.lock = sal_mutex_create("trace_lock"); 232 } 233 234 /* Alocate and initialize trace buffer */ 235 trace.buffer_start = 236 sal_alloc(MAX_TRACE_ENTRY_LEN * MAX_NUM_TRACE_ENTRIES, "bsltrace"); 237 238 if (trace.buffer_start == NULL) { 239 return 1; 240 } 241 sal_memset(trace.buffer_start, 242 0, 243 MAX_TRACE_ENTRY_LEN * MAX_NUM_TRACE_ENTRIES); 244 245 /* Initialize the trace buffer management info */ 246 trace.head = trace.buffer_start; 247 trace.buffer_size = MAX_TRACE_ENTRY_LEN * MAX_NUM_TRACE_ENTRIES; 248 trace.cur_num_entries = 0; 249 trace.max_num_entries = MAX_NUM_TRACE_ENTRIES; 250 trace.entry_length = MAX_TRACE_ENTRY_LEN; 251 252 /* Create and configure the trace sink */ 253 sink = &trace_sink; 254 bslsink_sink_t_init(sink); 255 sal_strncpy(sink->name, "trace", sizeof(sink->name)); 256 sink->vfprintf = bsltrace_vfprintf; 257 sink->cleanup = bsltrace_cleanup; 258 sink->enable_range.min = bslSeverityDebug; 259 sink->enable_range.max = bslSeverityDebug; 260 261 /* Configure the trace prefix */ 262 sal_strncpy(sink->prefix_format, "%u:%L%S%s (%P:%T):", 263 sizeof(sink->prefix_format)); 264 sink->prefix_range.min = bslSeverityDebug; 265 sink->prefix_range.max = bslSeverityDebug; 266 267 bslsink_sink_add(sink); 268 269 return 0; 270 }