Skip to content
Open
13 changes: 13 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

cmake_minimum_required(VERSION 3.21.0)

# Board specific overlays (these must be before find_package(Zephyr)
# ------------------------------------------------------------------

# Intel PTL: use ll_userspace_overlay if building for Linux upstream
if(DEFINED EXTRA_CONF_FILE AND (BOARD MATCHES "/ptl" OR BOARD_QUALIFIERS MATCHES "/ptl"))
string(FIND "${EXTRA_CONF_FILE}" "os_linux_overlay" _linux_overlay_idx)
string(FIND "${EXTRA_CONF_FILE}" "ll_userspace_overlay" _ll_overlay_idx)
if(_linux_overlay_idx GREATER_EQUAL 0 AND _ll_overlay_idx LESS 0)
list(APPEND EXTRA_CONF_FILE
"${CMAKE_CURRENT_SOURCE_DIR}/overlays/ptl/ll_userspace_overlay.conf")
endif()
endif()

find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
project(sample_sof)

Expand Down
14 changes: 8 additions & 6 deletions app/overlays/ptl/ll_userspace_overlay.conf
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ CONFIG_CROSS_CORE_STREAM=n
CONFIG_INTEL_ADSP_MIC_PRIVACY=n
CONFIG_XRUN_NOTIFICATIONS_ENABLE=n

# Extend the shared LL user-space heap to 512KiB. This
# is current maximum for PTL builds with virtual heap
# enabled and uses the vmh allocation intended for KBP.
# TODO: needs some better solution to allocate
CONFIG_SOF_ZEPHYR_SYS_USER_HEAP_SIZE=0x80000

# Allocate majority of heap to user-space but only
# via vregions. Keep 0x40000 for non-vregion allocs.
CONFIG_SOF_ZEPHYR_SYS_USER_HEAP_SIZE=0x40000
CONFIG_SOF_ZEPHYR_HEAP_SIZE=0x60000
CONFIG_VIRTUAL_HEAP=n

# sof-ptl-nocodec.tplg requires more than 64 partitions for DP
# (vregion is created for each pipeline)
CONFIG_MAX_DOMAIN_PARTITIONS=128
155 changes: 82 additions & 73 deletions src/audio/module_adapter/module_adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *
static
struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv,
const struct comp_ipc_config *config,
const struct module_ext_init_data *ext_init)
const struct module_ext_init_data *ext_init,
struct mod_alloc_ctx *ppl_alloc)
{
struct k_heap *mod_heap;
struct vregion *mod_vreg;
struct k_heap *mod_heap = NULL;
struct processing_module *mod;
struct mod_alloc_ctx *alloc;
struct comp_dev *dev;
/*
* For DP shared modules the struct processing_module object must be
Expand All @@ -92,49 +93,53 @@ struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv
*/
uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ?
SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER;
bool use_ppl_alloc = ppl_alloc &&
config->proc_domain == COMP_PROCESSING_DOMAIN_LL;

if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_SOF_VREGIONS) &&
IS_ENABLED(CONFIG_USERSPACE) && !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) {
mod_vreg = module_adapter_dp_heap_new(config, ext_init);
if (!mod_vreg) {
comp_cl_err(drv, "Failed to allocate DP module heap / vregion");
return NULL;
}
if (use_ppl_alloc) {
/* LL modules share the pipeline's alloc context */
alloc = ppl_alloc;
vregion_get(alloc->vreg);
} else {
struct vregion *mod_vreg = NULL;

if (IS_ENABLED(CONFIG_SOF_VREGIONS) && IS_ENABLED(CONFIG_USERSPACE) &&
!IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP) &&
config->proc_domain == COMP_PROCESSING_DOMAIN_DP) {
mod_vreg = module_adapter_dp_heap_new(config, ext_init);
if (!mod_vreg) {
comp_cl_err(drv, "Failed to allocate DP module heap / vregion");
return NULL;
}
#ifdef CONFIG_SOF_USERSPACE_LL
mod_heap = sof_sys_user_heap_get();
#else
mod_heap = NULL;
mod_heap = sof_sys_user_heap_get();
#endif
} else {
} else {
#ifdef CONFIG_SOF_USERSPACE_LL
mod_heap = sof_sys_user_heap_get();
comp_cl_dbg(drv, "using ll user heap for module");
mod_heap = sof_sys_user_heap_get();
comp_cl_dbg(drv, "using ll user heap for module");
#else
mod_heap = drv->user_heap;
mod_heap = drv->user_heap;
#endif
mod_vreg = NULL;
}
}
alloc = sof_heap_alloc(mod_heap, flags, sizeof(*alloc), 0);
if (!alloc) {
vregion_put(mod_vreg);
return NULL;
}

