From b120d37602daf008612cebe231089ecc578570d9 Mon Sep 17 00:00:00 2001 From: Krzysztof Frydryk Date: Fri, 24 Feb 2023 16:48:09 +0100 Subject: [PATCH] pipeline: Register and unregister pipelines CPS consumption on run/pause Register and unregister pipelines CPS consumption on run/pause Signed-off-by: Adrian Bonislawski Signed-off-by: Krzysztof Frydryk +Squashed commits: 924f0d26db2c pipeline: print warning if 0 KCPS received Signed-off-by: Adrian Bonislawski 7bb6e7ef3ba9 pipeline: register CPS consumption for a proper core Signed-off-by: Adrian Bonislawski 5f0c4e4c3160 pipeline: make CPC data "opt-in" with fallback Signed-off-by: Liam Girdwood Signed-off-by: Peter Ujfalusi --- src/audio/pipeline/pipeline-stream.c | 125 ++++++++++++++++++++++++++- src/platform/Kconfig | 8 ++ 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index 6fe795cf54f5..1e8b35d8f98c 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -268,17 +270,128 @@ static void pipeline_trigger_xrun(struct pipeline *p, struct comp_dev **host) } while (true); } +#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL +static int add_pipeline_cps_consumption(struct comp_dev *current, + struct comp_buffer *calling_buf, + struct pipeline_walk_context *ctx, int dir) +{ + struct pipeline_data *ppl_data = ctx->comp_data; + struct ipc4_base_module_cfg *cd; + int kcps, summary_cps; + + pipe_dbg(ppl_data->p, "add_pipeline_cps_consumption(), current->comp.id = %u, dir = %u", + dev_comp_id(current), dir); + + if (!comp_is_single_pipeline(current, ppl_data->start)) { + pipe_dbg(ppl_data->p, "add_pipeline_cps_consumption(), current is from another pipeline"); + return 0; + } + + /* complete component init */ + current->pipeline = ppl_data->p; + + /* modules created through module adapter have different priv_data */ + if (current->drv->type != SOF_COMP_MODULE_ADAPTER) { + cd = comp_get_drvdata(current); + } else { + struct processing_module *mod = comp_get_drvdata(current); + struct module_data *md = &mod->priv; + + cd = &md->cfg.base_cfg; + } + + if (cd->cpc == 0) { + /* Use maximum clock budget, assume 1ms chunk size */ + cd->cpc = CLK_MAX_CPU_HZ / 1000; + tr_warn(pipe, + "0 CPS requested for module: %#x, core: %d using safe max CPC: %u", + current->ipc_config.id, ppl_data->p->core, cd->cpc); + } + + kcps = cd->cpc * 1000 / ppl_data->p->period; + tr_info(pipe, "Registering module: %#x KCPS consumption: %d, core: %d", + current->ipc_config.id, kcps, ppl_data->p->core); + + core_kcps_adjust(ppl_data->p->core, kcps); + + summary_cps = core_kcps_get(ppl_data->p->core); + tr_info(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); + + return pipeline_for_each_comp(current, ctx, dir); +} + +static int remove_pipeline_cps_consumption(struct comp_dev *current, + struct comp_buffer *calling_buf, + struct pipeline_walk_context *ctx, int dir) +{ + struct pipeline_data *ppl_data = ctx->comp_data; + struct ipc4_base_module_cfg *cd; + int kcps, summary_cps; + + pipe_dbg(ppl_data->p, "remove_pipeline_cps_consumption(), current->comp.id = %u, dir = %u", + dev_comp_id(current), dir); + + if (!comp_is_single_pipeline(current, ppl_data->start)) { + pipe_dbg(ppl_data->p, "remove_pipeline_cps_consumption(), current is from another pipeline"); + return 0; + } + + /* complete component init */ + current->pipeline = ppl_data->p; + + /* modules created through module adapter have different priv_data */ + if (current->drv->type != SOF_COMP_MODULE_ADAPTER) { + cd = comp_get_drvdata(current); + } else { + struct processing_module *mod = comp_get_drvdata(current); + struct module_data *md = &mod->priv; + + cd = &md->cfg.base_cfg; + } + + kcps = cd->cpc * 1000 / ppl_data->p->period; + tr_info(pipe, "Unregistering module: %#x KCPS consumption: %d, core: %d", + current->ipc_config.id, kcps, ppl_data->p->core); + + core_kcps_adjust(ppl_data->p->core, -kcps); + + summary_cps = core_kcps_get(ppl_data->p->core); + tr_info(pipe, "Sum of KCPS consumption: %d, core: %d", summary_cps, ppl_data->p->core); + + return pipeline_for_each_comp(current, ctx, dir); +} +#endif + /* trigger pipeline in IPC context */ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) { int ret; - +#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL + bool clocks_handled = false; + struct pipeline_data data; + struct pipeline_walk_context walk_ctx = { + .comp_func = remove_pipeline_cps_consumption, + .comp_data = &data, + }; +#endif pipe_info(p, "pipe trigger cmd %d", cmd); p->trigger.aborted = false; switch (cmd) { case COMP_TRIGGER_PAUSE: +#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL + /* dirty - dont add kcps on fallthrough */ + clocks_handled = true; + /* setup walking ctx for adding consumption */ + data.start = p->source_comp; + data.p = p; + walk_ctx.comp_func = remove_pipeline_cps_consumption; + + ret = walk_ctx.comp_func(p->source_comp, NULL, &walk_ctx, PPL_DIR_DOWNSTREAM); + + COMPILER_FALLTHROUGH; +#endif case COMP_TRIGGER_STOP: if (p->status == COMP_STATE_PAUSED || p->xrun_bytes) { /* The task isn't running, trigger inline */ @@ -295,6 +408,16 @@ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) case COMP_TRIGGER_PRE_RELEASE: case COMP_TRIGGER_PRE_START: /* Add all connected pipelines to the list and trigger them all */ +#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL + /* setup walking ctx for removing consumption */ + if (!clocks_handled) { + data.start = p->source_comp; + data.p = p; + walk_ctx.comp_func = add_pipeline_cps_consumption; + + ret = walk_ctx.comp_func(p->source_comp, NULL, &walk_ctx, PPL_DIR_DOWNSTREAM); + } +#endif ret = pipeline_trigger_list(p, host, cmd); if (ret < 0) return ret; diff --git a/src/platform/Kconfig b/src/platform/Kconfig index b560674d9b46..08ba33d17264 100644 --- a/src/platform/Kconfig +++ b/src/platform/Kconfig @@ -365,6 +365,14 @@ config CAVS_USE_LPRO_IN_WAITI After waiti exit clock source will be restored. Choose n if unclear. +config KCPS_DYNAMIC_CLOCK_CONTROL + bool "Use KCPS budget to determine DSP clock" + default n + depends on IPC_MAJOR_4 + help + Select if we want to use compute budget + expressed in Kilo Cycles Per Second (KCPS) to determine DSP clock. + config L3_HEAP bool "Use L3 memory heap" default n