Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: qdsp6: audioreach: Simplify handing FE and BE graph connections

Current AudioReach design of connecting FE and BE graph is very complicated
and not reliable. Instead used the virtual damp widgets private data to help
identify the modules that needs connection at runtime. Also maintain a
inter-graph connection info in the graph info, which can be used to both
determine if the graphs are connected and at graph build time.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20221027102710.21407-5-srinivas.kandagatla@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Srinivas Kandagatla and committed by
Mark Brown
e4977b91 1c87d381

+126 -173
+25 -63
sound/soc/qcom/qdsp6/audioreach.c
··· 332 332 obj->prop_id_port.max_op_port = module->max_op_port; 333 333 } 334 334 335 - struct audioreach_module *audioreach_get_container_last_module( 336 - struct audioreach_container *container) 337 - { 338 - struct audioreach_module *module; 339 - 340 - list_for_each_entry(module, &container->modules_list, node) { 341 - if (module->dst_mod_inst_id == 0) 342 - return module; 343 - } 344 - 345 - return NULL; 346 - } 347 - EXPORT_SYMBOL_GPL(audioreach_get_container_last_module); 348 - 349 - static bool is_module_in_container(struct audioreach_container *container, int module_iid) 350 - { 351 - struct audioreach_module *module; 352 - 353 - list_for_each_entry(module, &container->modules_list, node) { 354 - if (module->instance_id == module_iid) 355 - return true; 356 - } 357 - 358 - return false; 359 - } 360 - 361 - struct audioreach_module *audioreach_get_container_first_module( 362 - struct audioreach_container *container) 363 - { 364 - struct audioreach_module *module; 365 - 366 - /* get the first module from both connected or un-connected containers */ 367 - list_for_each_entry(module, &container->modules_list, node) { 368 - if (module->src_mod_inst_id == 0 || 369 - !is_module_in_container(container, module->src_mod_inst_id)) 370 - return module; 371 - } 372 - return NULL; 373 - } 374 - EXPORT_SYMBOL_GPL(audioreach_get_container_first_module); 375 - 376 - struct audioreach_module *audioreach_get_container_next_module( 377 - struct audioreach_container *container, 378 - struct audioreach_module *module) 379 - { 380 - int nmodule_iid = module->dst_mod_inst_id; 381 - struct audioreach_module *nmodule; 382 - 383 - list_for_each_entry(nmodule, &container->modules_list, node) { 384 - if (nmodule->instance_id == nmodule_iid) 385 - return nmodule; 386 - } 387 - 388 - return NULL; 389 - } 390 - EXPORT_SYMBOL_GPL(audioreach_get_container_next_module); 391 - 392 335 static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj, 393 336 struct audioreach_container *container, 394 337 int sub_graph_id) ··· 343 400 obj->container_id = container->container_id; 344 401 obj->num_modules = container->num_modules; 345 402 i = 0; 346 - list_for_each_container_module(module, container) { 403 + list_for_each_entry(module, &container->modules_list, node) { 347 404 obj->mod_cfg[i].module_id = module->module_id; 348 405 obj->mod_cfg[i].instance_id = module->instance_id; 349 406 i++; 350 407 } 351 408 } 352 409 353 - static void audioreach_populate_graph(struct apm_graph_open_params *open, 410 + static void audioreach_populate_graph(struct q6apm *apm, struct audioreach_graph_info *info, 411 + struct apm_graph_open_params *open, 354 412 struct list_head *sg_list, 355 413 int num_sub_graphs) 356 414 { ··· 372 428 373 429 mlobj = &ml_data->mod_list_obj[0]; 374 430 431 + 432 + if (info->dst_mod_inst_id && info->src_mod_inst_id) { 433 + conn_obj = &mc_data->conn_obj[nconn]; 434 + conn_obj->src_mod_inst_id = info->src_mod_inst_id; 435 + conn_obj->src_mod_op_port_id = info->src_mod_op_port_id; 436 + conn_obj->dst_mod_inst_id = info->dst_mod_inst_id; 437 + conn_obj->dst_mod_ip_port_id = info->dst_mod_ip_port_id; 438 + nconn++; 439 + } 440 + 375 441 list_for_each_entry(sg, sg_list, node) { 376 442 struct apm_sub_graph_data *sg_cfg = &sg_data->sg_cfg[i++]; 377 443 ··· 393 439 apm_populate_container_config(cobj, container); 394 440 apm_populate_module_list_obj(mlobj, container, sg->sub_graph_id); 395 441 396 - list_for_each_container_module(module, container) { 442 + list_for_each_entry(module, &container->modules_list, node) { 397 443 uint32_t src_mod_inst_id; 398 444 399 445 src_mod_inst_id = module->src_mod_inst_id; ··· 416 462 } 417 463 } 418 464 419 - void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, int graph_id) 465 + void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info *info) 420 466 { 421 467 int payload_size, sg_sz, cont_sz, ml_sz, mp_sz, mc_sz; 422 468 struct apm_module_param_data *param_data; ··· 429 475 struct audioreach_module *module; 430 476 struct audioreach_sub_graph *sgs; 431 477 struct apm_mod_list_obj *mlobj; 478 + struct list_head *sg_list; 432 479 int num_modules_per_list; 433 480 int num_connections = 0; 434 481 int num_containers = 0; ··· 439 484 struct gpr_pkt *pkt; 440 485 void *p; 441 486 487 + sg_list = &info->sg_list; 488 + ml_sz = 0; 489 + 490 + /* add FE-BE connections */ 491 + if (info->dst_mod_inst_id && info->src_mod_inst_id) 492 + num_connections++; 493 + 442 494 list_for_each_entry(sgs, sg_list, node) { 443 495 num_sub_graphs++; 444 496 list_for_each_entry(container, &sgs->container_list, node) { 445 497 num_containers++; 446 498 num_modules += container->num_modules; 447 - list_for_each_container_module(module, container) { 499 + list_for_each_entry(module, &container->modules_list, node) { 448 500 if (module->src_mod_inst_id) 449 501 num_connections++; 450 502 } ··· 519 557 params.mod_conn_list_data->num_connections = num_connections; 520 558 p += mc_sz; 521 559 522 - audioreach_populate_graph(&params, sg_list, num_sub_graphs); 560 + audioreach_populate_graph(apm, info, &params, sg_list, num_sub_graphs); 523 561 524 562 return pkt; 525 563 }
+7 -13
sound/soc/qcom/qdsp6/audioreach.h
··· 595 595 int id; 596 596 uint32_t num_sub_graphs; 597 597 struct list_head sg_list; 598 + /* DPCM connection from FE Graph to BE graph */ 599 + uint32_t src_mod_inst_id; 600 + uint32_t src_mod_op_port_id; 601 + uint32_t dst_mod_inst_id; 602 + uint32_t dst_mod_ip_port_id; 598 603 }; 599 604 600 605 struct audioreach_sub_graph { ··· 698 693 void *audioreach_alloc_pkt(int payload_size, uint32_t opcode, 699 694 uint32_t token, uint32_t src_port, 700 695 uint32_t dest_port); 701 - void *audioreach_alloc_graph_pkt(struct q6apm *apm, 702 - struct list_head *sg_list, 703 - int graph_id); 696 + void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info 697 + *info); 704 698 /* Topology specific */ 705 699 int audioreach_tplg_init(struct snd_soc_component *component); 706 700 ··· 720 716 int audioreach_shared_memory_send_eos(struct q6apm_graph *graph); 721 717 int audioreach_gain_set_vol_ctrl(struct q6apm *apm, 722 718 struct audioreach_module *module, int vol); 723 - struct audioreach_module *audioreach_get_container_last_module( 724 - struct audioreach_container *container); 725 - struct audioreach_module *audioreach_get_container_first_module( 726 - struct audioreach_container *container); 727 - struct audioreach_module *audioreach_get_container_next_module( 728 - struct audioreach_container *container, 729 - struct audioreach_module *module); 730 - #define list_for_each_container_module(mod, cont) \ 731 - for (mod = audioreach_get_container_first_module(cont); mod != NULL; \ 732 - mod = audioreach_get_container_next_module(cont, mod)) 733 719 #endif /* __AUDIOREACH_H__ */
+1 -82
sound/soc/qcom/qdsp6/q6apm.c
··· 63 63 graph->info = info; 64 64 graph->id = graph_id; 65 65 66 - graph->graph = audioreach_alloc_graph_pkt(apm, &info->sg_list, graph_id); 66 + graph->graph = audioreach_alloc_graph_pkt(apm, info); 67 67 if (IS_ERR(graph->graph)) { 68 68 void *err = graph->graph; 69 69 ··· 176 176 } 177 177 178 178 return NULL; 179 - } 180 - 181 - static struct audioreach_module *q6apm_graph_get_last_module(struct q6apm *apm, u32 sgid) 182 - { 183 - struct audioreach_container *container; 184 - struct audioreach_module *module; 185 - struct audioreach_sub_graph *sg; 186 - 187 - mutex_lock(&apm->lock); 188 - sg = idr_find(&apm->sub_graphs_idr, sgid); 189 - mutex_unlock(&apm->lock); 190 - if (!sg) 191 - return NULL; 192 - 193 - container = list_last_entry(&sg->container_list, struct audioreach_container, node); 194 - module = audioreach_get_container_last_module(container); 195 - 196 - return module; 197 - } 198 - 199 - static struct audioreach_module *q6apm_graph_get_first_module(struct q6apm *apm, u32 sgid) 200 - { 201 - struct audioreach_container *container; 202 - struct audioreach_module *module; 203 - struct audioreach_sub_graph *sg; 204 - 205 - mutex_lock(&apm->lock); 206 - sg = idr_find(&apm->sub_graphs_idr, sgid); 207 - mutex_unlock(&apm->lock); 208 - if (!sg) 209 - return NULL; 210 - 211 - container = list_first_entry(&sg->container_list, struct audioreach_container, node); 212 - module = audioreach_get_container_first_module(container); 213 - 214 - return module; 215 - } 216 - 217 - bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid, u32 dst_sgid) 218 - { 219 - struct audioreach_module *module; 220 - u32 iid; 221 - 222 - module = q6apm_graph_get_last_module(apm, src_sgid); 223 - if (!module) 224 - return false; 225 - 226 - iid = module->instance_id; 227 - module = q6apm_graph_get_first_module(apm, dst_sgid); 228 - if (!module) 229 - return false; 230 - 231 - if (module->src_mod_inst_id == iid) 232 - return true; 233 - 234 - return false; 235 - } 236 - 237 - int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid, bool connect) 238 - { 239 - struct audioreach_module *module; 240 - u32 iid; 241 - 242 - if (connect) { 243 - module = q6apm_graph_get_last_module(apm, src_sgid); 244 - if (!module) 245 - return -ENODEV; 246 - 247 - iid = module->instance_id; 248 - } else { 249 - iid = 0; 250 - } 251 - 252 - module = q6apm_graph_get_first_module(apm, dst_sgid); 253 - if (!module) 254 - return -ENODEV; 255 - 256 - /* set src module in dst subgraph first module */ 257 - module->src_mod_inst_id = iid; 258 - 259 - return 0; 260 179 } 261 180 262 181 int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
-5
sound/soc/qcom/qdsp6/q6apm.h
··· 142 142 /* Callback for graph specific */ 143 143 struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, 144 144 uint32_t mid); 145 - 146 145 void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv); 147 - int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid, 148 - bool connect); 149 - bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid, 150 - u32 dst_sgid); 151 146 int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph); 152 147 153 148 #endif /* __APM_GRAPH_ */
+93 -10
sound/soc/qcom/qdsp6/topology.c
··· 872 872 return 0; 873 873 } 874 874 875 - static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp, 875 + static struct snd_ar_control *audioreach_find_widget(struct snd_soc_component *comp, 876 + const char *name) 877 + { 878 + struct q6apm *apm = dev_get_drvdata(comp->dev); 879 + struct snd_ar_control *control; 880 + 881 + list_for_each_entry(control, &apm->widget_list, node) { 882 + if (control->w && !strcmp(name, control->w->name)) 883 + return control; 884 + } 885 + 886 + return NULL; 887 + } 888 + 889 + static struct audioreach_module *audioreach_find_module(struct snd_soc_component *comp, 876 890 const char *name) 877 891 { 878 892 struct q6apm *apm = dev_get_drvdata(comp->dev); ··· 904 890 static int audioreach_route_load(struct snd_soc_component *scomp, int index, 905 891 struct snd_soc_dapm_route *route) 906 892 { 907 - struct audioreach_module *src, *sink; 893 + struct audioreach_module *src_module, *sink_module; 894 + struct snd_ar_control *control; 895 + struct snd_soc_dapm_widget *w; 896 + int i; 908 897 909 - src = audioreach_find_widget(scomp, route->source); 910 - sink = audioreach_find_widget(scomp, route->sink); 898 + /* check if these are actual modules */ 899 + src_module = audioreach_find_module(scomp, route->source); 900 + sink_module = audioreach_find_module(scomp, route->sink); 911 901 912 - if (src && sink) { 913 - src->dst_mod_inst_id = sink->instance_id; 914 - sink->src_mod_inst_id = src->instance_id; 902 + if (sink_module && !src_module) { 903 + control = audioreach_find_widget(scomp, route->source); 904 + if (control) 905 + control->module_instance_id = sink_module->instance_id; 906 + 907 + } else if (!sink_module && src_module && route->control) { 908 + /* check if this is a virtual mixer */ 909 + control = audioreach_find_widget(scomp, route->sink); 910 + if (!control || !control->w) 911 + return 0; 912 + 913 + w = control->w; 914 + 915 + for (i = 0; i < w->num_kcontrols; i++) { 916 + if (!strcmp(route->control, w->kcontrol_news[i].name)) { 917 + struct soc_mixer_control *sm; 918 + struct snd_soc_dobj *dobj; 919 + struct snd_ar_control *scontrol; 920 + 921 + sm = (struct soc_mixer_control *)w->kcontrol_news[i].private_value; 922 + dobj = &sm->dobj; 923 + scontrol = dobj->private; 924 + scontrol->module_instance_id = src_module->instance_id; 925 + } 926 + } 927 + 915 928 } 916 929 917 930 return 0; ··· 969 928 return 0; 970 929 } 971 930 931 + static void audioreach_connect_sub_graphs(struct q6apm *apm, 932 + struct snd_ar_control *m1, 933 + struct snd_ar_control *m2, 934 + bool connect) 935 + { 936 + struct audioreach_graph_info *info; 937 + 938 + mutex_lock(&apm->lock); 939 + info = idr_find(&apm->graph_info_idr, m2->graph_id); 940 + mutex_unlock(&apm->lock); 941 + 942 + if (connect) { 943 + info->src_mod_inst_id = m1->module_instance_id; 944 + info->src_mod_op_port_id = 1; 945 + info->dst_mod_inst_id = m2->module_instance_id; 946 + info->dst_mod_ip_port_id = 2; 947 + 948 + } else { 949 + info->src_mod_inst_id = 0; 950 + info->src_mod_op_port_id = 0; 951 + info->dst_mod_inst_id = 0; 952 + info->dst_mod_ip_port_id = 0; 953 + } 954 + } 955 + 956 + static bool audioreach_is_vmixer_connected(struct q6apm *apm, 957 + struct snd_ar_control *m1, 958 + struct snd_ar_control *m2) 959 + { 960 + struct audioreach_graph_info *info; 961 + 962 + mutex_lock(&apm->lock); 963 + info = idr_find(&apm->graph_info_idr, m2->graph_id); 964 + mutex_unlock(&apm->lock); 965 + 966 + if (info->dst_mod_inst_id == m2->module_instance_id && 967 + info->src_mod_inst_id == m1->module_instance_id) 968 + return true; 969 + 970 + return false; 971 + } 972 + 972 973 static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol, 973 974 struct snd_ctl_elem_value *ucontrol) 974 975 { ··· 1023 940 struct q6apm *data = dev_get_drvdata(c->dev); 1024 941 bool connected; 1025 942 1026 - connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid); 943 + connected = audioreach_is_vmixer_connected(data, scontrol, dapm_scontrol); 1027 944 if (connected) 1028 945 ucontrol->value.integer.value[0] = 1; 1029 946 else ··· 1044 961 struct q6apm *data = dev_get_drvdata(c->dev); 1045 962 1046 963 if (ucontrol->value.integer.value[0]) { 1047 - q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true); 964 + audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, true); 1048 965 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL); 1049 966 } else { 1050 - q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false); 967 + audioreach_connect_sub_graphs(data, scontrol, dapm_scontrol, false); 1051 968 snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL); 1052 969 } 1053 970 return 0;