pipeline: implement proper position offset retrieval

Implements proper position offset retrieval in order to
update current stream position in mailbox. Previous one
was using pipeline_id in calculations, which has been
failing for bigger values. Lack of error handling has
also been a problem. This new solution uses predefined
list of available offsets and picks the first free from
the list. This way it will fail only if we exceed the
maximum number of simultaneously supported offsets.

Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
This commit is contained in:
Tomasz Lauda 2020-03-16 16:56:22 +01:00 committed by Tomasz Lauda
parent cff7ca4e4a
commit b20191b362
4 changed files with 102 additions and 3 deletions

View File

@ -63,10 +63,16 @@ struct pipeline *pipeline_new(struct sof_ipc_pipe_new *pipe_desc,
/* init pipeline */ /* init pipeline */
p->sched_comp = cd; p->sched_comp = cd;
p->posn_offset = pipe_desc->pipeline_id *
sizeof(struct sof_ipc_stream_posn);
p->status = COMP_STATE_INIT; p->status = COMP_STATE_INIT;
ret = pipeline_posn_offset_get(&p->posn_offset);
if (ret < 0) {
pipe_cl_err("pipeline_new() error: pipeline_posn_offset_get failed %d",
ret);
rfree(p);
return NULL;
}
ret = memcpy_s(&p->ipc_pipe, sizeof(p->ipc_pipe), ret = memcpy_s(&p->ipc_pipe, sizeof(p->ipc_pipe),
pipe_desc, sizeof(*pipe_desc)); pipe_desc, sizeof(*pipe_desc));
assert(!ret); assert(!ret);
@ -262,6 +268,8 @@ int pipeline_free(struct pipeline *p)
ipc_msg_free(p->msg); ipc_msg_free(p->msg);
pipeline_posn_offset_put(p->posn_offset);
/* now free the pipeline */ /* now free the pipeline */
rfree(p); rfree(p);

View File

@ -10,9 +10,15 @@
#include <sof/drivers/ipc.h> #include <sof/drivers/ipc.h>
#include <sof/lib/cpu.h> #include <sof/lib/cpu.h>
#include <sof/lib/mailbox.h>
#include <sof/lib/memory.h>
#include <sof/sof.h>
#include <sof/spinlock.h>
#include <sof/trace/trace.h> #include <sof/trace/trace.h>
#include <ipc/stream.h>
#include <ipc/topology.h> #include <ipc/topology.h>
#include <user/trace.h> #include <user/trace.h>
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -21,7 +27,6 @@ struct comp_dev;
struct ipc; struct ipc;
struct sof_ipc_buffer; struct sof_ipc_buffer;
struct sof_ipc_pcm_params; struct sof_ipc_pcm_params;
struct sof_ipc_stream_posn;
struct task; struct task;
/* /*
@ -79,6 +84,9 @@ struct task;
#define PPL_DIR_DOWNSTREAM 0 #define PPL_DIR_DOWNSTREAM 0
#define PPL_DIR_UPSTREAM 1 #define PPL_DIR_UPSTREAM 1
#define PPL_POSN_OFFSETS \
(MAILBOX_STREAM_SIZE / sizeof(struct sof_ipc_stream_posn))
/* /*
* Audio pipeline. * Audio pipeline.
*/ */
@ -107,6 +115,81 @@ struct pipeline {
/* static pipeline */ /* static pipeline */
extern struct pipeline *pipeline_static; extern struct pipeline *pipeline_static;
struct pipeline_posn {
bool posn_offset[PPL_POSN_OFFSETS]; /**< available offsets */
spinlock_t lock; /**< lock mechanism */
};
static SHARED_DATA struct pipeline_posn pipeline_posn;
/**
* \brief Retrieves pipeline position structure.
* \return Pointer to pipeline position structure.
*/
static inline struct pipeline_posn *pipeline_posn_get(void)
{
return sof_get()->pipeline_posn;
}
/**
* \brief Initializes pipeline position structure.
* \param[in,out] sof Pointer to sof structure.
*/
static inline void pipeline_posn_init(struct sof *sof)
{
sof->pipeline_posn = platform_shared_get(&pipeline_posn,
sizeof(pipeline_posn));
spinlock_init(&sof->pipeline_posn->lock);
platform_shared_commit(sof->pipeline_posn, sizeof(*sof->pipeline_posn));
}
/**
* \brief Retrieves first free pipeline position offset.
* \param[in,out] posn_offset Pipeline position offset to be set.
* \return Error code.
*/
static inline int pipeline_posn_offset_get(uint32_t *posn_offset)
{
struct pipeline_posn *pipeline_posn = pipeline_posn_get();
int ret = -EINVAL;
uint32_t i;
spin_lock(&pipeline_posn->lock);
for (i = 0; i < PPL_POSN_OFFSETS; ++i) {
if (!pipeline_posn->posn_offset[i]) {
*posn_offset = i * sizeof(struct sof_ipc_stream_posn);
pipeline_posn->posn_offset[i] = true;
ret = 0;
break;
}
}
platform_shared_commit(pipeline_posn, sizeof(*pipeline_posn));
spin_unlock(&pipeline_posn->lock);
return ret;
}
/**
* \brief Frees pipeline position offset.
* \param[in] posn_offset Pipeline position offset to be freed.
*/
static inline void pipeline_posn_offset_put(uint32_t posn_offset)
{
struct pipeline_posn *pipeline_posn = pipeline_posn_get();
int i = posn_offset / sizeof(struct sof_ipc_stream_posn);
spin_lock(&pipeline_posn->lock);
pipeline_posn->posn_offset[i] = false;
platform_shared_commit(pipeline_posn, sizeof(*pipeline_posn));
spin_unlock(&pipeline_posn->lock);
}
/* checks if two pipelines have the same scheduling component */ /* checks if two pipelines have the same scheduling component */
static inline bool pipeline_is_same_sched_comp(struct pipeline *current, static inline bool pipeline_is_same_sched_comp(struct pipeline *current,
struct pipeline *previous) struct pipeline *previous)

View File

@ -27,6 +27,7 @@ struct pm_runtime_data;
struct sa; struct sa;
struct timer; struct timer;
struct trace; struct trace;
struct pipeline_posn;
struct probe_pdata; struct probe_pdata;
/** /**
@ -95,6 +96,9 @@ struct sof {
/* probes */ /* probes */
struct probe_pdata *probe; struct probe_pdata *probe;
/* pipelines stream position */
struct pipeline_posn *pipeline_posn;
__aligned(PLATFORM_DCACHE_ALIGN) int alignment[0]; __aligned(PLATFORM_DCACHE_ALIGN) int alignment[0];
} __aligned(PLATFORM_DCACHE_ALIGN); } __aligned(PLATFORM_DCACHE_ALIGN);

View File

@ -9,6 +9,7 @@
*/ */
#include <sof/audio/component_ext.h> #include <sof/audio/component_ext.h>
#include <sof/audio/pipeline.h>
#include <sof/debug/panic.h> #include <sof/debug/panic.h>
#include <sof/drivers/ipc.h> #include <sof/drivers/ipc.h>
#include <sof/lib/alloc.h> #include <sof/lib/alloc.h>
@ -104,6 +105,9 @@ int task_main_start(struct sof *sof)
/* init self-registered modules */ /* init self-registered modules */
sys_module_init(); sys_module_init();
/* init pipeline position offsets */
pipeline_posn_init(sof);
#if STATIC_PIPE #if STATIC_PIPE
/* init static pipeline */ /* init static pipeline */
ret = init_static_pipeline(sof->ipc); ret = init_static_pipeline(sof->ipc);