1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2019-2022 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 <rtos/alloc.h>
14 #include <rtos/init.h>
15 #include <sof/lib/dma.h>
16 #include <sof/lib/notifier.h>
17 #include <sof/lib/uuid.h>
18 #include <sof/ipc/topology.h>
19 #include <sof/ipc/driver.h>
20 #include <rtos/timer.h>
21 #include <sof/schedule/ll_schedule.h>
22 #include <sof/schedule/schedule.h>
23 #include <rtos/task.h>
24 #if CONFIG_IPC_MAJOR_4
25 #include <ipc4/gateway.h>
26 #include <ipc4/module.h>
27 #include <sof/audio/component.h>
28 #include <sof/audio/component_ext.h>
29 #include <sof/ut.h>
30 
31 /* 7CAD0808-AB10-CD23-EF45-12AB34CD56EF */
32 DECLARE_SOF_RT_UUID("probe", probe_uuid, 0x7CAD0808, 0xAB10, 0xCD23,
33 		    0xEF, 0x45, 0x12, 0xAB, 0x34, 0xCD, 0x56, 0xEF);
34 
35 static const struct comp_driver comp_probe;
36 #elif CONFIG_IPC_MAJOR_3
37 /* 9d1fb66e-4ffb-497f-994b-17719686596e */
38 DECLARE_SOF_RT_UUID("probe", probe_uuid, 0x9d1fb66e, 0x4ffb, 0x497f,
39 		    0x99, 0x4b, 0x17, 0x71, 0x96, 0x86, 0x59, 0x6e);
40 #else
41 #error "No or invalid IPC MAJOR version selected."
42 #endif /* CONFIG_IPC_MAJOR_4 */
43 
44 DECLARE_TR_CTX(pr_tr, SOF_UUID(probe_uuid), LOG_LEVEL_INFO);
45 
46 /* 2f0b1901-cac0-4b87-812f-f2d5e4f19e4a */
47 DECLARE_SOF_UUID("probe-task", probe_task_uuid, 0x2f0b1901, 0xcac0, 0x4b87,
48 		 0x81, 0x2f, 0xf2, 0xd5, 0xe4, 0xf1, 0x9e, 0x4a);
49 
50 LOG_MODULE_REGISTER(probe, CONFIG_SOF_LOG_LEVEL);
51 
52 #define PROBE_DMA_INVALID	0xFFFFFFFF
53 #define PROBE_POINT_INVALID	0xFFFFFFFF
54 
55 #define PROBE_BUFFER_LOCAL_SIZE	8192
56 #define DMA_ELEM_SIZE		32
57 
58 /**
59  * DMA buffer
60  */
61 struct probe_dma_buf {
62 	uintptr_t w_ptr;	/**< write pointer */
63 	uintptr_t r_ptr;	/**< read pointer */
64 	uintptr_t addr;		/**< buffer start pointer */
65 	uintptr_t end_addr;	/**< buffer end pointer */
66 	uint32_t size;		/**< buffer size */
67 	uint32_t avail;		/**< buffer avail data */
68 };
69 
70 /**
71  * Probe DMA
72  */
73 struct probe_dma_ext {
74 	uint32_t stream_tag;		/**< DMA stream tag */
75 	uint32_t dma_buffer_size;	/**< DMA buffer size */
76 	struct dma_sg_config config;	/**< DMA SG config */
77 	struct probe_dma_buf dmapb;	/**< DMA buffer pointer */
78 	struct dma_copy dc;		/**< DMA copy */
79 };
80 
81 /**
82  * Probe main struct
83  */
84 struct probe_pdata {
85 	struct probe_dma_ext ext_dma;				  /**< extraction DMA */
86 	struct probe_dma_ext inject_dma[CONFIG_PROBE_DMA_MAX];	  /**< injection DMA */
87 	struct probe_point probe_points[CONFIG_PROBE_POINTS_MAX]; /**< probe points */
88 	struct probe_data_packet header;			  /**< data packet header */
89 	struct task dmap_work;					  /**< probe task */
90 };
91 
92 /**
93  * \brief Allocate and initialize probe buffer with correct alignment.
94  * \param[out] buffer return value.
95  * \param[in] size of buffer.
96  * \param[in] align the buffer.
97  * \return 0 on success, error code otherwise.
98  */
probe_dma_buffer_init(struct probe_dma_buf * buffer,uint32_t size,uint32_t align)99 static int probe_dma_buffer_init(struct probe_dma_buf *buffer, uint32_t size,
100 				 uint32_t align)
101 {
102 	/* allocate new buffer */
103 	buffer->addr = (uintptr_t)rballoc_align(0, SOF_MEM_CAPS_DMA,
104 						size, align);
105 
106 	if (!buffer->addr) {
107 		tr_err(&pr_tr, "probe_dma_buffer_init(): alloc failed");
108 		return -ENOMEM;
109 	}
110 
111 	bzero((void *)buffer->addr, size);
112 	dcache_writeback_region((__sparse_force void __sparse_cache *)buffer->addr, size);
113 
114 	/* initialise the DMA buffer */
115 	buffer->size = size;
116 	buffer->w_ptr = buffer->addr;
117 	buffer->r_ptr = buffer->addr;
118 	buffer->end_addr = buffer->addr + buffer->size;
119 	buffer->avail = 0;
120 
121 	return 0;
122 }
123 
124 /**
125  * \brief Request DMA and initialize DMA for probes with correct alignment,
126  *	  size and specific channel.
127  *
128  * \param[out] dma probe returned
129  * \param[in] direction of the DMA
130  * \return 0 on success, error code otherwise.
131  */
probe_dma_init(struct probe_dma_ext * dma,uint32_t direction)132 static int probe_dma_init(struct probe_dma_ext *dma, uint32_t direction)
133 {
134 	struct dma_sg_config config = { 0 };
135 	uint32_t elem_addr, addr_align;
136 	const uint32_t elem_size = sizeof(uint64_t) * DMA_ELEM_SIZE;
137 	const uint32_t elem_num = PROBE_BUFFER_LOCAL_SIZE / elem_size;
138 	uint32_t channel;
139 	int err = 0;
140 
141 #if CONFIG_IPC_MAJOR_4
142 	channel = ((union ipc4_connector_node_id)dma->stream_tag).f.v_index + 1;
143 #else
144 	channel = dma->stream_tag;
145 #endif
146 	/* request DMA in the dir LMEM->HMEM with shared access */
147 	dma->dc.dmac = dma_get(direction, 0, DMA_DEV_HOST,
148 			       DMA_ACCESS_SHARED);
149 	if (!dma->dc.dmac) {
150 		tr_err(&pr_tr, "probe_dma_init(): dma->dc.dmac = NULL");
151 		return -ENODEV;
152 	}
153 
154 	/* get required address alignment for dma buffer */
155 #if CONFIG_ZEPHYR_NATIVE_DRIVERS
156 	err = dma_get_attribute(dma->dc.dmac->z_dev, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT,
157 				&addr_align);
158 #else
159 	err = dma_get_attribute_legacy(dma->dc.dmac, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT,
160 				       &addr_align);
161 #endif
162 	if (err < 0)
163 		return err;
164 
165 	/* initialize dma buffer */
166 	err = probe_dma_buffer_init(&dma->dmapb, PROBE_BUFFER_LOCAL_SIZE, addr_align);
167 	if (err < 0)
168 		return err;
169 
170 	err = dma_copy_set_stream_tag(&dma->dc, channel);
171 	if (err < 0)
172 		return err;
173 
174 	elem_addr = (uint32_t)dma->dmapb.addr;
175 
176 	config.direction = direction;
177 	config.src_width = sizeof(uint32_t);
178 	config.dest_width = sizeof(uint32_t);
179 	config.cyclic = 0;
180 
181 	err = dma_sg_alloc(&config.elem_array, SOF_MEM_ZONE_RUNTIME,
182 			   config.direction, elem_num, elem_size, elem_addr, 0);
183 	if (err < 0)
184 		return err;
185 
186 	err = dma_set_config_legacy(dma->dc.chan, &config);
187 	if (err < 0)
188 		return err;
189 
190 	dma_sg_free(&config.elem_array);
191 
192 	return 0;
193 }
194 
195 /**
196  * \brief Stop, deinit and free DMA and buffer used by probes.
197  *
198  * \return 0 on success, error code otherwise.
199  */
probe_dma_deinit(struct probe_dma_ext * dma)200 static int probe_dma_deinit(struct probe_dma_ext *dma)
201 {
202 	int err = 0;
203 
204 	err = dma_stop_legacy(dma->dc.chan);
205 	if (err < 0) {
206 		tr_err(&pr_tr, "probe_dma_deinit(): dma_stop() failed");
207 		return err;
208 	}
209 
210 	dma_channel_put_legacy(dma->dc.chan);
211 	dma_put(dma->dc.dmac);
212 
213 	rfree((void *)dma->dmapb.addr);
214 	dma->dmapb.addr = 0;
215 
216 	dma->stream_tag = PROBE_DMA_INVALID;
217 
218 	return 0;
219 }
220 
221 /*
222  * \brief Probe task for extraction.
223  *
224  * Copy extraction probes data to host if available.
225  * Return err if dma copy failed.
226  */
probe_task(void * data)227 static enum task_state probe_task(void *data)
228 {
229 	struct probe_pdata *_probe = probe_get();
230 	uint32_t copy_align, avail;
231 	int err;
232 
233 	if (!_probe->ext_dma.dmapb.avail)
234 		return SOF_TASK_STATE_RESCHEDULE;
235 #if CONFIG_ZEPHYR_NATIVE_DRIVERS
236 	err = dma_get_attribute(_probe->ext_dma.dc.dmac->z_dev, DMA_ATTR_COPY_ALIGNMENT,
237 				&copy_align);
238 #else
239 	err = dma_get_attribute_legacy(_probe->ext_dma.dc.dmac, DMA_ATTR_COPY_ALIGNMENT,
240 				       &copy_align);
241 #endif
242 	if (err < 0) {
243 		tr_err(&pr_tr, "probe_task(): dma_get_attribute failed.");
244 		return SOF_TASK_STATE_COMPLETED;
245 	}
246 
247 	avail = ALIGN_DOWN(_probe->ext_dma.dmapb.avail, copy_align);
248 	if (avail + _probe->ext_dma.dmapb.r_ptr >= _probe->ext_dma.dmapb.end_addr)
249 		avail = _probe->ext_dma.dmapb.end_addr - _probe->ext_dma.dmapb.r_ptr;
250 
251 	if (avail > 0)
252 		err = dma_copy_to_host_nowait(&_probe->ext_dma.dc,
253 					      &_probe->ext_dma.config, 0,
254 					      (void *)_probe->ext_dma.dmapb.r_ptr,
255 					      avail);
256 	else
257 		return SOF_TASK_STATE_RESCHEDULE;
258 
259 	if (err < 0) {
260 		tr_err(&pr_tr, "probe_task(): dma_copy_to_host() failed.");
261 		return err;
262 	}
263 
264 	/* buffer data sent, set read pointer and clear avail bytes */
265 	_probe->ext_dma.dmapb.r_ptr += avail;
266 	if (_probe->ext_dma.dmapb.r_ptr >= _probe->ext_dma.dmapb.end_addr)
267 		_probe->ext_dma.dmapb.r_ptr -= _probe->ext_dma.dmapb.size;
268 	_probe->ext_dma.dmapb.avail -= avail;
269 
270 	return SOF_TASK_STATE_RESCHEDULE;
271 }
272 
probe_init(const struct probe_dma * probe_dma)273 int probe_init(const struct probe_dma *probe_dma)
274 {
275 	struct probe_pdata *_probe = probe_get();
276 	uint32_t i;
277 	int err;
278 
279 	tr_dbg(&pr_tr, "probe_init()");
280 
281 	if (_probe) {
282 		tr_err(&pr_tr, "probe_init(): Probes already initialized.");
283 		return -EINVAL;
284 	}
285 
286 	/* alloc probes main struct */
287 	sof_get()->probe = rzalloc(SOF_MEM_ZONE_SYS_RUNTIME, 0, SOF_MEM_CAPS_RAM,
288 				   sizeof(*_probe));
289 	_probe = probe_get();
290 
291 	if (!_probe) {
292 		tr_err(&pr_tr, "probe_init(): Alloc failed.");
293 		return -ENOMEM;
294 	}
295 
296 	/* setup extraction dma if requested */
297 	if (probe_dma) {
298 		tr_dbg(&pr_tr, "\tstream_tag = %u, dma_buffer_size = %u",
299 		       probe_dma->stream_tag, probe_dma->dma_buffer_size);
300 
301 		_probe->ext_dma.stream_tag = probe_dma->stream_tag;
302 		_probe->ext_dma.dma_buffer_size = probe_dma->dma_buffer_size;
303 
304 		err = probe_dma_init(&_probe->ext_dma, DMA_DIR_LMEM_TO_HMEM);
305 		if (err < 0) {
306 			tr_err(&pr_tr, "probe_init(): probe_dma_init() failed");
307 			_probe->ext_dma.stream_tag = PROBE_DMA_INVALID;
308 			return err;
309 		}
310 
311 		err = dma_start_legacy(_probe->ext_dma.dc.chan);
312 		if (err < 0) {
313 			tr_err(&pr_tr, "probe_init(): failed to start extraction dma");
314 
315 			return -EBUSY;
316 		}
317 		/* init task for extraction probes */
318 		schedule_task_init_ll(&_probe->dmap_work,
319 				      SOF_UUID(probe_task_uuid),
320 				      SOF_SCHEDULE_LL_TIMER, SOF_TASK_PRI_LOW,
321 				      probe_task, _probe, 0, 0);
322 	} else {
323 		tr_dbg(&pr_tr, "\tno extraction DMA setup");
324 
325 		_probe->ext_dma.stream_tag = PROBE_DMA_INVALID;
326 	}
327 
328 	/* initialize injection DMAs as invalid */
329 	for (i = 0; i < CONFIG_PROBE_DMA_MAX; i++)
330 		_probe->inject_dma[i].stream_tag = PROBE_DMA_INVALID;
331 
332 	/* initialize probe points as invalid */
333 	for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++)
334 		_probe->probe_points[i].stream_tag = PROBE_POINT_INVALID;
335 
336 	return 0;
337 }
338 
probe_deinit(void)339 int probe_deinit(void)
340 {
341 	struct probe_pdata *_probe = probe_get();
342 	uint32_t i;
343 	int err;
344 
345 	tr_dbg(&pr_tr, "probe_deinit()");
346 
347 	if (!_probe) {
348 		tr_err(&pr_tr, "probe_deinit(): Not initialized.");
349 
350 		return -EINVAL;
351 	}
352 
353 	/* check for attached injection probe DMAs */
354 	for (i = 0; i < CONFIG_PROBE_DMA_MAX; i++) {
355 		if (_probe->inject_dma[i].stream_tag != PROBE_DMA_INVALID) {
356 			tr_err(&pr_tr, "probe_deinit(): Cannot deinitialize with injection DMAs attached.");
357 			return -EINVAL;
358 		}
359 	}
360 
361 	/* check for connected probe points */
362 	for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++) {
363 		if (_probe->probe_points[i].stream_tag != PROBE_POINT_INVALID) {
364 			tr_err(&pr_tr, "probe_deinit(): Cannot deinitialize with probe points connected.");
365 			return -EINVAL;
366 		}
367 	}
368 
369 	if (_probe->ext_dma.stream_tag != PROBE_DMA_INVALID) {
370 		tr_dbg(&pr_tr, "probe_deinit() Freeing task and extraction DMA.");
371 		schedule_task_free(&_probe->dmap_work);
372 		err = probe_dma_deinit(&_probe->ext_dma);
373 		if (err < 0)
374 			return err;
375 	}
376 
377 	sof_get()->probe = NULL;
378 	rfree(_probe);
379 
380 	return 0;
381 }
382 
probe_dma_add(uint32_t count,const struct probe_dma * probe_dma)383 int probe_dma_add(uint32_t count, const struct probe_dma *probe_dma)
384 {
385 	struct probe_pdata *_probe = probe_get();
386 	uint32_t i;
387 	uint32_t j;
388 	uint32_t stream_tag;
389 	uint32_t first_free;
390 	int err;
391 
392 	tr_dbg(&pr_tr, "probe_dma_add() count = %u", count);
393 
394 	if (!_probe) {
395 		tr_err(&pr_tr, "probe_dma_add(): Not initialized.");
396 
397 		return -EINVAL;
398 	}
399 
400 	/* Iterate over all (DMA) fields if there are multiple of them */
401 	/* add them if there is free place and they are not already attached */
402 	for (i = 0; i < count; i++) {
403 		tr_dbg(&pr_tr, "\tprobe_dma[%u] stream_tag = %u, dma_buffer_size = %u",
404 		       i, probe_dma[i].stream_tag,
405 		       probe_dma[i].dma_buffer_size);
406 
407 		first_free = CONFIG_PROBE_DMA_MAX;
408 
409 		/* looking for first free dma slot */
410 		for (j = 0; j < CONFIG_PROBE_DMA_MAX; j++) {
411 			stream_tag = _probe->inject_dma[j].stream_tag;
412 
413 			if (stream_tag == PROBE_DMA_INVALID) {
414 				if (first_free == CONFIG_PROBE_DMA_MAX)
415 					first_free = j;
416 
417 				continue;
418 			}
419 
420 			if (stream_tag == probe_dma[i].stream_tag) {
421 				tr_err(&pr_tr, "probe_dma_add(): Probe DMA %u already attached.",
422 				       stream_tag);
423 				return -EINVAL;
424 			}
425 		}
426 
427 		if (first_free == CONFIG_PROBE_DMA_MAX) {
428 			tr_err(&pr_tr, "probe_dma_add(): Exceeded maximum number of DMAs attached = "
429 			       META_QUOTE(CONFIG_PROBE_DMA_MAX));
430 			return -EINVAL;
431 		}
432 
433 		_probe->inject_dma[first_free].stream_tag =
434 			probe_dma[i].stream_tag;
435 		_probe->inject_dma[first_free].dma_buffer_size =
436 			probe_dma[i].dma_buffer_size;
437 
438 		err = probe_dma_init(&_probe->inject_dma[first_free],
439 				     DMA_DIR_HMEM_TO_LMEM);
440 		if (err < 0) {
441 			tr_err(&pr_tr, "probe_dma_add(): probe_dma_init() failed");
442 			_probe->inject_dma[first_free].stream_tag =
443 				PROBE_DMA_INVALID;
444 			return err;
445 		}
446 	}
447 
448 	return 0;
449 }
450 
451 /**
452  * \brief Check if stream_tag is used by probes.
453  * \param[in] stream_tag DMA stream tag.
454  * \return 0 if not used, 1 otherwise.
455  */
is_probe_stream_used(uint32_t stream_tag)456 static int is_probe_stream_used(uint32_t stream_tag)
457 {
458 	struct probe_pdata *_probe = probe_get();
459 	uint32_t i;
460 
461 	for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++) {
462 		if (_probe->probe_points[i].stream_tag == stream_tag)
463 			return 1;
464 	}
465 
466 	return 0;
467 }
468 
probe_dma_remove(uint32_t count,const uint32_t * stream_tag)469 int probe_dma_remove(uint32_t count, const uint32_t *stream_tag)
470 {
471 	struct probe_pdata *_probe = probe_get();
472 	uint32_t i;
473 	uint32_t j;
474 	int err;
475 
476 	tr_dbg(&pr_tr, "probe_dma_remove() count = %u", count);
477 
478 	if (!_probe) {
479 		tr_err(&pr_tr, "probe_dma_remove(): Not initialized.");
480 
481 		return -EINVAL;
482 	}
483 
484 	/* remove each DMA if they are not used */
485 	for (i = 0; i < count; i++) {
486 		tr_dbg(&pr_tr, "\tstream_tag[%u] = %u", i, stream_tag[i]);
487 
488 		if (is_probe_stream_used(stream_tag[i]))
489 			return -EINVAL;
490 
491 		for (j = 0; j < CONFIG_PROBE_DMA_MAX; j++) {
492 			if (_probe->inject_dma[j].stream_tag == stream_tag[i]) {
493 				err = probe_dma_deinit(&_probe->inject_dma[j]);
494 				if (err < 0)
495 					return err;
496 			}
497 		}
498 	}
499 
500 	return 0;
501 }
502 
503 /**
504  * \brief Copy data to probe buffer and update buffer pointers.
505  * \param[out] pbuf DMA buffer.
506  * \param[in] data pointer.
507  * \param[in] bytes size.
508  * \return 0 on success, error code otherwise.
509  */
copy_to_pbuffer(struct probe_dma_buf * pbuf,void * data,uint32_t bytes)510 static int copy_to_pbuffer(struct probe_dma_buf *pbuf, void *data,
511 			   uint32_t bytes)
512 {
513 	uint32_t head;
514 	uint32_t tail;
515 
516 	if (bytes == 0)
517 		return 0;
518 
519 	/* check if there is free room in probe buffer */
520 	if (pbuf->size - pbuf->avail < bytes)
521 		return -EINVAL;
522 
523 	/* check if it will not exceed end_addr */
524 	if ((char *)pbuf->end_addr - (char *)pbuf->w_ptr < bytes) {
525 		head = (char *)pbuf->end_addr - (char *)pbuf->w_ptr;
526 		tail = bytes - head;
527 	} else {
528 		head = bytes;
529 		tail = 0;
530 	}
531 
532 	/* copy data to probe buffer */
533 	if (memcpy_s((void *)pbuf->w_ptr, pbuf->end_addr - pbuf->w_ptr, data, head)) {
534 		tr_err(&pr_tr, "copy_to_pbuffer(): memcpy_s() failed");
535 		return -EINVAL;
536 	}
537 	dcache_writeback_region((__sparse_force void __sparse_cache *)pbuf->w_ptr, head);
538 
539 	/* buffer ended so needs to do a second copy */
540 	if (tail) {
541 		pbuf->w_ptr = pbuf->addr;
542 		if (memcpy_s((void *)pbuf->w_ptr, (char *)pbuf->end_addr - (char *)pbuf->w_ptr,
543 			     (char *)data + head, tail)) {
544 			tr_err(&pr_tr, "copy_to_pbuffer(): memcpy_s() failed");
545 			return -EINVAL;
546 		}
547 		dcache_writeback_region((__sparse_force void __sparse_cache *)pbuf->w_ptr, tail);
548 		pbuf->w_ptr = pbuf->w_ptr + tail;
549 	} else {
550 		pbuf->w_ptr = pbuf->w_ptr + head;
551 	}
552 
553 	pbuf->avail = (uintptr_t)pbuf->avail + bytes;
554 
555 	return 0;
556 }
557 
558 /**
559  * \brief Copy data from probe buffer and update buffer pointers.
560  * \param[out] pbuf DMA buffer.
561  * \param[out] data pointer.
562  * \param[in] bytes size.
563  * \return 0 on success, error code otherwise.
564  */
copy_from_pbuffer(struct probe_dma_buf * pbuf,void * data,uint32_t bytes)565 static int copy_from_pbuffer(struct probe_dma_buf *pbuf, void *data,
566 			     uint32_t bytes)
567 {
568 	uint32_t head;
569 	uint32_t tail;
570 
571 	if (bytes == 0)
572 		return 0;
573 	/* not enough data available so set it to 0 */
574 	if (pbuf->avail < bytes) {
575 		memset(data, 0, bytes);
576 		return 0;
577 	}
578 
579 	/* check if memcpy needs to be divided into two stages */
580 	if (pbuf->end_addr - pbuf->r_ptr < bytes) {
581 		head = pbuf->end_addr - pbuf->r_ptr;
582 		tail = bytes - head;
583 	} else {
584 		head = bytes;
585 		tail = 0;
586 	}
587 
588 	/* data from DMA so invalidate it */
589 	dcache_invalidate_region((__sparse_force void __sparse_cache *)pbuf->r_ptr, head);
590 	if (memcpy_s(data, bytes, (void *)pbuf->r_ptr, head)) {
591 		tr_err(&pr_tr, "copy_from_pbuffer(): memcpy_s() failed");
592 		return -EINVAL;
593 	}
594 
595 	/* second stage copy */
596 	if (tail) {
597 		/* starting from the beginning of the buffer */
598 		pbuf->r_ptr = pbuf->addr;
599 		dcache_invalidate_region((__sparse_force void __sparse_cache *)pbuf->r_ptr, tail);
600 		if (memcpy_s((char *)data + head, tail, (void *)pbuf->r_ptr, tail)) {
601 			tr_err(&pr_tr, "copy_from_pbuffer(): memcpy_s() failed");
602 			return -EINVAL;
603 		}
604 		pbuf->r_ptr = pbuf->r_ptr + tail;
605 	} else {
606 		pbuf->r_ptr = pbuf->r_ptr + head;
607 	}
608 
609 	/* subtract used bytes */
610 	pbuf->avail -= bytes;
611 
612 	return 0;
613 }
614 
615 /**
616  * \brief Generate probe data packet header, update timestamp, calc crc
617  *	  and copy data to probe buffer.
618  * \param[in] buffer_id component buffer id
619  * \param[in] size data size.
620  * \param[in] format audio format.
621  * \param[out] checksum.
622  * \return 0 on success, error code otherwise.
623  */
probe_gen_header(uint32_t buffer_id,uint32_t size,uint32_t format,uint64_t * checksum)624 static int probe_gen_header(uint32_t buffer_id, uint32_t size,
625 			    uint32_t format, uint64_t *checksum)
626 {
627 	struct probe_pdata *_probe = probe_get();
628 	struct probe_data_packet *header;
629 	uint64_t timestamp;
630 
631 	header = &_probe->header;
632 	timestamp = sof_cycle_get_64();
633 
634 	header->sync_word = PROBE_EXTRACT_SYNC_WORD;
635 	header->buffer_id = buffer_id;
636 	header->format = format;
637 	header->timestamp_low = (uint32_t)timestamp;
638 	header->timestamp_high = (uint32_t)(timestamp >> 32);
639 	header->data_size_bytes = size;
640 
641 	/* calc checksum to check validation by probe parse app */
642 	*checksum = header->sync_word +
643 		    header->buffer_id  +
644 		    header->format +
645 		    header->timestamp_high +
646 		    header->timestamp_low +
647 		    header->data_size_bytes;
648 
649 	dcache_writeback_region((__sparse_force void __sparse_cache *)header, sizeof(*header));
650 
651 	return copy_to_pbuffer(&_probe->ext_dma.dmapb, header,
652 			       sizeof(struct probe_data_packet));
653 }
654 
655 /**
656  * \brief Generate description of audio format for extraction probes.
657  * \param[in] frame_fmt format
658  * \param[in] rate sample rate.
659  * \param[in] channels number of channels
660  * \return format.
661  */
probe_gen_format(uint32_t frame_fmt,uint32_t rate,uint32_t channels)662 static uint32_t probe_gen_format(uint32_t frame_fmt, uint32_t rate,
663 				 uint32_t channels)
664 {
665 	uint32_t format = 0;
666 	uint32_t sample_rate;
667 	uint32_t valid_bytes;
668 	uint32_t container_bytes;
669 	uint32_t float_fmt = 0;
670 
671 	switch (frame_fmt) {
672 	case SOF_IPC_FRAME_S16_LE:
673 		valid_bytes = 2;
674 		container_bytes = 2;
675 		break;
676 	case SOF_IPC_FRAME_S24_4LE:
677 		valid_bytes = 3;
678 		container_bytes = 4;
679 		break;
680 	case SOF_IPC_FRAME_S32_LE:
681 		valid_bytes = 4;
682 		container_bytes = 4;
683 		break;
684 	case SOF_IPC_FRAME_FLOAT:
685 		valid_bytes = 4;
686 		container_bytes = 4;
687 		float_fmt = 1;
688 		break;
689 	default:
690 		tr_err(&pr_tr, "probe_gen_format(): Invalid frame format specified = 0x%08x",
691 		       frame_fmt);
692 		assert(false);
693 		return 0;
694 	}
695 
696 	switch (rate) {
697 	case 8000:
698 		sample_rate = 0;
699 		break;
700 	case 11025:
701 		sample_rate = 1;
702 		break;
703 	case 12000:
704 		sample_rate = 2;
705 		break;
706 	case 16000:
707 		sample_rate = 3;
708 		break;
709 	case 22050:
710 		sample_rate = 4;
711 		break;
712 	case 24000:
713 		sample_rate = 5;
714 		break;
715 	case 32000:
716 		sample_rate = 6;
717 		break;
718 	case 44100:
719 		sample_rate = 7;
720 		break;
721 	case 48000:
722 		sample_rate = 8;
723 		break;
724 	case 64000:
725 		sample_rate = 9;
726 		break;
727 	case 88200:
728 		sample_rate = 10;
729 		break;
730 	case 96000:
731 		sample_rate = 11;
732 		break;
733 	case 128000:
734 		sample_rate = 12;
735 		break;
736 	case 176400:
737 		sample_rate = 13;
738 		break;
739 	case 192000:
740 		sample_rate = 14;
741 		break;
742 	default:
743 		sample_rate = 15;
744 	}
745 
746 	format |= (1 << PROBE_SHIFT_FMT_TYPE) & PROBE_MASK_FMT_TYPE;
747 	format |= (sample_rate << PROBE_SHIFT_SAMPLE_RATE) & PROBE_MASK_SAMPLE_RATE;
748 	format |= ((channels - 1) << PROBE_SHIFT_NB_CHANNELS) & PROBE_MASK_NB_CHANNELS;
749 	format |= ((valid_bytes - 1) << PROBE_SHIFT_SAMPLE_SIZE) & PROBE_MASK_SAMPLE_SIZE;
750 	format |= ((container_bytes - 1) << PROBE_SHIFT_CONTAINER_SIZE) & PROBE_MASK_CONTAINER_SIZE;
751 	format |= (float_fmt << PROBE_SHIFT_SAMPLE_FMT) & PROBE_MASK_SAMPLE_FMT;
752 	format |= (1 << PROBE_SHIFT_INTERLEAVING_ST) & PROBE_MASK_INTERLEAVING_ST;
753 
754 	return format;
755 }
756 
757 /*
758  * Check if more than 75% of buffer is already used,
759  * and if yes, rescheduled the probe task immediately.
760  */
kick_probe_task(struct probe_pdata * _probe)761 static void kick_probe_task(struct probe_pdata *_probe)
762 {
763 	if (_probe->ext_dma.dmapb.size - _probe->ext_dma.dmapb.avail <
764 		_probe->ext_dma.dmapb.size >> 2)
765 		reschedule_task(&_probe->dmap_work, 0);
766 }
767 
768 #if CONFIG_LOG_BACKEND_SOF_PROBE
probe_logging_hook(uint8_t * buffer,size_t length)769 static void probe_logging_hook(uint8_t *buffer, size_t length)
770 {
771 	struct probe_pdata *_probe = probe_get();
772 	uint64_t checksum;
773 	int ret;
774 
775 	ret = probe_gen_header(PROBE_LOGGING_BUFFER_ID, length, 0, &checksum);
776 	if (ret < 0)
777 		return;
778 
779 	ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
780 			      buffer, length);
781 	if (ret < 0)
782 		return;
783 
784 	ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
785 			      &checksum, sizeof(checksum));
786 	if (ret < 0)
787 		return;
788 
789 	kick_probe_task(_probe);
790 }
791 #endif
792 
793 /**
794  * \brief General extraction probe callback, called from buffer produce.
795  *	  It will search for probe point connected to this buffer.
796  *	  Extraction probe: generate format, header and copy data to probe buffer.
797  *	  Injection probe: find corresponding DMA, check avail data, copy data,
798  *	  update pointers and request more data from host if needed.
799  * \param[in] arg pointer (not used).
800  * \param[in] type of notify.
801  * \param[in] data pointer.
802  */
probe_cb_produce(void * arg,enum notify_id type,void * data)803 static void probe_cb_produce(void *arg, enum notify_id type, void *data)
804 {
805 	struct probe_pdata *_probe = probe_get();
806 	struct buffer_cb_transact *cb_data = data;
807 	struct comp_buffer __sparse_cache *buffer = cb_data->buffer;
808 	struct probe_dma_ext *dma;
809 	uint32_t buffer_id;
810 	uint32_t head, tail;
811 	uint32_t free_bytes = 0;
812 	int32_t copy_bytes = 0;
813 	int ret;
814 	uint32_t i, j;
815 	uint32_t format;
816 	uint64_t checksum;
817 
818 	buffer_id = *(int *)arg;
819 
820 	/* search for probe point connected to this buffer */
821 	for (i = 0; i < CONFIG_PROBE_POINTS_MAX; i++)
822 		if (_probe->probe_points[i].buffer_id.full_id == buffer_id)
823 			break;
824 
825 	if (i == CONFIG_PROBE_POINTS_MAX) {
826 		tr_err(&pr_tr, "probe_cb_produce(): probe not found for buffer id: %d",
827 		       buffer_id);
828 		return;
829 	}
830 
831 	if (_probe->probe_points[i].purpose == PROBE_PURPOSE_EXTRACTION) {
832 		format = probe_gen_format(buffer->stream.frame_fmt,
833 					  buffer->stream.rate,
834 					  buffer->stream.channels);
835 		ret = probe_gen_header(buffer_id,
836 				       cb_data->transaction_amount,
837 				       format, &checksum);
838 		if (ret < 0)
839 			goto err;
840 
841 		/* check if transaction amount exceeds component buffer end addr */
842 		/* if yes: divide copying into two stages, head and tail */
843 		if ((char *)cb_data->transaction_begin_address +
844 		    cb_data->transaction_amount > (char *)buffer->stream.end_addr) {
845 			head = (uintptr_t)buffer->stream.end_addr -
846 			       (uintptr_t)cb_data->transaction_begin_address;
847 			tail = (uintptr_t)cb_data->transaction_amount - head;
848 			ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
849 					      cb_data->transaction_begin_address,
850 					      head);
851 			if (ret < 0)
852 				goto err;
853 
854 			ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
855 					      buffer->stream.addr, tail);
856 			if (ret < 0)
857 				goto err;
858 		} else {
859 			ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
860 					      cb_data->transaction_begin_address,
861 					      cb_data->transaction_amount);
862 			if (ret < 0)
863 				goto err;
864 		}
865 
866 		ret = copy_to_pbuffer(&_probe->ext_dma.dmapb,
867 				      &checksum, sizeof(checksum));
868 		if (ret < 0)
869 			goto err;
870 
871 		kick_probe_task(_probe);
872 	} else {
873 		/* search for DMA used by this probe point */
874 		for (j = 0; j < CONFIG_PROBE_DMA_MAX; j++) {
875 			if (_probe->inject_dma[j].stream_tag !=
876 			    PROBE_DMA_INVALID &&
877 			    _probe->inject_dma[j].stream_tag ==
878 			    _probe->probe_points[i].stream_tag) {
879 				break;
880 			}
881 		}
882 		if (j == CONFIG_PROBE_DMA_MAX) {
883 			tr_err(&pr_tr, "probe_cb_produce(): dma not found");
884 			return;
885 		}
886 		dma = &_probe->inject_dma[j];
887 		/* get avail data info */
888 		ret = dma_get_data_size_legacy(dma->dc.chan,
889 					       &dma->dmapb.avail,
890 					       &free_bytes);
891 		if (ret < 0) {
892 			tr_err(&pr_tr, "probe_cb_produce(): dma_get_data_size() failed, ret = %u",
893 			       ret);
894 			goto err;
895 		}
896 
897 		/* check if transaction amount exceeds component buffer end addr */
898 		/* if yes: divide copying into two stages, head and tail */
899 		if ((char *)cb_data->transaction_begin_address +
900 			cb_data->transaction_amount > (char *)buffer->stream.end_addr) {
901 			head = (char *)buffer->stream.end_addr -
902 				(char *)cb_data->transaction_begin_address;
903 			tail = cb_data->transaction_amount - head;
904 
905 			ret = copy_from_pbuffer(&dma->dmapb,
906 						cb_data->transaction_begin_address, head);
907 			if (ret < 0)
908 				goto err;
909 
910 			ret = copy_from_pbuffer(&dma->dmapb,
911 						buffer->stream.addr, tail);
912 			if (ret < 0)
913 				goto err;
914 		} else {
915 			ret = copy_from_pbuffer(&dma->dmapb,
916 						cb_data->transaction_begin_address,
917 						cb_data->transaction_amount);
918 			if (ret < 0)
919 				goto err;
920 		}
921 
922 		/* calc how many data can be requested */
923 		copy_bytes = dma->dmapb.r_ptr - dma->dmapb.w_ptr;
924 		if (copy_bytes < 0)
925 			copy_bytes += dma->dmapb.size;
926 
927 		/* align down to request at least 32 */
928 		copy_bytes = ALIGN_DOWN(copy_bytes, 32);
929 
930 		/* check if copy_bytes is still valid for dma copy */
931 		if (copy_bytes > 0) {
932 			ret = dma_copy_to_host_nowait(&dma->dc,
933 						      &dma->config, 0,
934 						      (void *)dma->dmapb.r_ptr,
935 						      copy_bytes);
936 			if (ret < 0)
937 				goto err;
938 
939 			/* update pointers */
940 			dma->dmapb.w_ptr = dma->dmapb.w_ptr + copy_bytes;
941 			if (dma->dmapb.w_ptr > dma->dmapb.end_addr)
942 				dma->dmapb.w_ptr = dma->dmapb.w_ptr - dma->dmapb.size;
943 		}
944 	}
945 	return;
946 err:
947 	tr_err(&pr_tr, "probe_cb_produce(): failed to generate probe data");
948 }
949 
950 /**
951  * \brief Callback for buffer free, it will remove probe point.
952  * \param[in] arg pointer (not used).
953  * \param[in] type of notify.
954  * \param[in] data pointer.
955  */
probe_cb_free(void * arg,enum notify_id type,void * data)956 static void probe_cb_free(void *arg, enum notify_id type, void *data)
957 {
958 	uint32_t buffer_id = *(int *)arg;
959 	int ret;
960 
961 	tr_dbg(&pr_tr, "probe_cb_free() buffer_id = %u", buffer_id);
962 
963 	ret = probe_point_remove(1, &buffer_id);
964 	if (ret < 0)
965 		tr_err(&pr_tr, "probe_cb_free(): probe_point_remove() failed");
966 }
967 
probe_purpose_needs_ext_dma(uint32_t purpose)968 static bool probe_purpose_needs_ext_dma(uint32_t purpose)
969 {
970 #if CONFIG_IPC_MAJOR_4
971 	return purpose == PROBE_PURPOSE_EXTRACTION;
972 #else
973 	return purpose == PROBE_PURPOSE_EXTRACTION || purpose == PROBE_PURPOSE_LOGGING;
974 #endif
975 }
976 
977 #if CONFIG_IPC_MAJOR_4
ipc4_get_buffer(struct ipc_comp_dev * dev,probe_point_id_t probe_point)978 static struct comp_buffer *ipc4_get_buffer(struct ipc_comp_dev *dev, probe_point_id_t probe_point)
979 {
980 	struct comp_buffer *buf;
981 	struct comp_buffer __sparse_cache *buf_c;
982 	struct list_item *sink_list, *source_list;
983 	unsigned int queue_id;
984 
985 	switch (probe_point.fields.type) {
986 	case PROBE_TYPE_INPUT:
987 		list_for_item(source_list, &dev->cd->bsource_list) {
988 			buf = container_of(source_list, struct comp_buffer, sink_list);
989 			buf_c = buffer_acquire(buf);
990 			queue_id = IPC4_SRC_QUEUE_ID(buf_c->id);
991 			buffer_release(buf_c);
992 
993 			if (queue_id == probe_point.fields.index)
994 				return buf;
995 		}
996 		break;
997 	case PROBE_TYPE_OUTPUT:
998 		list_for_item(sink_list, &dev->cd->bsink_list) {
999 			buf = container_of(sink_list, struct comp_buffer, source_list);
1000 			buf_c = buffer_acquire(buf);
1001 			queue_id = IPC4_SINK_QUEUE_ID(buf_c->id);
1002 			buffer_release(buf_c);
1003 
1004 			if (queue_id == probe_point.fields.index)
1005 				return buf;
1006 		}
1007 	}
1008 
1009 	return NULL;
1010 }
1011 #endif
1012 
enable_logs(const struct probe_point * probe)1013 static bool enable_logs(const struct probe_point *probe)
1014 {
1015 #if CONFIG_IPC_MAJOR_4
1016 	return probe->buffer_id.fields.module_id == 0;
1017 #else
1018 	return probe->purpose == PROBE_PURPOSE_LOGGING;
1019 #endif
1020 }
1021 
verify_purpose(uint32_t purpose)1022 static bool verify_purpose(uint32_t purpose)
1023 {
1024 #if CONFIG_IPC_MAJOR_4
1025 	return purpose == PROBE_PURPOSE_EXTRACTION ||
1026 	       purpose == PROBE_PURPOSE_INJECTION;
1027 #else
1028 	return purpose == PROBE_PURPOSE_EXTRACTION ||
1029 	       purpose == PROBE_PURPOSE_INJECTION ||
1030 	       purpose == PROBE_PURPOSE_LOGGING;
1031 #endif
1032 }
1033 
probe_point_add(uint32_t count,const struct probe_point * probe)1034 int probe_point_add(uint32_t count, const struct probe_point *probe)
1035 {
1036 	struct probe_pdata *_probe = probe_get();
1037 	uint32_t i;
1038 	uint32_t j;
1039 	uint32_t buffer_id;
1040 	uint32_t first_free;
1041 	uint32_t dma_found;
1042 	uint32_t fw_logs;
1043 	struct ipc_comp_dev *dev = NULL;
1044 #if CONFIG_IPC_MAJOR_4
1045 	struct comp_buffer *buf = NULL;
1046 #endif
1047 	tr_dbg(&pr_tr, "probe_point_add() count = %u", count);
1048 
1049 	if (!_probe) {
1050 		tr_err(&pr_tr, "probe_point_add(): Not initialized.");
1051 
1052 		return -EINVAL;
1053 	}
1054 
1055 	/* add all probe points if they are corresponding to valid component and DMA */
1056 	for (i = 0; i < count; i++) {
1057 		const probe_point_id_t *buf_id = &probe[i].buffer_id;
1058 		uint32_t stream_tag;
1059 
1060 		tr_dbg(&pr_tr, "\tprobe[%u] buffer_id = %u, purpose = %u, stream_tag = %u",
1061 		       i, buf_id->full_id, probe[i].purpose,
1062 		       probe[i].stream_tag);
1063 
1064 		if (!verify_purpose(probe[i].purpose)) {
1065 			tr_err(&pr_tr, "probe_point_add() error: invalid purpose %d",
1066 			       probe[i].purpose);
1067 
1068 			return -EINVAL;
1069 		}
1070 
1071 		if (_probe->ext_dma.stream_tag == PROBE_DMA_INVALID &&
1072 		    probe_purpose_needs_ext_dma(probe[i].purpose)) {
1073 			tr_err(&pr_tr, "probe_point_add(): extraction DMA not enabled.");
1074 			return -EINVAL;
1075 		}
1076 
1077 		fw_logs = enable_logs(&probe[i]);
1078 
1079 		if (!fw_logs && probe[i].purpose == PROBE_PURPOSE_EXTRACTION) {
1080 #if CONFIG_IPC_MAJOR_4
1081 			dev = ipc_get_comp_by_id(ipc_get(),
1082 						 IPC4_COMP_ID(buf_id->fields.module_id,
1083 							      buf_id->fields.instance_id));
1084 #else
1085 			dev = ipc_get_comp_by_id(ipc_get(), buf_id->full_id);
1086 #endif
1087 			/* check if buffer exists */
1088 			if (!dev) {
1089 				tr_err(&pr_tr, "probe_point_add(): No device with ID %u found.",
1090 				       buf_id->full_id);
1091 
1092 				return -EINVAL;
1093 			}
1094 #if CONFIG_IPC_MAJOR_4
1095 			buf = ipc4_get_buffer(dev, *buf_id);
1096 			if (!buf) {
1097 				tr_err(&pr_tr, "probe_point_add(): buffer %u not found.",
1098 				       buf_id->full_id);
1099 
1100 				return -EINVAL;
1101 			}
1102 #else
1103 			if (dev->type != COMP_TYPE_BUFFER) {
1104 				tr_err(&pr_tr, "probe_point_add(): Device ID %u is not a buffer.",
1105 				       buf_id->full_id);
1106 
1107 				return -EINVAL;
1108 			}
1109 #endif
1110 		}
1111 
1112 		first_free = CONFIG_PROBE_POINTS_MAX;
1113 
1114 		/* search for first free probe slot */
1115 		for (j = 0; j < CONFIG_PROBE_POINTS_MAX; j++) {
1116 			if (_probe->probe_points[j].stream_tag ==
1117 			    PROBE_POINT_INVALID) {
1118 				if (first_free == CONFIG_PROBE_POINTS_MAX)
1119 					first_free = j;
1120 
1121 				continue;
1122 			}
1123 			/* and check if probe is already attached */
1124 			buffer_id = _probe->probe_points[j].buffer_id.full_id;
1125 			if (buffer_id == buf_id->full_id) {
1126 				if (_probe->probe_points[j].purpose ==
1127 				    probe[i].purpose) {
1128 					tr_err(&pr_tr, "probe_point_add(): Probe already attached to buffer %u with purpose %u",
1129 					       buffer_id,
1130 					       probe[i].purpose);
1131 
1132 					return -EINVAL;
1133 				}
1134 			}
1135 		}
1136 
1137 		if (first_free == CONFIG_PROBE_POINTS_MAX) {
1138 			tr_err(&pr_tr, "probe_point_add(): Maximum number of probe points connected aleady: "
1139 			       META_QUOTE(CONFIG_PROBE_POINTS_MAX));
1140 
1141 			return -EINVAL;
1142 		}
1143 
1144 		/* if connecting injection probe, check for associated DMA */
1145 		if (probe[i].purpose == PROBE_PURPOSE_INJECTION) {
1146 			dma_found = 0;
1147 
1148 			for (j = 0; j < CONFIG_PROBE_DMA_MAX; j++) {
1149 				if (_probe->inject_dma[j].stream_tag !=
1150 				    PROBE_DMA_INVALID &&
1151 				    _probe->inject_dma[j].stream_tag ==
1152 				    probe[i].stream_tag) {
1153 					dma_found = 1;
1154 					break;
1155 				}
1156 			}
1157 
1158 			if (!dma_found) {
1159 				tr_err(&pr_tr, "probe_point_add(): No DMA with stream tag %u found for injection.",
1160 				       probe[i].stream_tag);
1161 
1162 				return -EINVAL;
1163 			}
1164 			if (dma_start_legacy(_probe->inject_dma[j].dc.chan) < 0) {
1165 				tr_err(&pr_tr, "probe_point_add(): failed to start dma");
1166 
1167 				return -EBUSY;
1168 			}
1169 
1170 			stream_tag = probe[i].stream_tag;
1171 		} else {
1172 			/* prepare extraction DMA */
1173 			for (j = 0; j < CONFIG_PROBE_POINTS_MAX; j++) {
1174 				if (_probe->probe_points[j].stream_tag != PROBE_DMA_INVALID &&
1175 				    probe_purpose_needs_ext_dma(_probe->probe_points[j].purpose))
1176 					break;
1177 			}
1178 
1179 			if (j == CONFIG_PROBE_POINTS_MAX) {
1180 				tr_dbg(&pr_tr, "probe_point_add(): start probe task");
1181 				schedule_task(&_probe->dmap_work, 1000, 1000);
1182 			}
1183 			/* ignore probe stream tag for extraction probes */
1184 			stream_tag = _probe->ext_dma.stream_tag;
1185 		}
1186 
1187 		/* probe point valid, save it */
1188 		_probe->probe_points[first_free].buffer_id = *buf_id;
1189 		_probe->probe_points[first_free].purpose = probe[i].purpose;
1190 		_probe->probe_points[first_free].stream_tag = stream_tag;
1191 
1192 		if (fw_logs) {
1193 #if CONFIG_LOG_BACKEND_SOF_PROBE
1194 			probe_logging_init(probe_logging_hook);
1195 #else
1196 			return -EINVAL;
1197 #endif
1198 		} else {
1199 			probe_point_id_t *new_buf_id = &_probe->probe_points[first_free].buffer_id;
1200 
1201 #if CONFIG_IPC_MAJOR_4
1202 			notifier_register(&new_buf_id->full_id, buf, NOTIFIER_ID_BUFFER_PRODUCE,
1203 					  &probe_cb_produce, 0);
1204 			notifier_register(&new_buf_id->full_id, buf, NOTIFIER_ID_BUFFER_FREE,
1205 					  &probe_cb_free, 0);
1206 #else
1207 			notifier_register(&new_buf_id->full_id, dev->cb, NOTIFIER_ID_BUFFER_PRODUCE,
1208 					  &probe_cb_produce, 0);
1209 			notifier_register(&new_buf_id->full_id, dev->cb, NOTIFIER_ID_BUFFER_FREE,
1210 					  &probe_cb_free, 0);
1211 #endif
1212 		}
1213 	}
1214 
1215 	return 0;
1216 }
1217 
1218 #if CONFIG_IPC_MAJOR_3
probe_dma_info(struct sof_ipc_probe_info_params * data,uint32_t max_size)1219 int probe_dma_info(struct sof_ipc_probe_info_params *data, uint32_t max_size)
1220 {
1221 	struct probe_pdata *_probe = probe_get();
1222 	uint32_t i = 0;
1223 	uint32_t j = 0;
1224 
1225 	tr_dbg(&pr_tr, "probe_dma_info()");
1226 
1227 	if (!_probe) {
1228 		tr_err(&pr_tr, "probe_dma_info(): Not initialized.");
1229 
1230 		return -EINVAL;
1231 	}
1232 
1233 	data->rhdr.hdr.size = sizeof(*data);
1234 
1235 	/* search all injection DMAs to send them in reply */
1236 	while (i < CONFIG_PROBE_DMA_MAX &&
1237 	       data->rhdr.hdr.size + sizeof(struct probe_dma) < max_size) {
1238 		/* save it if valid */
1239 		if (_probe->inject_dma[i].stream_tag != PROBE_DMA_INVALID) {
1240 			data->probe_dma[j].stream_tag =
1241 				_probe->inject_dma[i].stream_tag;
1242 			data->probe_dma[j].dma_buffer_size =
1243 				_probe->inject_dma[i].dma_buffer_size;
1244 			j++;
1245 			/* and increase reply header size */
1246 			data->rhdr.hdr.size += sizeof(struct probe_dma);
1247 		}
1248 
1249 		i++;
1250 	}
1251 
1252 	data->num_elems = j;
1253 
1254 	return 1;
1255 }
1256 
probe_point_info(struct sof_ipc_probe_info_params * data,uint32_t max_size)1257 int probe_point_info(struct sof_ipc_probe_info_params *data, uint32_t max_size)
1258 {
1259 	struct probe_pdata *_probe = probe_get();
1260 	uint32_t i = 0;
1261 	uint32_t j = 0;
1262 
1263 	tr_dbg(&pr_tr, "probe_point_info()");
1264 
1265 	if (!_probe) {
1266 		tr_err(&pr_tr, "probe_point_info(): Not initialized.");
1267 
1268 		return -EINVAL;
1269 	}
1270 
1271 	data->rhdr.hdr.size = sizeof(*data);
1272 	/* search for all probe points to send them in reply */
1273 	while (i < CONFIG_PROBE_POINTS_MAX &&
1274 	       data->rhdr.hdr.size + sizeof(struct probe_point) < max_size) {
1275 		if (_probe->probe_points[i].stream_tag != PROBE_POINT_INVALID) {
1276 			data->probe_point[j].buffer_id =
1277 				_probe->probe_points[i].buffer_id;
1278 			data->probe_point[j].purpose =
1279 				_probe->probe_points[i].purpose;
1280 			data->probe_point[j].stream_tag =
1281 				_probe->probe_points[i].stream_tag;
1282 			j++;
1283 			data->rhdr.hdr.size += sizeof(struct probe_point);
1284 		}
1285 
1286 		i++;
1287 	}
1288 
1289 	data->num_elems = j;
1290 
1291 	return 1;
1292 }
1293 #endif
1294 
probe_point_remove(uint32_t count,const uint32_t * buffer_id)1295 int probe_point_remove(uint32_t count, const uint32_t *buffer_id)
1296 {
1297 	struct probe_pdata *_probe = probe_get();
1298 	struct ipc_comp_dev *dev;
1299 	uint32_t i;
1300 	uint32_t j;
1301 #if CONFIG_IPC_MAJOR_4
1302 	struct comp_buffer *buf;
1303 #endif
1304 
1305 	tr_dbg(&pr_tr, "probe_point_remove() count = %u", count);
1306 
1307 	if (!_probe) {
1308 		tr_err(&pr_tr, "probe_point_remove(): Not initialized.");
1309 		return -EINVAL;
1310 	}
1311 	/* remove each requested probe point */
1312 	for (i = 0; i < count; i++) {
1313 		tr_dbg(&pr_tr, "\tbuffer_id[%u] = %u", i, buffer_id[i]);
1314 
1315 		for (j = 0; j < CONFIG_PROBE_POINTS_MAX; j++) {
1316 			probe_point_id_t *buf_id = &_probe->probe_points[j].buffer_id;
1317 
1318 			if (_probe->probe_points[j].stream_tag != PROBE_POINT_INVALID &&
1319 			    buf_id->full_id == buffer_id[i]) {
1320 #if CONFIG_IPC_MAJOR_4
1321 				dev = ipc_get_comp_by_id(ipc_get(),
1322 							 IPC4_COMP_ID(buf_id->fields.module_id,
1323 								      buf_id->fields.instance_id));
1324 				if (dev) {
1325 					buf = ipc4_get_buffer(dev, *buf_id);
1326 					if (buf) {
1327 						notifier_unregister(NULL, buf,
1328 								    NOTIFIER_ID_BUFFER_PRODUCE);
1329 						notifier_unregister(NULL, buf,
1330 								    NOTIFIER_ID_BUFFER_FREE);
1331 					}
1332 				}
1333 #else
1334 				dev = ipc_get_comp_by_id(ipc_get(), buffer_id[i]);
1335 				if (dev) {
1336 					notifier_unregister(_probe, dev->cb,
1337 							    NOTIFIER_ID_BUFFER_PRODUCE);
1338 					notifier_unregister(_probe, dev->cb, NOTIFIER_ID_BUFFER_FREE);
1339 				}
1340 #endif
1341 				_probe->probe_points[j].stream_tag =
1342 					PROBE_POINT_INVALID;
1343 			}
1344 		}
1345 	}
1346 	for (j = 0; j < CONFIG_PROBE_POINTS_MAX; j++) {
1347 		if (_probe->probe_points[j].stream_tag != PROBE_DMA_INVALID &&
1348 		    _probe->probe_points[j].purpose == PROBE_PURPOSE_EXTRACTION)
1349 			break;
1350 	}
1351 	if (j == CONFIG_PROBE_POINTS_MAX) {
1352 		tr_dbg(&pr_tr, "probe_point_remove(): cancel probe task");
1353 		schedule_task_cancel(&_probe->dmap_work);
1354 	}
1355 
1356 	return 0;
1357 }
1358 
1359 #if CONFIG_IPC_MAJOR_4
probe_new(const struct comp_driver * drv,const struct comp_ipc_config * config,const void * spec)1360 static struct comp_dev *probe_new(const struct comp_driver *drv,
1361 				  const struct comp_ipc_config *config, const void *spec)
1362 {
1363 	const struct ipc4_probe_module_cfg *probe_cfg = spec;
1364 	struct comp_dev *dev;
1365 	int ret;
1366 
1367 	comp_cl_info(&comp_probe, "probe_new()");
1368 
1369 	dev = comp_alloc(drv, sizeof(*dev));
1370 	if (!dev)
1371 		return NULL;
1372 
1373 	dev->ipc_config = *config;
1374 
1375 	ret = probe_init(&probe_cfg->gtw_cfg);
1376 	if (ret < 0) {
1377 		comp_free(dev);
1378 		return NULL;
1379 	}
1380 	dev->state = COMP_STATE_READY;
1381 
1382 	return dev;
1383 }
1384 
probe_free(struct comp_dev * dev)1385 static void probe_free(struct comp_dev *dev)
1386 {
1387 	probe_deinit();
1388 	rfree(dev);
1389 }
1390 
probe_set_large_config(struct comp_dev * dev,uint32_t param_id,bool first_block,bool last_block,uint32_t data_offset,const char * data)1391 static int probe_set_large_config(struct comp_dev *dev, uint32_t param_id,
1392 				  bool first_block,
1393 				  bool last_block,
1394 				  uint32_t data_offset,
1395 				  const char *data)
1396 {
1397 	comp_dbg(dev, "probe_set_large_config()");
1398 
1399 	switch (param_id) {
1400 	case IPC4_PROBE_MODULE_PROBE_POINTS_ADD:
1401 		return probe_point_add(data_offset / sizeof(struct probe_point),
1402 				       (const struct probe_point *)data);
1403 	case IPC4_PROBE_MODULE_DISCONNECT_PROBE_POINTS:
1404 		return probe_point_remove(data_offset / sizeof(uint32_t), (const uint32_t *)data);
1405 	case IPC4_PROBE_MODULE_INJECTION_DMA_ADD:
1406 		return probe_dma_add(data_offset / (2 * sizeof(uint32_t)),
1407 				     (const struct probe_dma *)data);
1408 	case IPC4_PROBE_MODULE_INJECTION_DMA_DETACH:
1409 		return probe_dma_remove(data_offset / sizeof(uint32_t), (const uint32_t *)data);
1410 	default:
1411 		return -EINVAL;
1412 	}
1413 }
1414 
probe_get_large_config(struct comp_dev * dev,uint32_t param_id,bool first_block,bool last_block,uint32_t * data_offset,char * data)1415 static int probe_get_large_config(struct comp_dev *dev, uint32_t param_id,
1416 				  bool first_block,
1417 				  bool last_block,
1418 				  uint32_t *data_offset,
1419 				  char *data)
1420 {
1421 	return 0;
1422 }
1423 
1424 static const struct comp_driver comp_probe = {
1425 	.uid	= SOF_RT_UUID(probe_uuid),
1426 	.tctx	= &pr_tr,
1427 	.ops	= {
1428 		.create			= probe_new,
1429 		.free			= probe_free,
1430 		.set_large_config	= probe_set_large_config,
1431 		.get_large_config	= probe_get_large_config,
1432 	},
1433 };
1434 
1435 static SHARED_DATA struct comp_driver_info comp_probe_info = {
1436 	.drv = &comp_probe,
1437 };
1438 
sys_comp_probe_init(void)1439 UT_STATIC void sys_comp_probe_init(void)
1440 {
1441 	comp_register(platform_shared_get(&comp_probe_info,
1442 					  sizeof(comp_probe_info)));
1443 }
1444 
1445 DECLARE_MODULE(sys_comp_probe_init);
1446 SOF_MODULE_INIT(probe, sys_comp_probe_init);
1447 #endif
1448