Commit 97e6d8cb authored by Mark Brown's avatar Mark Brown

ASoC: SOF: ipc4: Querry CPC value from firmware's

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

The MOD_INIT_INSTANCE message contains a CPC (Cycles Per Chunk/processing unit)
parameter.
This CPC value is used by the firmware to calculate the total cycles needed by
the enabled module instances and based on this it can decide to set the
frequency of the DSP core(s).

The manifest section of the firmware image contains a module configuration
section, where a per module table of configurations are listed with measured
CPC values as triplet of IBS/IBS/CPC (Input/Output buffer size - corresponding
to the selected audio format).

In case the CPC value is 0 (missing from the manifest or the
configuration cannot be matched) the firmware will force the DSP cores
to maximum speed to avoid audio glitches due to starvation.  In these
cases the kernel will print a warning message to let the SOF developers
know about the gap and provide information to correct it with a firmware
update.
parents 17cf9fae d8a2c987
......@@ -112,16 +112,13 @@ static ssize_t sof_ipc4_fw_parse_ext_man(struct snd_sof_dev *sdev,
return -EINVAL;
}
/* a module's config is always the same size */
fw_module->bss_size = fm_config[fm_entry->cfg_offset].is_bytes;
fw_module->fw_mod_cfg = &fm_config[fm_entry->cfg_offset];
dev_dbg(sdev->dev,
"module %s: UUID %pUL cfg_count: %u, bss_size: %#x\n",
fm_entry->name, &fm_entry->uuid, fm_entry->cfg_count,
fw_module->bss_size);
fm_config[fm_entry->cfg_offset].is_bytes);
} else {
fw_module->bss_size = 0;
dev_dbg(sdev->dev, "module %s: UUID %pUL\n", fm_entry->name,
&fm_entry->uuid);
}
......@@ -426,6 +423,71 @@ int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev)
return ret;
}
/**
* sof_ipc4_update_cpc_from_manifest - Update the cpc in base config from manifest
* @sdev: SOF device
* @fw_module: pointer struct sof_ipc4_fw_module to parse
* @basecfg: Pointer to the base_config to update
*/
void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_module *fw_module,
struct sof_ipc4_base_module_cfg *basecfg)
{
const struct sof_man4_module_config *fw_mod_cfg;
u32 cpc_pick = 0;
u32 max_cpc = 0;
const char *msg;
int i;
if (!fw_module->fw_mod_cfg) {
msg = "No mod_cfg available for CPC lookup in the firmware file's manifest";
goto no_cpc;
}
/*
* Find the best matching (highest) CPC value based on the module's
* IBS/OBS configuration inferred from the audio format selection.
*
* The CPC value in each module config entry has been measured and
* recorded as a IBS/OBS/CPC triplet and stored in the firmware file's
* manifest
*/
fw_mod_cfg = fw_module->fw_mod_cfg;
for (i = 0; i < fw_module->man4_module_entry.cfg_count; i++) {
if (basecfg->obs == fw_mod_cfg[i].obs &&
basecfg->ibs == fw_mod_cfg[i].ibs &&
cpc_pick < fw_mod_cfg[i].cpc)
cpc_pick = fw_mod_cfg[i].cpc;
if (max_cpc < fw_mod_cfg[i].cpc)
max_cpc = fw_mod_cfg[i].cpc;
}
basecfg->cpc = cpc_pick;
/* We have a matching configuration for CPC */
if (basecfg->cpc)
return;
/*
* No matching IBS/OBS found, the firmware manifest is missing
* information in the module's module configuration table.
*/
if (!max_cpc)
msg = "No CPC value available in the firmware file's manifest";
else if (!cpc_pick)
msg = "No CPC match in the firmware file's manifest";
no_cpc:
dev_warn(sdev->dev, "%s (UUID: %pUL): %s (ibs/obs: %u/%u)\n",
fw_module->man4_module_entry.name,
&fw_module->man4_module_entry.uuid, msg, basecfg->ibs,
basecfg->obs);
dev_warn_once(sdev->dev, "Please try to update the firmware.\n");
dev_warn_once(sdev->dev, "If the issue persists, file a bug at\n");
dev_warn_once(sdev->dev, "https://github.com/thesofproject/sof/issues/\n");
}
const struct sof_ipc_fw_loader_ops ipc4_loader_ops = {
.validate = sof_ipc4_validate_firmware,
.parse_ext_manifest = sof_ipc4_fw_parse_basefw_ext_man,
......
......@@ -28,14 +28,14 @@ enum sof_ipc4_mtrace_type {
/**
* struct sof_ipc4_fw_module - IPC4 module info
* @sof_man4_module: Module info
* @fw_mod_cfg: Pointer to the module config start of the module
* @m_ida: Module instance identifier
* @bss_size: Module object size
* @private: Module private data
*/
struct sof_ipc4_fw_module {
struct sof_man4_module man4_module_entry;
const struct sof_man4_module_config *fw_mod_cfg;
struct ida m_ida;
u32 bss_size;
void *private;
};
......@@ -114,4 +114,10 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev);
int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev);
struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
const guid_t *uuid);
struct sof_ipc4_base_module_cfg;
void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_module *fw_module,
struct sof_ipc4_base_module_cfg *basecfg);
#endif
......@@ -39,8 +39,6 @@ static const struct sof_topology_token pipeline_tokens[] = {
};
static const struct sof_topology_token ipc4_comp_tokens[] = {
{SOF_TKN_COMP_CPC, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_base_module_cfg, cpc)},
{SOF_TKN_COMP_IS_PAGES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_base_module_cfg, is_pages)},
};
......@@ -235,7 +233,7 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
"Number of input audio formats: %d. Number of output audio formats: %d\n",
available_fmt->num_input_formats, available_fmt->num_output_formats);
/* set cpc and is_pages in the module's base_config */
/* set is_pages in the module's base_config */
ret = sof_update_ipc_object(scomp, module_base_cfg, SOF_COMP_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*module_base_cfg), 1);
if (ret) {
......@@ -244,8 +242,8 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
return ret;
}
dev_dbg(scomp->dev, "widget %s cpc: %d is_pages: %d\n",
swidget->widget->name, module_base_cfg->cpc, module_base_cfg->is_pages);
dev_dbg(scomp->dev, "widget %s: is_pages: %d\n", swidget->widget->name,
module_base_cfg->is_pages);
if (available_fmt->num_input_formats) {
in_format = kcalloc(available_fmt->num_input_formats,
......@@ -723,9 +721,9 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
}
dev_dbg(scomp->dev,
"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x, cpc %d\n",
"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n",
swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l,
gain->data.init_val, gain->base_config.cpc);
gain->data.init_val);
ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
if (ret)
......@@ -936,8 +934,8 @@ static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget)
}
static void
sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
struct sof_ipc4_base_module_cfg *base_config)
sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
struct sof_ipc4_base_module_cfg *base_config)
{
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
struct snd_sof_widget *pipe_widget;
......@@ -968,6 +966,13 @@ sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widg
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
pipeline->mem_usage += total;
/* Update base_config->cpc from the module manifest */
sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
dev_dbg(sdev->dev, "%s: ibs / obs / cpc: %u / %u / %u\n",
swidget->widget->name, base_config->ibs, base_config->obs,
base_config->cpc);
}
static int sof_ipc4_widget_assign_instance_id(struct snd_sof_dev *sdev,
......@@ -1711,7 +1716,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
*data, copier_data->gtw_cfg.config_length * 4);
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
sof_ipc4_update_resource_usage(sdev, swidget, &copier_data->base_config);
return 0;
}
......@@ -1748,7 +1753,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
}
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
sof_ipc4_update_resource_usage(sdev, swidget, &gain->base_config);
return 0;
}
......@@ -1785,7 +1790,7 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
}
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
sof_ipc4_update_resource_usage(sdev, swidget, &mixer->base_config);
return 0;
}
......@@ -1822,7 +1827,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
}
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config);
sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config);
/* update pipeline_params for sink widgets */
rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE);
......@@ -1959,7 +1964,7 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
}
/* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &process->base_config);
sof_ipc4_update_resource_usage(sdev, swidget, &process->base_config);
/* ipc_config_data is composed of the base_config followed by an optional extension */
memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment