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