if (!mod_vreg)
mod = sof_heap_alloc(mod_heap, flags, sizeof(*mod), 0);
else if (flags & SOF_MEM_FLAG_COHERENT)
mod = vregion_alloc_coherent(mod_vreg, sizeof(*mod));
else
mod = vregion_alloc(mod_vreg, sizeof(*mod));
memset(alloc, 0, sizeof(*alloc));
alloc->heap = mod_heap;
alloc->vreg = mod_vreg;
}

mod = sof_ctx_alloc(alloc, flags, sizeof(*mod), 0);
if (!mod) {
comp_cl_err(drv, "failed to allocate memory for module");
goto emod;
}

struct mod_alloc_ctx *alloc = sof_heap_alloc(mod_heap, flags, sizeof(*alloc), 0);

if (!alloc)
goto ealloc;

memset(mod, 0, sizeof(*mod));
alloc->heap = mod_heap;
alloc->vreg = mod_vreg;
mod->priv.resources.alloc = alloc;
mod_resource_init(mod);

Expand All @@ -144,11 +149,7 @@ struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv
* then it can be cached. Effectively it can be only cached in
* single-core configurations.
*/
if (mod_vreg)
dev = vregion_alloc_coherent(mod_vreg, sizeof(*dev));
else
dev = sof_heap_alloc(mod_heap, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0);

dev = sof_ctx_alloc(alloc, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0);
if (!dev) {
comp_cl_err(drv, "failed to allocate memory for comp_dev");
goto edev;
Expand All @@ -163,41 +164,39 @@ struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv
return mod;

edev:
sof_heap_free(mod_heap, alloc);
ealloc:
if (mod_vreg)
vregion_free(mod_vreg, mod);
else
sof_heap_free(mod_heap, mod);
sof_ctx_free(alloc, mod);
emod:
vregion_put(mod_vreg);
vregion_put(alloc->vreg);
if (!use_ppl_alloc)
sof_heap_free(mod_heap, alloc);

return NULL;
}

static void module_adapter_mem_free(struct processing_module *mod)
{
struct mod_alloc_ctx *alloc = mod->priv.resources.alloc;
struct k_heap *mod_heap = alloc->heap;
bool ppl_alloc = mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL &&
mod->dev->pipeline && mod->dev->pipeline->alloc == alloc;

/*
* In principle it shouldn't even be needed to free individual objects
* on the module heap since we're freeing the heap itself too
*/
#if CONFIG_IPC_MAJOR_4
sof_heap_free(mod_heap, mod->priv.cfg.input_pins);
sof_heap_free(alloc->heap, mod->priv.cfg.input_pins);
#endif
if (alloc->vreg) {
struct vregion *mod_vreg = alloc->vreg;

vregion_free(mod_vreg, mod->dev);
vregion_free(mod_vreg, mod);
if (!vregion_put(mod_vreg))
sof_heap_free(alloc->heap, alloc);
sof_ctx_free(alloc, mod->dev);
sof_ctx_free(alloc, mod);

if (ppl_alloc) {
/* alloc belongs to pipeline, just release vregion reference */
vregion_put(alloc->vreg);
} else if (alloc->vreg) {
if (!vregion_put(alloc->vreg))
rfree(alloc);
} else {
sof_heap_free(mod_heap, mod->dev);
sof_heap_free(mod_heap, mod);
sof_heap_free(mod_heap, alloc);
rfree(alloc);
}
}

Expand Down Expand Up @@ -248,8 +247,19 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
NULL;
#endif

struct processing_module *mod = module_adapter_mem_alloc(drv, config, ext_init);
struct mod_alloc_ctx *ppl_alloc = NULL;
#if CONFIG_IPC_MAJOR_4
struct ipc_comp_dev *ipc_pipe;
struct ipc *ipc = ipc_get();

/* resolve the pipeline pointer early to pass its alloc to mem_alloc */
ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id,
IPC_COMP_IGNORE_REMOTE);
if (ipc_pipe && ipc_pipe->pipeline)
ppl_alloc = ipc_pipe->pipeline->alloc;
#endif

struct processing_module *mod = module_adapter_mem_alloc(drv, config, ext_init, ppl_alloc);
if (!mod)
return NULL;

Expand All @@ -273,6 +283,21 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
dst->ext_data = &ext_data;
#endif

