Skip to content

Commit 9ebcafd

Browse files
author
Jyri Sarha
committed
pipeline: allocate shared vregion for LL modules in the pipeline
Create a per-pipeline vregion in pipeline_new() when the IPC4 pipeline extension payload specifies the required heap size, and attach it to the pipeline's alloc context. LL modules on a pipeline with a vregion use it as their allocation backend via vregion_get(), instead of the driver's default heap, and share the pipeline's mod_alloc_ctx. A use_ppl_alloc flag gates the sharing to LL modules only, so DP modules continue to create their own vregion and alloc context as before. Also the behaviour in the case the where ppl_alloc is not available remains unchanged. module_adapter_mem_free() detects whether a module's alloc belongs to its pipeline and either just releases the vregion reference (ppl_alloc case) or tears down the module's own alloc. Setting of dev->pipeline is moved earlier in module_adapter_new_ext() so that we can still use module_adapter_mem_free() in its error handling. Call vregion_set_interim() for the pipeline vregion in pipeline_complete() to switch the allocator to interim mode after all lifetime allocations are done, and release it in pipeline_free(), warning if the refcount does not reach zero. Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
1 parent deac1c8 commit 9ebcafd

2 files changed

Lines changed: 122 additions & 67 deletions

File tree

src/audio/module_adapter/module_adapter.c

Lines changed: 99 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -75,23 +75,14 @@ static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *
7575
}
7676

7777
static
78-
struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv,
79-
const struct comp_ipc_config *config,
80-
const struct module_ext_init_data *ext_init)
78+
struct mod_alloc_ctx *module_adapter_dp_alloc_ctx_new(const struct comp_driver *drv,
79+
const struct comp_ipc_config *config,
80+
const struct module_ext_init_data *ext_init,
81+
uint32_t flags)
8182
{
8283
struct k_heap *mod_heap;
8384
struct vregion *mod_vreg;
84-
struct processing_module *mod;
85-
struct comp_dev *dev;
86-
/*
87-
* For DP shared modules the struct processing_module object must be
88-
* accessible from all cores. Unfortunately at this point there's no
89-
* information of components the module will be bound to. So we need to
90-
* allocate shared memory for each DP module.
91-
* To be removed when pipeline 2.0 is ready.
92-
*/
93-
uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ?
94-
SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER;
85+
struct mod_alloc_ctx *alloc;
9586

9687
if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_SOF_VREGIONS) &&
9788
IS_ENABLED(CONFIG_USERSPACE) && !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) {
@@ -114,27 +105,59 @@ struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv
114105
#endif
115106
mod_vreg = NULL;
116107
}
108+
alloc = sof_heap_alloc(mod_heap, flags, sizeof(*alloc), 0);
109+
if (!alloc) {
110+
comp_cl_err(drv, "sof_alloc_ctx allocation failed");
111+
vregion_put(mod_vreg);
112+
return NULL;
113+
}
117114

118-
if (!mod_vreg)
119-
mod = sof_heap_alloc(mod_heap, flags, sizeof(*mod), 0);
120-
else if (flags & SOF_MEM_FLAG_COHERENT)
121-
mod = vregion_alloc_coherent(mod_vreg, sizeof(*mod));
122-
else
123-
mod = vregion_alloc(mod_vreg, sizeof(*mod));
115+
memset(alloc, 0, sizeof(*alloc));
116+
alloc->heap = mod_heap;
117+
alloc->vreg = mod_vreg;
118+
119+
return alloc;
120+
}
121+
122+
static
123+
struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv,
124+
const struct comp_ipc_config *config,
125+
const struct module_ext_init_data *ext_init,
126+
struct mod_alloc_ctx *ppl_alloc)
127+
{
128+
struct processing_module *mod;
129+
struct mod_alloc_ctx *alloc;
130+
struct comp_dev *dev;
131+
/*
132+
* For DP shared modules the struct processing_module object must be
133+
* accessible from all cores. Unfortunately at this point there's no
134+
* information of components the module will be bound to. So we need to
135+
* allocate shared memory for each DP module.
136+
* To be removed when pipeline 2.0 is ready.
137+
*/
138+
uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ?
139+
SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER;
140+
141+
if (config->proc_domain == COMP_PROCESSING_DOMAIN_LL) {
142+
/* LL modules share the pipeline's alloc context */
143+
alloc = ppl_alloc;
144+
vregion_get(alloc->vreg);
145+
} else if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP) {
146+
alloc = module_adapter_dp_alloc_ctx_new(drv, config, ext_init, flags);
147+
if (!alloc)
148+
return NULL;
149+
} else {
150+
comp_cl_err(drv, "bad proc_domain %d", config->proc_domain);
151+
return NULL;
152+
}
124153

154+
mod = sof_ctx_alloc(alloc, flags, sizeof(*mod), 0);
125155
if (!mod) {
126156
comp_cl_err(drv, "failed to allocate memory for module");
127157
goto emod;
128158
}
129159

130-
struct mod_alloc_ctx *alloc = sof_heap_alloc(mod_heap, flags, sizeof(*alloc), 0);
131-
132-
if (!alloc)
133-
goto ealloc;
134-
135160
memset(mod, 0, sizeof(*mod));
136-
alloc->heap = mod_heap;
137-
alloc->vreg = mod_vreg;
138161
mod->priv.resources.alloc = alloc;
139162
mod_resource_init(mod);
140163

@@ -144,11 +167,7 @@ struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv
144167
* then it can be cached. Effectively it can be only cached in
145168
* single-core configurations.
146169
*/
147-
if (mod_vreg)
148-
dev = vregion_alloc_coherent(mod_vreg, sizeof(*dev));
149-
else
150-
dev = sof_heap_alloc(mod_heap, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0);
151-
170+
dev = sof_ctx_alloc(alloc, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0);
152171
if (!dev) {
153172
comp_cl_err(drv, "failed to allocate memory for comp_dev");
154173
goto edev;
@@ -163,41 +182,45 @@ struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv
163182
return mod;
164183

165184
edev:
166-
sof_heap_free(mod_heap, alloc);
167-
ealloc:
168-
if (mod_vreg)
169-
vregion_free(mod_vreg, mod);
170-
else
171-
sof_heap_free(mod_heap, mod);
185+
sof_ctx_free(alloc, mod);
172186
emod:
173-
vregion_put(mod_vreg);
187+
vregion_put(alloc->vreg);
188+
if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP)
189+
sof_heap_free(alloc->heap, alloc);
174190

175191
return NULL;
176192
}
177193

178194
static void module_adapter_mem_free(struct processing_module *mod)
179195
{
180196
struct mod_alloc_ctx *alloc = mod->priv.resources.alloc;
181-
struct k_heap *mod_heap = alloc->heap;
197+
bool ppl_alloc = mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL &&
198+
mod->dev->pipeline && mod->dev->pipeline->alloc == alloc;
182199

183200
/*
184201
* In principle it shouldn't even be needed to free individual objects
185202
* on the module heap since we're freeing the heap itself too
186203
*/
187204
#if CONFIG_IPC_MAJOR_4
188-
sof_heap_free(mod_heap, mod->priv.cfg.input_pins);
205+
sof_heap_free(alloc->heap, mod->priv.cfg.input_pins);
189206
#endif
190-
if (alloc->vreg) {
191-
struct vregion *mod_vreg = alloc->vreg;
207+
sof_ctx_free(alloc, mod->dev);
208+
sof_ctx_free(alloc, mod);
192209

193-
vregion_free(mod_vreg, mod->dev);
194-
vregion_free(mod_vreg, mod);
195-
if (!vregion_put(mod_vreg))
210+
if (ppl_alloc) {
211+
/* alloc belongs to pipeline, just release vregion reference */
212+
vregion_put(alloc->vreg);
213+
} else if (alloc->vreg) {
214+
/*
215+
* This is DP userpsace case
216+
* Only remove the alloc ctx, if vreg was freed. If it was not
217+
* the DP userspace thread is still holding a reference to it,
218+
* and will free alloc ctx eventually.
219+
*/
220+
if (!vregion_put(alloc->vreg))
196221
sof_heap_free(alloc->heap, alloc);
197222
} else {
198-
sof_heap_free(mod_heap, mod->dev);
199-
sof_heap_free(mod_heap, mod);
200-
sof_heap_free(mod_heap, alloc);
223+
sof_heap_free(alloc->heap, alloc);
201224
}
202225
}
203226

@@ -248,8 +271,19 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
248271
NULL;
249272
#endif
250273

251-
struct processing_module *mod = module_adapter_mem_alloc(drv, config, ext_init);
274+
struct mod_alloc_ctx *ppl_alloc = NULL;
275+
#if CONFIG_IPC_MAJOR_4
276+
struct ipc_comp_dev *ipc_pipe;
277+
struct ipc *ipc = ipc_get();
252278

279+
/* resolve the pipeline pointer early to pass its alloc to mem_alloc */
280+
ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id,
281+
IPC_COMP_IGNORE_REMOTE);
282+
if (ipc_pipe && ipc_pipe->pipeline)
283+
ppl_alloc = ipc_pipe->pipeline->alloc;
284+
#endif
285+
286+
struct processing_module *mod = module_adapter_mem_alloc(drv, config, ext_init, ppl_alloc);
253287
if (!mod)
254288
return NULL;
255289

