From db78be6980292ee06857733a2eba1fdaa91155db Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Thu, 11 May 2023 12:42:21 +0200 Subject: [PATCH] copier: pipeline period recalculation In case of a deep buffering pipelines don't require scheduling on every millisecond. We can calculate period based on the gateway buffer size. At pipeline creation we assume that it can work on longer periods, period value is set to zero to be later adjust base on the pipeline components. Signed-off-by: Tomasz Leman --- src/audio/copier/copier.c | 36 +++++++++++++++++++++++++++++ src/audio/pipeline/pipeline-graph.c | 9 ++++++++ src/include/sof/audio/component.h | 3 +++ src/include/sof/audio/pipeline.h | 2 ++ src/ipc/ipc4/helper.c | 21 +++++++++++++++-- 5 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 0bb2306d2a6e..9197fbd4fe28 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -40,6 +40,7 @@ #include #include #include +#include #if CONFIG_ZEPHYR_NATIVE_DRIVERS #include @@ -92,6 +93,41 @@ static int copier_init(struct processing_module *mod) } dev->pipeline = ipc_pipe->pipeline; + /* Calculation of the period in which the component should be scheduled based on + * the input buffer size. + */ + if (copier->gtw_cfg.dma_buffer_size > 0 && dev->pipeline->deep_buffering) { + /* Size of the single frame in bytes. */ + uint32_t frame_size = copier->base.audio_fmt.channels_count * + (copier->base.audio_fmt.depth >> 3); + /* Size of the one second of audio data in bytes. */ + uint32_t one_s = frame_size * copier->base.audio_fmt.sampling_frequency; + /* Size of the ten millisecond of audio data in bytes. */ + uint32_t ten_ms = DIV_ROUND_UP(one_s, 100); + /* The number of ten milliseconds chunks of data that will fit into the buffer. */ + uint32_t chunk_count = copier->gtw_cfg.dma_buffer_size / ten_ms; + + /* If buffer can fit at more than ten milliseconds of data we can try to schedule + * pipe on periods bigger than one millisecond. + */ + if (chunk_count) { + dev->deep_buffering = true; + if (chunk_count == 1) + dev->period = (5 * LL_TIMER_PERIOD_US); + else + dev->period = (10 * LL_TIMER_PERIOD_US); + + /* If a component that may run on bigger periods has already been added to + * the pipeline, the pipe must run at the lowest possible value. + */ + if (!dev->pipeline->period || dev->pipeline->period < dev->period) { + dev->pipeline->period = dev->period; + comp_cl_warn(&comp_copier, + "changing the period for the pipe (new value %u)", + dev->pipeline->period); + } + } + } node_id = copier->gtw_cfg.node_id; /* copier is linked to gateway */ diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 82fe49bbed20..dc8eea32e399 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -302,6 +303,14 @@ int pipeline_complete(struct pipeline *p, struct comp_dev *source, data.start = source; data.p = p; + /* If a component has been added to the pipeline that cannot run on longer periods + * we need to set pipe period to one ms. + */ + if (!p->deep_buffering) { + p->period = LL_TIMER_PERIOD_US; + pipe_info(p, "setting pipe period to %llu us", LL_TIMER_PERIOD_US); + } + /* now walk downstream from source component and * complete component task and pipeline initialization */ diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 4a24d08ffb28..cb1a9d82b346 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -591,6 +591,9 @@ struct comp_dev { bool is_shared; /**< indicates whether component is shared * across cores */ + bool deep_buffering; /**< indicates whether component is able to work + * deep buffering + */ struct comp_ipc_config ipc_config; /**< Component IPC configuration */ struct tr_ctx tctx; /**< trace settings */ diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 8dc5ea16d51d..a1a123842262 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -94,6 +94,8 @@ struct pipeline { bool aborted; /* STOP or PAUSE failed, stay active */ bool pending; /* trigger scheduled but not executed yet */ } trigger; + /* pipe can use long periods for scheduling in case of a deep buffering */ + bool deep_buffering; }; struct pipeline_walk_context { diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 91babe75b97d..e210b02fd528 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -18,7 +18,6 @@ #include #include #include -#include #include /* TODO: Remove platform-specific code, see https://github.com/thesofproject/sof/issues/7549 */ @@ -206,7 +205,8 @@ static int ipc4_create_pipeline(struct ipc4_pipeline_create *pipe_desc) } pipe->time_domain = SOF_TIME_DOMAIN_TIMER; - pipe->period = LL_TIMER_PERIOD_US; + pipe->period = 0; + pipe->deep_buffering = true; /* sched_id is set in FW so initialize it to a invalid value */ pipe->sched_id = 0xFFFFFFFF; @@ -869,6 +869,23 @@ int ipc4_add_comp_dev(struct comp_dev *dev) /* add new component to the list */ list_item_append(&icd->list, &ipc->comp_list); + /* If new component added to the pipeline is not fitted for deep buffering we need to + * inform pipeline it cannot work on long periods. + */ + if (!dev->deep_buffering) { + if (!dev->pipeline) { + const uint32_t pipe_id = dev->ipc_config.pipeline_id; + struct ipc_comp_dev *ipc_comp = + ipc_get_comp_by_ppl_id(ipc, + COMP_TYPE_PIPELINE, + pipe_id); + + dev->pipeline = ipc_comp->pipeline; + } + + dev->pipeline->deep_buffering = false; + } + return IPC4_SUCCESS; };