#if CONFIG_IPC_MAJOR_4
/*
* Set the pipeline pointer if ipc_pipe is valid. Do this
* early so that we can use module_adapter_mem_free() in error
* handling.
*/
if (ipc_pipe) {
dev->pipeline = ipc_pipe->pipeline;

/* LL modules have the same period as the pipeline */
if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL)
dev->period = ipc_pipe->pipeline->period;
}
#endif

#if CONFIG_ZEPHYR_DP_SCHEDULER
/* create a task for DP processing */
if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP) {
Expand Down Expand Up @@ -306,22 +331,6 @@ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
else
goto err;

#if CONFIG_IPC_MAJOR_4
struct ipc_comp_dev *ipc_pipe;
struct ipc *ipc = ipc_get();

/* set the pipeline pointer if ipc_pipe is valid */
ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id,
IPC_COMP_IGNORE_REMOTE);
if (ipc_pipe) {
dev->pipeline = ipc_pipe->pipeline;

/* LL modules have the same period as the pipeline */
if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL)
dev->period = ipc_pipe->pipeline->period;
}
#endif

/* Init processing module */
ret = module_init(mod);
if (ret) {
Expand Down
49 changes: 42 additions & 7 deletions src/audio/pipeline/pipeline-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <ipc/stream.h>
#include <ipc/topology.h>
#include <ipc4/module.h>
#include <ipc4/pipeline.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
Expand Down Expand Up @@ -174,6 +175,7 @@ void pipeline_posn_grant_access(struct k_thread *thread)
struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_t priority,
uint32_t comp_id, struct create_pipeline_params *pparams)
{
struct mod_alloc_ctx *alloc;
struct sof_ipc_stream_posn posn;
struct pipeline *p;
int ret;
Expand All @@ -184,17 +186,36 @@ struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_
/* show heap status */
heap_trace_all(0);

alloc = sof_heap_alloc(heap, SOF_MEM_FLAG_USER, sizeof(*alloc), 0);
if (!alloc) {
pipe_cl_err("Failed to allocate pipeline alloc context");
return NULL;
}

memset(alloc, 0, sizeof(*alloc));
alloc->heap = heap;

/* Create vregion for pipeline and its modules if size info is available */
if (IS_ENABLED(CONFIG_SOF_VREGIONS) &&
pparams && pparams->mem_data && pparams->mem_data->heap_bytes) {
size_t buf_size = pparams->mem_data->heap_bytes;
uintptr_t vreg_start;

alloc->vreg = vregion_create_map(&vreg_start, &buf_size);
if (!alloc->vreg)
pipe_cl_err("Failed to create pipeline vregion of %zu bytes, using heap",
pparams->mem_data->heap_bytes);
}

/* allocate new pipeline */
p = sof_heap_alloc(heap, SOF_MEM_FLAG_USER, sizeof(*p), 0);
p = sof_ctx_zalloc(alloc, SOF_MEM_FLAG_USER, sizeof(*p), 0);
if (!p) {
pipe_cl_err("Out of Memory");
return NULL;
goto free_alloc;
}

memset(p, 0, sizeof(*p));

/* init pipeline */
p->heap = heap;
p->alloc = alloc;
p->comp_id = comp_id;
p->priority = priority;
p->pipeline_id = pipeline_id;
Expand Down Expand Up @@ -236,7 +257,10 @@ struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_

return p;
free:
sof_heap_free(heap, p);
sof_ctx_free(alloc, p);
free_alloc:
vregion_put(alloc->vreg);
rfree(alloc);
return NULL;
}

Expand Down Expand Up @@ -321,6 +345,8 @@ void pipeline_disconnect(struct comp_dev *comp, struct comp_buffer *buffer, int
/* pipelines must be inactive */
int pipeline_free(struct pipeline *p)
{
struct mod_alloc_ctx *alloc = p->alloc;

pipe_dbg(p, "entry");

/*
Expand All @@ -336,7 +362,12 @@ int pipeline_free(struct pipeline *p)
pipeline_posn_offset_put(p->posn_offset);

/* now free the pipeline */
sof_heap_free(p->heap, p);
sof_ctx_free(alloc, p);

/* free alloc context and vregion */
if (vregion_put(alloc->vreg))
pipe_cl_warn("pipeline vregion still in use");
sof_heap_free(alloc->heap, alloc);

/* show heap status */
heap_trace_all(0);
Expand Down Expand Up @@ -449,6 +480,10 @@ int pipeline_complete(struct pipeline *p, struct comp_dev *source,

p->source_comp = source;
p->sink_comp = sink;

if (p->alloc && p->alloc->vreg)
vregion_set_interim(p->alloc->vreg);

p->status = COMP_STATE_READY;

/* show heap status */
Expand Down
Loading
Loading