1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2019 Intel Corporation. All rights reserved.
4 //
5 // Author: Artur Kloniecki <arturx.kloniecki@linux.intel.com>
6 // Author: Adrian Bonislawski <adrian.bonislawski@linux.intel.com>
7
8 #include <sof/audio/buffer.h>
9 #include <sof/audio/component.h>
10 #include <sof/probe/probe.h>
11 #include <sof/trace/trace.h>
12 #include <user/trace.h>
13 #include <sof/lib/alloc.h>
14 #include <sof/lib/dma.h>
15 #include <sof/lib/notifier.h>
16 #include <sof/lib/uuid.h>
17 #include <sof/ipc/topology.h>
18 #include <sof/ipc/driver.h>
19 #include <sof/drivers/timer.h>
20 #include <sof/schedule/ll_schedule.h>
21 #include <sof/schedule/schedule.h>
22 #include <sof/schedule/task.h>
23
24 /* 9d1fb66e-4ffb-497f-994b-17719686596e */
25 DECLARE_SOF_UUID("probe", probe_uuid, 0x9d1fb66e, 0x4ffb, 0x497f,
26 0x99, 0x4b, 0x17, 0x71, 0x96, 0x86, 0x59, 0x6e);
27
28 DECLARE_TR_CTX(pr_tr, SOF_UUID(probe_uuid), LOG_LEVEL_INFO);
29
30 /* 2f0b1901-cac0-4b87-812f-f2d5e4f19e4a */
31 DECLARE_SOF_UUID("probe-task", probe_task_uuid, 0x2f0b1901, 0xcac0, 0x4b87,
32 0x81, 0x2f, 0xf2, 0xd5, 0xe4, 0xf1, 0x9e, 0x4a);
33
34 #define PROBE_DMA_INVALID 0xFFFFFFFF
35 #define PROBE_POINT_INVALID 0xFFFFFFFF
36
37 #define PROBE_BUFFER_LOCAL_SIZE 8192
38 #define DMA_ELEM_SIZE 32
39
40 /**
41 * DMA buffer
42 */
43 struct probe_dma_buf {
44 uintptr_t w_ptr; /**< write pointer */
45 uintptr_t r_ptr; /**< read pointer */
46 uintptr_t addr; /**< buffer start pointer */
47 uintptr_t end_addr; /**< buffer end pointer */
48 uint32_t size; /**< buffer size */
49 uint32_t avail; /**< buffer avail data */
50 };
51
52 /**
53 * Probe DMA
54 */
55 struct probe_dma_ext {
56 uint32_t stream_tag; /**< DMA stream tag */
57 uint32_t dma_buffer_size; /**< DMA buffer size */
58 struct dma_sg_config config; /**< DMA SG config */
59 struct probe_dma_buf dmapb; /**< DMA buffer pointer */
60 struct dma_copy dc; /**< DMA copy */
61 };
62
63 /**
64 * Probe main struct
65 */
66 struct probe_pdata {
67 struct probe_dma_ext ext_dma; /**< extraction DMA */
68 struct probe_dma_ext inject_dma[CONFIG_PROBE_DMA_MAX]; /**< injection DMA */
69 struct probe_point probe_points[CONFIG_PROBE_POINTS_MAX]; /**< probe points */
70 struct probe_data_packet header; /**< data packet header */
71 struct task dmap_work; /**< probe task */
72 };
73
74 /**
75 * \brief Allocate and initialize probe buffer with correct alignment.
76 * \param[out] buffer return value.
77 * \param[in] size of buffer.
78 * \param[in] align the buffer.
79 * \return 0 on success, error code otherwise.
80 */
probe_dma_buffer_init(struct probe_dma_buf * buffer,uint32_t size,uint32_t align)81 static int probe_dma_buffer_init(struct probe_dma_buf *buffer, uint32_t size,
82 uint32_t align)
83 {
84 /* allocate new buffer */
85 buffer->addr = (uintptr_t)rballoc_align(0, SOF_MEM_CAPS_DMA,
86 size, align);
87
88 if (!buffer->addr) {
89 tr_err(&pr_tr, "probe_dma_buffer_init(): alloc failed");
90 return -ENOMEM;
91 }
92
93 bzero((void *)buffer->addr, size);
94 dcache_writeback_region((void *)buffer->addr, size);
95
96 /* initialise the DMA buffer */
97 buffer->size = size;
98 buffer->w_ptr = buffer->addr;
99 buffer->r_ptr = buffer->addr;
100 buffer->end_addr = buffer->addr + buffer->size;
101 buffer->avail = 0;
102
103 return 0;
104 }
105
106 /**
107 * \brief Request DMA and initialize DMA for probes with correct alignment,
108 * size and specific channel.
109 *
110 * \param[out] dma probe returned
111 * \param[in] direction of the DMA
112 * \return 0 on success, error code otherwise.
113 */
probe_dma_init(struct probe_dma_ext * dma,uint32_t direction)114 static int probe_dma_init(struct probe_dma_ext *dma, uint32_t direction)
115 {
116 struct dma_sg_config config;
117 uint32_t elem_addr, addr_align;
118 const uint32_t elem_size = sizeof(uint64_t) * DMA_ELEM_SIZE;
119 const uint32_t elem_num = PROBE_BUFFER_LOCAL_SIZE / elem_size;
120 int err = 0;
121
122 /* request DMA in the dir LMEM->HMEM with shared access */
123 dma->dc.dmac = dma_get(direction, 0, DMA_DEV_HOST,
124 DMA_ACCESS_SHARED);
125 if (!dma->dc.dmac) {
126 tr_err(&pr_tr, "probe_dma_init(): dma->dc.dmac = NULL");
127 return -ENODEV;
128 }
129
130 /* get required address alignment for dma buffer */
131 err = dma_get_attribute(dma->dc.dmac, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT,
132 &addr_align);
133 if (err < 0)
134 return err;
135
136 /* initialize dma buffer */
137 err = probe_dma_buffer_init(&dma->dmapb, PROBE_BUFFER_LOCAL_SIZE, addr_align);
138 if (err < 0)
139 return err;
140
141 err = dma_copy_set_stream_tag(&dma->dc, dma->stream_tag);
142 if (err < 0)
143 return err;
144
145 elem_addr = (uint32_t)dma->dmapb.addr;
146
147 config.direction = direction;
148 config.src_width = sizeof(uint32_t);
149 config.dest_width = sizeof(uint32_t);
150 config.cyclic = 0;
151
152 err = dma_sg_alloc(&config.elem_array, SOF_MEM_ZONE_RUNTIME,
153 config.direction, elem_num, elem_size, elem_addr, 0);
154 if (err < 0)
155 return err;
156
157 err = dma_set_config(dma->dc.chan, &config);
158 if (err < 0)
159 return err;
160
161 dma_sg_free(&config.elem_array);
162
163 return 0;
164 }
165
166 /**
167 * \brief Stop, deinit and free DMA and buffer used by probes.
168 *
169 * \return 0 on success, error code otherwise.
170 */
probe_dma_deinit(struct probe_dma_ext * dma)171 static int probe_dma_deinit(struct probe_dma_ext *dma)
172 {
173 int err = 0;
174
175 err = dma_stop(dma->dc.chan);
176 if (err < 0) {
177 tr_err(&pr_tr, "probe_dma_deinit(): dma_stop() failed");
178 return err;
179 }
180
181 dma_channel_put(dma->dc.chan);
182 dma_put(dma->dc.dmac);
183
184 rfree((void *)dma->dmapb.addr);
185 dma->dmapb.addr = 0;
186
187 dma->stream_tag = PROBE_DMA_INVALID;
188
189 return 0;
190 }
191
192 /*
193 * \brief Probe task for extraction.
194 *
195 * Copy extraction probes data to host if available.
196 * Return err if dma copy failed.
197 */
probe_task(void * data)198 static enum task_state probe_task(void *data)
199 {
200 struct probe_pdata *_probe = probe_get();
201 int err;
202
203 if (_probe->ext_dma.dmapb.avail > 0)
204 err = dma_copy_to_host_nowait(&_probe->ext_dma.dc,
205 &_probe->ext_dma.config, 0,
206 (void *)_probe->ext_dma.dmapb.r_ptr,
207 _probe->ext_dma.dmapb.avail);
208 else
209 return SOF_TASK_STATE_RESCHEDULE;
210
211 if (err < 0) {
212 tr_err(&pr_tr, "probe_task(): dma_copy_to_host_nowait() failed.");
213 return err;
214 }
215
216 /* buffer data sent, set read pointer and clear avail bytes */
217 _probe->ext_dma.dmapb.r_ptr = _probe->ext_dma.dmapb.w_ptr;
218 _probe->ext_dma.dmapb.avail = 0;
219
220 return SOF_TASK_STATE_RESCHEDULE;
221 }
222
probe_init(struct probe_dma * probe_dma)223 int probe_init(struct probe_dma *probe_dma)
224 {
225 struct probe_pdata *_probe = probe_get();
226 uint32_t i;
227 int err;
228
229 tr_dbg(&pr_tr, "probe_init()");
230
231 if (_probe) {
232 tr_err(&pr_tr, "probe_init(): Probes already initialized.");
233 return -EINVAL;
234 }
235
236 /* alloc probes main struct */
237 sof_get()->probe = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM,
238 sizeof(*_probe));
239 _probe = probe_get();
240
241 if (!_probe) {
242 tr_err(&pr_tr, "probe_init(): Alloc failed.");
243 return -ENOMEM;
244 }
245
246 /* setup extraction dma if requested */
247 if (probe_dma) {
248 tr_dbg(&pr_tr, "\tstream_tag = %u, dma_buffer_size = %u",
249 probe_dma->stream_tag, probe_dma->dma_buffer_size);
250
251 _probe->ext_dma.stream_tag = probe_dma->stream_tag;
252 _probe->ext_dma.dma_buffer_size = probe_dma->dma_buffer_size;
253
254 err = probe_dma_init(&_probe->ext_dma, DMA_DIR_LMEM_TO_HMEM);
255 if (err < 0) {
256 tr_err(&pr_tr, "probe_init(): probe_dma_init() failed");
257 _probe->ext_dma.stream_tag = PROBE_DMA_INVALID;
258 return err;
259 }
260
261 err = dma_start(_probe->ext_dma.dc.chan);
262 if (err < 0) {
263 tr_err(&pr_tr, "probe_init(): failed to start extraction dma");
264
265 return -EBUSY;
266 }
267 /* init task for extraction probes */
268 schedule_task_init_ll(&_probe->dmap_work,
269 SOF_UUID(probe_task_uuid),
270 SOF_SCHEDULE_LL_TIMER, SOF_TASK_PRI_LOW,
271 probe_task, _probe, 0, 0);
272 } else {
273 tr_dbg(&pr_tr, "\tno extraction DMA setup");
274
275 _probe->ext_dma.stream_tag = PROBE_DMA_INVALID;
276 }
277
278 /* initialize injection DMAs as invalid */
279 for (i = 0; i < CONFIG_PROBE_DMA_MAX; i++)
280 _probe->inject_dma[i].stream_tag = PROBE_DMA_INVALID;
281
282 /* initialize probe points as invalid */
283 for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++)
284 _probe->probe_points[i].stream_tag = PROBE_POINT_INVALID;
285
286 return 0;
287 }
288
probe_deinit(void)289 int probe_deinit(void)
290 {
291 struct probe_pdata *_probe = probe_get();
292 uint32_t i;
293 int err;
294
295 tr_dbg(&pr_tr, "probe_deinit()");
296
297 if (!_probe) {
298 tr_err(&pr_tr, "probe_deinit(): Not initialized.");
299
300 return -EINVAL;
301 }
302
303 /* check for attached injection probe DMAs */
304 for (i = 0; i < CONFIG_PROBE_DMA_MAX; i++) {
305 if (_probe->inject_dma[i].stream_tag != PROBE_DMA_INVALID) {
306 tr_err(&pr_tr, "probe_deinit(): Cannot deinitialize with injection DMAs attached.");
307 return -EINVAL;
308 }
309 }
310
311 /* check for connected probe points */
312 for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++) {
313 if (_probe->probe_points[i].stream_tag != PROBE_POINT_INVALID) {
314 tr_err(&pr_tr, "probe_deinit(): Cannot deinitialize with probe points connected.");
315 return -EINVAL;
316 }
317 }
318
319 if (_probe->ext_dma.stream_tag != PROBE_DMA_INVALID) {
320 tr_dbg(&pr_tr, "probe_deinit() Freeing task and extraction DMA.");
321 schedule_task_free(&_probe->dmap_work);
322 err = probe_dma_deinit(&_probe->ext_dma);
323 if (err < 0)
324 return err;
325 }
326
327 sof_get()->probe = NULL;
328 rfree(_probe);
329
330 return 0;
331 }
332
probe_dma_add(uint32_t count,struct probe_dma * probe_dma)333 int probe_dma_add(uint32_t count, struct probe_dma *probe_dma)
334 {
335 struct probe_pdata *_probe = probe_get();
336 uint32_t i;
337 uint32_t j;
338 uint32_t stream_tag;
339 uint32_t first_free;
340 int err;
341
342 tr_dbg(&pr_tr, "probe_dma_add() count = %u", count);
343
344 if (!_probe) {
345 tr_err(&pr_tr, "probe_dma_add(): Not initialized.");
346
347 return -EINVAL;
348 }
349
350 /* Iterate over all (DMA) fields if there are multiple of them */
351 /* add them if there is free place and they are not already attached */
352 for (i = 0; i < count; i++) {
353 tr_dbg(&pr_tr, "\tprobe_dma[%u] stream_tag = %u, dma_buffer_size = %u",
354 i, probe_dma[i].stream_tag,
355 probe_dma[i].dma_buffer_size);
356
357 first_free = CONFIG_PROBE_DMA_MAX;
358
359 /* looking for first free dma slot */
360 for (j = 0; j < CONFIG_PROBE_DMA_MAX; j++) {
361 stream_tag = _probe->inject_dma[j].stream_tag;
362
363 if (stream_tag == PROBE_DMA_INVALID) {
364 if (first_free == CONFIG_PROBE_DMA_MAX)
365 first_free = j;
366
367 continue;
368 }
369
370 if (stream_tag == probe_dma[i].stream_tag) {
371 tr_err(&pr_tr, "probe_dma_add(): Probe DMA %u already attached.",
372 stream_tag);
373 return -EINVAL;
374 }
375 }
376
377 if (first_free == CONFIG_PROBE_DMA_MAX) {
378 tr_err(&pr_tr, "probe_dma_add(): Exceeded maximum number of DMAs attached = "
379 META_QUOTE(CONFIG_PROBE_DMA_MAX));
380 return -EINVAL;
381 }
382
383 _probe->inject_dma[first_free].stream_tag =
384 probe_dma[i].stream_tag;
385 _probe->inject_dma[first_free].dma_buffer_size =
386 probe_dma[i].dma_buffer_size;
387
388 err = probe_dma_init(&_probe->inject_dma[first_free],
389 DMA_DIR_HMEM_TO_LMEM);
390 if (err < 0) {
391 tr_err(&pr_tr, "probe_dma_add(): probe_dma_init() failed");
392 _probe->inject_dma[first_free].stream_tag =
393 PROBE_DMA_INVALID;
394 return err;
395 }
396 }
397
398 return 0;
399 }
400
probe_dma_info(struct sof_ipc_probe_info_params * data,uint32_t max_size)401 int probe_dma_info(struct sof_ipc_probe_info_params *data, uint32_t max_size)
402 {
403 struct probe_pdata *_probe = probe_get();
404 uint32_t i = 0;
405 uint32_t j = 0;
406
407 tr_dbg(&pr_tr, "probe_dma_info()");
408
409 if (!_probe) {
410 tr_err(&pr_tr, "probe_dma_info(): Not initialized.");
411
412 return -EINVAL;
413 }
414
415 data->rhdr.hdr.size = sizeof(*data);
416
417 /* search all injection DMAs to send them in reply */
418 while (i < CONFIG_PROBE_DMA_MAX &&
419 data->rhdr.hdr.size + sizeof(struct probe_dma) < max_size) {
420 /* save it if valid */
421 if (_probe->inject_dma[i].stream_tag != PROBE_DMA_INVALID) {
422 data->probe_dma[j].stream_tag =
423 _probe->inject_dma[i].stream_tag;
424 data->probe_dma[j].dma_buffer_size =
425 _probe->inject_dma[i].dma_buffer_size;
426 j++;
427 /* and increase reply header size */
428 data->rhdr.hdr.size += sizeof(struct probe_dma);
429 }
430
431 i++;
432 }
433
434 data->num_elems = j;
435
436 return 1;
437 }
438
439 /**
440 * \brief Check if stream_tag is used by probes.
441 * \param[in] stream_tag DMA stream tag.
442 * \return 0 if not used, 1 otherwise.
443 */
is_probe_stream_used(uint32_t stream_tag)444 static int is_probe_stream_used(uint32_t stream_tag)
445 {
446 struct probe_pdata *_probe = probe_get();
447 uint32_t i;
448
449 for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++) {
450 if (_probe->probe_points[i].stream_tag == stream_tag)
451 return 1;
452 }
453
454 return 0;
455 }
456
probe_dma_remove(uint32_t count,uint32_t * stream_tag)457 int probe_dma_remove(uint32_t count, uint32_t *stream_tag)
458 {
459 struct probe_pdata *_probe = probe_get();
460 uint32_t i;
461 uint32_t j;
462 int err;
463
464 tr_dbg(&pr_tr, "probe_dma_remove() count = %u", count);
465
466 if (!_probe) {
467 tr_err(&pr_tr, "probe_dma_remove(): Not initialized.");
468
469 return -EINVAL;
470 }
471
472 /* remove each DMA if they are not used */
473 for (i = 0; i < count; i++) {
474 tr_dbg(&pr_tr, "\tstream_tag[%u] = %u", i, stream_tag[i]);
475
476 if (is_probe_stream_used(stream_tag[i]))
477 return -EINVAL;
478
479 for (j = 0; j < CONFIG_PROBE_DMA_MAX; j++) {
480 if (_probe->inject_dma[j].stream_tag == stream_tag[i]) {
481 err = probe_dma_deinit(&_probe->inject_dma[j]);
482 if (err < 0)
483 return err;
484 }
485 }
486 }
487
488 return 0;
489 }
490
491 /**
492 * \brief Copy data to probe buffer and update buffer pointers.
493 * \param[out] pbuf DMA buffer.
494 * \param[in] data pointer.
495 * \param[in] bytes size.
496 * \return 0 on success, error code otherwise.
497 */
copy_to_pbuffer(struct probe_dma_buf * pbuf,void * data,uint32_t bytes)498 static int copy_to_pbuffer(struct probe_dma_buf *pbuf, void *data,
499 uint32_t bytes)
500 {
501 uint32_t head;
502 uint32_t tail;
503
504 if (bytes == 0)
505 return 0;
506
507 /* check if it will not exceed end_addr */
508 if ((char *)pbuf->end_addr - (char *)pbuf->w_ptr < bytes) {
509 head = (char *)pbuf->end_addr - (char *)pbuf->w_ptr;
510 tail = bytes - head;
511 } else {
512 head = bytes;
513 tail = 0;
514 }
515
516 /* copy data to probe buffer */
517 if (memcpy_s((void *)pbuf->w_ptr, pbuf->end_addr - pbuf->w_ptr, data, head)) {
518 tr_err(&pr_tr, "copy_to_pbuffer(): memcpy_s() failed");
519 return -EINVAL;
520 }
521 dcache_writeback_region((void *)pbuf->w_ptr, head);
522
523 /* buffer ended so needs to do a second copy */
524 if (tail) {
525 pbuf->w_ptr = pbuf->addr;
526 if (memcpy_s((void *)pbuf->w_ptr, (char *)pbuf->end_addr - (char *)pbuf->w_ptr,
527 (char *)data + head, tail)) {
528 tr_err(&pr_tr, "copy_to_pbuffer(): memcpy_s() failed");
529 return -EINVAL;
530 }
531 dcache_writeback_region((void *)pbuf->w_ptr, tail);
532 pbuf->w_ptr = pbuf->w_ptr + tail;
533 } else {
534 pbuf->w_ptr = pbuf->w_ptr + head;
535 }
536
537 pbuf->avail = (uintptr_t)pbuf->avail + bytes;
538
539 return 0;
540 }
541
542 /**
543 * \brief Copy data from probe buffer and update buffer pointers.
544 * \param[out] pbuf DMA buffer.
545 * \param[out] data pointer.
546 * \param[in] bytes size.
547 * \return 0 on success, error code otherwise.
548 */
copy_from_pbuffer(struct probe_dma_buf * pbuf,void * data,uint32_t bytes)549 static int copy_from_pbuffer(struct probe_dma_buf *pbuf, void *data,
550 uint32_t bytes)
551 {
552 uint32_t head;
553 uint32_t tail;
554
555 if (bytes == 0)
556 return 0;
557 /* not enough data available so set it to 0 */
558 if (pbuf->avail < bytes) {
559 memset(data, 0, bytes);
560 return 0;
561 }
562
563 /* check if memcpy needs to be divided into two stages */
564 if (pbuf->end_addr - pbuf->r_ptr < bytes) {
565 head = pbuf->end_addr - pbuf->r_ptr;
566 tail = bytes - head;
567 } else {
568 head = bytes;
569 tail = 0;
570 }
571
572 /* data from DMA so invalidate it */
573 dcache_invalidate_region((void *)pbuf->r_ptr, head);
574 if (memcpy_s(data, bytes, (void *)pbuf->r_ptr, head)) {
575 tr_err(&pr_tr, "copy_from_pbuffer(): memcpy_s() failed");
576 return -EINVAL;
577 }
578
579 /* second stage copy */
580 if (tail) {
581 /* starting from the beginning of the buffer */
582 pbuf->r_ptr = pbuf->addr;
583 dcache_invalidate_region((void *)pbuf->r_ptr, tail);
584 if (memcpy_s((char *)data + head, tail, (void *)pbuf->r_ptr, tail)) {
585 tr_err(&pr_tr, "copy_from_pbuffer(): memcpy_s() failed");
586 return -EINVAL;
587 }
588 pbuf->r_ptr = pbuf->r_ptr + tail;
589 } else {
590 pbuf->r_ptr = pbuf->r_ptr + head;
591 }
592
593 /* subtract used bytes */
594 pbuf->avail -= bytes;
595
596 return 0;
597 }
598
599 /**
600 * \brief Generate probe data packet header, update timestamp, calc crc
601 * and copy data to probe buffer.
602 * \param[in] buffer component buffer pointer.
603 * \param[in] size data size.
604 * \param[in] format audio format.
605 * \return 0 on success, error code otherwise.
606 */
probe_gen_header(struct comp_buffer * buffer,uint32_t size,uint32_t format)607 static int probe_gen_header(struct comp_buffer *buffer, uint32_t size,
608 uint32_t format)
609 {
610 struct probe_pdata *_probe = probe_get();
611 struct probe_data_packet *header;
612 uint64_t timestamp;
613 uint32_t crc;
614
615 header = &_probe->header;
616 timestamp = platform_timer_get(timer_get());
617
618 header->sync_word = PROBE_EXTRACT_SYNC_WORD;
619 header->buffer_id = buffer->id;
620 header->format = format;
621 header->timestamp_low = (uint32_t)timestamp;
622 header->timestamp_high = (uint32_t)(timestamp >> 32);
623 header->checksum = 0;
624 header->data_size_bytes = size;
625
626 /* calc crc to check validation by probe parse app */
627 crc = crc32(0, header, sizeof(*header));
628 header->checksum = crc;
629
630 dcache_writeback_region(header, sizeof(*header));
631
632 return copy_to_pbuffer(&_probe->ext_dma.dmapb, header,
633 sizeof(struct probe_data_packet));
634 }
635
636 /**
637 * \brief Generate description of audio format for extraction probes.
638 * \param[in] frame_fmt format
639 * \param[in] rate sample rate.
640 * \param[in] channels number of channels
641 * \return format.
642 */
probe_gen_format(uint32_t frame_fmt,uint32_t rate,uint32_t channels)643 static uint32_t probe_gen_format(uint32_t frame_fmt, uint32_t rate,
644 uint32_t channels)
645 {
646 uint32_t format = 0;
647 uint32_t sample_rate;
648 uint32_t valid_bytes;
649 uint32_t container_bytes;
650 uint32_t float_fmt = 0;
651
652 switch (frame_fmt) {
653 case SOF_IPC_FRAME_S16_LE:
654 valid_bytes = 2;
655 container_bytes = 2;
656 break;
657 case SOF_IPC_FRAME_S24_4LE:
658 valid_bytes = 3;
659 container_bytes = 4;
660 break;
661 case SOF_IPC_FRAME_S32_LE:
662 valid_bytes = 4;
663 container_bytes = 4;
664 break;
665 case SOF_IPC_FRAME_FLOAT:
666 valid_bytes = 4;
667 container_bytes = 4;
668 float_fmt = 1;
669 break;
670 default:
671 tr_err(&pr_tr, "probe_gen_format(): Invalid frame format specified = 0x%08x",
672 frame_fmt);
673 assert(false);
674 }
675
676 switch (rate) {
677 case 8000:
678 sample_rate = 0;
679 break;
680 case 11025:
681 sample_rate = 1;
682 break;
683 case 12000:
684 sample_rate = 2;
685 break;
686 case 16000:
687 sample_rate = 3;
688 break;
689 case 22050:
690 sample_rate = 4;
691 break;
692 case 24000:
693 sample_rate = 5;
694 break;
695 case 32000:
696 sample_rate = 6;
697 break;
698 case 44100:
699 sample_rate = 7;
700 break;
701 case 48000:
702 sample_rate = 8;
703 break;
704 case 64000:
705 sample_rate = 9;
706 break;
707 case 88200:
708 sample_rate = 10;
709 break;
710 case 96000:
711 sample_rate = 11;
712 break;
713 case 128000:
714 sample_rate = 12;
715 break;
716 case 176400:
717 sample_rate = 13;
718 break;
719 case 192000:
720 sample_rate = 14;
721 break;
722 default:
723 sample_rate = 15;
724 }
725
726 format |= (1 << PROBE_SHIFT_FMT_TYPE) & PROBE_MASK_FMT_TYPE;
727 format |= (sample_rate << PROBE_SHIFT_SAMPLE_RATE) & PROBE_MASK_SAMPLE_RATE;
728 format |= ((channels - 1) << PROBE_SHIFT_NB_CHANNELS) & PROBE_MASK_NB_CHANNELS;
729 format |= ((valid_bytes - 1) << PROBE_SHIFT_SAMPLE_SIZE) & PROBE_MASK_SAMPLE_SIZE;
730 format |= ((container_bytes - 1) << PROBE_SHIFT_CONTAINER_SIZE) & PROBE_MASK_CONTAINER_SIZE;
731 format |= (float_fmt << PROBE_SHIFT_SAMPLE_FMT) & PROBE_MASK_SAMPLE_FMT;
732 format |= (1 << PROBE_SHIFT_INTERLEAVING_ST) & PROBE_MASK_INTERLEAVING_ST;
733
734 return format;
735 }
736
737 /**
738 * \brief General extraction probe callback, called from buffer produce.
739 * It will search for probe point connected to this buffer.
740 * Extraction probe: generate format, header and copy data to probe buffer.
741 * Injection probe: find corresponding DMA, check avail data, copy data,
742 * update pointers and request more data from host if needed.
743 * \param[in] arg pointer (not used).
744 * \param[in] type of notify.
745 * \param[in] data pointer.
746 */
probe_cb_produce(void * arg,enum notify_id type,void * data)747 static void probe_cb_produce(void *arg, enum notify_id type, void *data)
748 {
749 struct probe_pdata *_probe = probe_get();
750 struct buffer_cb_transact *cb_data = data;
751 struct comp_buffer *buffer = cb_data->buffer;
752 struct probe_dma_ext *dma;
753 uint32_t buffer_id;
754 uint32_t head, tail;
755 uint32_t free_bytes = 0;
756 int32_t copy_bytes = 0;
757 int ret;
758 uint32_t i, j;
759 uint32_t format;
760
761 buffer_id = buffer->id;
762
763 /* search for probe point connected to this buffer */
764 for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++)
765 if (_probe->probe_points[i].buffer_id == buffer_id)
766 break;
767
768 if (i == CONFIG_PROBE_POINTS_MAX) {
769 tr_err(&pr_tr, "probe_cb_produce(): probe not found for buffer id: %d",
770 buffer_id);
771 return;
772 }
773
774 if (_probe->probe_points[i].purpose == PROBE_PURPOSE_EXTRACTION) {
775 format = probe_gen_format(buffer->stream.frame_fmt,
776 buffer->stream.rate,
777 buffer->stream.channels);
778 ret = probe_gen_header(buffer,
779 cb_data->transaction_amount,
780 format);
781 if (ret < 0)
782 goto err;
783
784 /* check if transaction amount exceeds component buffer end addr */
785 /* if yes: divide copying into two stages, head and tail */
786 if ((char *)cb_data->transaction_begin_address +
787 cb_data->transaction_amount > (char *)buffer->stream.end_addr) {
788 head = (uintptr_t)buffer->stream.end_addr -
789 (uintptr_t)cb_data->transaction_begin_address;
790 tail = (uintptr_t)cb_data->transaction_amount - head;
791 ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
792 cb_data->transaction_begin_address,
793 head);
794 if (ret < 0)
795 goto err;
796
797 ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
798 buffer->stream.addr, tail);
799 if (ret < 0)
800 goto err;
801 } else {
802 ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
803 cb_data->transaction_begin_address,
804 cb_data->transaction_amount);
805 if (ret < 0)
806 goto err;
807 }
808 /* check if more than 75% of buffer size is already used */
809 if (_probe->ext_dma.dmapb.size - _probe->ext_dma.dmapb.avail <
810 _probe->ext_dma.dmapb.size >> 2)
811 probe_task(NULL);
812 } else {
813 /* search for DMA used by this probe point */
814 for (j = 0; j < CONFIG_PROBE_DMA_MAX; j++) {
815 if (_probe->inject_dma[j].stream_tag !=
816 PROBE_DMA_INVALID &&
817 _probe->inject_dma[j].stream_tag ==
818 _probe->probe_points[i].stream_tag) {
819 break;
820 }
821 }
822 if (j == CONFIG_PROBE_DMA_MAX) {
823 tr_err(&pr_tr, "probe_cb_produce(): dma not found");
824 return;
825 }
826 dma = &_probe->inject_dma[j];
827 /* get avail data info */
828 ret = dma_get_data_size(dma->dc.chan,
829 &dma->dmapb.avail,
830 &free_bytes);
831 if (ret < 0) {
832 tr_err(&pr_tr, "probe_cb_produce(): dma_get_data_size() failed, ret = %u",
833 ret);
834 goto err;
835 }
836
837 /* check if transaction amount exceeds component buffer end addr */
838 /* if yes: divide copying into two stages, head and tail */
839 if ((char *)cb_data->transaction_begin_address +
840 cb_data->transaction_amount > (char *)cb_data->buffer->stream.end_addr) {
841 head = (char *)cb_data->buffer->stream.end_addr -
842 (char *)cb_data->transaction_begin_address;
843 tail = cb_data->transaction_amount - head;
844
845 ret = copy_from_pbuffer(&dma->dmapb,
846 cb_data->transaction_begin_address, head);
847 if (ret < 0)
848 goto err;
849
850 ret = copy_from_pbuffer(&dma->dmapb,
851 cb_data->buffer->stream.addr, tail);
852 if (ret < 0)
853 goto err;
854 } else {
855 ret = copy_from_pbuffer(&dma->dmapb,
856 cb_data->transaction_begin_address,
857 cb_data->transaction_amount);
858 if (ret < 0)
859 goto err;
860 }
861
862 /* calc how many data can be requested */
863 copy_bytes = dma->dmapb.r_ptr - dma->dmapb.w_ptr;
864 if (copy_bytes < 0)
865 copy_bytes += dma->dmapb.size;
866
867 /* align down to request at least 32 */
868 copy_bytes = ALIGN_DOWN(copy_bytes, 32);
869
870 /* check if copy_bytes is still valid for dma copy */
871 if (copy_bytes > 0) {
872 ret = dma_copy_to_host_nowait(&dma->dc,
873 &dma->config, 0,
874 (void *)dma->dmapb.r_ptr,
875 copy_bytes);
876 if (ret < 0)
877 goto err;
878
879 /* update pointers */
880 dma->dmapb.w_ptr = dma->dmapb.w_ptr + copy_bytes;
881 if (dma->dmapb.w_ptr > dma->dmapb.end_addr)
882 dma->dmapb.w_ptr = dma->dmapb.w_ptr - dma->dmapb.size;
883 }
884 }
885 return;
886 err:
887 tr_err(&pr_tr, "probe_cb_produce(): failed to generate probe data");
888 }
889
890 /**
891 * \brief Callback for buffer free, it will remove probe point.
892 * \param[in] arg pointer (not used).
893 * \param[in] type of notify.
894 * \param[in] data pointer.
895 */
probe_cb_free(void * arg,enum notify_id type,void * data)896 static void probe_cb_free(void *arg, enum notify_id type, void *data)
897 {
898 struct buffer_cb_free *cb_data = data;
899 uint32_t buffer_id = cb_data->buffer->id;
900 int ret;
901
902 tr_dbg(&pr_tr, "probe_cb_free() buffer_id = %u", buffer_id);
903
904 ret = probe_point_remove(1, &buffer_id);
905 if (ret < 0)
906 tr_err(&pr_tr, "probe_cb_free(): probe_point_remove() failed");
907 }
908
probe_point_add(uint32_t count,struct probe_point * probe)909 int probe_point_add(uint32_t count, struct probe_point *probe)
910 {
911 struct probe_pdata *_probe = probe_get();
912 uint32_t i;
913 uint32_t j;
914 uint32_t buffer_id;
915 uint32_t first_free;
916 uint32_t dma_found;
917 struct ipc_comp_dev *dev;
918
919 tr_dbg(&pr_tr, "probe_point_add() count = %u", count);
920
921 if (!_probe) {
922 tr_err(&pr_tr, "probe_point_add(): Not initialized.");
923
924 return -EINVAL;
925 }
926
927 /* add all probe points if they are corresponding to valid component and DMA */
928 for (i = 0; i < count; i++) {
929 tr_dbg(&pr_tr, "\tprobe[%u] buffer_id = %u, purpose = %u, stream_tag = %u",
930 i, probe[i].buffer_id, probe[i].purpose,
931 probe[i].stream_tag);
932
933 if (probe[i].purpose != PROBE_PURPOSE_EXTRACTION &&
934 probe[i].purpose != PROBE_PURPOSE_INJECTION) {
935 tr_err(&pr_tr, "probe_point_add() error: invalid purpose %d",
936 probe[i].purpose);
937
938 return -EINVAL;
939 }
940
941 if (probe[i].purpose == PROBE_PURPOSE_EXTRACTION &&
942 _probe->ext_dma.stream_tag == PROBE_DMA_INVALID) {
943 tr_err(&pr_tr, "probe_point_add(): Setting probe for extraction, while extraction DMA not enabled.");
944
945 return -EINVAL;
946 }
947
948 /* check if buffer exists */
949 dev = ipc_get_comp_by_id(ipc_get(), probe[i].buffer_id);
950 if (!dev) {
951 tr_err(&pr_tr, "probe_point_add(): No device with ID %u found.",
952 probe[i].buffer_id);
953
954 return -EINVAL;
955 }
956
957 if (dev->type != COMP_TYPE_BUFFER) {
958 tr_err(&pr_tr, "probe_point_add(): Device ID %u is not a buffer.",
959 probe[i].buffer_id);
960
961 return -EINVAL;
962 }
963
964 first_free = CONFIG_PROBE_POINTS_MAX;
965
966 /* search for first free probe slot */
967 for (j = 0; j < CONFIG_PROBE_POINTS_MAX; j++) {
968 if (_probe->probe_points[j].stream_tag ==
969 PROBE_POINT_INVALID) {
970 if (first_free == CONFIG_PROBE_POINTS_MAX)
971 first_free = j;
972
973 continue;
974 }
975 /* and check if probe is already attached */
976 buffer_id = _probe->probe_points[j].buffer_id;
977 if (buffer_id == probe[i].buffer_id) {
978 if (_probe->probe_points[j].purpose ==
979 probe[i].purpose) {
980 tr_err(&pr_tr, "probe_point_add(): Probe already attached to buffer %u with purpose %u",
981 buffer_id,
982 probe[i].purpose);
983
984 return -EINVAL;
985 }
986 }
987 }
988
989 if (first_free == CONFIG_PROBE_POINTS_MAX) {
990 tr_err(&pr_tr, "probe_point_add(): Maximum number of probe points connected aleady: "
991 META_QUOTE(CONFIG_PROBE_POINTS_MAX));
992
993 return -EINVAL;
994 }
995
996 /* if connecting injection probe, check for associated DMA */
997 if (probe[i].purpose == PROBE_PURPOSE_INJECTION) {
998 dma_found = 0;
999
1000 for (j = 0; j < CONFIG_PROBE_DMA_MAX; j++) {
1001 if (_probe->inject_dma[j].stream_tag !=
1002 PROBE_DMA_INVALID &&
1003 _probe->inject_dma[j].stream_tag ==
1004 probe[i].stream_tag) {
1005 dma_found = 1;
1006 break;
1007 }
1008 }
1009
1010 if (!dma_found) {
1011 tr_err(&pr_tr, "probe_point_add(): No DMA with stream tag %u found for injection.",
1012 probe[i].stream_tag);
1013
1014 return -EINVAL;
1015 }
1016 if (dma_start(_probe->inject_dma[j].dc.chan) < 0) {
1017 tr_err(&pr_tr, "probe_point_add(): failed to start dma");
1018
1019 return -EBUSY;
1020 }
1021 } else if (probe[i].purpose == PROBE_PURPOSE_EXTRACTION) {
1022 for (j = 0; j < CONFIG_PROBE_POINTS_MAX; j++) {
1023 if (_probe->probe_points[j].stream_tag != PROBE_DMA_INVALID &&
1024 _probe->probe_points[j].purpose == PROBE_PURPOSE_EXTRACTION)
1025 break;
1026 }
1027 if (j == CONFIG_PROBE_POINTS_MAX) {
1028 tr_dbg(&pr_tr, "probe_point_add(): start probe task");
1029 schedule_task(&_probe->dmap_work, 1000, 1000);
1030 }
1031 /* ignore probe stream tag for extraction probes */
1032 probe[i].stream_tag = _probe->ext_dma.stream_tag;
1033 }
1034
1035 /* probe point valid, save it */
1036 _probe->probe_points[first_free].buffer_id = probe[i].buffer_id;
1037 _probe->probe_points[first_free].purpose = probe[i].purpose;
1038 _probe->probe_points[first_free].stream_tag =
1039 probe[i].stream_tag;
1040
1041 notifier_register(_probe, dev->cb, NOTIFIER_ID_BUFFER_PRODUCE,
1042 &probe_cb_produce, 0);
1043 notifier_register(_probe, dev->cb, NOTIFIER_ID_BUFFER_FREE,
1044 &probe_cb_free, 0);
1045 }
1046
1047 return 0;
1048 }
1049
probe_point_info(struct sof_ipc_probe_info_params * data,uint32_t max_size)1050 int probe_point_info(struct sof_ipc_probe_info_params *data, uint32_t max_size)
1051 {
1052 struct probe_pdata *_probe = probe_get();
1053 uint32_t i = 0;
1054 uint32_t j = 0;
1055
1056 tr_dbg(&pr_tr, "probe_point_info()");
1057
1058 if (!_probe) {
1059 tr_err(&pr_tr, "probe_point_info(): Not initialized.");
1060
1061 return -EINVAL;
1062 }
1063
1064 data->rhdr.hdr.size = sizeof(*data);
1065 /* search for all probe points to send them in reply */
1066 while (i < CONFIG_PROBE_POINTS_MAX &&
1067 data->rhdr.hdr.size + sizeof(struct probe_point) < max_size) {
1068 if (_probe->probe_points[i].stream_tag != PROBE_POINT_INVALID) {
1069 data->probe_point[j].buffer_id =
1070 _probe->probe_points[i].buffer_id;
1071 data->probe_point[j].purpose =
1072 _probe->probe_points[i].purpose;
1073 data->probe_point[j].stream_tag =
1074 _probe->probe_points[i].stream_tag;
1075 j++;
1076 data->rhdr.hdr.size += sizeof(struct probe_point);
1077 }
1078
1079 i++;
1080 }
1081
1082 data->num_elems = j;
1083
1084 return 1;
1085 }
1086
probe_point_remove(uint32_t count,uint32_t * buffer_id)1087 int probe_point_remove(uint32_t count, uint32_t *buffer_id)
1088 {
1089 struct probe_pdata *_probe = probe_get();
1090 struct ipc_comp_dev *dev;
1091 uint32_t i;
1092 uint32_t j;
1093
1094 tr_dbg(&pr_tr, "probe_point_remove() count = %u", count);
1095
1096 if (!_probe) {
1097 tr_err(&pr_tr, "probe_point_remove(): Not initialized.");
1098 return -EINVAL;
1099 }
1100 /* remove each requested probe point */
1101 for (i = 0; i < count; i++) {
1102 tr_dbg(&pr_tr, "\tbuffer_id[%u] = %u", i, buffer_id[i]);
1103
1104 for (j = 0; j < CONFIG_PROBE_POINTS_MAX; j++) {
1105 if (_probe->probe_points[j].stream_tag != PROBE_POINT_INVALID &&
1106 _probe->probe_points[j].buffer_id == buffer_id[i]) {
1107 dev = ipc_get_comp_by_id(ipc_get(), buffer_id[i]);
1108 if (dev) {
1109 notifier_unregister(_probe, dev->cb,
1110 NOTIFIER_ID_BUFFER_PRODUCE);
1111 notifier_unregister(_probe, dev->cb,
1112 NOTIFIER_ID_BUFFER_FREE);
1113 }
1114
1115 _probe->probe_points[j].stream_tag =
1116 PROBE_POINT_INVALID;
1117 }
1118 }
1119 }
1120 for (j = 0; j < CONFIG_PROBE_POINTS_MAX; j++) {
1121 if (_probe->probe_points[j].stream_tag != PROBE_DMA_INVALID &&
1122 _probe->probe_points[j].purpose == PROBE_PURPOSE_EXTRACTION)
1123 break;
1124 }
1125 if (j == CONFIG_PROBE_POINTS_MAX) {
1126 tr_dbg(&pr_tr, "probe_point_remove(): cancel probe task");
1127 schedule_task_cancel(&_probe->dmap_work);
1128 }
1129
1130 return 0;
1131 }
1132