copier: New pipeline latency calculation algorithm

New algorithm for calculating the pipeline latency based on
the number of buffered data blocks between the first and last
component.

Signed-off-by: Adrian Warecki <adrian.warecki@intel.com>
This commit is contained in:
Adrian Warecki 2022-07-01 22:37:39 +02:00 committed by Liam Girdwood
parent e8c34fd62e
commit c4f4c978af
5 changed files with 126 additions and 36 deletions

View File

@ -399,12 +399,17 @@ static int create_dai(struct comp_dev *parent_dev, struct copier_data *cd,
return ret;
}
static int init_pipeline_reg(struct copier_data *cd)
static int init_pipeline_reg(struct comp_dev *dev)
{
struct copier_data *cd = comp_get_drvdata(dev);
struct ipc4_pipeline_registers pipe_reg;
uint8_t gateway_id;
uint32_t gateway_id;
int ret;
ret = comp_get_attribute(dev, COMP_ATTR_VDMA_INDEX, &gateway_id);
if (ret)
return ret;
gateway_id = cd->config.gtw_cfg.node_id.f.v_index;
if (gateway_id >= IPC4_MAX_PIPELINE_REG_SLOTS) {
comp_cl_err(&comp_copier, "gateway_id %u out of array bounds.", gateway_id);
return -EINVAL;
@ -483,7 +488,7 @@ static struct comp_dev *copier_new(const struct comp_driver *drv,
if (cd->direction == SOF_IPC_STREAM_PLAYBACK) {
ipc_pipe->pipeline->source_comp = dev;
if (init_pipeline_reg(cd))
if (init_pipeline_reg(dev))
goto error_cd;
} else {
ipc_pipe->pipeline->sink_comp = dev;
@ -692,9 +697,9 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd)
if (ret < 0 || !cd->endpoint_num || !cd->pipeline_reg_offset)
return ret;
dai_copier = pipeline_get_dai_comp(dev->pipeline->pipeline_id, &latency);
dai_copier = pipeline_get_dai_comp_latency(dev->pipeline->pipeline_id, &latency);
if (!dai_copier) {
comp_err(dev, "failed to find dai comp");
comp_err(dev, "failed to find dai comp or sink pipeline not running.");
return ret;
}
@ -713,7 +718,7 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd)
return 0;
}
comp_position(dai_cd->endpoint[IPC4_COPIER_GATEWAY_PIN], &posn);
comp_position(dai_copier, &posn);
/* update stream start and end offset for running message in host copier
* host driver uses DMA link counter to calculate stream position, but it is
@ -1239,6 +1244,33 @@ static uint64_t copier_get_processed_data(struct comp_dev *dev, uint32_t stream_
return ret;
}
static int copier_get_attribute(struct comp_dev *dev, uint32_t type, void *value)
{
struct copier_data *cd = comp_get_drvdata(dev);
switch (type) {
case COMP_ATTR_VDMA_INDEX:
*(uint32_t *)value = cd->config.gtw_cfg.node_id.f.v_index;
break;
default:
return -EINVAL;
}
return 0;
}
static int copier_position(struct comp_dev *dev, struct sof_ipc_stream_posn *posn)
{
struct copier_data *cd = comp_get_drvdata(dev);
/* Exit if no endpoints */
if (!cd->endpoint_num)
return -EINVAL;
/* Return position from the default gateway pin */
return comp_position(cd->endpoint[IPC4_COPIER_GATEWAY_PIN], posn);
}
static const struct comp_driver comp_copier = {
.uid = SOF_RT_UUID(copier_comp_uuid),
.tctx = &copier_comp_tr,
@ -1253,6 +1285,8 @@ static const struct comp_driver comp_copier = {
.prepare = copier_prepare,
.reset = copier_reset,
.get_total_data_processed = copier_get_processed_data,
.get_attribute = copier_get_attribute,
.position = copier_position,
},
};

View File

