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
3 changes: 2 additions & 1 deletion src/audio/pipeline/pipeline-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ void pipeline_posn_init(struct sof *sof)
}

/* create new pipeline - returns pipeline id or negative error */
struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id)
struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id,
struct pipeline_params *pparams)
{
struct sof_ipc_stream_posn posn;
struct pipeline *p;
Expand Down
38 changes: 37 additions & 1 deletion src/include/ipc4/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,41 @@ enum ipc4_pipeline_state {
SOF_IPC4_PIPELINE_STATE_SAVED
};

/* IDs for all pipeline ext data types in struct ipc4_pipeline_init_ext_object */
enum ipc4_pipeline_ext_obj_id {
IPC4_GLB_PIPE_EXT_OBJ_ID_INVALID = 0,
IPC4_GLB_PIPE_EXT_OBJ_ID_MEM_DATA = 1,
IPC4_GLB_PIPE_EXT_OBJ_ID_MAX = IPC4_GLB_PIPE_EXT_OBJ_ID_MEM_DATA,
};

/* data object for vendor bespoke data with ABI growth and backwards compat */
struct ipc4_pipeline_ext_object {
uint32_t last_object : 1; /* object is last in array if 1 else object follows. */
uint32_t object_id : 15; /* unique ID for this object or globally */
uint32_t object_words : 16; /* size in dwords (excluding this structure) */
} __packed __aligned(4);
/* the object data will be placed in memory here and will have size "object_words" */

/* Ext array data object for pipeline instance's memory requirements */
struct ipc4_pipeline_ext_obj_mem_data {
uint32_t domain_id; /* userspace domain ID */
uint32_t stack_bytes; /* required stack size in bytes */
uint32_t heap_bytes; /* required heap size in bytes */
uint32_t lifetime_bytes;/* required memory for init in bytes */
uint32_t shared_bytes; /* required shared memory in bytes */
} __packed __aligned(4);
Copy link
Collaborator

Choose a reason for hiding this comment

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

on the one hand bytes are simple to understand and work with. OTOH if we use a larger unit (words, or cache lines, or pages), then we (1) can potentially use a smaller integer, (2) avoid the need to check and enforce alignment. No strong preference, just a thought

Copy link
Member

Choose a reason for hiding this comment

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

bytes fine here since these are uint32_t - we should have enough space.


/*
* Host Driver sends this message to create a new pipeline instance.
*/
struct ipc4_pipeline_ext_payload {
uint32_t payload_words : 24; /* size in dwords (excluding this structure) */
uint32_t data_obj_array : 1; /* struct ipc4_pipeline_ext_object data */
uint32_t rsvd0 : 7;
uint32_t rsvd1;
uint32_t rsvd2;
} __packed __aligned(4);

/*!
* lp - indicates whether the pipeline should be kept on running in low power
* mode. On BXT the driver should set this flag to 1 for WoV pipeline.
Expand Down Expand Up @@ -106,7 +141,8 @@ struct ipc4_pipeline_create {
uint32_t rsvd1 : 3;
uint32_t attributes : 16;
uint32_t core_id : 4;
uint32_t rsvd2 : 6;
uint32_t rsvd2 : 5;
uint32_t payload : 1;
uint32_t _reserved_2 : 2;
} r;
} extension;
Expand Down
13 changes: 12 additions & 1 deletion src/include/sof/audio/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ struct pipeline_task {
struct comp_dev *sched_comp; /**< pipeline scheduling component */
};

/** \brief For storing IPC payload data. */
struct pipeline_params {
uint32_t domain_id;
size_t stack_bytes;
size_t lifetime_bytes;
size_t interim_bytes;
size_t shared_bytes;
};

#define pipeline_task_get(t) container_of(t, struct pipeline_task, task)

/*
Expand All @@ -148,9 +157,11 @@ struct pipeline_task {
* \param[in] pipeline_id Pipeline ID number.
* \param[in] priority Pipeline scheduling priority.
* \param[in] comp_id Pipeline component ID number.
* \param[in] pparams Pipeline parameters from IPC payload, maybe NULL.
* \return New pipeline pointer or NULL.
*/
struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id);
struct pipeline *pipeline_new(uint32_t pipeline_id, uint32_t priority, uint32_t comp_id,
struct pipeline_params *pparams);

