[PATCH 0/3] ASoC: Intel: avs: Add support for sending initial module config
In some cases it may be desirable to provide default initial configuration for FW module using payload. To facilitate such solution extend topology to contain initial config information, parse it and then send data to FW if present.
Amadeusz Sławiński (3): ASoC: Intel: avs: UAPI: Add tokens for initial config feature ASoC: Intel: avs: Add topology parsing support for initial config ASoC: Intel: avs: Send initial config to module if present
include/uapi/sound/intel/avs/tokens.h | 9 ++ sound/soc/intel/avs/path.c | 33 ++++++ sound/soc/intel/avs/topology.c | 163 +++++++++++++++++++++++++- sound/soc/intel/avs/topology.h | 13 ++ 4 files changed, 216 insertions(+), 2 deletions(-)
Allow for defining initial config which will be send after module initialization to configure initial module state. This is only useful for modules which need to be configured on init.
Reviewed-by: Cezary Rojewski cezary.rojewski@intel.com Signed-off-by: Amadeusz Sławiński amadeuszx.slawinski@linux.intel.com --- include/uapi/sound/intel/avs/tokens.h | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/include/uapi/sound/intel/avs/tokens.h b/include/uapi/sound/intel/avs/tokens.h index 4ffe546aa409a..4beca03405c07 100644 --- a/include/uapi/sound/intel/avs/tokens.h +++ b/include/uapi/sound/intel/avs/tokens.h @@ -19,6 +19,8 @@ enum avs_tplg_token { AVS_TKN_MANIFEST_NUM_MODCFGS_EXT_U32 = 6, AVS_TKN_MANIFEST_NUM_PPLCFGS_U32 = 7, AVS_TKN_MANIFEST_NUM_BINDINGS_U32 = 8, + AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32 = 9, + AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32 = 10,
/* struct avs_tplg_library */ AVS_TKN_LIBRARY_ID_U32 = 101, @@ -109,6 +111,8 @@ enum avs_tplg_token { AVS_TKN_MOD_PROC_DOMAIN_U8 = 1705, AVS_TKN_MOD_MODCFG_EXT_ID_U32 = 1706, AVS_TKN_MOD_KCONTROL_ID_U32 = 1707, + AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32 = 1708, + AVS_TKN_MOD_INIT_CONFIG_ID_U32 = 1709,
/* struct avs_tplg_path_template */ AVS_TKN_PATH_TMPL_ID_U32 = 1801, @@ -125,6 +129,11 @@ enum avs_tplg_token {
/* struct avs_tplg_kcontrol */ AVS_TKN_KCONTROL_ID_U32 = 2301, + + /* struct avs_tplg_init_config */ + AVS_TKN_INIT_CONFIG_ID_U32 = 2401, + AVS_TKN_INIT_CONFIG_PARAM_U8 = 2402, + AVS_TKN_INIT_CONFIG_LENGTH_U32 = 2403, };
#endif
Add topology parsing for initial config.
Reviewed-by: Cezary Rojewski cezary.rojewski@intel.com Signed-off-by: Amadeusz Sławiński amadeuszx.slawinski@linux.intel.com --- sound/soc/intel/avs/topology.c | 163 ++++++++++++++++++++++++++++++++- sound/soc/intel/avs/topology.h | 13 +++ 2 files changed, 174 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index 778236d3fd280..4bdb4e0ce144a 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1118,6 +1118,21 @@ static const struct avs_tplg_token_parser module_parsers[] = { .offset = offsetof(struct avs_tplg_module, ctl_id), .parse = avs_parse_byte_token, }, + { + .token = AVS_TKN_MOD_INIT_CONFIG_NUM_IDS_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_module, num_config_ids), + .parse = avs_parse_byte_token, + }, +}; + +static const struct avs_tplg_token_parser init_config_parsers[] = { + { + .token = AVS_TKN_MOD_INIT_CONFIG_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = 0, + .parse = avs_parse_word_token, + }, };
static struct avs_tplg_module * @@ -1125,17 +1140,50 @@ avs_tplg_module_create(struct snd_soc_component *comp, struct avs_tplg_pipeline struct snd_soc_tplg_vendor_array *tuples, u32 block_size) { struct avs_tplg_module *module; + u32 esize; int ret;
+ /* See where config id block starts. */ + ret = avs_tplg_vendor_entry_size(tuples, block_size, + AVS_TKN_MOD_INIT_CONFIG_ID_U32, &esize); + if (ret) + return ERR_PTR(ret); + module = devm_kzalloc(comp->card->dev, sizeof(*module), GFP_KERNEL); if (!module) return ERR_PTR(-ENOMEM);
ret = avs_parse_tokens(comp, module, module_parsers, - ARRAY_SIZE(module_parsers), tuples, block_size); + ARRAY_SIZE(module_parsers), tuples, esize); if (ret < 0) return ERR_PTR(ret);
+ block_size -= esize; + /* Parse trailing config ids if any. */ + if (block_size) { + u32 num_config_ids = module->num_config_ids; + u32 *config_ids; + + if (!num_config_ids) + return ERR_PTR(-EINVAL); + + config_ids = devm_kcalloc(comp->card->dev, num_config_ids, sizeof(*config_ids), + GFP_KERNEL); + if (!config_ids) + return ERR_PTR(-ENOMEM); + + tuples = avs_tplg_vendor_array_at(tuples, esize); + ret = parse_dictionary_entries(comp, tuples, block_size, + config_ids, num_config_ids, sizeof(*config_ids), + AVS_TKN_MOD_INIT_CONFIG_ID_U32, + init_config_parsers, + ARRAY_SIZE(init_config_parsers)); + if (ret) + return ERR_PTR(ret); + + module->config_ids = config_ids; + } + module->owner = owner; INIT_LIST_HEAD(&module->node);
@@ -1416,6 +1464,81 @@ avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *o return template; }
+static const struct avs_tplg_token_parser mod_init_config_parsers[] = { + { + .token = AVS_TKN_MOD_INIT_CONFIG_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_init_config, id), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_INIT_CONFIG_PARAM_U8, + .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE, + .offset = offsetof(struct avs_tplg_init_config, param), + .parse = avs_parse_byte_token, + }, + { + .token = AVS_TKN_INIT_CONFIG_LENGTH_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_init_config, length), + .parse = avs_parse_word_token, + }, +}; + +static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, + struct snd_soc_tplg_vendor_array *tuples, + u32 block_size) +{ + struct avs_soc_component *acomp = to_avs_soc_component(comp); + struct avs_tplg *tplg = acomp->tplg; + int ret, i; + + /* Parse tuple section telling how many init configs there are. */ + ret = parse_dictionary_header(comp, tuples, (void **)&tplg->init_configs, + &tplg->num_init_configs, + sizeof(*tplg->init_configs), + AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32); + if (ret) + return ret; + + block_size -= le32_to_cpu(tuples->size); + /* With header parsed, move on to parsing entries. */ + tuples = avs_tplg_vendor_array_next(tuples); + + for (i = 0; i < tplg->num_init_configs; i++) { + struct avs_tplg_init_config *config = &tplg->init_configs[i]; + struct snd_soc_tplg_vendor_array *tmp; + void *init_config_data; + u32 esize; + + /* + * Usually to get section length we search for first token of next group of data, + * but in this case we can't as tuples are followed by raw data. + */ + tmp = avs_tplg_vendor_array_next(tuples); + esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size); + + ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config), + AVS_TKN_MOD_INIT_CONFIG_ID_U32, + mod_init_config_parsers, + ARRAY_SIZE(mod_init_config_parsers)); + + block_size -= esize; + + /* handle raw data section */ + init_config_data = (void *)tuples + esize; + esize = config->length; + + config->data = devm_kmemdup(comp->card->dev, init_config_data, esize, GFP_KERNEL); + if (!config->data) + return -ENOMEM; + + tuples = init_config_data + esize; + } + + return 0; +} + static int avs_route_load(struct snd_soc_component *comp, int index, struct snd_soc_dapm_route *route) { @@ -1571,6 +1694,7 @@ static int avs_manifest(struct snd_soc_component *comp, int index, struct snd_soc_tplg_vendor_array *tuples = manifest->priv.array; struct avs_soc_component *acomp = to_avs_soc_component(comp); size_t remaining = le32_to_cpu(manifest->priv.size); + bool has_init_config = true; u32 offset; int ret;
@@ -1668,8 +1792,43 @@ static int avs_manifest(struct snd_soc_component *comp, int index, remaining -= offset; tuples = avs_tplg_vendor_array_at(tuples, offset);
+ ret = avs_tplg_vendor_array_lookup(tuples, remaining, + AVS_TKN_MANIFEST_NUM_CONDPATH_TMPLS_U32, &offset); + if (ret) { + dev_err(comp->dev, "condpath lookup failed: %d\n", ret); + return ret; + } + /* Bindings dictionary. */ - return avs_tplg_parse_bindings(comp, tuples, remaining); + ret = avs_tplg_parse_bindings(comp, tuples, offset); + if (ret < 0) + return ret; + + remaining -= offset; + tuples = avs_tplg_vendor_array_at(tuples, offset); + + ret = avs_tplg_vendor_array_lookup(tuples, remaining, + AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32, &offset); + if (ret == -ENOENT) { + dev_dbg(comp->dev, "init config lookup failed: %d\n", ret); + has_init_config = false; + } else if (ret) { + dev_err(comp->dev, "init config lookup failed: %d\n", ret); + return ret; + } + + if (!has_init_config) + return 0; + + remaining -= offset; + tuples = avs_tplg_vendor_array_at(tuples, offset); + + /* Initial configs dictionary. */ + ret = avs_tplg_parse_initial_configs(comp, tuples, remaining); + if (ret < 0) + return ret; + + return 0; }
#define AVS_CONTROL_OPS_VOLUME 257 diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 6e1c8e9b24964..6a59dd766603f 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -33,6 +33,9 @@ struct avs_tplg { u32 num_pplcfgs; struct avs_tplg_binding *bindings; u32 num_bindings; + u32 num_condpath_tmpls; + struct avs_tplg_init_config *init_configs; + u32 num_init_configs;
struct list_head path_tmpl_list; }; @@ -147,6 +150,14 @@ struct avs_tplg_path_template { struct list_head node; };
+struct avs_tplg_init_config { + u32 id; + + u8 param; + size_t length; + void *data; +}; + struct avs_tplg_path { u32 id;
@@ -183,6 +194,8 @@ struct avs_tplg_module { u8 domain; struct avs_tplg_modcfg_ext *cfg_ext; u32 ctl_id; + u32 num_config_ids; + u32 *config_ids;
struct avs_tplg_pipeline *owner; /* Pipeline modules management. */
Hi Amadeusz,
kernel test robot noticed the following build warnings:
[auto build test WARNING on broonie-sound/for-next] [also build test WARNING on tiwai-sound/for-next tiwai-sound/for-linus linus/master v6.8-rc3 next-20240207] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Amadeusz-S-awi-ski/ASoC-Intel... base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next patch link: https://lore.kernel.org/r/20240207120946.2140480-3-amadeuszx.slawinski%40lin... patch subject: [PATCH 2/3] ASoC: Intel: avs: Add topology parsing support for initial config config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20240208/202402080403.reu2fMfN-lkp@i...) compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 7dd790db8b77c4a833c06632e903dc4f13877a64) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240208/202402080403.reu2fMfN-lkp@i...)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot lkp@intel.com | Closes: https://lore.kernel.org/oe-kbuild-all/202402080403.reu2fMfN-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from sound/soc/intel/avs/topology.c:11: In file included from include/sound/soc.h:21: In file included from include/linux/regmap.h:20: In file included from include/linux/iopoll.h:14: In file included from include/linux/io.h:13: In file included from arch/s390/include/asm/io.h:78: include/asm-generic/io.h:547:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 547 | val = __raw_readb(PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:560:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 560 | val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr)); | ~~~~~~~~~~ ^ include/uapi/linux/byteorder/big_endian.h:37:59: note: expanded from macro '__le16_to_cpu' 37 | #define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x)) | ^ include/uapi/linux/swab.h:102:54: note: expanded from macro '__swab16' 102 | #define __swab16(x) (__u16)__builtin_bswap16((__u16)(x)) | ^ In file included from sound/soc/intel/avs/topology.c:11: In file included from include/sound/soc.h:21: In file included from include/linux/regmap.h:20: In file included from include/linux/iopoll.h:14: In file included from include/linux/io.h:13: In file included from arch/s390/include/asm/io.h:78: include/asm-generic/io.h:573:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 573 | val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr)); | ~~~~~~~~~~ ^ include/uapi/linux/byteorder/big_endian.h:35:59: note: expanded from macro '__le32_to_cpu' 35 | #define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x)) | ^ include/uapi/linux/swab.h:115:54: note: expanded from macro '__swab32' 115 | #define __swab32(x) (__u32)__builtin_bswap32((__u32)(x)) | ^ In file included from sound/soc/intel/avs/topology.c:11: In file included from include/sound/soc.h:21: In file included from include/linux/regmap.h:20: In file included from include/linux/iopoll.h:14: In file included from include/linux/io.h:13: In file included from arch/s390/include/asm/io.h:78: include/asm-generic/io.h:584:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 584 | __raw_writeb(value, PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:594:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 594 | __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:604:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 604 | __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); | ~~~~~~~~~~ ^ include/asm-generic/io.h:692:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 692 | readsb(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:700:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 700 | readsw(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:708:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 708 | readsl(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:717:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 717 | writesb(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:726:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 726 | writesw(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^ include/asm-generic/io.h:735:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] 735 | writesl(PCI_IOBASE + addr, buffer, count); | ~~~~~~~~~~ ^
sound/soc/intel/avs/topology.c:1490:13: warning: parameter 'block_size' set but not used [-Wunused-but-set-parameter]
1490 | u32 block_size) | ^ 13 warnings generated.
vim +/block_size +1490 sound/soc/intel/avs/topology.c
1487 1488 static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, 1489 struct snd_soc_tplg_vendor_array *tuples,
1490 u32 block_size)
1491 { 1492 struct avs_soc_component *acomp = to_avs_soc_component(comp); 1493 struct avs_tplg *tplg = acomp->tplg; 1494 int ret, i; 1495 1496 /* Parse tuple section telling how many init configs there are. */ 1497 ret = parse_dictionary_header(comp, tuples, (void **)&tplg->init_configs, 1498 &tplg->num_init_configs, 1499 sizeof(*tplg->init_configs), 1500 AVS_TKN_MANIFEST_NUM_INIT_CONFIGS_U32); 1501 if (ret) 1502 return ret; 1503 1504 block_size -= le32_to_cpu(tuples->size); 1505 /* With header parsed, move on to parsing entries. */ 1506 tuples = avs_tplg_vendor_array_next(tuples); 1507 1508 for (i = 0; i < tplg->num_init_configs; i++) { 1509 struct avs_tplg_init_config *config = &tplg->init_configs[i]; 1510 struct snd_soc_tplg_vendor_array *tmp; 1511 void *init_config_data; 1512 u32 esize; 1513 1514 /* 1515 * Usually to get section length we search for first token of next group of data, 1516 * but in this case we can't as tuples are followed by raw data. 1517 */ 1518 tmp = avs_tplg_vendor_array_next(tuples); 1519 esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size); 1520 1521 ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config), 1522 AVS_TKN_MOD_INIT_CONFIG_ID_U32, 1523 mod_init_config_parsers, 1524 ARRAY_SIZE(mod_init_config_parsers)); 1525 1526 block_size -= esize; 1527 1528 /* handle raw data section */ 1529 init_config_data = (void *)tuples + esize; 1530 esize = config->length; 1531 1532 config->data = devm_kmemdup(comp->card->dev, init_config_data, esize, GFP_KERNEL); 1533 if (!config->data) 1534 return -ENOMEM; 1535 1536 tuples = init_config_data + esize; 1537 } 1538 1539 return 0; 1540 } 1541
If there are initial configs to send to module on init do send them.
Reviewed-by: Cezary Rojewski cezary.rojewski@intel.com Signed-off-by: Amadeusz Sławiński amadeuszx.slawinski@linux.intel.com --- sound/soc/intel/avs/path.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+)
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index 3aa16ee8d34c1..e785fc2a7008f 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -547,6 +547,33 @@ static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_mod return avs_modext_create(adev, mod); }
+static int avs_path_module_send_init_configs(struct avs_dev *adev, struct avs_path_module *mod) +{ + struct avs_soc_component *acomp; + + acomp = to_avs_soc_component(mod->template->owner->owner->owner->owner->comp); + + u32 num_ids = mod->template->num_config_ids; + u32 *ids = mod->template->config_ids; + + for (int i = 0; i < num_ids; i++) { + struct avs_tplg_init_config *config = &acomp->tplg->init_configs[ids[i]]; + size_t len = config->length; + void *data = config->data; + u32 param = config->param; + int ret; + + ret = avs_ipc_set_large_config(adev, mod->module_id, mod->instance_id, + param, data, len); + if (ret) { + dev_err(adev->dev, "send initial module config failed: %d\n", ret); + return AVS_IPC_RET(ret); + } + } + + return 0; +} + static void avs_path_module_free(struct avs_dev *adev, struct avs_path_module *mod) { kfree(mod); @@ -580,6 +607,12 @@ avs_path_module_create(struct avs_dev *adev, return ERR_PTR(ret); }
+ ret = avs_path_module_send_init_configs(adev, mod); + if (ret) { + kfree(mod); + return ERR_PTR(ret); + } + return mod; }
participants (2)
-
Amadeusz Sławiński
-
kernel test robot