1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/logging/log_internal.h>
7 #include <zephyr/logging/log_ctrl.h>
8 #include <zephyr/internal/syscall_handler.h>
9 #include <zephyr/init.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/logging/log_link.h>
12 #include <zephyr/sys/iterable_sections.h>
13
14 #include "log_cache.h"
15
16 LOG_MODULE_REGISTER(log_mgmt);
17
18 #ifndef CONFIG_LOG_DOMAIN_NAME_CACHE_ENTRY_SIZE
19 #define CONFIG_LOG_DOMAIN_NAME_CACHE_ENTRY_SIZE 1
20 #endif
21
22 #ifndef CONFIG_LOG_DOMAIN_NAME_CACHE_ENTRY_COUNT
23 #define CONFIG_LOG_DOMAIN_NAME_CACHE_ENTRY_COUNT 1
24 #endif
25
26 #ifndef CONFIG_LOG_SOURCE_NAME_CACHE_ENTRY_SIZE
27 #define CONFIG_LOG_SOURCE_NAME_CACHE_ENTRY_SIZE 1
28 #endif
29
30 #ifndef CONFIG_LOG_SOURCE_NAME_CACHE_ENTRY_COUNT
31 #define CONFIG_LOG_SOURCE_NAME_CACHE_ENTRY_COUNT 1
32 #endif
33
34 #define DCACHE_BUF_SIZE \
35 (CONFIG_LOG_DOMAIN_NAME_CACHE_ENTRY_SIZE + sizeof(struct log_cache_entry)) * \
36 CONFIG_LOG_DOMAIN_NAME_CACHE_ENTRY_COUNT
37
38 #define SCACHE_BUF_SIZE \
39 (CONFIG_LOG_SOURCE_NAME_CACHE_ENTRY_SIZE + sizeof(struct log_cache_entry)) * \
40 CONFIG_LOG_SOURCE_NAME_CACHE_ENTRY_COUNT
41
42 static uint8_t dname_cache_buffer[DCACHE_BUF_SIZE] __aligned(sizeof(uint32_t));
43 static uint8_t sname_cache_buffer[SCACHE_BUF_SIZE] __aligned(sizeof(uint32_t));
44
45 static struct log_cache dname_cache;
46 static struct log_cache sname_cache;
47
48 struct log_source_id {
49 uint8_t domain_id;
50 uint16_t source_id;
51 };
52
53 union log_source_ids {
54 struct log_source_id id;
55 uintptr_t raw;
56 };
57
domain_id_cmp(uintptr_t id0,uintptr_t id1)58 static bool domain_id_cmp(uintptr_t id0, uintptr_t id1)
59 {
60 return id0 == id1;
61 }
62
source_id_cmp(uintptr_t id0,uintptr_t id1)63 static bool source_id_cmp(uintptr_t id0, uintptr_t id1)
64 {
65 union log_source_ids s0 = { .raw = id0 };
66 union log_source_ids s1 = { .raw = id1 };
67
68 return (s0.id.source_id == s1.id.source_id) &&
69 (s0.id.domain_id == s1.id.domain_id);
70 }
71
72 /* Implementation of functions related to controlling logging sources and backends:
73 * - getting/setting source details like name, filtering
74 * - controlling backends filtering
75 */
76
77 /** @brief Return link and relative domain id based on absolute domain id.
78 *
79 * @param[in] domain_id Aboslute domain ID.
80 * @param[out] rel_domain_id Domain ID elative to the link domain ID as output.
81 *
82 * @return Link to which given domain belongs. NULL if link was not found.
83 */
get_link_domain(uint8_t domain_id,uint8_t * rel_domain_id)84 static const struct log_link *get_link_domain(uint8_t domain_id, uint8_t *rel_domain_id)
85 {
86 uint8_t domain_max;
87
88 STRUCT_SECTION_FOREACH(log_link, link) {
89 domain_max = link->ctrl_blk->domain_offset +
90 link->ctrl_blk->domain_cnt;
91 if (domain_id < domain_max) {
92
93 *rel_domain_id = domain_id - link->ctrl_blk->domain_offset;
94 return link;
95 }
96 }
97
98 *rel_domain_id = 0;
99
100 return NULL;
101 }
102
103 /** @brief Get source offset used for getting runtime filter.
104 *
105 * Runtime filters for each link are dynamically allocated as an array of
106 * filters for all domains in the link. In order to fetch link associated with
107 * given source an index in the array must be retrieved.
108 */
get_source_offset(const struct log_link * link,uint8_t rel_domain_id)109 static uint32_t get_source_offset(const struct log_link *link,
110 uint8_t rel_domain_id)
111 {
112 uint32_t offset = 0;
113
114 for (uint8_t i = 0; i < rel_domain_id; i++) {
115 offset += log_link_sources_count(link, i);
116 }
117
118 return offset;
119 }
120
z_log_link_get_dynamic_filter(uint8_t domain_id,uint32_t source_id)121 uint32_t *z_log_link_get_dynamic_filter(uint8_t domain_id, uint32_t source_id)
122 {
123 uint8_t rel_domain_id;
124 const struct log_link *link = get_link_domain(domain_id, &rel_domain_id);
125 uint32_t source_offset = 0;
126
127 __ASSERT_NO_MSG(link != NULL);
128
129 source_offset = get_source_offset(link, rel_domain_id);
130
131 return &link->ctrl_blk->filters[source_offset + source_id];
132 }
133
134 #ifdef CONFIG_LOG_MULTIDOMAIN
link_filters_init(const struct log_link * link)135 static int link_filters_init(const struct log_link *link)
136 {
137 uint32_t total_cnt = get_source_offset(link, link->ctrl_blk->domain_cnt);
138
139 link->ctrl_blk->filters = k_malloc(sizeof(uint32_t) * total_cnt);
140 if (link->ctrl_blk->filters == NULL) {
141 LOG_ERR("Failed to allocate buffer for runtime filtering.");
142 __ASSERT(0, "Failed to allocate buffer.");
143 return -ENOMEM;
144 }
145
146 memset(link->ctrl_blk->filters, 0, sizeof(uint32_t) * total_cnt);
147 LOG_DBG("%s: heap used for filters:%d",
148 link->name, (int)(total_cnt * sizeof(uint32_t)));
149
150 return 0;
151 }
152 #endif
153
cache_init(void)154 static void cache_init(void)
155 {
156 int err;
157 static const struct log_cache_config dname_cache_config = {
158 .buf = dname_cache_buffer,
159 .buf_len = sizeof(dname_cache_buffer),
160 .item_size = CONFIG_LOG_DOMAIN_NAME_CACHE_ENTRY_SIZE,
161 .cmp = domain_id_cmp
162 };
163 static const struct log_cache_config sname_cache_config = {
164 .buf = sname_cache_buffer,
165 .buf_len = sizeof(sname_cache_buffer),
166 .item_size = CONFIG_LOG_SOURCE_NAME_CACHE_ENTRY_SIZE,
167 .cmp = source_id_cmp
168 };
169
170 err = log_cache_init(&dname_cache, &dname_cache_config);
171 __ASSERT_NO_MSG(err == 0);
172
173 err = log_cache_init(&sname_cache, &sname_cache_config);
174 __ASSERT_NO_MSG(err == 0);
175 }
176
z_log_ext_domain_count(void)177 uint8_t z_log_ext_domain_count(void)
178 {
179 uint8_t cnt = 0;
180
181 STRUCT_SECTION_FOREACH(log_link, link) {
182 cnt += log_link_domains_count(link);
183 }
184
185 return cnt;
186 }
187
link_source_count(uint8_t domain_id)188 static uint16_t link_source_count(uint8_t domain_id)
189 {
190 uint8_t rel_domain_id;
191 const struct log_link *link = get_link_domain(domain_id, &rel_domain_id);
192
193 __ASSERT_NO_MSG(link != NULL);
194
195 return log_link_sources_count(link, rel_domain_id);
196 }
197
log_src_cnt_get(uint32_t domain_id)198 uint32_t log_src_cnt_get(uint32_t domain_id)
199 {
200 if (z_log_is_local_domain(domain_id)) {
201 return z_log_sources_count();
202 }
203
204 return link_source_count(domain_id);
205 }
206
207 /* First check in cache if not there fetch from remote.
208 * When fetched from remote put in cache.
209 *
210 * @note Execution time depends on whether entry is in cache.
211 */
link_source_name_get(uint8_t domain_id,uint32_t source_id)212 static const char *link_source_name_get(uint8_t domain_id, uint32_t source_id)
213 {
214 uint8_t *cached;
215 size_t cache_size = sname_cache.item_size;
216 union log_source_ids id = {
217 .id = {
218 .domain_id = domain_id,
219 .source_id = source_id
220 }
221 };
222
223 /* If not in cache fetch from link and cache it. */
224 if (!log_cache_get(&sname_cache, id.raw, &cached)) {
225 uint8_t rel_domain_id;
226 const struct log_link *link = get_link_domain(domain_id, &rel_domain_id);
227 int err;
228
229 __ASSERT_NO_MSG(link != NULL);
230
231 err = log_link_get_source_name(link, rel_domain_id, source_id,
232 cached, &cache_size);
233 if (err < 0) {
234 return NULL;
235 }
236
237 log_cache_put(&sname_cache, cached);
238 }
239
240 return (const char *)cached;
241 }
242
log_source_name_get(uint32_t domain_id,uint32_t source_id)243 const char *log_source_name_get(uint32_t domain_id, uint32_t source_id)
244 {
245 if (z_log_is_local_domain(domain_id)) {
246 if (IS_ENABLED(CONFIG_LOG_FMT_SECTION_STRIP)) {
247 return "unknown";
248 }
249 if (source_id < log_src_cnt_get(domain_id)) {
250 return TYPE_SECTION_START(log_const)[source_id].name;
251 } else {
252 return NULL;
253 }
254 }
255
256 return link_source_name_get(domain_id, source_id);
257 }
258
259 /* First check in cache if not there fetch from remote.
260 * When fetched from remote put in cache.
261 *
262 * @note Execution time depends on whether entry is in cache.
263 */
link_domain_name_get(uint8_t domain_id)264 static const char *link_domain_name_get(uint8_t domain_id)
265 {
266 uint8_t *cached;
267 size_t cache_size = dname_cache.item_size;
268 uintptr_t id = (uintptr_t)domain_id;
269 static const char *invalid_domain = "invalid";
270
271 /* If not in cache fetch from link and cache it. */
272 if (!log_cache_get(&dname_cache, id, &cached)) {
273 uint8_t rel_domain_id;
274 const struct log_link *link = get_link_domain(domain_id, &rel_domain_id);
275 int err;
276
277 __ASSERT_NO_MSG(link != NULL);
278
279 err = log_link_get_domain_name(link, rel_domain_id, cached, &cache_size);
280 if (err < 0) {
281 log_cache_release(&dname_cache, cached);
282 return invalid_domain;
283 }
284
285 log_cache_put(&dname_cache, cached);
286 }
287
288 return (const char *)cached;
289 }
290
log_domain_name_get(uint32_t domain_id)291 const char *log_domain_name_get(uint32_t domain_id)
292 {
293 if (z_log_is_local_domain(domain_id)) {
294 return CONFIG_LOG_DOMAIN_NAME;
295 }
296
297 return link_domain_name_get(domain_id);
298 }
299
link_compiled_level_get(uint8_t domain_id,uint32_t source_id)300 static uint8_t link_compiled_level_get(uint8_t domain_id, uint32_t source_id)
301 {
302 uint8_t rel_domain_id;
303 const struct log_link *link = get_link_domain(domain_id, &rel_domain_id);
304 uint8_t level;
305
306 __ASSERT_NO_MSG(link != NULL);
307
308 return !log_link_get_levels(link, rel_domain_id, source_id, &level, NULL) ?
309 level : 0;
310 }
311
log_compiled_level_get(uint8_t domain_id,uint32_t source_id)312 uint8_t log_compiled_level_get(uint8_t domain_id, uint32_t source_id)
313 {
314 if (z_log_is_local_domain(domain_id)) {
315 if (source_id < log_src_cnt_get(domain_id)) {
316 return TYPE_SECTION_START(log_const)[source_id].level;
317 } else {
318 return LOG_LEVEL_NONE;
319 }
320 }
321
322 return link_compiled_level_get(domain_id, source_id);
323 }
324
z_log_link_set_runtime_level(uint8_t domain_id,uint16_t source_id,uint8_t level)325 int z_log_link_set_runtime_level(uint8_t domain_id, uint16_t source_id, uint8_t level)
326 {
327 uint8_t rel_domain_id;
328 const struct log_link *link = get_link_domain(domain_id, &rel_domain_id);
329
330 __ASSERT_NO_MSG(link != NULL);
331
332 return log_link_set_runtime_level(link, rel_domain_id, source_id, level);
333 }
334
get_dynamic_filter(uint8_t domain_id,uint32_t source_id)335 static uint32_t *get_dynamic_filter(uint8_t domain_id, uint32_t source_id)
336 {
337 if (z_log_is_local_domain(domain_id)) {
338 return &TYPE_SECTION_START(log_dynamic)[source_id].filters;
339 }
340
341 return z_log_link_get_dynamic_filter(domain_id, source_id);
342 }
343
z_log_runtime_filters_init(void)344 void z_log_runtime_filters_init(void)
345 {
346 /*
347 * Initialize aggregated runtime filter levels (no backends are
348 * attached yet, so leave backend slots in each dynamic filter set
349 * alone for now).
350 *
351 * Each log source's aggregated runtime level is set to match its
352 * compile-time level. When backends are attached later on in
353 * log_init(), they'll be initialized to the same value.
354 */
355 for (int i = 0; i < z_log_sources_count(); i++) {
356 uint32_t *filters = z_log_dynamic_filters_get(i);
357 uint8_t level = log_compiled_level_get(Z_LOG_LOCAL_DOMAIN_ID, i);
358
359 level = MAX(level, CONFIG_LOG_OVERRIDE_LEVEL);
360 LOG_FILTER_SLOT_SET(filters,
361 LOG_FILTER_AGGR_SLOT_IDX,
362 level);
363 }
364 }
365
log_source_id_get(const char * name)366 int log_source_id_get(const char *name)
367 {
368 if (IS_ENABLED(CONFIG_LOG_FMT_SECTION_STRIP)) {
369 return -1;
370 }
371
372 for (int i = 0; i < log_src_cnt_get(Z_LOG_LOCAL_DOMAIN_ID); i++) {
373 const char *sname = log_source_name_get(Z_LOG_LOCAL_DOMAIN_ID, i);
374
375 if ((sname != NULL) && (strcmp(sname, name) == 0)) {
376 return i;
377 }
378 }
379 return -1;
380 }
381
max_filter_get(uint32_t filters)382 static uint32_t max_filter_get(uint32_t filters)
383 {
384 uint32_t max_filter = LOG_LEVEL_NONE;
385 int first_slot = LOG_FILTER_FIRST_BACKEND_SLOT_IDX;
386 int i;
387
388 for (i = first_slot; i < LOG_FILTERS_NUM_OF_SLOTS; i++) {
389 uint32_t tmp_filter = LOG_FILTER_SLOT_GET(&filters, i);
390
391 if (tmp_filter > max_filter) {
392 max_filter = tmp_filter;
393 }
394 }
395
396 return max_filter;
397 }
398
set_runtime_filter(uint8_t backend_id,uint8_t domain_id,uint32_t source_id,uint32_t level)399 static void set_runtime_filter(uint8_t backend_id, uint8_t domain_id,
400 uint32_t source_id, uint32_t level)
401 {
402 uint32_t prev_max;
403 uint32_t new_max;
404 uint32_t *filters = get_dynamic_filter(domain_id, source_id);
405
406 prev_max = LOG_FILTER_SLOT_GET(filters, LOG_FILTER_AGGR_SLOT_IDX);
407
408 LOG_FILTER_SLOT_SET(filters, backend_id, level);
409
410 /* Once current backend filter is updated recalculate
411 * aggregated maximal level
412 */
413 new_max = max_filter_get(*filters);
414
415 LOG_FILTER_SLOT_SET(filters, LOG_FILTER_AGGR_SLOT_IDX, new_max);
416
417 if (!z_log_is_local_domain(domain_id) && (new_max != prev_max)) {
418 (void)z_log_link_set_runtime_level(domain_id, source_id, level);
419 }
420 }
421
filter_get(uint8_t id,uint32_t domain_id,int16_t source_id,bool runtime)422 static uint32_t filter_get(uint8_t id, uint32_t domain_id, int16_t source_id, bool runtime)
423 {
424 __ASSERT_NO_MSG(source_id < log_src_cnt_get(domain_id));
425
426 if (IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) && runtime) {
427 if (source_id < 0) {
428 return LOG_LEVEL_DBG;
429 }
430
431 return LOG_FILTER_SLOT_GET(get_dynamic_filter(domain_id, source_id), id);
432 }
433
434 return log_compiled_level_get(domain_id, source_id);
435 }
436
437
filter_set(int id,uint32_t domain_id,int16_t source_id,uint32_t level)438 uint32_t filter_set(int id, uint32_t domain_id, int16_t source_id, uint32_t level)
439 {
440 if (!IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) {
441 return log_compiled_level_get(domain_id, source_id);
442 }
443
444 __ASSERT_NO_MSG(source_id < log_src_cnt_get(domain_id));
445
446
447 if (id < 0) {
448 uint32_t max = 0U;
449 size_t backend_cnt;
450
451 if (IS_ENABLED(CONFIG_LOG_FRONTEND)) {
452 max = filter_set(LOG_FRONTEND_SLOT_ID, domain_id, source_id, level);
453 if (IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY)) {
454 return max;
455 }
456 }
457
458 STRUCT_SECTION_COUNT(log_backend, &backend_cnt);
459 for (size_t i = 0; i < backend_cnt; i++) {
460 uint32_t current = filter_set(log_backend_id_get(log_backend_get(i)),
461 domain_id, source_id, level);
462
463 max = MAX(current, max);
464 }
465
466 return max;
467 }
468
469 level = MIN(level, MAX(filter_get(id, domain_id, source_id, false),
470 CONFIG_LOG_OVERRIDE_LEVEL));
471 set_runtime_filter(id, domain_id, source_id, level);
472
473 return level;
474 }
475
z_impl_log_filter_set(struct log_backend const * const backend,uint32_t domain_id,int16_t source_id,uint32_t level)476 uint32_t z_impl_log_filter_set(struct log_backend const *const backend,
477 uint32_t domain_id, int16_t source_id,
478 uint32_t level)
479 {
480 int id = (backend == NULL) ? -1 : log_backend_id_get(backend);
481
482 return filter_set(id, domain_id, source_id, level);
483 }
484
z_impl_log_frontend_filter_set(int16_t source_id,uint32_t level)485 uint32_t z_impl_log_frontend_filter_set(int16_t source_id, uint32_t level)
486 {
487 return filter_set(LOG_FRONTEND_SLOT_ID, Z_LOG_LOCAL_DOMAIN_ID, source_id, level);
488 }
489
490 #ifdef CONFIG_USERSPACE
z_vrfy_log_filter_set(struct log_backend const * const backend,uint32_t domain_id,int16_t src_id,uint32_t level)491 uint32_t z_vrfy_log_filter_set(struct log_backend const *const backend,
492 uint32_t domain_id,
493 int16_t src_id,
494 uint32_t level)
495 {
496 K_OOPS(K_SYSCALL_VERIFY_MSG(backend == NULL,
497 "Setting per-backend filters from user mode is not supported"));
498 K_OOPS(K_SYSCALL_VERIFY_MSG(domain_id == Z_LOG_LOCAL_DOMAIN_ID,
499 "Invalid log domain_id"));
500 K_OOPS(K_SYSCALL_VERIFY_MSG(src_id < (int16_t)log_src_cnt_get(domain_id),
501 "Invalid log source id"));
502 K_OOPS(K_SYSCALL_VERIFY_MSG(
503 (level <= LOG_LEVEL_DBG),
504 "Invalid log level"));
505
506 return z_impl_log_filter_set(NULL, domain_id, src_id, level);
507 }
508 #include <zephyr/syscalls/log_filter_set_mrsh.c>
509 #endif
510
link_filter_set(const struct log_link * link,struct log_backend const * const backend,uint32_t level)511 static void link_filter_set(const struct log_link *link,
512 struct log_backend const *const backend,
513 uint32_t level)
514 {
515 if (log_link_is_active(link) != 0) {
516 return;
517 }
518
519 for (uint8_t d = link->ctrl_blk->domain_offset;
520 d < link->ctrl_blk->domain_offset + link->ctrl_blk->domain_cnt; d++) {
521 for (uint16_t s = 0; s < log_src_cnt_get(d); s++) {
522 log_filter_set(backend, d, s, level);
523 }
524 }
525 }
526
backend_filter_set(struct log_backend const * const backend,uint32_t level)527 static void backend_filter_set(struct log_backend const *const backend,
528 uint32_t level)
529 {
530 if (!IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) {
531 return;
532 }
533
534 for (uint16_t s = 0; s < log_src_cnt_get(0); s++) {
535 log_filter_set(backend, 0, s, level);
536 }
537
538 if (!IS_ENABLED(CONFIG_LOG_MULTIDOMAIN)) {
539 return;
540 }
541
542 /* Set level in activated links. */
543 STRUCT_SECTION_FOREACH(log_link, link) {
544 link_filter_set(link, backend, level);
545 }
546 }
547
log_backend_get_by_name(const char * backend_name)548 const struct log_backend *log_backend_get_by_name(const char *backend_name)
549 {
550 STRUCT_SECTION_FOREACH(log_backend, backend) {
551 if (strcmp(backend_name, backend->name) == 0) {
552 return backend;
553 }
554 }
555
556 return NULL;
557 }
558
log_backend_enable(struct log_backend const * const backend,void * ctx,uint32_t level)559 void log_backend_enable(struct log_backend const *const backend,
560 void *ctx,
561 uint32_t level)
562 {
563 /* As first slot in filtering mask is reserved, backend ID has offset.*/
564 uint32_t id = LOG_FILTER_FIRST_BACKEND_SLOT_IDX;
565
566 id += backend - log_backend_get(0);
567
568 log_backend_id_set(backend, id);
569 backend->cb->level = level;
570 backend_filter_set(backend, level);
571 log_backend_activate(backend, ctx);
572
573 z_log_notify_backend_enabled();
574 }
575
log_backend_disable(struct log_backend const * const backend)576 void log_backend_disable(struct log_backend const *const backend)
577 {
578 if (log_backend_is_active(backend)) {
579 backend_filter_set(backend, LOG_LEVEL_NONE);
580 }
581
582 log_backend_deactivate(backend);
583 }
584
log_filter_get(struct log_backend const * const backend,uint32_t domain_id,int16_t source_id,bool runtime)585 uint32_t log_filter_get(struct log_backend const *const backend,
586 uint32_t domain_id, int16_t source_id, bool runtime)
587 {
588 int id = (backend == NULL) ? -1 : log_backend_id_get(backend);
589
590 return filter_get(id, domain_id, source_id, runtime);
591 }
592
log_frontend_filter_get(int16_t source_id,bool runtime)593 uint32_t log_frontend_filter_get(int16_t source_id, bool runtime)
594 {
595 if (!IS_ENABLED(CONFIG_LOG_FRONTEND)) {
596 return LOG_LEVEL_NONE;
597 }
598
599 return filter_get(LOG_FRONTEND_SLOT_ID, Z_LOG_LOCAL_DOMAIN_ID, source_id, runtime);
600 }
601
z_log_links_initiate(void)602 void z_log_links_initiate(void)
603 {
604 int err;
605
606 cache_init();
607
608 STRUCT_SECTION_FOREACH(log_link, link) {
609 #ifdef CONFIG_MPSC_PBUF
610 if (link->mpsc_pbuf) {
611 mpsc_pbuf_init(link->mpsc_pbuf, link->mpsc_pbuf_config);
612 }
613 #endif
614
615 err = log_link_initiate(link, NULL);
616 __ASSERT(err == 0, "Failed to initialize link");
617 }
618 }
619
620 #ifdef CONFIG_LOG_MULTIDOMAIN
backends_link_init(const struct log_link * link)621 static void backends_link_init(const struct log_link *link)
622 {
623 for (int i = 0; i < log_backend_count_get(); i++) {
624 const struct log_backend *backend = log_backend_get(i);
625
626
627 if (!log_backend_is_active(backend)) {
628 continue;
629 }
630
631 link_filter_set(link, backend, backend->cb->level);
632 }
633 }
634
z_log_links_activate(uint32_t active_mask,uint8_t * offset)635 uint32_t z_log_links_activate(uint32_t active_mask, uint8_t *offset)
636 {
637 uint32_t mask = 0x1;
638 uint32_t out_mask = 0;
639
640 /* Initiate offset to 1. */
641 if (*offset == 0) {
642 *offset = 1;
643 }
644
645 STRUCT_SECTION_FOREACH(log_link, link) {
646 if (active_mask & mask) {
647 int err = log_link_activate(link);
648
649 if (err == 0) {
650 uint8_t domain_cnt = log_link_domains_count(link);
651
652 link->ctrl_blk->domain_offset = *offset;
653 link->ctrl_blk->domain_cnt = domain_cnt;
654 *offset += domain_cnt;
655 if (IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) {
656 link_filters_init(link);
657 backends_link_init(link);
658 }
659 } else {
660 __ASSERT_NO_MSG(err == -EINPROGRESS);
661 out_mask |= mask;
662 }
663 }
664
665 mask <<= 1;
666 }
667
668 return out_mask;
669 }
670 #endif
671