/**
* \brief Free's a pipeline.
Expand Down
2 changes: 1 addition & 1 deletion src/ipc/ipc3/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc)

/* create the pipeline */
pipe = pipeline_new(pipe_desc->pipeline_id, pipe_desc->priority,
pipe_desc->comp_id);
pipe_desc->comp_id, NULL);
if (!pipe) {
tr_err(&ipc_tr, "pipeline_new() failed");
return -ENOMEM;
Expand Down
123 changes: 117 additions & 6 deletions src/ipc/ipc4/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i
ipc_config.ipc_config_size = module_init->extension.r.param_block_size * sizeof(uint32_t);
ipc_config.ipc_extended_init = module_init->extension.r.extended_init;

dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE,
MAILBOX_HOSTBOX_SIZE);
sys_cache_data_invd_range((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE,
ipc_config.ipc_config_size);

data = ipc4_get_comp_new_data();

Expand Down Expand Up @@ -229,7 +229,92 @@ struct ipc_comp_dev *ipc_get_comp_by_ppl_id(struct ipc *ipc, uint16_t type,
return NULL;
}

__cold static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc)
/*
* This function currently only decodes the payload and prints out
* data it finds, but it does not store it anywhere.
*/
__cold static int ipc4_create_pipeline_payload_decode(char *data, struct pipeline_params *pparams)
{
const struct ipc4_pipeline_ext_payload *hdr =
(struct ipc4_pipeline_ext_payload *)data;
const struct ipc4_pipeline_ext_object *obj;
size_t hdr_cache_size = ALIGN_UP(sizeof(*hdr), CONFIG_DCACHE_LINE_SIZE);
bool last_object;
size_t size;

sys_cache_data_invd_range((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE,
hdr_cache_size);
size = hdr->payload_words * sizeof(uint32_t);
last_object = !hdr->data_obj_array;

if (hdr->payload_words * sizeof(uint32_t) < sizeof(*hdr)) {
tr_err(&ipc_tr, "Payload size too small: %u : %#x", hdr->payload_words,
*((uint32_t *)hdr));
return -EINVAL;
}

tr_info(&ipc_tr, "payload size %u array %u: %#x", hdr->payload_words, hdr->data_obj_array,
*((uint32_t *)hdr));

if (ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE) > hdr_cache_size)
sys_cache_data_invd_range((__sparse_force void __sparse_cache *)
((char *)MAILBOX_HOSTBOX_BASE + hdr_cache_size),
ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE) -
hdr_cache_size);

obj = (const struct ipc4_pipeline_ext_object *)(hdr + 1);
while (!last_object) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

for (obj = (const struct ipc4_pipeline_ext_object *)(hdr + 1); !last_object; obj = next_obj)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like while() better, especially as its now a better match to module_ext_init_decode() implementation

const struct ipc4_pipeline_ext_object *next_obj;

/* Check if there is space for the object header */
if ((char *)(obj + 1) - data > size) {
tr_err(&ipc_tr, "obj header overflow, %u > %u",
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't the format be %zu for size here and below?

(char *)(obj + 1) - data, size);
return -EINVAL;
}

/* Calculate would be next object position and check if current object fits */
next_obj = (const struct ipc4_pipeline_ext_object *)
(((uint32_t *)(obj + 1)) + obj->object_words);
if ((char *)next_obj - data > size) {
tr_err(&ipc_tr, "object size overflow, %u > %u",
(char *)obj - data, size);
return -EINVAL;
}

switch (obj->object_id) {
case IPC4_GLB_PIPE_EXT_OBJ_ID_MEM_DATA:
{
/* Get mem_data struct that follows the obj struct */
const struct ipc4_pipeline_ext_obj_mem_data *mem_data =
(const struct ipc4_pipeline_ext_obj_mem_data *)(obj + 1);

if (obj->object_words * sizeof(uint32_t) < sizeof(*mem_data)) {
tr_err(&ipc_tr, "mem_data object does not fit %u < %u",
obj->object_words * sizeof(uint32_t), sizeof(*mem_data));
return -EINVAL;
}
tr_info(&ipc_tr,
"init_ext_obj_mem_data domain %u stack %u heap %u lifetime %u shared %u",
mem_data->domain_id, mem_data->stack_bytes, mem_data->heap_bytes,
mem_data->lifetime_bytes, mem_data->shared_bytes);
break;
}
default:
tr_info(&ipc_tr, "Unknown ext init object id %u of %u words",
Copy link
Collaborator

Choose a reason for hiding this comment

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

tr_warn() or tr_dbg()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you have agains info 😄? If I must change this I'd go with warn, as if somebody is indeed reading the logs, it could be useful to know that the firmware is not able to use all info from the pipeline create payload.

Copy link
Collaborator

Choose a reason for hiding this comment

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

supposedly we have all the different logging levels for a reason, so we might as well use them ;-) It's just that a message, beginning with "Unknown" but with a neutral status is a bit unclear to me. Is it bad or not? If it isn't bad - do I need to know about it? If not - maybe make it dbg(). If it does indeed indicate a potential problem, then a warn()

obj->object_id, obj->object_words);
}
/* Read the last object flag from obj header */
last_object = obj->last_object;
/* Move to next object */
obj = next_obj;
}