@@ -273,6 +307,21 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
273307
dst->ext_data = &ext_data;
274308
#endif
275309

310+
#if CONFIG_IPC_MAJOR_4
311+
/*
312+
* Set the pipeline pointer if ipc_pipe is valid. Do this
313+
* early so that we can use module_adapter_mem_free() in error
314+
* handling.
315+
*/
316+
if (ipc_pipe) {
317+
dev->pipeline = ipc_pipe->pipeline;
318+
319+
/* LL modules have the same period as the pipeline */
320+
if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL)
321+
dev->period = ipc_pipe->pipeline->period;
322+
}
323+
#endif
324+
276325
#if CONFIG_ZEPHYR_DP_SCHEDULER
277326
/* create a task for DP processing */
278327
if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP) {
@@ -306,22 +355,6 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
306355
else
307356
goto err;
308357

309-
#if CONFIG_IPC_MAJOR_4
310-
struct ipc_comp_dev *ipc_pipe;
311-
struct ipc *ipc = ipc_get();
312-
313-
/* set the pipeline pointer if ipc_pipe is valid */
314-
ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id,
315-
IPC_COMP_IGNORE_REMOTE);
316-
if (ipc_pipe) {
317-
dev->pipeline = ipc_pipe->pipeline;
318-
319-
/* LL modules have the same period as the pipeline */
320-
if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL)
321-
dev->period = ipc_pipe->pipeline->period;
322-
}
323-
#endif
324-
325358
/* Init processing module */
326359
ret = module_init(mod);
327360
if (ret) {

src/audio/pipeline/pipeline-graph.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <ipc/stream.h>
2828
#include <ipc/topology.h>
2929
#include <ipc4/module.h>
30+
#include <ipc4/pipeline.h>
3031
#include <errno.h>
3132
#include <stdbool.h>
3233
#include <stddef.h>
@@ -194,6 +195,18 @@ struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_
194195
memset(alloc, 0, sizeof(*alloc));
195196
alloc->heap = heap;
196197

198+
/* Create vregion for pipeline and its modules if size info is available */
199+
if (IS_ENABLED(CONFIG_SOF_VREGIONS) &&
200+
pparams && pparams->mem_data && pparams->mem_data->heap_bytes) {
201+
size_t buf_size = pparams->mem_data->heap_bytes;
202+
uintptr_t vreg_start;
203+
204+
alloc->vreg = vregion_create_map(&vreg_start, &buf_size);
205+
if (!alloc->vreg)
206+
pipe_cl_err("Failed to create pipeline vregion of %zu bytes, using heap",
207+
pparams->mem_data->heap_bytes);
208+
}
209+
197210
/* allocate new pipeline */
198211
p = sof_ctx_zalloc(alloc, SOF_MEM_FLAG_USER, sizeof(*p), 0);
199212
if (!p) {
@@ -246,7 +259,8 @@ struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_
246259
free:
247260
sof_ctx_free(alloc, p);
248261
free_alloc:
249-
sof_heap_free(heap, alloc);
262+
vregion_put(alloc->vreg);
263+
rfree(alloc);
250264
return NULL;
251265
}
252266

@@ -349,6 +363,10 @@ int pipeline_free(struct pipeline *p)
349363

350364
/* now free the pipeline */
351365
sof_ctx_free(alloc, p);
366+
367+
/* free alloc context and vregion */
368+
if (vregion_put(alloc->vreg))
369+
pipe_cl_warn("pipeline vregion still in use");
352370
sof_heap_free(alloc->heap, alloc);
353371

354372
/* show heap status */
@@ -426,6 +444,10 @@ int pipeline_complete(struct pipeline *p, struct comp_dev *source,
426444

427445
p->source_comp = source;
428446
p->sink_comp = sink;
447+
448+
if (p->alloc->vreg)
449+
vregion_set_interim(p->alloc->vreg);
450+
429451
p->status = COMP_STATE_READY;
430452

431453
/* show heap status */

0 commit comments

Comments
 (0)