1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/ztest.h>
7 #include <zephyr/logging/log_frontend_stmesp_demux.h>
8 #include <zephyr/logging/log_frontend.h>
9 
10 #define M_HW  0x80
11 #define M_ID0 0x30
12 #define M_ID1 0x3131
13 #define M_ID2 0x20
14 
15 #define TOTAL_LEN(len)                                                                             \
16 	ROUND_UP(len + offsetof(struct log_frontend_stmesp_demux_log, data), 2 * sizeof(uint32_t))
17 #define TOTAL_WLEN(len) (TOTAL_LEN(len) / sizeof(uint32_t))
18 
19 static const uint16_t ids[] = {M_ID0, M_ID1, M_ID2, M_HW};
20 
log_frontend_init(void)21 void log_frontend_init(void)
22 {
23 	/* empty */
24 }
25 
log_frontend_msg(const void * source,const struct log_msg_desc desc,uint8_t * package,const void * data)26 void log_frontend_msg(const void *source, const struct log_msg_desc desc, uint8_t *package,
27 		      const void *data)
28 {
29 	/* empty */
30 }
31 
log_frontend_panic(void)32 void log_frontend_panic(void)
33 {
34 	/* empty */
35 }
36 
claim_packet(uint16_t exp_m_idx,uint64_t exp_ts,uint16_t exp_len,uint8_t exp_id,int line)37 static void claim_packet(uint16_t exp_m_idx, uint64_t exp_ts, uint16_t exp_len, uint8_t exp_id,
38 			 int line)
39 {
40 	union log_frontend_stmesp_demux_packet packet = log_frontend_stmesp_demux_claim();
41 
42 	if (packet.generic == NULL) {
43 		zassert_equal(exp_len, 0, "%d: Expected a packet", line);
44 		return;
45 	}
46 
47 	zassert_equal(packet.generic_packet->type, LOG_FRONTEND_STMESP_DEMUX_TYPE_LOG);
48 	zassert_equal(exp_ts, packet.log->timestamp, "%d: Unexpected ts %llu/%x (exp:%llu/%x)",
49 		      line, packet.log->timestamp, packet.log->timestamp, exp_ts, exp_ts);
50 	zassert_equal(exp_m_idx, ids[packet.log->hdr.major], "%d: Unexpected major:%d (exp:%d)",
51 		      line, packet.log->hdr.major, exp_m_idx);
52 	zassert_equal(exp_len, packet.log->hdr.total_len, "%d: Unexpected len:%d (exp:%d)", line,
53 		      packet.log->hdr.total_len, exp_len);
54 	for (int i = 0; i < exp_len; i++) {
55 		zassert_equal(packet.log->data[i], i + exp_id,
56 			      "%d: Unexpected data(%d) at %d index (exp:%d)", line,
57 			      packet.log->data[i], i, i + exp_id);
58 	}
59 
60 	log_frontend_stmesp_demux_free(packet);
61 }
62 
63 #define CLAIM_PACKET(_exp_m_idx, _exp_ts, _exp_len, _exp_id)                                       \
64 	claim_packet(_exp_m_idx, _exp_ts, _exp_len, _exp_id, __LINE__)
65 
claim_trace_point(uint16_t exp_m_idx,uint16_t exp_id,uint64_t exp_ts,uint32_t * exp_data,int line)66 static void claim_trace_point(uint16_t exp_m_idx, uint16_t exp_id, uint64_t exp_ts,
67 			      uint32_t *exp_data, int line)
68 {
69 	union log_frontend_stmesp_demux_packet packet = log_frontend_stmesp_demux_claim();
70 
71 	zassert_equal(packet.generic_packet->type, LOG_FRONTEND_STMESP_DEMUX_TYPE_TRACE_POINT);
72 	zassert_equal(exp_ts, packet.trace_point->timestamp,
73 		      "%d: Unexpected ts %llu/%x (exp:%llu/%x)", line,
74 		      packet.trace_point->timestamp, packet.trace_point->timestamp, exp_ts, exp_ts);
75 	zassert_equal(exp_id, packet.trace_point->id, "%d: Unexpected id:%d (exp:%d)", line,
76 		      packet.trace_point->id, exp_id);
77 	zassert_equal(exp_m_idx, ids[packet.trace_point->major],
78 		      "%d: Unexpected major:%d (exp:%d)", line, packet.trace_point->major,
79 		      exp_m_idx);
80 	if (exp_data) {
81 		zassert_equal(1, packet.trace_point->has_data);
82 		zassert_equal(*exp_data, packet.trace_point->data,
83 			      "%d: Unexpected data:%d (exp:%d)", line, packet.trace_point->data,
84 			      *exp_data);
85 	} else {
86 		zassert_equal(0, packet.trace_point->has_data);
87 	}
88 
89 	log_frontend_stmesp_demux_free(packet);
90 }
91 
92 #define CLAIM_TRACE_POINT(_exp_m_idx, _exp_id, _exp_ts, _exp_data)                                 \
93 	claim_trace_point(_exp_m_idx, _exp_id, _exp_ts, _exp_data, __LINE__)
94 
claim_hw_event(uint8_t exp_evt,uint64_t exp_ts,int line)95 static void claim_hw_event(uint8_t exp_evt, uint64_t exp_ts, int line)
96 {
97 	union log_frontend_stmesp_demux_packet packet = log_frontend_stmesp_demux_claim();
98 
99 	zassert_equal(packet.generic_packet->type, LOG_FRONTEND_STMESP_DEMUX_TYPE_HW_EVENT);
100 	zassert_equal(exp_ts, packet.hw_event->timestamp, "%d: Unexpected ts %llu/%x (exp:%llu/%x)",
101 		      line, packet.hw_event->timestamp, packet.hw_event->timestamp, exp_ts, exp_ts);
102 	zassert_equal(exp_evt, packet.hw_event->evt, "%d: Unexpected id:%d (exp:%d)", line,
103 		      packet.hw_event->evt, exp_evt);
104 
105 	log_frontend_stmesp_demux_free(packet);
106 }
107 
108 #define CLAIM_HW_EVENT(_exp_evt, _exp_ts) claim_hw_event(_exp_evt, _exp_ts, __LINE__)
109 
110 #define DEMUX_EMPTY() CLAIM_PACKET(0, 0, 0, 0)
111 
write_trace_point(uint16_t * m_id,uint16_t * c_id,uint32_t * data,uint64_t ts)112 static int write_trace_point(uint16_t *m_id, uint16_t *c_id, uint32_t *data, uint64_t ts)
113 {
114 	if (m_id) {
115 		log_frontend_stmesp_demux_major(*m_id);
116 	}
117 
118 	if (c_id) {
119 		log_frontend_stmesp_demux_channel(*c_id);
120 	}
121 
122 	return log_frontend_stmesp_demux_packet_start(data, &ts);
123 }
124 
write_hw_event(uint8_t evt,uint64_t ts)125 static int write_hw_event(uint8_t evt, uint64_t ts)
126 {
127 	uint32_t data = (uint32_t)evt;
128 
129 	log_frontend_stmesp_demux_major(M_HW);
130 
131 	return log_frontend_stmesp_demux_packet_start(&data, &ts);
132 }
133 
packet_start(uint16_t * m_id,uint16_t * c_id,uint32_t data,uint64_t ts,int exp_rv,int line)134 static void packet_start(uint16_t *m_id, uint16_t *c_id, uint32_t data, uint64_t ts, int exp_rv,
135 			 int line)
136 {
137 	int rv;
138 
139 	if (m_id) {
140 		log_frontend_stmesp_demux_major(*m_id);
141 	}
142 
143 	if (c_id) {
144 		log_frontend_stmesp_demux_channel(*c_id);
145 	}
146 
147 	rv = log_frontend_stmesp_demux_packet_start(&data, &ts);
148 	zassert_equal(rv, exp_rv, "%d: Unexpected ret:%d (exp:%d)", line, rv, exp_rv);
149 }
150 #define PACKET_START(_m_id, _c_id, _data, _ts, _exp_rv)                                            \
151 	packet_start(_m_id, _c_id, _data, _ts, _exp_rv, __LINE__)
152 
packet_data(uint16_t * m_id,uint16_t * c_id,uint8_t * data,size_t len)153 static void packet_data(uint16_t *m_id, uint16_t *c_id, uint8_t *data, size_t len)
154 {
155 	if (m_id) {
156 		log_frontend_stmesp_demux_major(*m_id);
157 	}
158 
159 	if (c_id) {
160 		log_frontend_stmesp_demux_channel(*c_id);
161 	}
162 
163 	log_frontend_stmesp_demux_data(data, len);
164 }
165 
packet_end(uint16_t * m_id,uint16_t * c_id)166 static void packet_end(uint16_t *m_id, uint16_t *c_id)
167 {
168 	if (m_id) {
169 		log_frontend_stmesp_demux_major(*m_id);
170 	}
171 
172 	if (c_id) {
173 		log_frontend_stmesp_demux_channel(*c_id);
174 	}
175 
176 	log_frontend_stmesp_demux_packet_end();
177 }
178 
write_data(uint16_t len,uint8_t id)179 static void write_data(uint16_t len, uint8_t id)
180 {
181 	for (int i = 0; i < len; i++) {
182 		uint8_t d = i + id;
183 
184 		log_frontend_stmesp_demux_data(&d, 1);
185 	}
186 }
187 
write_packet(uint16_t m_id,uint16_t c_id,uint64_t ts,uint16_t len,uint8_t id)188 static void write_packet(uint16_t m_id, uint16_t c_id, uint64_t ts, uint16_t len, uint8_t id)
189 {
190 	union log_frontend_stmesp_demux_header hdr = {.log = {.total_len = len}};
191 
192 	log_frontend_stmesp_demux_major(m_id);
193 	log_frontend_stmesp_demux_channel(c_id);
194 	log_frontend_stmesp_demux_packet_start(&hdr.raw, NULL);
195 	log_frontend_stmesp_demux_timestamp(ts);
196 	write_data(len, id);
197 	log_frontend_stmesp_demux_packet_end();
198 }
199 
demux_init(void)200 static void demux_init(void)
201 {
202 	struct log_frontend_stmesp_demux_config config = {.m_ids = ids,
203 							  .m_ids_cnt = ARRAY_SIZE(ids)};
204 	int err;
205 
206 	err = log_frontend_stmesp_demux_init(&config);
207 	zassert_equal(err, 0, NULL);
208 }
209 
ZTEST(log_frontend_stmesp_demux_test,test_init)210 ZTEST(log_frontend_stmesp_demux_test, test_init)
211 {
212 	/* Ids limit is 8 */
213 	static const uint16_t m_ids[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
214 	struct log_frontend_stmesp_demux_config config = {.m_ids = m_ids,
215 							  .m_ids_cnt = ARRAY_SIZE(m_ids)};
216 	int err;
217 
218 	err = log_frontend_stmesp_demux_init(&config);
219 	zassert_equal(err, -EINVAL, NULL);
220 
221 	config.m_ids_cnt = 8;
222 	err = log_frontend_stmesp_demux_init(&config);
223 	zassert_equal(err, 0, NULL);
224 }
225 
ZTEST(log_frontend_stmesp_demux_test,test_basic)226 ZTEST(log_frontend_stmesp_demux_test, test_basic)
227 {
228 	uint16_t m = M_ID0;
229 	uint16_t c = 0;
230 	uint8_t data = 1;
231 
232 	demux_init();
233 
234 	/* Writing to packet that was not started has no effect. */
235 	packet_data(&m, &c, &data, 1);
236 	packet_end(&m, &c);
237 
238 	write_packet(M_ID0, 1, 1, 10, 1);
239 	write_packet(M_ID0, 2, 2, 10, 2);
240 	write_packet(M_ID1, 1, 3, 10, 3);
241 
242 	CLAIM_PACKET(M_ID0, 1, 10, 1);
243 	CLAIM_PACKET(M_ID0, 2, 10, 2);
244 	CLAIM_PACKET(M_ID1, 3, 10, 3);
245 
246 	DEMUX_EMPTY();
247 
248 	zassert_equal(log_frontend_stmesp_demux_get_dropped(), 0, NULL);
249 }
250 
ZTEST(log_frontend_stmesp_demux_test,test_overwrite)251 ZTEST(log_frontend_stmesp_demux_test, test_overwrite)
252 {
253 	uint64_t ts = 0;
254 	uint32_t len = 10;
255 	uint32_t total_wlen = TOTAL_WLEN(len);
256 	int i;
257 
258 	demux_init();
259 
260 	for (i = 0; i < (CONFIG_LOG_FRONTEND_STMESP_DEMUX_BUFFER_SIZE / total_wlen); i++) {
261 		write_packet(M_ID0, 1, ts + i, len, i);
262 	}
263 	zassert_equal(log_frontend_stmesp_demux_get_dropped(), 0, NULL);
264 
265 	write_packet(M_ID0, 1, ts + i, len, i);
266 
267 	uint32_t dropped = log_frontend_stmesp_demux_get_dropped();
268 
269 	zassert_true(dropped >= 1, NULL);
270 
271 	for (i = dropped; i < (CONFIG_LOG_FRONTEND_STMESP_DEMUX_BUFFER_SIZE / total_wlen) + 1;
272 	     i++) {
273 		CLAIM_PACKET(M_ID0, ts + i, len, i);
274 	}
275 
276 	DEMUX_EMPTY();
277 }
278 
ZTEST(log_frontend_stmesp_demux_test,test_mix)279 ZTEST(log_frontend_stmesp_demux_test, test_mix)
280 {
281 	uint16_t m_id = M_ID0;
282 	uint16_t c_id0 = 2;
283 	uint16_t c_id1 = 1;
284 	uint64_t ts0 = 0x1234567890;
285 	uint64_t ts1 = 0x3434343445;
286 	int len0 = 12;
287 	int len1 = 14;
288 	union log_frontend_stmesp_demux_header hdr0 = {.log = {.total_len = len0}};
289 	union log_frontend_stmesp_demux_header hdr1 = {.log = {.total_len = len1}};
290 
291 	zassert_true(c_id0 != CONFIG_LOG_FRONTEND_STMESP_FLUSH_PORT_ID);
292 	zassert_true(c_id1 != CONFIG_LOG_FRONTEND_STMESP_FLUSH_PORT_ID);
293 
294 	demux_init();
295 
296 	/* Write 2 packets mixing them. */
297 	PACKET_START(&m_id, &c_id0, hdr0.raw, ts0, 0);
298 
299 	PACKET_START(&m_id, &c_id1, hdr1.raw, ts1, 0);
300 	packet_data(&m_id, &c_id0, NULL, 0);
301 	write_data(len0, 0);
302 	packet_data(&m_id, &c_id1, NULL, 0);
303 	write_data(len1, 1);
304 	packet_end(&m_id, &c_id0);
305 	packet_end(&m_id, &c_id1);
306 
307 	/* Expect demuxed packets. */
308 	CLAIM_PACKET(M_ID0, ts0, len0, 0);
309 	CLAIM_PACKET(M_ID0, ts1, len1, 1);
310 
311 	DEMUX_EMPTY();
312 }
313 
ZTEST(log_frontend_stmesp_demux_test,test_drop_too_many_active)314 ZTEST(log_frontend_stmesp_demux_test, test_drop_too_many_active)
315 {
316 	BUILD_ASSERT(CONFIG_LOG_FRONTEND_STMESP_DEMUX_ACTIVE_PACKETS == 3,
317 		     "Test assumes certain configuration");
318 
319 	uint16_t m_id0 = M_ID0;
320 	uint16_t m_id1 = M_ID1;
321 	uint16_t c_id0 = 2;
322 	uint16_t c_id1 = 1;
323 	int len = 4;
324 	uint64_t ts = 0;
325 	uint8_t data[] = {1, 2, 3, 4};
326 	union log_frontend_stmesp_demux_header hdr = {.log = {.total_len = len}};
327 
328 	zassert_true(c_id0 != CONFIG_LOG_FRONTEND_STMESP_FLUSH_PORT_ID);
329 	zassert_true(c_id1 != CONFIG_LOG_FRONTEND_STMESP_FLUSH_PORT_ID);
330 
331 	demux_init();
332 
333 	PACKET_START(NULL, NULL, hdr.raw, ts, -EINVAL);
334 
335 	/* Start writing to 3 packets */
336 	PACKET_START(&m_id0, &c_id0, hdr.raw, ts, 0);
337 	packet_data(NULL, NULL, data, 1);
338 	PACKET_START(&m_id0, &c_id1, hdr.raw, ts + 1, 0);
339 	PACKET_START(&m_id1, &c_id0, hdr.raw, ts + 2, 0);
340 	packet_data(NULL, NULL, data, 1);
341 
342 	zassert_equal(log_frontend_stmesp_demux_get_dropped(), 0, NULL);
343 	/* Starting forth packet results in dropping. */
344 	PACKET_START(&m_id1, &c_id1, hdr.raw, ts + 3, -ENOMEM);
345 	zassert_equal(log_frontend_stmesp_demux_get_dropped(), 1, NULL);
346 
347 	/* Complete first packet. */
348 	packet_data(&m_id0, &c_id0, &data[1], 3);
349 	packet_end(NULL, NULL);
350 
351 	PACKET_START(&m_id1, &c_id1, hdr.raw, ts + 3, 0);
352 	zassert_equal(log_frontend_stmesp_demux_get_dropped(), 0, NULL);
353 }
354 
ZTEST(log_frontend_stmesp_demux_test,test_max_utilization)355 ZTEST(log_frontend_stmesp_demux_test, test_max_utilization)
356 {
357 	int utilization;
358 	uint32_t len = 10;
359 
360 	if (!IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_DEMUX_MAX_UTILIZATION)) {
361 		utilization = log_frontend_stmesp_demux_max_utilization();
362 		zassert_equal(utilization, -ENOTSUP, NULL);
363 		return;
364 	}
365 
366 	demux_init();
367 	utilization = log_frontend_stmesp_demux_max_utilization();
368 	zassert_equal(utilization, 0, NULL);
369 
370 	write_packet(M_ID0, 0, 1, len, 1);
371 	utilization = log_frontend_stmesp_demux_max_utilization();
372 
373 	int exp_utilization = TOTAL_LEN(len);
374 
375 	zassert_equal(utilization, exp_utilization, NULL);
376 }
377 
ZTEST(log_frontend_stmesp_demux_test,test_trace_point)378 ZTEST(log_frontend_stmesp_demux_test, test_trace_point)
379 {
380 	uint16_t m_id0 = M_ID0;
381 	uint16_t m_id1 = M_ID1;
382 	uint16_t id0 = 2;
383 	uint16_t id1 = 0;
384 	uint16_t c_id0 = CONFIG_LOG_FRONTEND_STMESP_TP_CHAN_BASE + id0;
385 	uint16_t c_id1 = CONFIG_LOG_FRONTEND_STMESP_TP_CHAN_BASE + id1;
386 	uint32_t data = 0x11223344;
387 	uint64_t t0 = 0x1122334455;
388 	uint64_t t1 = 0x5522334455;
389 	int err;
390 
391 	demux_init();
392 
393 	err = write_trace_point(&m_id0, &c_id0, NULL, t0);
394 	zassert_equal(err, 1);
395 
396 	err = write_trace_point(NULL, &c_id0, NULL, t0);
397 	zassert_equal(err, 1);
398 
399 	err = write_trace_point(NULL, &c_id0, &data, t0);
400 	zassert_equal(err, 1);
401 
402 	err = write_trace_point(NULL, &c_id1, &data, t1);
403 	zassert_equal(err, 1);
404 
405 	err = write_trace_point(&m_id1, &c_id0, NULL, t0);
406 	zassert_equal(err, 1);
407 
408 	err = write_trace_point(&m_id1, &c_id1, NULL, t1);
409 	zassert_equal(err, 1);
410 
411 	CLAIM_TRACE_POINT(m_id0, c_id0, t0, NULL);
412 	CLAIM_TRACE_POINT(m_id0, c_id0, t0, NULL);
413 	CLAIM_TRACE_POINT(m_id0, c_id0, t0, &data);
414 	CLAIM_TRACE_POINT(m_id0, c_id1, t1, &data);
415 	CLAIM_TRACE_POINT(m_id1, c_id0, t0, NULL);
416 	CLAIM_TRACE_POINT(m_id1, c_id1, t1, NULL);
417 
418 	DEMUX_EMPTY();
419 }
420 
ZTEST(log_frontend_stmesp_demux_test,test_hw_event)421 ZTEST(log_frontend_stmesp_demux_test, test_hw_event)
422 {
423 	uint64_t t0 = 0x1122334455;
424 	uint64_t t1 = 0x5522334455;
425 	int err;
426 
427 	demux_init();
428 
429 	err = write_hw_event(0, t0);
430 	zassert_equal(err, 1);
431 
432 	err = write_hw_event(1, t1);
433 	zassert_equal(err, 1);
434 
435 	CLAIM_HW_EVENT(0, t0);
436 	CLAIM_HW_EVENT(1, t1);
437 
438 	DEMUX_EMPTY();
439 }
440 
ZTEST(log_frontend_stmesp_demux_test,test_reset)441 ZTEST(log_frontend_stmesp_demux_test, test_reset)
442 {
443 	uint16_t m_id0 = M_ID0;
444 	uint16_t m_id1 = M_ID1;
445 	uint16_t c_id0 = 2;
446 	uint16_t c_id1 = 1;
447 	int len = 4;
448 	uint64_t ts = 0;
449 	uint8_t data[] = {1, 2, 3, 4};
450 	union log_frontend_stmesp_demux_header hdr = {.log = {.total_len = len}};
451 
452 	zassert_true(c_id0 != CONFIG_LOG_FRONTEND_STMESP_FLUSH_PORT_ID);
453 	zassert_true(c_id1 != CONFIG_LOG_FRONTEND_STMESP_FLUSH_PORT_ID);
454 
455 	demux_init();
456 
457 	PACKET_START(NULL, NULL, hdr.raw, ts, -EINVAL);
458 
459 	/* Start writing to 3 packets */
460 	PACKET_START(&m_id0, &c_id0, hdr.raw, ts, 0);
461 	packet_data(NULL, NULL, data, 1);
462 	PACKET_START(&m_id0, &c_id1, hdr.raw, ts + 1, 0);
463 	PACKET_START(&m_id1, &c_id0, hdr.raw, ts + 2, 0);
464 	packet_data(NULL, NULL, data, 4);
465 	packet_end(NULL, NULL);
466 
467 	log_frontend_stmesp_demux_reset();
468 	zassert_equal(log_frontend_stmesp_demux_get_dropped(), 2, NULL);
469 
470 	CLAIM_PACKET(M_ID1, ts + 2, len, 1);
471 	DEMUX_EMPTY();
472 }
473 
474 ZTEST_SUITE(log_frontend_stmesp_demux_test, NULL, NULL, NULL, NULL, NULL);
475