@ -422,48 +422,94 @@ int pipeline_for_each_comp(struct comp_dev *current,
return 0;
}
/* visit connected pipeline to find the dai comp and latency */
struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id, uint32_t *latency)
/* visit connected pipeline to find the dai comp */
struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id)
{
struct ipc_comp_dev *sink;
struct ipc *ipc = ipc_get();
*latency = 0;
sink = ipc_get_ppl_sink_comp(ipc, pipeline_id);
if (!sink)
return NULL;
while (sink) {
struct comp_dev *buff_comp;
struct comp_buffer *buffer;
struct comp_dev *comp;
*latency += sink->cd->pipeline->period;
/* dai is found */
if (list_is_empty(&sink->cd->bsink_list)) {
struct list_item *list;
list = comp_buffer_list(sink->cd, PPL_DIR_UPSTREAM);
buffer = buffer_from_list(list->next, struct comp_buffer, PPL_DIR_UPSTREAM);
break;
}
if (list_is_empty(&sink->cd->bsink_list))
return sink->cd;
buffer = buffer_from_list(comp_buffer_list(sink->cd, PPL_DIR_DOWNSTREAM)->next,
struct comp_buffer, PPL_DIR_DOWNSTREAM);
buff_comp = buffer_get_comp(buffer, PPL_DIR_DOWNSTREAM);
comp = buffer_get_comp(buffer, PPL_DIR_DOWNSTREAM);
/* buffer_comp is in another pipeline and it is not complete */
if (!buff_comp->pipeline)
if (!comp->pipeline)
return NULL;
sink = ipc_get_ppl_sink_comp(ipc, buff_comp->pipeline->pipeline_id);
if (!sink)
return NULL;
sink = ipc_get_ppl_sink_comp(ipc, comp->pipeline->pipeline_id);
}
/* convert it to ms */
*latency /= 1000;
return sink->cd;
return NULL;
}
#if CONFIG_IPC_MAJOR_4
/* visit connected pipeline to find the dai comp and latency.
* This function walks down through a pipelines chain looking for the target dai component.
* Calculates the delay of each pipeline by determining the number of buffered blocks.
*/
struct comp_dev *pipeline_get_dai_comp_latency(uint32_t pipeline_id, uint32_t *latency)
{
struct ipc_comp_dev *ipc_sink;
struct ipc_comp_dev *ipc_source;
struct comp_dev *source;
struct ipc *ipc = ipc_get();
*latency = 0;
/* Walks through the ipc component list and get source endpoint component of the given
* pipeline.
*/
ipc_source = ipc_get_ppl_src_comp(ipc, pipeline_id);
if (!ipc_source)
return NULL;
source = ipc_source->cd;
/* Walks through the ipc component list and get sink endpoint component of the given
* pipeline. This function returns the first sink. We assume that dai is connected to pin 0.
*/
ipc_sink = ipc_get_ppl_sink_comp(ipc, pipeline_id);
while (ipc_sink) {
struct comp_buffer *buffer;
uint64_t input_data, output_data;
struct ipc4_base_module_cfg *input_base_cfg;
struct ipc4_base_module_cfg *output_base_cfg;
/* Calculate pipeline latency */
input_data = comp_get_total_data_processed(source, 0, true);
output_data = comp_get_total_data_processed(ipc_sink->cd, 0, false);
if (!input_data || !output_data)
return NULL;
input_base_cfg = ipc4_comp_get_base_module_cfg(source);
output_base_cfg = ipc4_comp_get_base_module_cfg(ipc_sink->cd);
*latency += input_data / input_base_cfg->ibs - output_data / output_base_cfg->obs;
/* If the component doesn't have a sink buffer, this is a dai. */
if (list_is_empty(&ipc_sink->cd->bsink_list))
return ipc_sink->cd;
/* Get a component connected to our sink buffer - hop to a next pipeline */
buffer = buffer_from_list(comp_buffer_list(ipc_sink->cd, PPL_DIR_DOWNSTREAM)->next,
struct comp_buffer, PPL_DIR_DOWNSTREAM);
source = buffer_get_comp(buffer, PPL_DIR_DOWNSTREAM);
/* buffer_comp is in another pipeline and it is not complete */
if (!source->pipeline)
return NULL;
/* Get a next sink component */
ipc_sink = ipc_get_ppl_sink_comp(ipc, source->pipeline->pipeline_id);
}
return NULL;
}
#endif

View File

@ -128,6 +128,7 @@ enum {
#define COMP_ATTR_COPY_TYPE 0 /**< Comp copy type attribute */
#define COMP_ATTR_HOST_BUFFER 1 /**< Comp host buffer attribute */
#define COMP_ATTR_COPY_DIR 2 /**< Comp copy direction */
#define COMP_ATTR_VDMA_INDEX 3 /**< Comp index of the virtual DMA at the gateway. */
/** @}*/
/** \name Trace macros

View File

@ -200,13 +200,22 @@ int pipeline_reset(struct pipeline *p, struct comp_dev *host_cd);
int pipeline_for_each_comp(struct comp_dev *current,
struct pipeline_walk_context *ctx, int dir);
/**
* \brief Walks pipeline graph to find dai component.
* \param[in] pipeline_id is the start pipeline id.
* \return dai component.
*/
struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id);
#if CONFIG_IPC_MAJOR_4
/**
* \brief Walks pipeline graph to find dai component and latency.
* \param[in] pipeline_id is the start pipeline id.
* \param[out] latency to dai.
* \return dai component.
*/
struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id, uint32_t *latency);
struct comp_dev *pipeline_get_dai_comp_latency(uint32_t pipeline_id, uint32_t *latency);
#endif
/**
* Retrieves pipeline id from pipeline.

View File

@ -396,12 +396,12 @@ static int update_dir_to_pipeline_component(uint32_t *ppl_id, uint32_t count)
struct comp_dev *dai;
struct list_item *clist;
struct ipc *ipc;
uint32_t latency, i;
uint32_t i;
ipc = ipc_get();
/* only dai has direction based on gateway type */
dai = pipeline_get_dai_comp(ppl_id[0], &latency);
dai = pipeline_get_dai_comp(ppl_id[0]);
/* skip host copier to host copier case */
if (!dai) {
tr_info(&ipc_tr, "no dai is found");