mirror of https://github.com/thesofproject/sof.git
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:
parent
e8c34fd62e
commit
c4f4c978af
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue