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