1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2016 Intel Corporation. All rights reserved.
4 //
5 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6 //         Keyon Jie <yang.jie@linux.intel.com>
7 
8 #include <sof/audio/buffer.h>
9 #include <sof/audio/component_ext.h>
10 #include <sof/audio/pipeline.h>
11 #include <sof/audio/ipc-config.h>
12 #include <sof/common.h>
13 #include <sof/drivers/idc.h>
14 #include <sof/ipc/topology.h>
15 #include <sof/ipc/common.h>
16 #include <sof/ipc/msg.h>
17 #include <sof/lib/alloc.h>
18 #include <sof/lib/cache.h>
19 #include <sof/lib/mailbox.h>
20 #include <sof/list.h>
21 #include <sof/platform.h>
22 #include <sof/sof.h>
23 #include <ipc/dai.h>
24 #include <ipc/header.h>
25 #include <ipc/stream.h>
26 #include <ipc/topology.h>
27 #include <errno.h>
28 #include <stdbool.h>
29 #include <stddef.h>
30 #include <stdint.h>
31 
32 extern struct tr_ctx comp_tr;
33 
34 /**
35  * Retrieves component config data from component ipc.
36  * @param comp Component ipc data.
37  * @return Pointer to the component config data.
38  */
comp_config(struct sof_ipc_comp * comp)39 static inline struct sof_ipc_comp_config *comp_config(struct sof_ipc_comp *comp)
40 {
41 	return (struct sof_ipc_comp_config *)(comp + 1);
42 }
43 
ipc_build_stream_posn(struct sof_ipc_stream_posn * posn,uint32_t type,uint32_t id)44 void ipc_build_stream_posn(struct sof_ipc_stream_posn *posn, uint32_t type,
45 			   uint32_t id)
46 {
47 	posn->rhdr.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | type | id;
48 	posn->rhdr.hdr.size = sizeof(*posn);
49 	posn->comp_id = id;
50 }
51 
ipc_build_comp_event(struct sof_ipc_comp_event * event,uint32_t type,uint32_t id)52 void ipc_build_comp_event(struct sof_ipc_comp_event *event, uint32_t type,
53 			  uint32_t id)
54 {
55 	event->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | SOF_IPC_COMP_NOTIFICATION |
56 		id;
57 	event->rhdr.hdr.size = sizeof(*event);
58 	event->src_comp_type = type;
59 	event->src_comp_id = id;
60 }
61 
ipc_build_trace_posn(struct sof_ipc_dma_trace_posn * posn)62 void ipc_build_trace_posn(struct sof_ipc_dma_trace_posn *posn)
63 {
64 	posn->rhdr.hdr.cmd =  SOF_IPC_GLB_TRACE_MSG |
65 		SOF_IPC_TRACE_DMA_POSITION;
66 	posn->rhdr.hdr.size = sizeof(*posn);
67 }
68 
get_drv(struct sof_ipc_comp * comp)69 static const struct comp_driver *get_drv(struct sof_ipc_comp *comp)
70 {
71 	struct comp_driver_list *drivers = comp_drivers_get();
72 	struct list_item *clist;
73 	const struct comp_driver *drv = NULL;
74 	struct comp_driver_info *info;
75 	struct sof_ipc_comp_ext *comp_ext;
76 
77 	/* do we have extended data ? */
78 	if (!comp->ext_data_length) {
79 		/* search driver list for driver type */
80 		list_for_item(clist, &drivers->list) {
81 			info = container_of(clist, struct comp_driver_info, list);
82 			if (info->drv->type == comp->type) {
83 				drv = info->drv;
84 				break;
85 			}
86 		}
87 
88 		if (!drv)
89 			tr_err(&comp_tr, "get_drv(): driver not found, comp->type = %u",
90 			       comp->type);
91 
92 		goto out;
93 	}
94 
95 	/* Basic sanity check of the total size and extended data
96 	 * length. A bit lax because in this generic code we don't know
97 	 * which derived comp we have and how much its specific members
98 	 * add.
99 	 */
100 	if (comp->hdr.size < sizeof(*comp) + comp->ext_data_length) {
101 		tr_err(&comp_tr, "Invalid size, hdr.size=0x%x, ext_data_length=0x%x\n",
102 		       comp->hdr.size, comp->ext_data_length);
103 		goto out;
104 	}
105 
106 	comp_ext = (struct sof_ipc_comp_ext *)
107 		   ((uint8_t *)comp + comp->hdr.size -
108 		    comp->ext_data_length);
109 
110 	/* UUID is first item in extended data - check its big enough */
111 	if (comp->ext_data_length < UUID_SIZE) {
112 		tr_err(&comp_tr, "UUID is invalid!\n");
113 		goto out;
114 	}
115 
116 	/* search driver list with UUID */
117 	spin_lock(&drivers->lock);
118 	list_for_item(clist, &drivers->list) {
119 		info = container_of(clist, struct comp_driver_info,
120 				    list);
121 		if (!memcmp(info->drv->uid, comp_ext->uuid,
122 			    UUID_SIZE)) {
123 			drv = info->drv;
124 			break;
125 		}
126 	}
127 
128 	if (!drv)
129 		tr_err(&comp_tr,
130 		       "get_drv(): the provided UUID (%8x%8x%8x%8x) doesn't match to any driver!",
131 		       *(uint32_t *)(&comp_ext->uuid[0]),
132 		       *(uint32_t *)(&comp_ext->uuid[4]),
133 		       *(uint32_t *)(&comp_ext->uuid[8]),
134 		       *(uint32_t *)(&comp_ext->uuid[12]));
135 
136 out:
137 	if (drv)
138 		tr_dbg(&comp_tr, "get_drv(), found driver type %d, uuid %pU",
139 		       drv->type, drv->tctx->uuid_p);
140 
141 	spin_unlock(&drivers->lock);
142 
143 	return drv;
144 }
145 
146 /* build generic IPC data for all components */
comp_common_builder(struct sof_ipc_comp * comp,struct comp_ipc_config * config)147 static void comp_common_builder(struct sof_ipc_comp *comp,
148 				struct comp_ipc_config *config)
149 {
150 	struct sof_ipc_comp_config *ipc_config;
151 
152 	/* create the new component */
153 	memset(config, 0, sizeof(*config));
154 	config->core = comp->core;
155 	config->id = comp->id;
156 	config->pipeline_id = comp->pipeline_id;
157 	config->type = comp->type;
158 
159 	/* buffers dont have the following data */
160 	if (comp->type != SOF_COMP_BUFFER) {
161 		/* ipc common config is always after sof_ipc_comp */
162 		ipc_config = (struct sof_ipc_comp_config *)(comp + 1);
163 		config->frame_fmt = ipc_config->frame_fmt;
164 		config->periods_sink = ipc_config->periods_sink;
165 		config->periods_source = ipc_config->periods_source;
166 		config->xrun_action = ipc_config->xrun_action;
167 	}
168 }
169 /*
170  * Stores all the "legacy" init IPC data locally.
171  */
172 union ipc_config_specific {
173 	struct ipc_config_host host;
174 	struct ipc_config_dai dai;
175 	struct ipc_config_volume volume;
176 	struct ipc_config_src src;
177 	struct ipc_config_asrc asrc;
178 	struct ipc_config_tone tone;
179 	struct ipc_config_process process;
180 	struct ipc_comp_file file;
181 } __attribute__((packed, aligned(4)));
182 
183 /* build component specific data */
comp_specific_builder(struct sof_ipc_comp * comp,union ipc_config_specific * config)184 static void comp_specific_builder(struct sof_ipc_comp *comp,
185 				  union ipc_config_specific *config)
186 {
187 #if CONFIG_LIBRARY
188 	struct sof_ipc_comp_file *file = (struct sof_ipc_comp_file *)comp;
189 #else
190 	struct sof_ipc_comp_host *host = (struct sof_ipc_comp_host *)comp;
191 	struct sof_ipc_comp_dai *dai = (struct sof_ipc_comp_dai *)comp;
192 #endif
193 	struct sof_ipc_comp_volume *vol = (struct sof_ipc_comp_volume *)comp;
194 	struct sof_ipc_comp_process *proc = (struct sof_ipc_comp_process *)comp;
195 	struct sof_ipc_comp_src *src = (struct sof_ipc_comp_src *)comp;
196 	struct sof_ipc_comp_asrc *asrc = (struct sof_ipc_comp_asrc *)comp;
197 	struct sof_ipc_comp_tone *tone = (struct sof_ipc_comp_tone *)comp;
198 
199 	memset(config, 0, sizeof(*config));
200 
201 	switch (comp->type) {
202 #if CONFIG_LIBRARY
203 	/* test bench maps host and DAIs to a file */
204 	case SOF_COMP_HOST:
205 	case SOF_COMP_SG_HOST:
206 	case SOF_COMP_DAI:
207 	case SOF_COMP_SG_DAI:
208 		config->file.channels = file->channels;
209 		config->file.fn = file->fn;
210 		config->file.frame_fmt = file->frame_fmt;
211 		config->file.mode = file->mode;
212 		config->file.rate = file->rate;
213 		break;
214 #else
215 	case SOF_COMP_HOST:
216 	case SOF_COMP_SG_HOST:
217 		config->host.direction = host->direction;
218 		config->host.no_irq = host->no_irq;
219 		config->host.dmac_config = host->dmac_config;
220 		break;
221 	case SOF_COMP_DAI:
222 	case SOF_COMP_SG_DAI:
223 		config->dai.dai_index = dai->dai_index;
224 		config->dai.direction = dai->direction;
225 		config->dai.type = dai->type;
226 		break;
227 #endif
228 	case SOF_COMP_VOLUME:
229 		config->volume.channels = vol->channels;
230 		config->volume.initial_ramp = vol->initial_ramp;
231 		config->volume.max_value = vol->max_value;
232 		config->volume.min_value = vol->min_value;
233 		config->volume.ramp = vol->ramp;
234 		break;
235 	case SOF_COMP_SRC:
236 		config->src.rate_mask = src->rate_mask;
237 		config->src.sink_rate = src->sink_rate;
238 		config->src.source_rate = src->source_rate;
239 		break;
240 	case SOF_COMP_TONE:
241 		config->tone.ampl_mult = tone->ampl_mult;
242 		config->tone.amplitude = tone->amplitude;
243 		config->tone.freq_mult = tone->freq_mult;
244 		config->tone.frequency = tone->frequency;
245 		config->tone.length = tone->length;
246 		config->tone.period = tone->period;
247 		config->tone.ramp_step = tone->ramp_step;
248 		config->tone.repeats = tone->repeats;
249 		config->tone.sample_rate = tone->sample_rate;
250 		break;
251 	case SOF_COMP_ASRC:
252 		config->asrc.source_rate = src->source_rate;
253 		config->asrc.sink_rate = src->sink_rate;
254 		config->asrc.asynchronous_mode = asrc->asynchronous_mode;
255 		config->asrc.operation_mode = asrc->operation_mode;
256 		break;
257 	case SOF_COMP_EQ_IIR:
258 	case SOF_COMP_EQ_FIR:
259 	case SOF_COMP_KEYWORD_DETECT:
260 	case SOF_COMP_KPB:
261 	case SOF_COMP_SELECTOR:
262 	case SOF_COMP_DEMUX:
263 	case SOF_COMP_MUX:
264 	case SOF_COMP_DCBLOCK:
265 	case SOF_COMP_SMART_AMP:
266 	case SOF_COMP_CODEC_ADAPTOR:
267 	case SOF_COMP_NONE:
268 		config->process.type = proc->type;
269 		config->process.size = proc->size;
270 		config->process.data = proc->data;
271 		break;
272 	default:
273 		break;
274 	}
275 }
276 
comp_new(struct sof_ipc_comp * comp)277 struct comp_dev *comp_new(struct sof_ipc_comp *comp)
278 {
279 	struct comp_ipc_config config;
280 	union ipc_config_specific spec;
281 	struct comp_dev *cdev;
282 	const struct comp_driver *drv;
283 
284 	/* find the driver for our new component */
285 	drv = get_drv(comp);
286 	if (!drv)
287 		return NULL;
288 
289 	/* validate size of ipc config */
290 	if (IPC_IS_SIZE_INVALID(*comp_config(comp))) {
291 		IPC_SIZE_ERROR_TRACE(&comp_tr, *comp_config(comp));
292 		return NULL;
293 	}
294 
295 	tr_info(&comp_tr, "comp new %pU type %d id %d.%d",
296 		drv->tctx->uuid_p, comp->type, comp->pipeline_id, comp->id);
297 
298 	/* build the component */
299 	comp_common_builder(comp, &config);
300 	comp_specific_builder(comp, &spec);
301 	cdev = drv->ops.create(drv, &config, &spec);
302 	if (!cdev) {
303 		comp_cl_err(drv, "comp_new(): unable to create the new component");
304 		return NULL;
305 	}
306 
307 	list_init(&cdev->bsource_list);
308 	list_init(&cdev->bsink_list);
309 
310 	return cdev;
311 }
312 
ipc_pipeline_new(struct ipc * ipc,ipc_pipe_new * _pipe_desc)313 int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc)
314 {
315 	struct sof_ipc_pipe_new *pipe_desc = ipc_from_pipe_new(_pipe_desc);
316 	struct ipc_comp_dev *ipc_pipe;
317 	struct pipeline *pipe;
318 	int ret;
319 
320 	/* check whether the pipeline already exists */
321 	ipc_pipe = ipc_get_comp_by_id(ipc, pipe_desc->comp_id);
322 	if (ipc_pipe != NULL) {
323 		tr_err(&ipc_tr, "ipc_pipeline_new(): pipeline already exists, pipe_desc->comp_id = %u",
324 		       pipe_desc->comp_id);
325 		return -EINVAL;
326 	}
327 
328 	/* check whether pipeline id is already taken */
329 	ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE,
330 					  pipe_desc->pipeline_id);
331 	if (ipc_pipe) {
332 		tr_err(&ipc_tr, "ipc_pipeline_new(): pipeline id is already taken, pipe_desc->pipeline_id = %u",
333 		       pipe_desc->pipeline_id);
334 		return -EINVAL;
335 	}
336 
337 	/* create the pipeline */
338 	pipe = pipeline_new(pipe_desc->pipeline_id, pipe_desc->priority,
339 			    pipe_desc->comp_id);
340 	if (!pipe) {
341 		tr_err(&ipc_tr, "ipc_pipeline_new(): pipeline_new() failed");
342 		return -ENOMEM;
343 	}
344 
345 	/* configure pipeline */
346 	ret = pipeline_schedule_config(pipe, pipe_desc->sched_id,
347 				       pipe_desc->core, pipe_desc->period,
348 				       pipe_desc->period_mips,
349 				       pipe_desc->frames_per_sched,
350 				       pipe_desc->time_domain);
351 	if (ret) {
352 		tr_err(&ipc_tr, "ipc_pipeline_new(): pipeline_schedule_config() failed");
353 		return ret;
354 	}
355 
356 	/* set xrun time limit */
357 	ret = pipeline_xrun_set_limit(pipe, pipe_desc->xrun_limit_usecs);
358 	if (ret) {
359 		tr_err(&ipc_tr, "ipc_pipeline_new(): pipeline_xrun_set_limit() failed");
360 		return ret;
361 	}
362 
363 	/* allocate the IPC pipeline container */
364 	ipc_pipe = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM,
365 			   sizeof(struct ipc_comp_dev));
366 	if (!ipc_pipe) {
367 		pipeline_free(pipe);
368 		return -ENOMEM;
369 	}
370 
371 	ipc_pipe->pipeline = pipe;
372 	ipc_pipe->type = COMP_TYPE_PIPELINE;
373 	ipc_pipe->core = pipe_desc->core;
374 	ipc_pipe->id = pipe_desc->comp_id;
375 
376 	/* add new pipeline to the list */
377 	list_item_append(&ipc_pipe->list, &ipc->comp_list);
378 
379 	return 0;
380 }
381 
ipc_pipeline_free(struct ipc * ipc,uint32_t comp_id)382 int ipc_pipeline_free(struct ipc *ipc, uint32_t comp_id)
383 {
384 	struct ipc_comp_dev *ipc_pipe;
385 	int ret;
386 
387 	/* check whether pipeline exists */
388 	ipc_pipe = ipc_get_comp_by_id(ipc, comp_id);
389 	if (!ipc_pipe)
390 		return -ENODEV;
391 
392 	/* check core */
393 	if (!cpu_is_me(ipc_pipe->core))
394 		return ipc_process_on_core(ipc_pipe->core, false);
395 
396 	/* free buffer and remove from list */
397 	ret = pipeline_free(ipc_pipe->pipeline);
398 	if (ret < 0) {
399 		tr_err(&ipc_tr, "ipc_pipeline_free(): pipeline_free() failed");
400 		return ret;
401 	}
402 	ipc_pipe->pipeline = NULL;
403 	list_item_del(&ipc_pipe->list);
404 	rfree(ipc_pipe);
405 
406 	return 0;
407 }
408 
ipc_buffer_new(struct ipc * ipc,const struct sof_ipc_buffer * desc)409 int ipc_buffer_new(struct ipc *ipc, const struct sof_ipc_buffer *desc)
410 {
411 	struct ipc_comp_dev *ibd;
412 	struct comp_buffer *buffer;
413 	int ret = 0;
414 
415 	/* check whether buffer already exists */
416 	ibd = ipc_get_comp_by_id(ipc, desc->comp.id);
417 	if (ibd != NULL) {
418 		tr_err(&ipc_tr, "ipc_buffer_new(): buffer already exists, desc->comp.id = %u",
419 		       desc->comp.id);
420 		return -EINVAL;
421 	}
422 
423 	/* register buffer with pipeline */
424 	buffer = buffer_new(desc);
425 	if (!buffer) {
426 		tr_err(&ipc_tr, "ipc_buffer_new(): buffer_new() failed");
427 		return -ENOMEM;
428 	}
429 
430 	ibd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM,
431 		      sizeof(struct ipc_comp_dev));
432 	if (!ibd) {
433 		buffer_free(buffer);
434 		return -ENOMEM;
435 	}
436 	ibd->cb = buffer;
437 	ibd->type = COMP_TYPE_BUFFER;
438 	ibd->core = desc->comp.core;
439 	ibd->id = desc->comp.id;
440 
441 	/* add new buffer to the list */
442 	list_item_append(&ibd->list, &ipc->comp_list);
443 
444 	return ret;
445 }
446 
ipc_buffer_free(struct ipc * ipc,uint32_t buffer_id)447 int ipc_buffer_free(struct ipc *ipc, uint32_t buffer_id)
448 {
449 	struct ipc_comp_dev *ibd;
450 	struct ipc_comp_dev *icd;
451 	struct list_item *clist;
452 	struct comp_dev *sink = NULL, *source = NULL;
453 	bool sink_active = false;
454 	bool source_active = false;
455 
456 	/* check whether buffer exists */
457 	ibd = ipc_get_comp_by_id(ipc, buffer_id);
458 	if (!ibd)
459 		return -ENODEV;
460 
461 	/* check core */
462 	if (!cpu_is_me(ibd->core))
463 		return ipc_process_on_core(ibd->core, false);
464 
465 	/* try to find sink/source components to check if they still exists */
466 	list_for_item(clist, &ipc->comp_list) {
467 		icd = container_of(clist, struct ipc_comp_dev, list);
468 		if (icd->type != COMP_TYPE_COMPONENT)
469 			continue;
470 
471 		/* check comp state if sink and source are valid */
472 		if (ibd->cb->sink == icd->cd &&
473 		    ibd->cb->sink->state != COMP_STATE_READY) {
474 			sink = ibd->cb->sink;
475 			sink_active = true;
476 		}
477 
478 		if (ibd->cb->source == icd->cd &&
479 		    ibd->cb->source->state != COMP_STATE_READY) {
480 			source = ibd->cb->source;
481 			source_active = true;
482 		}
483 	}
484 
485 	/*
486 	 * A buffer could be connected to 2 different pipelines. When one pipeline is freed, the
487 	 * buffer comp that belongs in this pipeline will need to be freed even when the other
488 	 * pipeline that the buffer is connected to is active. Check if both ends are active before
489 	 * freeing the buffer.
490 	 */
491 	if (sink_active && source_active)
492 		return -EINVAL;
493 
494 	/*
495 	 * Disconnect the buffer from the active component before freeing it.
496 	 */
497 	if (sink)
498 		pipeline_disconnect(sink, ibd->cb, PPL_CONN_DIR_BUFFER_TO_COMP);
499 
500 	if (source)
501 		pipeline_disconnect(source, ibd->cb, PPL_CONN_DIR_COMP_TO_BUFFER);
502 
503 	/* free buffer and remove from list */
504 	buffer_free(ibd->cb);
505 	list_item_del(&ibd->list);
506 	rfree(ibd);
507 
508 	return 0;
509 }
510 
ipc_comp_to_buffer_connect(struct ipc_comp_dev * comp,struct ipc_comp_dev * buffer)511 static int ipc_comp_to_buffer_connect(struct ipc_comp_dev *comp,
512 				      struct ipc_comp_dev *buffer)
513 {
514 	int ret;
515 
516 	if (!cpu_is_me(comp->core))
517 		return ipc_process_on_core(comp->core, false);
518 
519 	tr_dbg(&ipc_tr, "ipc: comp sink %d, source %d  -> connect", buffer->id,
520 	       comp->id);
521 
522 	/* check if it's a connection between cores */
523 	if (buffer->core != comp->core) {
524 		dcache_invalidate_region(buffer->cb, sizeof(*buffer->cb));
525 
526 		buffer->cb->inter_core = true;
527 
528 		if (!comp->cd->is_shared) {
529 			comp->cd = comp_make_shared(comp->cd);
530 			if (!comp->cd)
531 				return -ENOMEM;
532 		}
533 	}
534 
535 	ret = pipeline_connect(comp->cd, buffer->cb,
536 			       PPL_CONN_DIR_COMP_TO_BUFFER);
537 
538 	dcache_writeback_invalidate_region(buffer->cb, sizeof(*buffer->cb));
539 
540 	return ret;
541 }
542 
ipc_buffer_to_comp_connect(struct ipc_comp_dev * buffer,struct ipc_comp_dev * comp)543 static int ipc_buffer_to_comp_connect(struct ipc_comp_dev *buffer,
544 				      struct ipc_comp_dev *comp)
545 {
546 	int ret;
547 
548 	if (!cpu_is_me(comp->core))
549 		return ipc_process_on_core(comp->core, false);
550 
551 	tr_dbg(&ipc_tr, "ipc: comp sink %d, source %d  -> connect", comp->id,
552 	       buffer->id);
553 
554 	/* check if it's a connection between cores */
555 	if (buffer->core != comp->core) {
556 		dcache_invalidate_region(buffer->cb, sizeof(*buffer->cb));
557 
558 		buffer->cb->inter_core = true;
559 
560 		if (!comp->cd->is_shared) {
561 			comp->cd = comp_make_shared(comp->cd);
562 			if (!comp->cd)
563 				return -ENOMEM;
564 		}
565 	}
566 
567 	ret = pipeline_connect(comp->cd, buffer->cb,
568 			       PPL_CONN_DIR_BUFFER_TO_COMP);
569 
570 	dcache_writeback_invalidate_region(buffer->cb, sizeof(*buffer->cb));
571 
572 	return ret;
573 }
574 
ipc_comp_connect(struct ipc * ipc,ipc_pipe_comp_connect * _connect)575 int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect)
576 {
577 	struct sof_ipc_pipe_comp_connect *connect = ipc_from_pipe_connect(_connect);
578 	struct ipc_comp_dev *icd_source;
579 	struct ipc_comp_dev *icd_sink;
580 
581 	/* check whether the components already exist */
582 	icd_source = ipc_get_comp_by_id(ipc, connect->source_id);
583 	if (!icd_source) {
584 		tr_err(&ipc_tr, "ipc_comp_connect(): source component does not exist, source_id = %u sink_id = %u",
585 		       connect->source_id, connect->sink_id);
586 		return -EINVAL;
587 	}
588 
589 	icd_sink = ipc_get_comp_by_id(ipc, connect->sink_id);
590 	if (!icd_sink) {
591 		tr_err(&ipc_tr, "ipc_comp_connect(): sink component does not exist, source_id = %d sink_id = %u",
592 		       connect->sink_id, connect->source_id);
593 		return -EINVAL;
594 	}
595 
596 	/* check source and sink types */
597 	if (icd_source->type == COMP_TYPE_BUFFER &&
598 	    icd_sink->type == COMP_TYPE_COMPONENT)
599 		return ipc_buffer_to_comp_connect(icd_source, icd_sink);
600 	else if (icd_source->type == COMP_TYPE_COMPONENT &&
601 		 icd_sink->type == COMP_TYPE_BUFFER)
602 		return ipc_comp_to_buffer_connect(icd_source, icd_sink);
603 	else {
604 		tr_err(&ipc_tr, "ipc_comp_connect(): invalid source and sink types, connect->source_id = %u, connect->sink_id = %u",
605 		       connect->source_id, connect->sink_id);
606 		return -EINVAL;
607 	}
608 }
609 
ipc_comp_new(struct ipc * ipc,ipc_comp * _comp)610 int ipc_comp_new(struct ipc *ipc, ipc_comp *_comp)
611 {
612 	struct sof_ipc_comp *comp = ipc_from_comp_new(_comp);
613 	struct comp_dev *cd;
614 	struct ipc_comp_dev *icd;
615 
616 	/* check core is valid */
617 	if (comp->core >= CONFIG_CORE_COUNT) {
618 		tr_err(&ipc_tr, "ipc_comp_new(): comp->core = %u", comp->core);
619 		return -EINVAL;
620 	}
621 
622 	/* check whether component already exists */
623 	icd = ipc_get_comp_by_id(ipc, comp->id);
624 	if (icd != NULL) {
625 		tr_err(&ipc_tr, "ipc_comp_new(): comp->id = %u", comp->id);
626 		return -EINVAL;
627 	}
628 
629 	/* create component */
630 	cd = comp_new(comp);
631 	if (!cd) {
632 		tr_err(&ipc_tr, "ipc_comp_new(): component cd = NULL");
633 		return -EINVAL;
634 	}
635 
636 	/* allocate the IPC component container */
637 	icd = rzalloc(SOF_MEM_ZONE_RUNTIME_SHARED, 0, SOF_MEM_CAPS_RAM,
638 		      sizeof(struct ipc_comp_dev));
639 	if (!icd) {
640 		tr_err(&ipc_tr, "ipc_comp_new(): alloc failed");
641 		rfree(cd);
642 		return -ENOMEM;
643 	}
644 	icd->cd = cd;
645 	icd->type = COMP_TYPE_COMPONENT;
646 	icd->core = comp->core;
647 	icd->id = comp->id;
648 
649 	/* add new component to the list */
650 	list_item_append(&icd->list, &ipc->comp_list);
651 
652 	return 0;
653 }
654