1 /* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright(c) 2016 Intel Corporation. All rights reserved.
4 *
5 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 * Keyon Jie <yang.jie@linux.intel.com>
7 * Artur Kloniecki <arturx.kloniecki@linux.intel.com>
8 * Karol Trzcinski <karolx.trzcinski@linux.intel.com>
9 */
10
11 #ifndef __SOF_TRACE_TRACE_H__
12 #define __SOF_TRACE_TRACE_H__
13
14 #ifndef RELATIVE_FILE
15 #error "This file requires RELATIVE_FILE to be defined. " \
16 "Add it to CMake's target with sof_append_relative_path_definitions."
17 #endif
18
19 #if !CONFIG_LIBRARY
20 #include <platform/trace/trace.h>
21 #endif
22 #include <sof/common.h>
23 #include <sof/sof.h>
24 #include <sof/trace/preproc.h>
25
26 #include <stdbool.h>
27 #include <stdint.h>
28 #if CONFIG_LIBRARY
29 #include <stdio.h>
30 #endif
31
32 struct sof;
33 struct trace;
34 struct tr_ctx;
35
36 /* bootloader trace values */
37 #define TRACE_BOOT_LDR_ENTRY 0x100
38 #define TRACE_BOOT_LDR_HPSRAM 0x110
39 #define TRACE_BOOT_LDR_MANIFEST 0x120
40 #define TRACE_BOOT_LDR_LPSRAM 0x130
41 #define TRACE_BOOT_LDR_L1DRAM 0x140
42 #define TRACE_BOOT_LDR_JUMP 0x150
43
44 #define TRACE_BOOT_LDR_PARSE_MODULE 0x210
45 #define TRACE_BOOT_LDR_PARSE_SEGMENT 0x220
46
47 /* general trace init codes - only used at boot
48 * when main trace is not available
49 */
50 #define TRACE_BOOT_START 0x1000
51 #define TRACE_BOOT_ARCH 0x2000
52 #define TRACE_BOOT_SYS 0x3000
53 #define TRACE_BOOT_PLATFORM 0x4000
54
55 /* system specific codes */
56 #define TRACE_BOOT_SYS_HEAP (TRACE_BOOT_SYS + 0x100)
57 #define TRACE_BOOT_SYS_TRACES (TRACE_BOOT_SYS + 0x200)
58 #define TRACE_BOOT_SYS_NOTIFIER (TRACE_BOOT_SYS + 0x300)
59 #define TRACE_BOOT_SYS_POWER (TRACE_BOOT_SYS + 0x400)
60
61 /* platform/device specific codes */
62 #define TRACE_BOOT_PLATFORM_ENTRY (TRACE_BOOT_PLATFORM + 0x100)
63 #define TRACE_BOOT_PLATFORM_IRQ (TRACE_BOOT_PLATFORM + 0x110)
64 #define TRACE_BOOT_PLATFORM_MBOX (TRACE_BOOT_PLATFORM + 0x120)
65 #define TRACE_BOOT_PLATFORM_SHIM (TRACE_BOOT_PLATFORM + 0x130)
66 #define TRACE_BOOT_PLATFORM_PMC (TRACE_BOOT_PLATFORM + 0x140)
67 #define TRACE_BOOT_PLATFORM_TIMER (TRACE_BOOT_PLATFORM + 0x150)
68 #define TRACE_BOOT_PLATFORM_CLOCK (TRACE_BOOT_PLATFORM + 0x160)
69 #define TRACE_BOOT_PLATFORM_SCHED (TRACE_BOOT_PLATFORM + 0x170)
70 #define TRACE_BOOT_PLATFORM_AGENT (TRACE_BOOT_PLATFORM + 0x180)
71 #define TRACE_BOOT_PLATFORM_CPU_FREQ (TRACE_BOOT_PLATFORM + 0x190)
72 #define TRACE_BOOT_PLATFORM_SSP_FREQ (TRACE_BOOT_PLATFORM + 0x1A0)
73 #define TRACE_BOOT_PLATFORM_DMA (TRACE_BOOT_PLATFORM + 0x1B0)
74 #define TRACE_BOOT_PLATFORM_IPC (TRACE_BOOT_PLATFORM + 0x1C0)
75 #define TRACE_BOOT_PLATFORM_IDC (TRACE_BOOT_PLATFORM + 0x1D0)
76 #define TRACE_BOOT_PLATFORM_DAI (TRACE_BOOT_PLATFORM + 0x1E0)
77 #define TRACE_BOOT_PLATFORM_SSP (TRACE_BOOT_PLATFORM + 0x1F0)
78 #define TRACE_BOOT_PLATFORM_SPI (TRACE_BOOT_PLATFORM + 0x200)
79 #define TRACE_BOOT_PLATFORM_DMA_TRACE (TRACE_BOOT_PLATFORM + 0x210)
80
81 #define _TRACE_EVENT_MAX_ARGUMENT_COUNT 4
82
trace_get(void)83 static inline struct trace *trace_get(void)
84 {
85 return sof_get()->trace;
86 }
87
88 /* Silences compiler warnings about unused variables */
89 #define trace_unused(class, ctx, id_1, id_2, format, ...) \
90 UNUSED(ctx, id_1, id_2, ##__VA_ARGS__)
91
92 struct trace_filter {
93 uint32_t uuid_id; /**< type id, or 0 when not important */
94 int32_t comp_id; /**< component id or -1 when not important */
95 int32_t pipe_id; /**< pipeline id or -1 when not important */
96 int32_t log_level; /**< new log level value */
97 };
98
99 #if CONFIG_TRACE
100
101 /*
102 * trace_event macro definition
103 *
104 * trace_event() macro is used for logging events that occur at runtime.
105 * It comes in 2 main flavours, atomic and non-atomic. Depending of definitions
106 * above, it might also propagate log messages to mbox if desired.
107 *
108 * First argument is always class of event being logged, as defined in
109 * user/trace.h - TRACE_CLASS_* (deprecated - do not use).
110 * Second argument is string literal in printf format, followed by up to 4
111 * parameters (uint32_t), that are used to expand into string fromat when
112 * parsing log data.
113 *
114 * All compile-time accessible data (verbosity, class, source file name, line
115 * index and string literal) are linked into .static_log_entries section
116 * of binary and then extracted by smex, so they do not contribute to loadable
117 * image size. This way more elaborate log messages are possible and encouraged,
118 * for better debugging experience, without worrying about runtime performance.
119 */
120
121 /* Map the different trace_xxxx_with_ids(... ) levels to the
122 * _trace_event_with_ids(level_xxxx, ...) macro shared across log
123 * levels.
124 */
125 #define trace_event_with_ids(class, ctx, id_1, id_2, format, ...) \
126 _trace_event_with_ids(LOG_LEVEL_INFO, class, ctx, id_1, id_2, \
127 format, ##__VA_ARGS__)
128
129 #define trace_event_atomic_with_ids(class, ctx, id_1, id_2, format, ...) \
130 _trace_event_atomic_with_ids(LOG_LEVEL_INFO, class, ctx, id_1, id_2, \
131 format, ##__VA_ARGS__)
132
133 #define trace_warn_with_ids(class, ctx, id_1, id_2, format, ...) \
134 _trace_event_with_ids(LOG_LEVEL_WARNING, class, ctx, id_1, id_2, \
135 format, ##__VA_ARGS__)
136
137 #define trace_warn_atomic_with_ids(class, ctx, id_1, id_2, format, ...) \
138 _trace_event_atomic_with_ids(LOG_LEVEL_WARNING, class, \
139 ctx, id_1, id_2, \
140 format, ##__VA_ARGS__)
141
142 void trace_flush_dma_to_mbox(void);
143 void trace_on(void);
144 void trace_off(void);
145 void trace_init(struct sof *sof);
146
147 /* All tracing macros in this file end up calling these functions in the end. */
148 void trace_log_filtered(bool send_atomic, const void *log_entry, const struct tr_ctx *ctx,
149 uint32_t lvl, uint32_t id_1, uint32_t id_2, int arg_count, ...);
150 void trace_log_unfiltered(bool send_atomic, const void *log_entry, const struct tr_ctx *ctx,
151 uint32_t lvl, uint32_t id_1, uint32_t id_2, int arg_count, ...);
152 struct sof_ipc_trace_filter_elem *trace_filter_fill(struct sof_ipc_trace_filter_elem *elem,
153 struct sof_ipc_trace_filter_elem *end,
154 struct trace_filter *filter);
155 int trace_filter_update(const struct trace_filter *elem);
156
157 #define _trace_event_with_ids(lvl, class, ctx, id_1, id_2, format, ...) \
158 _log_message(trace_log_filtered, false, lvl, class, ctx, id_1, id_2, format, ##__VA_ARGS__)
159
160 #define _trace_event_atomic_with_ids(lvl, class, ctx, id_1, id_2, format, ...) \
161 _log_message(trace_log_filtered, true, lvl, class, ctx, id_1, id_2, format, ##__VA_ARGS__)
162
163 /**
164 * Appends one SOF dictionary entry and log statement to the ring buffer
165 * implementing the 'etrace' in shared memory.
166 *
167 * @param atomic_context Take the trace->lock if false.
168 * @param log_entry_pointer dictionary index produced by the
169 * _DECLARE_LOG_ENTRY macro.
170 * @param n_args number of va_args
171 */
172 void mtrace_dict_entry(bool atomic_context, uint32_t log_entry_pointer, int n_args, ...);
173
174 /** Posts a fully prepared log header + log entry */
175 void mtrace_event(const char *complete_packet, uint32_t length);
176
177 /** The start of this linker output MUST match the 'ldc_entry_header'
178 * struct defined in the logger program running in user space.
179 */
180 #define _DECLARE_LOG_ENTRY(lvl, format, comp_class, n_params) \
181 __section(".static_log." #lvl) \
182 static const struct { \
183 uint32_t level; \
184 uint32_t component_class; \
185 uint32_t params_num; \
186 uint32_t line_idx; \
187 uint32_t file_name_len; \
188 uint32_t text_len; \
189 const char file_name[sizeof(RELATIVE_FILE)]; \
190 const char text[sizeof(format)]; \
191 } log_entry = { \
192 lvl, \
193 comp_class, \
194 n_params, \
195 __LINE__, \
196 sizeof(RELATIVE_FILE), \
197 sizeof(format), \
198 RELATIVE_FILE, \
199 format \
200 }
201
202 /* _log_message() */
203
204 #ifdef CONFIG_LIBRARY
205
206 extern int test_bench_trace;
207 char *get_trace_class(uint32_t trace_class);
208 #define _log_message(ignored_log_func, atomic, level, comp_class, ctx, id_1, id_2, format, ...) \
209 do { \
210 (void)ctx; \
211 (void)id_1; \
212 (void)id_2; \
213 if (test_bench_trace) { \
214 char *msg = "%s " format; \
215 fprintf(stderr, msg, get_trace_class(comp_class), ##__VA_ARGS__); \
216 fprintf(stderr, "\n"); \
217 } \
218 } while (0)
219
220 #define trace_point(x) do {} while (0)
221
222 #else /* CONFIG_LIBRARY */
223
224 #define trace_point(x) platform_trace_point(x)
225
226 #define BASE_LOG_ASSERT_FAIL_MSG \
227 unsupported_amount_of_params_in_trace_event\
228 _thrown_from_macro_BASE_LOG_in_trace_h
229
230 #define CT_ASSERT(COND, MESSAGE) \
231 ((void)sizeof(char[1 - 2 * !(COND)]))
232
233 #define trace_check_size_uint32(a) \
234 CT_ASSERT(sizeof(a) <= sizeof(uint32_t), "error: trace argument is bigger than a uint32_t");
235
236 #define STATIC_ASSERT_ARG_SIZE(...) \
237 META_MAP(1, trace_check_size_uint32, __VA_ARGS__)
238
239 /** _log_message is where the memory-saving dictionary magic described
240 * above happens: the "format" string argument is moved to a special
241 * linker section and replaced by a &log_entry pointer to it.
242 */
243 #define _log_message(log_func, atomic, lvl, comp_class, ctx, id_1, id_2, format, ...) \
244 do { \
245 _DECLARE_LOG_ENTRY(lvl, format, comp_class, \
246 META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__)); \
247 STATIC_ASSERT_ARG_SIZE(__VA_ARGS__); \
248 STATIC_ASSERT(_TRACE_EVENT_MAX_ARGUMENT_COUNT >= \
249 META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__), \
250 BASE_LOG_ASSERT_FAIL_MSG \
251 ); \
252 log_func(atomic, &log_entry, ctx, lvl, id_1, id_2, \
253 META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__), ##__VA_ARGS__); \
254 } while (0)
255
256 #endif /* CONFIG_LIBRARY */
257
258 #else /* CONFIG_TRACE */
259
260 #define trace_event_with_ids(class, ctx, id_1, id_2, format, ...) \
261 trace_unused(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
262 #define trace_event_atomic_with_ids(class, ctx, id_1, id_2, format, ...) \
263 trace_unused(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
264
265 #define trace_warn_with_ids(class, ctx, id_1, id_2, format, ...) \
266 trace_unused(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
267 #define trace_warn_atomic_with_ids(class, ctx, id_1, id_2, format, ...) \
268 trace_unused(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
269
270 #define trace_point(x) do {} while (0)
271
trace_flush_dma_to_mbox(void)272 static inline void trace_flush_dma_to_mbox(void) { }
trace_on(void)273 static inline void trace_on(void) { }
trace_off(void)274 static inline void trace_off(void) { }
trace_init(struct sof * sof)275 static inline void trace_init(struct sof *sof) { }
trace_filter_update(const struct trace_filter * filter)276 static inline int trace_filter_update(const struct trace_filter *filter)
277 { return 0; }
278
279 #endif /* CONFIG_TRACE */
280
281 #if CONFIG_TRACEV
282 /* Enable tr_dbg() statements by defining tracev_...() */
283 #define tracev_event_with_ids(class, ctx, id_1, id_2, format, ...) \
284 _trace_event_with_ids(LOG_LEVEL_VERBOSE, class, \
285 ctx, id_1, id_2, \
286 format, ##__VA_ARGS__)
287
288 #define tracev_event_atomic_with_ids(class, ctx, id_1, id_2, format, ...) \
289 _trace_event_atomic_with_ids(LOG_LEVEL_VERBOSE, class, \
290 ctx, id_1, id_2, \
291 format, ##__VA_ARGS__)
292
293 #else /* CONFIG_TRACEV */
294 #define tracev_event_with_ids(class, ctx, id_1, id_2, format, ...) \
295 trace_unused(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
296 #define tracev_event_atomic_with_ids(class, ctx, id_1, id_2, format, ...) \
297 trace_unused(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
298
299 #endif /* CONFIG_TRACEV */
300
301 /* The _error_ level has 2, 1 or 0 backends depending on Kconfig */
302 #if CONFIG_TRACEE
303 /* LOG_LEVEL_CRITICAL messages are duplicated to the mail box */
304 #define _trace_error_with_ids(class, ctx, id_1, id_2, format, ...) \
305 _log_message(trace_log_filtered, true, LOG_LEVEL_CRITICAL, class, ctx, id_1, \
306 id_2, format, ##__VA_ARGS__)
307 #define trace_error_with_ids(class, ctx, id_1, id_2, format, ...) \
308 _trace_error_with_ids(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
309 #define trace_error_atomic_with_ids(...) trace_error_with_ids(__VA_ARGS__)
310
311 #elif CONFIG_TRACE
312 /* Goes to trace_log_filtered() too but with a downgraded, LOG_INFO level */
313 #define trace_error_with_ids(...) trace_event_with_ids(__VA_ARGS__)
314 #define trace_error_atomic_with_ids(...) \
315 trace_event_atomic_with_ids(__VA_ARGS__)
316
317 #else /* CONFIG_TRACEE, CONFIG_TRACE */
318 #define trace_error_with_ids(class, ctx, id_1, id_2, format, ...) \
319 trace_unused(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
320 #define trace_error_atomic_with_ids(class, ctx, id_1, id_2, format, ...) \
321 trace_unused(class, ctx, id_1, id_2, format, ##__VA_ARGS__)
322
323 #endif /* CONFIG_TRACEE, CONFIG_TRACE */
324
325 /** Default value when there is no specific pipeline, dev, dai, etc. */
326 #define _TRACE_INV_ID -1
327
328 /** This has been replaced in commits 6ce635aa82 and earlier by the
329 * DECLARE_TR_CTX, tr_ctx and component UUID system below
330 */
331 #define _TRACE_INV_CLASS TRACE_CLASS_DEPRECATED
332
333 /**
334 * Trace context.
335 */
336 struct tr_ctx {
337 const struct sof_uuid_entry *uuid_p; /**< UUID pointer, use SOF_UUID() to init */
338 uint32_t level; /**< Default log level */
339 };
340
341 #if defined(UNIT_TEST) || defined(__ZEPHYR__)
342 #define TRACE_CONTEXT_SECTION
343 #else
344 #define TRACE_CONTEXT_SECTION __section(".trace_ctx")
345 #endif
346
347 /**
348 * Declares trace context.
349 * @param ctx_name (Symbol) name.
350 * @param uuid UUID pointer, use SOF_UUID() to inititalize.
351 * @param default_log_level Default log level.
352 */
353 #define DECLARE_TR_CTX(ctx_name, uuid, default_log_level) \
354 struct tr_ctx ctx_name TRACE_CONTEXT_SECTION = { \
355 .uuid_p = uuid, \
356 .level = default_log_level, \
357 }
358
359 /* tracing from device (component, pipeline, dai, ...) */
360
361 /** \brief Trace from a device on err level.
362 *
363 * @param get_ctx_m Macro that can retrieve trace context from dev
364 * @param get_id_m Macro that can retrieve device's id0 from the dev
365 * @param get_subid_m Macro that can retrieve device's id1 from the dev
366 * @param dev Device
367 * @param fmt Format followed by parameters
368 * @param ... Parameters
369 */
370 #define trace_dev_err(get_ctx_m, get_id_m, get_subid_m, dev, fmt, ...) \
371 trace_error_with_ids(_TRACE_INV_CLASS, get_ctx_m(dev), \
372 get_id_m(dev), get_subid_m(dev), \
373 fmt, ##__VA_ARGS__)
374
375 /** \brief Trace from a device on warning level. */
376 #define trace_dev_warn(get_ctx_m, get_id_m, get_subid_m, dev, fmt, ...) \
377 trace_warn_with_ids(_TRACE_INV_CLASS, get_ctx_m(dev), \
378 get_id_m(dev), get_subid_m(dev), \
379 fmt, ##__VA_ARGS__)
380
381 /** \brief Trace from a device on info level. */
382 #define trace_dev_info(get_ctx_m, get_id_m, get_subid_m, dev, fmt, ...) \
383 trace_event_with_ids(_TRACE_INV_CLASS, get_ctx_m(dev), \
384 get_id_m(dev), get_subid_m(dev), \
385 fmt, ##__VA_ARGS__)
386
387 /** \brief Trace from a device on dbg level. */
388 #define trace_dev_dbg(get_ctx_m, get_id_m, get_subid_m, dev, fmt, ...) \
389 tracev_event_with_ids(_TRACE_INV_CLASS, \
390 get_ctx_m(dev), get_id_m(dev), \
391 get_subid_m(dev), fmt, ##__VA_ARGS__)
392
393 /* tracing from infrastructure part */
394
395 #define tr_err(ctx, fmt, ...) \
396 trace_error_with_ids(_TRACE_INV_CLASS, ctx, \
397 _TRACE_INV_ID, _TRACE_INV_ID, fmt, ##__VA_ARGS__)
398
399 #define tr_err_atomic(ctx, fmt, ...) \
400 trace_error_atomic_with_ids(_TRACE_INV_CLASS, ctx, \
401 _TRACE_INV_ID, _TRACE_INV_ID, \
402 fmt, ##__VA_ARGS__)
403
404 #define tr_warn(ctx, fmt, ...) \
405 trace_warn_with_ids(_TRACE_INV_CLASS, ctx, \
406 _TRACE_INV_ID, _TRACE_INV_ID, fmt, ##__VA_ARGS__)
407
408 #define tr_warn_atomic(ctx, fmt, ...) \
409 trace_warn_atomic_with_ids(_TRACE_INV_CLASS, ctx, \
410 _TRACE_INV_ID, _TRACE_INV_ID, \
411 fmt, ##__VA_ARGS__)
412
413 #define tr_info(ctx, fmt, ...) \
414 trace_event_with_ids(_TRACE_INV_CLASS, ctx, \
415 _TRACE_INV_ID, _TRACE_INV_ID, fmt, ##__VA_ARGS__)
416
417 #define tr_info_atomic(ctx, fmt, ...) \
418 trace_event_atomic_with_ids(_TRACE_INV_CLASS, ctx, \
419 _TRACE_INV_ID, _TRACE_INV_ID, \
420 fmt, ##__VA_ARGS__)
421
422 /* tracev_ output depends on CONFIG_TRACEV=y */
423 #define tr_dbg(ctx, fmt, ...) \
424 tracev_event_with_ids(_TRACE_INV_CLASS, ctx, \
425 _TRACE_INV_ID, _TRACE_INV_ID, fmt, ##__VA_ARGS__)
426
427 #define tr_dbg_atomic(ctx, fmt, ...) \
428 tracev_event_atomic_with_ids(_TRACE_INV_CLASS, ctx, \
429 _TRACE_INV_ID, _TRACE_INV_ID, \
430 fmt, ##__VA_ARGS__)
431
432 #if CONFIG_TRACE
433
434 /** Direct, low-level access to mbox / shared memory logging when DMA
435 * tracing is either not initialized yet or disabled or found broken for
436 * any reason.
437 * To keep it simpler than and with minimal dependencies on
438 * the huge number of lines above, this does not check arguments at compile
439 * time.
440 * There is neither log level filtering, throttling or any other
441 * advanced feature.
442 */
443 #define mtrace_printf(log_level, format_str, ...) \
444 do { \
445 STATIC_ASSERT(META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__) \
446 <= _TRACE_EVENT_MAX_ARGUMENT_COUNT, \
447 too_many_mtrace_printf_arguments); \
448 _DECLARE_LOG_ENTRY(log_level, format_str, _TRACE_INV_CLASS, \
449 META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__)); \
450 mtrace_dict_entry(true, (uint32_t)&log_entry, \
451 META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__), \
452 ##__VA_ARGS__); \
453 } while (0)
454
455
456 #else
457
mtrace_printf(int log_level,const char * format_str,...)458 static inline void mtrace_printf(int log_level, const char *format_str, ...)
459 {
460 };
461
462 #endif /* CONFIG_TRACE */
463
464 #endif /* __SOF_TRACE_TRACE_H__ */
465