1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log_frontend_stmesp_demux.h>
8 #include <zephyr/logging/log_frontend_stmesp.h>
9 #include <zephyr/logging/log_ctrl.h>
10 #include <zephyr/sys/mpsc_pbuf.h>
11 #include <zephyr/sys/__assert.h>
12 #include <zephyr/logging/log_msg.h>
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(stmesp_demux);
15 
16 BUILD_ASSERT(sizeof(struct log_frontend_stmesp_demux_log_header) == sizeof(uint32_t),
17 		"Must fit in a word");
18 
19 #ifndef CONFIG_LOG_FRONTEND_STPESP_TURBO_SOURCE_PORT_ID
20 #define CONFIG_LOG_FRONTEND_STPESP_TURBO_SOURCE_PORT_ID 0
21 #endif
22 
23 #ifndef CONFIG_LOG_FRONTEND_STMESP_TURBO_LOG_BASE
24 #define CONFIG_LOG_FRONTEND_STMESP_TURBO_LOG_BASE 0x8000
25 #endif
26 
27 #define NUM_OF_ACTIVE CONFIG_LOG_FRONTEND_STMESP_DEMUX_ACTIVE_PACKETS
28 #define M_ID_OFF      16
29 #define M_ID_MASK     (BIT_MASK(16) << M_ID_OFF)
30 #define C_ID_MASK     BIT_MASK(16)
31 
32 #define M_CH_HW_EVENT 0x00800000
33 #define M_CH_INVALID  0xFFFFFFFF
34 
35 #define APP_M_ID  0x22
36 #define FLPR_M_ID 0x2D
37 #define PPR_M_ID  0x2E
38 
39 struct log_frontend_stmesp_demux_active_entry {
40 	sys_snode_t node;
41 	uint32_t m_ch;
42 	uint32_t ts;
43 	struct log_frontend_stmesp_demux_log *packet;
44 	int off;
45 };
46 
47 /* Coprocessors (FLPR, PPR) sends location where APP can find strings and logging
48  * source names utilizing the fact that APP has access to FLPR/PPR memory if it is
49  * an owner of that coprocessor. During the initialization FLPR/PPR sends 2 DMTS32
50  * to the specific channel. First word is an address where logging source constant
51  * data section is located and second is where a section with addresses to constant
52  * strings used for logging is located.
53  */
54 struct log_frontend_stmesp_coproc_sources {
55 	uint32_t m_id;
56 	uint32_t data_cnt;
57 	union {
58 		struct {
59 			const struct log_source_const_data *log_const;
60 			uintptr_t *log_str_section;
61 		} data;
62 		struct {
63 			uintptr_t data[2];
64 		} raw_data;
65 	};
66 };
67 
68 struct log_frontend_stmesp_demux {
69 	/* Pool for active entries. */
70 	struct k_mem_slab mslab;
71 
72 	/* List of currently active entries. */
73 	sys_slist_t active_entries;
74 
75 	/* The most recently used entry. */
76 	struct log_frontend_stmesp_demux_active_entry *curr;
77 
78 	struct mpsc_pbuf_buffer pbuf;
79 
80 	uint32_t curr_m_ch;
81 
82 	const uint16_t *m_ids;
83 
84 	uint32_t *source_ids;
85 
86 	uint16_t m_ids_cnt;
87 
88 	uint16_t source_id_len;
89 
90 	uint32_t dropped;
91 
92 	struct log_frontend_stmesp_coproc_sources coproc_sources[2];
93 };
94 
95 struct log_frontend_stmesp_entry_source_pair {
96 	uint16_t entry_id;
97 	uint16_t source_id;
98 };
99 
100 static uint32_t buffer[CONFIG_LOG_FRONTEND_STMESP_DEMUX_BUFFER_SIZE]
101 	__aligned(Z_LOG_MSG_ALIGNMENT);
102 
103 static struct log_frontend_stmesp_demux demux;
104 static uint32_t slab_buf[NUM_OF_ACTIVE * sizeof(struct log_frontend_stmesp_demux_active_entry)];
105 static bool skip;
106 
notify_drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * packet)107 static void notify_drop(const struct mpsc_pbuf_buffer *buffer,
108 			const union mpsc_pbuf_generic *packet)
109 {
110 	demux.dropped++;
111 }
112 
store_source_id(uint16_t m_id,uint16_t entry_id,uint16_t source_id)113 static void store_source_id(uint16_t m_id, uint16_t entry_id, uint16_t source_id)
114 {
115 	uint32_t *source_ids_data = &demux.source_ids[m_id * (demux.source_id_len + 1)];
116 	uint32_t *wr_idx = source_ids_data;
117 	struct log_frontend_stmesp_entry_source_pair *source_ids =
118 		(struct log_frontend_stmesp_entry_source_pair *)&source_ids_data[1];
119 
120 	source_ids[*wr_idx].entry_id = entry_id;
121 	source_ids[*wr_idx].source_id = source_id;
122 	*wr_idx = *wr_idx + 1;
123 	if (*wr_idx == (demux.source_id_len)) {
124 		*wr_idx = 0;
125 	}
126 }
127 
get_source_id(uint16_t m_id,uint16_t entry_id)128 static uint16_t get_source_id(uint16_t m_id, uint16_t entry_id)
129 {
130 	uint32_t *source_ids_data = &demux.source_ids[m_id * (demux.source_id_len + 1)];
131 	int32_t rd_idx = source_ids_data[0];
132 	uint32_t cnt = demux.source_id_len;
133 	struct log_frontend_stmesp_entry_source_pair *source_ids =
134 		(struct log_frontend_stmesp_entry_source_pair *)&source_ids_data[1];
135 
136 	do {
137 		rd_idx = (rd_idx == 0) ? (demux.source_id_len - 1) : (rd_idx - 1);
138 		if (source_ids[rd_idx].entry_id == entry_id) {
139 			return source_ids[rd_idx].source_id;
140 		}
141 		cnt--;
142 	} while (cnt);
143 
144 	return 0;
145 }
146 
calc_wlen(uint32_t total_len)147 static uint32_t calc_wlen(uint32_t total_len)
148 {
149 	return DIV_ROUND_UP(ROUND_UP(total_len, Z_LOG_MSG_ALIGNMENT), sizeof(uint32_t));
150 }
151 
get_wlen(const union mpsc_pbuf_generic * packet)152 static uint32_t get_wlen(const union mpsc_pbuf_generic *packet)
153 {
154 	union log_frontend_stmesp_demux_packet p = {.rgeneric = packet};
155 	uint32_t len;
156 
157 	switch (p.generic_packet->type) {
158 	case LOG_FRONTEND_STMESP_DEMUX_TYPE_TRACE_POINT:
159 		len = sizeof(struct log_frontend_stmesp_demux_trace_point) / sizeof(uint32_t);
160 		break;
161 	case LOG_FRONTEND_STMESP_DEMUX_TYPE_HW_EVENT:
162 		len = sizeof(struct log_frontend_stmesp_demux_hw_event) / sizeof(uint32_t);
163 		break;
164 	default:
165 		len = calc_wlen(p.log->hdr.total_len +
166 			offsetof(struct log_frontend_stmesp_demux_log, data));
167 		break;
168 	}
169 
170 	return len;
171 }
172 
log_frontend_stmesp_demux_init(const struct log_frontend_stmesp_demux_config * config)173 int log_frontend_stmesp_demux_init(const struct log_frontend_stmesp_demux_config *config)
174 {
175 	int err;
176 	static const struct mpsc_pbuf_buffer_config pbuf_config = {
177 		.buf = buffer,
178 		.size = ARRAY_SIZE(buffer),
179 		.notify_drop = notify_drop,
180 		.get_wlen = get_wlen,
181 		.flags = MPSC_PBUF_MODE_OVERWRITE |
182 			 (IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_DEMUX_MAX_UTILIZATION) ?
183 				MPSC_PBUF_MAX_UTILIZATION : 0)};
184 
185 	memset(buffer, 0, sizeof(buffer));
186 	mpsc_pbuf_init(&demux.pbuf, &pbuf_config);
187 
188 	sys_slist_init(&demux.active_entries);
189 
190 	if (config->m_ids_cnt > BIT(3)) {
191 		return -EINVAL;
192 	}
193 
194 	demux.m_ids = config->m_ids;
195 	demux.m_ids_cnt = config->m_ids_cnt;
196 	demux.dropped = 0;
197 	demux.curr_m_ch = M_CH_INVALID;
198 	demux.curr = NULL;
199 	demux.source_ids = config->source_id_buf;
200 	demux.source_id_len = config->source_id_buf_len / config->m_ids_cnt - 1;
201 
202 	err = k_mem_slab_init(&demux.mslab, slab_buf,
203 			      sizeof(struct log_frontend_stmesp_demux_active_entry),
204 			      NUM_OF_ACTIVE);
205 
206 	return err;
207 }
208 
log_frontend_stmesp_demux_major(uint16_t id)209 void log_frontend_stmesp_demux_major(uint16_t id)
210 {
211 	for (int i = 0; i < demux.m_ids_cnt; i++) {
212 		if (id == demux.m_ids[i]) {
213 			sys_snode_t *node;
214 
215 			demux.curr_m_ch = id << M_ID_OFF;
216 			demux.curr = NULL;
217 
218 			SYS_SLIST_FOR_EACH_NODE(&demux.active_entries, node) {
219 				struct log_frontend_stmesp_demux_active_entry *entry =
220 					CONTAINER_OF(node,
221 						struct log_frontend_stmesp_demux_active_entry,
222 						node);
223 
224 				if (entry->m_ch == demux.curr_m_ch) {
225 					demux.curr = entry;
226 					break;
227 				}
228 			}
229 			skip = false;
230 			return;
231 		}
232 	}
233 
234 	skip = true;
235 }
236 
log_frontend_stmesp_demux_channel(uint16_t id)237 void log_frontend_stmesp_demux_channel(uint16_t id)
238 {
239 	if (skip) {
240 		return;
241 	}
242 
243 	if (id == CONFIG_LOG_FRONTEND_STMESP_FLUSH_PORT_ID) {
244 		/* Flushing data that shall be discarded. */
245 		goto bail;
246 	}
247 
248 	demux.curr_m_ch &= ~C_ID_MASK;
249 	demux.curr_m_ch |= id;
250 
251 	sys_snode_t *node;
252 
253 	SYS_SLIST_FOR_EACH_NODE(&demux.active_entries, node) {
254 		struct log_frontend_stmesp_demux_active_entry *entry =
255 			CONTAINER_OF(node, struct log_frontend_stmesp_demux_active_entry, node);
256 
257 		if (entry->m_ch == demux.curr_m_ch) {
258 			demux.curr = entry;
259 			return;
260 		}
261 	}
262 
263 bail:
264 	demux.curr = NULL;
265 }
266 
get_major_id(uint16_t m_id)267 static uint8_t get_major_id(uint16_t m_id)
268 {
269 	for (int i = 0; i < demux.m_ids_cnt; i++) {
270 		if (m_id == demux.m_ids[i]) {
271 			return i;
272 		}
273 	}
274 
275 	__ASSERT_NO_MSG(0);
276 	return 0;
277 }
278 
store_turbo_log0(uint16_t m_id,uint16_t id,uint64_t * ts,uint16_t source_id)279 static void store_turbo_log0(uint16_t m_id, uint16_t id, uint64_t *ts, uint16_t source_id)
280 {
281 	struct log_frontend_stmesp_demux_trace_point packet = {
282 		.valid = 1,
283 		.type = LOG_FRONTEND_STMESP_DEMUX_TYPE_TRACE_POINT,
284 		.content_invalid = 0,
285 		.has_data = 0,
286 		.timestamp = ts ? *ts : 0,
287 		.major = m_id,
288 		.source_id = source_id,
289 		.id = id,
290 		.data = 0};
291 	static const size_t wlen = sizeof(packet) / sizeof(uint32_t);
292 
293 	mpsc_pbuf_put_data(&demux.pbuf, (const uint32_t *)&packet, wlen);
294 }
295 
store_turbo_log1(uint16_t m_id,uint16_t id,uint64_t * ts,uint32_t data)296 static void store_turbo_log1(uint16_t m_id, uint16_t id, uint64_t *ts, uint32_t data)
297 {
298 	struct log_frontend_stmesp_demux_trace_point packet = {
299 		.valid = 1,
300 		.type = LOG_FRONTEND_STMESP_DEMUX_TYPE_TRACE_POINT,
301 		.content_invalid = 0,
302 		.has_data = 0,
303 		.timestamp = ts ? *ts : 0,
304 		.major = m_id,
305 		.source_id = get_source_id(m_id, id),
306 		.id = id,
307 		.data = data};
308 	static const size_t wlen = sizeof(packet) / sizeof(uint32_t);
309 
310 	mpsc_pbuf_put_data(&demux.pbuf, (const uint32_t *)&packet, wlen);
311 }
312 
store_tracepoint(uint16_t m_id,uint16_t id,uint64_t * ts,uint32_t * data)313 static void store_tracepoint(uint16_t m_id, uint16_t id, uint64_t *ts, uint32_t *data)
314 {
315 	struct log_frontend_stmesp_demux_trace_point packet = {.valid = 1,
316 					       .type = LOG_FRONTEND_STMESP_DEMUX_TYPE_TRACE_POINT,
317 					       .content_invalid = 0,
318 					       .has_data = data ? 1 : 0,
319 					       .timestamp = ts ? *ts : 0,
320 					       .major = m_id,
321 					       .id = id,
322 					       .data = data ? *data : 0};
323 	static const size_t wlen = sizeof(packet) / sizeof(uint32_t);
324 
325 	mpsc_pbuf_put_data(&demux.pbuf, (const uint32_t *)&packet, wlen);
326 }
327 
log_frontend_stmesp_demux_hw_event(uint64_t * ts,uint8_t data)328 static void log_frontend_stmesp_demux_hw_event(uint64_t *ts, uint8_t data)
329 {
330 	struct log_frontend_stmesp_demux_hw_event packet = {.valid = 1,
331 					    .type = LOG_FRONTEND_STMESP_DEMUX_TYPE_HW_EVENT,
332 					    .content_invalid = 0,
333 					    .timestamp = ts ? *ts : 0,
334 					    .evt = data};
335 	static const size_t wlen = sizeof(packet) / sizeof(uint32_t);
336 
337 	mpsc_pbuf_put_data(&demux.pbuf, (const uint32_t *)&packet, wlen);
338 }
339 
340 /* Check if there are any active messages which are not completed for a significant
341  * amount of time. It may indicate that part of message was lost (due to reset,
342  * fault in the core or fault on the bus). In that case message shall be closed as
343  * incomplete to not block processing of other messages.
344  */
garbage_collector(uint32_t now)345 static void garbage_collector(uint32_t now)
346 {
347 	sys_snode_t *node;
348 
349 	SYS_SLIST_FOR_EACH_NODE(&demux.active_entries, node) {
350 		struct log_frontend_stmesp_demux_active_entry *entry =
351 			CONTAINER_OF(node, struct log_frontend_stmesp_demux_active_entry, node);
352 
353 		if ((now - entry->ts) > CONFIG_LOG_FRONTEND_STMESP_DEMUX_GC_TIMEOUT) {
354 			union log_frontend_stmesp_demux_packet p = {.log = entry->packet};
355 
356 			sys_slist_find_and_remove(&demux.active_entries, node);
357 			entry->packet->content_invalid = 1;
358 			mpsc_pbuf_commit(&demux.pbuf, p.generic);
359 			demux.dropped++;
360 			k_mem_slab_free(&demux.mslab, entry);
361 			/* After removing one we need to stop as removing disrupts
362 			 * iterating over the list as current node is no longer in
363 			 * the list.
364 			 */
365 			break;
366 		}
367 	}
368 }
369 
log_frontend_stmesp_demux_log0(uint16_t source_id,uint64_t * ts)370 int log_frontend_stmesp_demux_log0(uint16_t source_id, uint64_t *ts)
371 {
372 	if (skip) {
373 		return 0;
374 	}
375 
376 	if (demux.curr_m_ch == M_CH_INVALID) {
377 		return -EINVAL;
378 	}
379 
380 	if (demux.curr != NULL) {
381 		/* Previous package was incompleted. Finish it and potentially
382 		 * mark as incompleted if not all data is received.
383 		 */
384 		log_frontend_stmesp_demux_packet_end();
385 		return -EINVAL;
386 	}
387 
388 	uint16_t ch = demux.curr_m_ch & C_ID_MASK;
389 	uint16_t m = get_major_id(demux.curr_m_ch >> M_ID_OFF);
390 
391 	if (ch < CONFIG_LOG_FRONTEND_STMESP_TURBO_LOG_BASE) {
392 		return -EINVAL;
393 	}
394 
395 	store_turbo_log0(m, ch, ts, source_id);
396 
397 	return 1;
398 }
399 
log_frontend_stmesp_demux_source_id(uint16_t data)400 void log_frontend_stmesp_demux_source_id(uint16_t data)
401 {
402 	if (skip) {
403 		return;
404 	}
405 
406 	if (demux.curr_m_ch == M_CH_INVALID) {
407 		return;
408 	}
409 
410 	uint16_t ch = demux.curr_m_ch & C_ID_MASK;
411 	uint16_t m = get_major_id(demux.curr_m_ch >> M_ID_OFF);
412 
413 	store_source_id(m, ch, data);
414 }
415 
log_frontend_stmesp_demux_sname_get(uint32_t m_id,uint16_t s_id)416 const char *log_frontend_stmesp_demux_sname_get(uint32_t m_id, uint16_t s_id)
417 {
418 	if (!IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_TURBO_LOG)) {
419 		return "";
420 	}
421 
422 	if (demux.m_ids[m_id] == APP_M_ID) {
423 		return log_source_name_get(0, s_id);
424 	} else if (m_id == demux.coproc_sources[0].m_id) {
425 		return demux.coproc_sources[0].data.log_const[s_id].name;
426 	} else if (m_id == demux.coproc_sources[1].m_id) {
427 		return demux.coproc_sources[1].data.log_const[s_id].name;
428 	}
429 
430 	return "unknown";
431 }
432 
log_frontend_stmesp_demux_str_get(uint32_t m_id,uint16_t s_id)433 const char *log_frontend_stmesp_demux_str_get(uint32_t m_id, uint16_t s_id)
434 {
435 	if (!IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_TURBO_LOG)) {
436 		return "";
437 	}
438 
439 	uintptr_t *log_str_start = NULL;
440 
441 	if (demux.m_ids[m_id] == APP_M_ID) {
442 		log_str_start = (uintptr_t *)TYPE_SECTION_START(log_stmesp_ptr);
443 	} else if (m_id == demux.coproc_sources[0].m_id) {
444 		log_str_start = demux.coproc_sources[0].data.log_str_section;
445 	} else if (m_id == demux.coproc_sources[1].m_id) {
446 		log_str_start = demux.coproc_sources[1].data.log_str_section;
447 	}
448 
449 	if (log_str_start) {
450 		return (const char *)log_str_start[s_id];
451 	}
452 
453 	return "unknown";
454 }
455 
log_frontend_stmesp_demux_packet_start(uint32_t * data,uint64_t * ts)456 int log_frontend_stmesp_demux_packet_start(uint32_t *data, uint64_t *ts)
457 {
458 	if (skip) {
459 		return 0;
460 	}
461 
462 	struct log_frontend_stmesp_demux_active_entry *entry;
463 	union log_frontend_stmesp_demux_packet p;
464 	int err;
465 
466 	if (demux.curr_m_ch == M_CH_INVALID) {
467 		return -EINVAL;
468 	}
469 
470 	if (demux.curr_m_ch == M_CH_HW_EVENT) {
471 		/* HW event */
472 		log_frontend_stmesp_demux_hw_event(ts, (uint8_t)*data);
473 
474 		return 1;
475 	}
476 
477 	uint16_t ch = demux.curr_m_ch & C_ID_MASK;
478 	uint16_t m = get_major_id(demux.curr_m_ch >> M_ID_OFF);
479 
480 	if (IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_TURBO_LOG) &&
481 	    (ch == CONFIG_LOG_FRONTEND_STPESP_TURBO_SOURCE_PORT_ID)) {
482 		struct log_frontend_stmesp_coproc_sources *src =
483 			&demux.coproc_sources[demux.m_ids[m] == FLPR_M_ID ? 0 : 1];
484 
485 		if (src->data_cnt >= 2) {
486 			/* Unexpected packet. */
487 			return -EINVAL;
488 		}
489 
490 		src->m_id = m;
491 		src->raw_data.data[src->data_cnt++] = (uintptr_t)*data;
492 		return 0;
493 	}
494 
495 	if (demux.curr != NULL) {
496 		/* Previous package was incompleted. Finish it and potentially
497 		 * mark as incompleted if not all data is received.
498 		 */
499 		log_frontend_stmesp_demux_packet_end();
500 		return -EINVAL;
501 	}
502 
503 	if (ch >= CONFIG_LOG_FRONTEND_STMESP_TP_CHAN_BASE) {
504 		/* Trace point */
505 		if (ch >= CONFIG_LOG_FRONTEND_STMESP_TURBO_LOG_BASE) {
506 			store_turbo_log1(m, ch, ts, *data);
507 		} else {
508 			store_tracepoint(m, ch, ts, data);
509 		}
510 
511 		return 1;
512 	}
513 
514 	union log_frontend_stmesp_demux_header hdr = {.raw = *data};
515 	uint32_t pkt_len = hdr.log.total_len + offsetof(struct log_frontend_stmesp_demux_log, data);
516 	uint32_t wlen = calc_wlen(pkt_len);
517 	uint32_t now = k_uptime_get_32();
518 
519 	garbage_collector(now);
520 	err = k_mem_slab_alloc(&demux.mslab, (void **)&entry, K_NO_WAIT);
521 	if (err < 0) {
522 		goto on_nomem;
523 	}
524 
525 	entry->m_ch = demux.curr_m_ch;
526 	entry->off = 0;
527 	p.generic = mpsc_pbuf_alloc(&demux.pbuf, wlen, K_NO_WAIT);
528 	if (p.generic == NULL) {
529 		k_mem_slab_free(&demux.mslab, entry);
530 		goto on_nomem;
531 	}
532 
533 	entry->packet = p.log;
534 	entry->packet->type = LOG_FRONTEND_STMESP_DEMUX_TYPE_LOG;
535 	entry->packet->content_invalid = 0;
536 	if (ts) {
537 		entry->packet->timestamp = *ts;
538 	}
539 	entry->packet->hdr = hdr.log;
540 	entry->packet->hdr.major = m;
541 	entry->ts = now;
542 	demux.curr = entry;
543 	sys_slist_append(&demux.active_entries, &entry->node);
544 
545 	return 0;
546 
547 on_nomem:
548 	demux.curr = NULL;
549 	demux.dropped++;
550 	return -ENOMEM;
551 }
552 
log_frontend_stmesp_demux_timestamp(uint64_t ts)553 void log_frontend_stmesp_demux_timestamp(uint64_t ts)
554 {
555 	if (demux.curr == NULL) {
556 		return;
557 	}
558 
559 	demux.curr->packet->timestamp = ts;
560 }
561 
log_frontend_stmesp_demux_data(uint8_t * data,size_t len)562 void log_frontend_stmesp_demux_data(uint8_t *data, size_t len)
563 {
564 	if (demux.curr == NULL) {
565 		return;
566 	}
567 
568 	if (demux.curr->off + len <= demux.curr->packet->hdr.total_len) {
569 		memcpy(&demux.curr->packet->data[demux.curr->off], data, len);
570 		demux.curr->off += len;
571 	}
572 }
573 
log_frontend_stmesp_demux_packet_end(void)574 void log_frontend_stmesp_demux_packet_end(void)
575 {
576 	if (demux.curr == NULL) {
577 		return;
578 	}
579 
580 	union log_frontend_stmesp_demux_packet p = {.log = demux.curr->packet};
581 
582 	if (demux.curr->off != demux.curr->packet->hdr.total_len) {
583 		demux.curr->packet->content_invalid = 1;
584 		demux.dropped++;
585 	}
586 
587 	mpsc_pbuf_commit(&demux.pbuf, p.generic);
588 
589 	sys_slist_find_and_remove(&demux.active_entries, &demux.curr->node);
590 	k_mem_slab_free(&demux.mslab, demux.curr);
591 	demux.curr = NULL;
592 }
593 
log_frontend_stmesp_demux_get_dropped(void)594 uint32_t log_frontend_stmesp_demux_get_dropped(void)
595 {
596 	uint32_t rv = demux.dropped;
597 
598 	demux.dropped = 0;
599 
600 	return rv;
601 }
602 
log_frontend_stmesp_demux_claim(void)603 union log_frontend_stmesp_demux_packet log_frontend_stmesp_demux_claim(void)
604 {
605 	union log_frontend_stmesp_demux_packet p;
606 
607 	/* Discard any invalid packets. */
608 	while ((p.rgeneric = mpsc_pbuf_claim(&demux.pbuf)) != NULL) {
609 		if (p.generic_packet->content_invalid) {
610 			mpsc_pbuf_free(&demux.pbuf, p.rgeneric);
611 		} else {
612 			break;
613 		}
614 	}
615 
616 	return p;
617 }
618 
log_frontend_stmesp_demux_free(union log_frontend_stmesp_demux_packet packet)619 void log_frontend_stmesp_demux_free(union log_frontend_stmesp_demux_packet packet)
620 {
621 	mpsc_pbuf_free(&demux.pbuf, packet.rgeneric);
622 }
623 
log_frontend_stmesp_demux_reset(void)624 void log_frontend_stmesp_demux_reset(void)
625 {
626 	sys_snode_t *node;
627 
628 	while ((node = sys_slist_get(&demux.active_entries)) != NULL) {
629 		struct log_frontend_stmesp_demux_active_entry *entry =
630 			CONTAINER_OF(node, struct log_frontend_stmesp_demux_active_entry, node);
631 		union log_frontend_stmesp_demux_packet p = {.log = entry->packet};
632 
633 		entry->packet->content_invalid = 1;
634 		mpsc_pbuf_commit(&demux.pbuf, p.generic);
635 		demux.dropped++;
636 		demux.curr_m_ch = M_CH_INVALID;
637 
638 		k_mem_slab_free(&demux.mslab, entry);
639 	}
640 }
641 
log_frontend_stmesp_demux_is_idle(void)642 bool log_frontend_stmesp_demux_is_idle(void)
643 {
644 	return sys_slist_is_empty(&demux.active_entries);
645 }
646 
log_frontend_stmesp_demux_max_utilization(void)647 int log_frontend_stmesp_demux_max_utilization(void)
648 {
649 	uint32_t max;
650 	int rv = mpsc_pbuf_get_max_utilization(&demux.pbuf, &max);
651 
652 	return rv == 0 ? max : rv;
653 }
654