Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/audio/component.c
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ static bool comp_check_eos(struct comp_dev *dev)
enum sof_audio_buffer_state sink_state = AUDIOBUF_STATE_INITIAL;
struct comp_buffer *buffer;

if (!dev->pipeline->expect_eos)
if (!dev->expect_eos)
return false;

comp_dev_for_each_producer(dev, buffer) {
Expand Down
2 changes: 1 addition & 1 deletion src/audio/host-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ static inline bool host_handle_eos(struct host_data *hd, struct comp_dev *dev,
struct sof_audio_buffer *buffer = &hd->local_buffer->audio_buffer;
enum sof_audio_buffer_state state = audio_buffer_get_state(buffer);

if (!dev->pipeline->expect_eos)
if (!dev->expect_eos)
return false;

if (!avail_samples) {
Expand Down
6 changes: 3 additions & 3 deletions src/audio/module_adapter/module/cadence.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LOG_MODULE_REGISTER(cadence_codec, CONFIG_SOF_LOG_LEVEL);
/*****************************************************************************/
/* Cadence API functions array */
/*****************************************************************************/
struct cadence_api cadence_api_table[] = {
const struct cadence_api cadence_api_table[] = {
#ifdef CONFIG_CADENCE_CODEC_WRAPPER
{
.id = CADENCE_CODEC_WRAPPER_ID,
Expand Down Expand Up @@ -541,7 +541,7 @@ int cadence_codec_process_data(struct processing_module *mod,
return 0;
}

if (dev->pipeline->expect_eos) {
if (dev->expect_eos) {
/* Signal that the stream is expected to end anytime soon */
API_CALL(cd, XA_API_CMD_INPUT_OVER, 0, NULL, ret);
if (ret != LIB_NO_ERROR) {
Expand Down Expand Up @@ -596,7 +596,7 @@ int cadence_codec_process_data(struct processing_module *mod,
return ret;
}

if (dev->pipeline->expect_eos) {
if (dev->expect_eos) {
/*
* AAC decoder cannot signal DONE, check if it stopped
* producing data when EOS is expected
Expand Down
16 changes: 10 additions & 6 deletions src/audio/module_adapter/module/generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,13 @@ int module_init(struct processing_module *mod)

/* Now we can proceed with module specific initialization */
#if CONFIG_SOF_USERSPACE_APPLICATION
if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP)
ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_INIT_INSTANCE, NULL);
else
if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) {
union scheduler_dp_thread_ipc_param param = {
.ext_data = mod->priv.cfg.ext_data,
};

ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_INIT_INSTANCE, &param);
} else
#endif
ret = interface->init(mod);

Expand Down Expand Up @@ -202,9 +206,9 @@ void *z_impl_mod_balloc_align(struct processing_module *mod, size_t size, size_t
return NULL;
}

/* Allocate buffer memory for module */
void *ptr = sof_heap_alloc(res->alloc->heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER,
size, alignment);
/* Allocate buffer memory for module, same as mod_alloc_ext() */
void *ptr = sof_ctx_alloc(res->alloc, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER,
size, alignment);

if (!ptr) {
comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.",
Expand Down
33 changes: 33 additions & 0 deletions src/audio/pipeline/pipeline-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,39 @@ int pipeline_free(struct pipeline *p)
return 0;
}

static int pipeline_comp_set_eos(struct comp_dev *current,
struct comp_buffer *calling_buf,
struct pipeline_walk_context *ctx, int dir)
{
if (ctx->comp_data != (void *)current->pipeline)
return 0;

current->expect_eos = *(bool *)ctx->buff_data;

return pipeline_for_each_comp(current, ctx, dir);
}

void pipeline_set_eos(struct pipeline *p, bool eos)
{
struct pipeline_walk_context walk_ctx = {
.comp_func = pipeline_comp_set_eos,
.comp_data = p,
.buff_data = &eos,
};
struct comp_dev *start;
int dir;

if (p->source_comp->direction == SOF_IPC_STREAM_PLAYBACK) {
dir = PPL_DIR_UPSTREAM;
start = p->sink_comp;
} else {
dir = PPL_DIR_DOWNSTREAM;
start = p->source_comp;
}

walk_ctx.comp_func(start, NULL, &walk_ctx, dir);
}

static int pipeline_comp_complete(struct comp_dev *current,
struct comp_buffer *calling_buf,
struct pipeline_walk_context *ctx, int dir)
Expand Down
1 change: 1 addition & 0 deletions src/include/sof/audio/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ struct comp_dev {
/* runtime */
uint16_t state; /**< COMP_STATE_ */
uint32_t frames; /**< number of frames we copy to sink */
bool expect_eos; /**< end of stream expected */
struct pipeline *pipeline; /**< pipeline we belong to */

struct task *task; /**< component's processing task used
Expand Down
2 changes: 1 addition & 1 deletion src/include/sof/audio/module_adapter/module/cadence.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ struct ipc4_cadence_module_cfg {
} __packed __aligned(4);
#endif

extern struct cadence_api cadence_api_table[];
extern const struct cadence_api cadence_api_table[];

int cadence_codec_set_configuration(struct processing_module *mod, uint32_t config_id,
enum module_cfg_fragment_position pos,
Expand Down
8 changes: 7 additions & 1 deletion src/include/sof/audio/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ struct pipeline {
int32_t xrun_bytes; /* last xrun length */
uint32_t status; /* pipeline status */
struct tr_ctx tctx; /* trace settings */
bool expect_eos; /* pipeline is expecting end of stream */

/* scheduling */
#ifdef CONFIG_IPC_MAJOR_4
Expand Down Expand Up @@ -225,6 +224,13 @@ void pipeline_posn_grant_access(struct k_thread *thread);
*/
int pipeline_reset(struct pipeline *p, struct comp_dev *host_cd);

/**
* \brief Sets End Of Stream state for all devices in the pipeline.
* \param[in] p pipeline.
* \param[in] eos End Of Stream state.
*/
void pipeline_set_eos(struct pipeline *p, bool eos);

/**
* \brief Walks the pipeline graph for each component.
* \param[in] current Current pipeline component.
Expand Down
6 changes: 6 additions & 0 deletions src/include/sof/schedule/dp_schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <ipc4/pipeline.h>

struct processing_module;
struct module_ext_init_data;

/**
*
Expand Down Expand Up @@ -115,6 +116,11 @@ struct sof_sink;
*/
union scheduler_dp_thread_ipc_param {
const struct bind_info *bind_data;
/* SOF_IPC4_MOD_INIT_INSTANCE: ext_data points to the caller's stack frame and is
* only valid until scheduler_dp_thread_ipc() returns; ipc_thread_flatten() copies
* it by value into DP-thread-accessible memory before the DP thread runs init().
*/
const struct module_ext_init_data *ext_data;
struct {
unsigned int trigger_cmd;
enum ipc4_pipeline_state state;
Expand Down
6 changes: 3 additions & 3 deletions src/ipc/ipc4/handler-user.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd)

switch (cmd) {
case SOF_IPC4_PIPELINE_STATE_RUNNING:
if (ppl_icd->pipeline->expect_eos) {
if (ppl_icd->pipeline->source_comp && ppl_icd->pipeline->source_comp->expect_eos) {
ipc_cmd_err(&ipc_tr, "pipeline %d: Can't transition from EOS to RUNNING",
ppl_icd->id);
return IPC4_INVALID_REQUEST;
Expand Down Expand Up @@ -320,7 +320,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd)
ppl_icd->id, status);
return IPC4_INVALID_REQUEST;
}
ppl_icd->pipeline->expect_eos = true;
pipeline_set_eos(ppl_icd->pipeline, true);
return 0; /* Must return here. Any other transition clears expect_eos. */
/* special case - TODO */
case SOF_IPC4_PIPELINE_STATE_SAVED:
Expand All @@ -334,7 +334,7 @@ int ipc4_pipeline_prepare(struct ipc_comp_dev *ppl_icd, uint32_t cmd)
if (ret < 0)
return IPC4_INVALID_REQUEST;

ppl_icd->pipeline->expect_eos = false;
pipeline_set_eos(ppl_icd->pipeline, false);

return ret;
}
Expand Down
18 changes: 18 additions & 0 deletions src/library_manager/llext_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,14 @@ static int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx, unsigne
{
unsigned int i;

/*
* n_mod == 0 is reachable for a genuine (non-NULL) library context, e.g.
* before its module segments are registered - without this check the
* i == 0 case below reads ctx->mod[-1], out of bounds.
*/
if (!ctx->n_mod)
return -ENOENT;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all three of these changes are needed? With the below 2 changes, this one might not be needed any more?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only the ctx->n_mod check is needed


for (i = 0; i < ctx->n_mod; i++)
if (ctx->mod[i].start_idx > idx)
break;
Expand Down Expand Up @@ -1002,6 +1010,11 @@ static int llext_manager_add_mod_domain(struct lib_manager_module *mctx, struct
int llext_manager_add_domain(const uint32_t component_id, struct k_mem_domain *domain)
{
const uint32_t module_id = IPC4_MOD_ID(component_id);

/* Native (base firmware) modules aren't managed by lib_manager, nothing to add */
if (!LIB_MANAGER_GET_LIB_ID(module_id))
return 0;

struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id);
const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id);
const int mod_idx = llext_manager_mod_find(ctx, entry_index);
Expand Down Expand Up @@ -1087,6 +1100,11 @@ static int llext_manager_rm_mod_domain(struct lib_manager_module *mctx, struct k
int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *domain)
{
const uint32_t module_id = IPC4_MOD_ID(component_id);

/* Native (base firmware) modules aren't managed by lib_manager, nothing to remove */
if (!LIB_MANAGER_GET_LIB_ID(module_id))
return 0;

struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id);
const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id);
const int mod_idx = llext_manager_mod_find(ctx, entry_index);
Expand Down
20 changes: 20 additions & 0 deletions src/schedule/zephyr_dp_schedule_application.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ struct ipc4_flat {
struct sof_source *source[CONFIG_MODULE_MAX_CONNECTIONS];
struct sof_sink *sink[CONFIG_MODULE_MAX_CONNECTIONS];
} pipeline_state;
/*
* SOF_IPC4_MOD_INIT_INSTANCE: a by-value copy of the caller's
* ext_data. The original lives on the calling thread's stack,
* which the DP thread's memory domain doesn't have access to.
* The pointers it contains reference the IPC mailbox, which stays
* valid and is covered by the DP thread's SOF_DP_PART_CFG partition.
*/
struct module_ext_init_data init_instance;
};
};

Expand All @@ -73,6 +81,12 @@ static int ipc_thread_flatten(unsigned int cmd, const union scheduler_dp_thread_
flat->bind.bu = *param->bind_data->ipc4_data;
flat->bind.type = param->bind_data->bind_type;
break;
case SOF_IPC4_MOD_INIT_INSTANCE:
if (param->ext_data)
flat->init_instance = *param->ext_data;
else
flat->init_instance = (struct module_ext_init_data){ 0 };
break;
case SOF_IPC4_GLB_SET_PIPELINE_STATE:
flat->pipeline_state.trigger_cmd = param->pipeline_state.trigger_cmd;
switch (param->pipeline_state.trigger_cmd) {
Expand Down Expand Up @@ -133,7 +147,13 @@ static void ipc_thread_unflatten_run(struct processing_module *pmod, struct ipc4
flat->ret = ops->free(pmod);
break;
case SOF_IPC4_MOD_INIT_INSTANCE:
/*
* Repoint ext_data at the copy ipc_thread_flatten() made in DP-thread-
* accessible memory; the original caller-stack copy is out of reach here.
*/
pmod->priv.cfg.ext_data = &flat->init_instance;
flat->ret = ops->init(pmod);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, that's because the only tested until now module in DP mode was SRC and it doesn't access .ext_data in its struct module_interface instance

pmod->priv.cfg.ext_data = NULL;
break;
case SOF_IPC4_GLB_SET_PIPELINE_STATE:
switch (flat->pipeline_state.trigger_cmd) {
Expand Down
2 changes: 1 addition & 1 deletion test/cmocka/src/audio/mux/demux_copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ static int setup_test_case(void **state)
dummy_pipe = test_malloc(sizeof(*dummy_pipe));
if (!dummy_pipe)
return -ENOMEM;
dummy_pipe->expect_eos = false;
dev->expect_eos = false;
dev->pipeline = dummy_pipe;

mod = comp_mod(dev);
Expand Down
2 changes: 1 addition & 1 deletion test/cmocka/src/audio/mux/mux_copy.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ static int setup_test_case(void **state)
dummy_pipe = test_malloc(sizeof(*dummy_pipe));
if (!dummy_pipe)
return -ENOMEM;
dummy_pipe->expect_eos = false;
dev->expect_eos = false;
dev->pipeline = dummy_pipe;

mod = comp_mod(dev);
Expand Down
10 changes: 10 additions & 0 deletions tools/topology/topology2/include/components/decoder.conf
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ Class.Widget."decoder" {

# cadence codec UUID
uuid "43:84:21:d8:f3:5f:4c:4a:b3:88:6c:fe:07:b9:56:aa"

# Cadence codec memory tables (persist/scratch/input/output) can exceed the
# generic widget-common.conf default; give decoders more headroom. This same
# vregion also backs every buffer bound to a DP module (ipc4_comp_connect()
# allocates from dp->mod->priv.resources.alloc), so it must cover the
# codec's own memory tables plus every connected buffer, not just the codec.
heap_bytes_requirement 196608

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be squashed with an earlier one

# Cadence codec init (e.g. xa_aac_dec) can need more stack than the
# generic widget-common.conf default when run in the DP userspace thread.
stack_bytes_requirement 16384
no_pm "true"
num_output_pins 1
num_input_pins 1
Expand Down
10 changes: 10 additions & 0 deletions tools/topology/topology2/include/components/encoder.conf
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ Class.Widget."encoder" {

# cadence codec UUID
uuid "43:84:21:d8:f3:5f:4c:4a:b3:88:6c:fe:07:b9:56:aa"

# Cadence codec memory tables (persist/scratch/input/output) can exceed the
# generic widget-common.conf default; give encoders more headroom. This same
# vregion also backs every buffer bound to a DP module (ipc4_comp_connect()
# allocates from dp->mod->priv.resources.alloc), so it must cover the
# codec's own memory tables plus every connected buffer, not just the codec.
heap_bytes_requirement 131072
# Cadence codec init (e.g. xa_mp3_enc) can need more stack than the
# generic widget-common.conf default when run in the DP userspace thread.
stack_bytes_requirement 16384
no_pm "true"
num_output_pins 1
num_input_pins 1
Expand Down
11 changes: 9 additions & 2 deletions zephyr/lib/vregion.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,15 @@ struct vregion *vregion_create(size_t memsize)
*/
total_size = ALIGN_UP(memsize, CONFIG_MM_DRV_PAGE_SIZE);

/* allocate vregion metadata separately to keep it inaccessible to the user */
vr = rmalloc(0, sizeof(*vr));
/*
* allocate vregion metadata separately to keep it inaccessible to the
* user. The vregion is created on the DP module's own core but is
* later read/written from other cores too (e.g. buffer_new() on the
* IPC core routes through it for buffers connecting to this module),
* so it must be coherent - plain cached memory left writes from the
* creating core invisible to other cores without an explicit flush.
*/
vr = rmalloc(SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, sizeof(*vr));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

until now all accesses to vregion metadata were taking place on the same core. Do you have a DP module on a core different, than the rest of the pipeline?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like we do — the decoder/encoder consistently ends up on core 1 while the rest of the pipeline (and the IPC thread connecting buffers to it) runs on core 0.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, @jsarha was saying that it didn't work for him IIRC?

if (!vr)
return NULL;

Expand Down
Loading