return 0;
}

__cold static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc,
struct pipeline_params *pparams)
{
struct ipc_comp_dev *ipc_pipe;
struct pipeline *pipe;
Expand All @@ -246,7 +331,8 @@ __cold static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc)
}

/* create the pipeline */
pipe = pipeline_new(pipe_desc->primary.r.instance_id, pipe_desc->primary.r.ppl_priority, 0);
pipe = pipeline_new(pipe_desc->primary.r.instance_id, pipe_desc->primary.r.ppl_priority, 0,
pparams);
if (!pipe) {
tr_err(&ipc_tr, "ipc: pipeline_new() failed");
return IPC4_OUT_OF_MEMORY;
Expand Down Expand Up @@ -280,11 +366,28 @@ __cold static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc)
return IPC4_SUCCESS;
}

#if CONFIG_LIBRARY
static inline char *ipc4_get_pipe_create_data(void)
{
struct ipc *ipc = ipc_get();
char *data = (char *)ipc->comp_data + sizeof(struct ipc4_pipeline_create);

return data;
}
#else
__cold static inline char *ipc4_get_pipe_create_data(void)
{
assert_can_be_cold();

return (char *)MAILBOX_HOSTBOX_BASE;
}
#endif

/* Only called from ipc4_new_pipeline(), which is __cold */
__cold int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc)
{
struct ipc4_pipeline_create *pipe_desc = ipc_from_pipe_new(_pipe_desc);

struct pipeline_params pparams;
assert_can_be_cold();

tr_dbg(&ipc_tr, "ipc: pipeline id = %u", (uint32_t)pipe_desc->primary.r.instance_id);
Expand All @@ -293,7 +396,15 @@ __cold int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc)
if (!cpu_is_me(pipe_desc->extension.r.core_id))
return ipc4_process_on_core(pipe_desc->extension.r.core_id, false);

return ipc4_create_pipeline(pipe_desc);
if (pipe_desc->extension.r.payload) {
char *data;

data = ipc4_get_pipe_create_data();

ipc4_create_pipeline_payload_decode(data, &pparams);
}

return ipc4_create_pipeline(pipe_desc, &pparams);
}

__cold static inline int ipc_comp_free_remote(struct comp_dev *dev)
Expand Down
3 changes: 2 additions & 1 deletion test/cmocka/src/audio/pipeline/pipeline_new.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ static void test_audio_pipeline_pipeline_new_creation(void **state)
/*Testing component*/
struct pipeline *result = pipeline_new(test_data->pipe_id,
test_data->priority,
test_data->comp_id);
test_data->comp_id,
NULL);

/*Pipeline should have been created so pointer can't be null*/
assert_non_null(result);
Expand Down
2 changes: 2 additions & 0 deletions tools/topology/topology2/include/common/tokens.conf
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Object.Base.VendorToken {
domain_id 419
stack_bytes_requirement 420
heap_bytes_requirement 421
lifetime_bytes_requirement 422
shared_bytes_requirement 423
}

"2" {
Expand Down
19 changes: 19 additions & 0 deletions tools/topology/topology2/include/components/widget-common.conf
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,22 @@ DefineAttribute."heap_bytes_requirement" {
token_ref "comp.word"
}

## Liftime memory alllocation requirement in bytes for this component.
## this token's value indicates the amount of allocated memory needed at component init phase
DefineAttribute."lifetime_bytes_requirement" {
# Token set reference name and type
token_ref "comp.word"
}

## Shared memory alllocation requirement in bytes for this component.
## this token's value indicates the amount of shared memory the component may need to alocated
DefineAttribute."shared_bytes_requirement" {
# Token set reference name and type
token_ref "comp.word"
}

# These default values are here until we have measured module specif numbers
stack_bytes_requirement 8192
heap_bytes_requirement 4096
lifetime_bytes_requirement 16384
shared_bytes_requirement 4096
Loading