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; 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; 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) { if (gateway_id >= IPC4_MAX_PIPELINE_REG_SLOTS) {
comp_cl_err(&comp_copier, "gateway_id %u out of array bounds.", gateway_id); comp_cl_err(&comp_copier, "gateway_id %u out of array bounds.", gateway_id);
return -EINVAL; return -EINVAL;
@ -483,7 +488,7 @@ static struct comp_dev *copier_new(const struct comp_driver *drv,
if (cd->direction == SOF_IPC_STREAM_PLAYBACK) { if (cd->direction == SOF_IPC_STREAM_PLAYBACK) {
ipc_pipe->pipeline->source_comp = dev; ipc_pipe->pipeline->source_comp = dev;
if (init_pipeline_reg(cd)) if (init_pipeline_reg(dev))
goto error_cd; goto error_cd;
} else { } else {
ipc_pipe->pipeline->sink_comp = dev; 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) if (ret < 0 || !cd->endpoint_num || !cd->pipeline_reg_offset)
return ret; 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) { 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; return ret;
} }
@ -713,7 +718,7 @@ static int copier_comp_trigger(struct comp_dev *dev, int cmd)
return 0; 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 /* 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 * 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; 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 = { static const struct comp_driver comp_copier = {
.uid = SOF_RT_UUID(copier_comp_uuid), .uid = SOF_RT_UUID(copier_comp_uuid),
.tctx = &copier_comp_tr, .tctx = &copier_comp_tr,
@ -1253,6 +1285,8 @@ static const struct comp_driver comp_copier = {
.prepare = copier_prepare, .prepare = copier_prepare,
.reset = copier_reset, .reset = copier_reset,
.get_total_data_processed = copier_get_processed_data, .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; return 0;
} }
/* visit connected pipeline to find the dai comp and latency */ /* visit connected pipeline to find the dai comp */
struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id, uint32_t *latency) struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id)
{ {
struct ipc_comp_dev *sink; struct ipc_comp_dev *sink;
struct ipc *ipc = ipc_get(); struct ipc *ipc = ipc_get();
*latency = 0;
sink = ipc_get_ppl_sink_comp(ipc, pipeline_id); sink = ipc_get_ppl_sink_comp(ipc, pipeline_id);
if (!sink)
return NULL;
while (sink) { while (sink) {
struct comp_dev *buff_comp;
struct comp_buffer *buffer; struct comp_buffer *buffer;
struct comp_dev *comp;
*latency += sink->cd->pipeline->period;
/* dai is found */ /* dai is found */
if (list_is_empty(&sink->cd->bsink_list)) { if (list_is_empty(&sink->cd->bsink_list))
struct list_item *list; return sink->cd;
list = comp_buffer_list(sink->cd, PPL_DIR_UPSTREAM);
buffer = buffer_from_list(list->next, struct comp_buffer, PPL_DIR_UPSTREAM);
break;
}
buffer = buffer_from_list(comp_buffer_list(sink->cd, PPL_DIR_DOWNSTREAM)->next, buffer = buffer_from_list(comp_buffer_list(sink->cd, PPL_DIR_DOWNSTREAM)->next,
struct comp_buffer, PPL_DIR_DOWNSTREAM); 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 */ /* buffer_comp is in another pipeline and it is not complete */
if (!buff_comp->pipeline) if (!comp->pipeline)
return NULL; return NULL;
sink = ipc_get_ppl_sink_comp(ipc, buff_comp->pipeline->pipeline_id); sink = ipc_get_ppl_sink_comp(ipc, comp->pipeline->pipeline_id);
if (!sink)
return NULL;
} }
/* convert it to ms */ return NULL;
*latency /= 1000;
return sink->cd;
} }
#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_COPY_TYPE 0 /**< Comp copy type attribute */
#define COMP_ATTR_HOST_BUFFER 1 /**< Comp host buffer attribute */ #define COMP_ATTR_HOST_BUFFER 1 /**< Comp host buffer attribute */
#define COMP_ATTR_COPY_DIR 2 /**< Comp copy direction */ #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 /** \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, int pipeline_for_each_comp(struct comp_dev *current,
struct pipeline_walk_context *ctx, int dir); 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. * \brief Walks pipeline graph to find dai component and latency.
* \param[in] pipeline_id is the start pipeline id. * \param[in] pipeline_id is the start pipeline id.
* \param[out] latency to dai. * \param[out] latency to dai.
* \return dai component. * \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. * 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 comp_dev *dai;
struct list_item *clist; struct list_item *clist;
struct ipc *ipc; struct ipc *ipc;
uint32_t latency, i; uint32_t i;
ipc = ipc_get(); ipc = ipc_get();
/* only dai has direction based on gateway type */ /* 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 */ /* skip host copier to host copier case */
if (!dai) { if (!dai) {
tr_info(&ipc_tr, "no dai is found"); tr_info(&ipc_tr, "no dai is found");