@@ -269,6 +269,10 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc
269269 is_virtual_widget (sdev , sink_widget -> widget , __func__ ))
270270 return 0 ;
271271
272+ /* skip route if source/sink widget is not set up */
273+ if (!src_widget -> use_count || !sink_widget -> use_count )
274+ return 0 ;
275+
272276 /* find route matching source and sink widgets */
273277 list_for_each_entry (sroute , & sdev -> route_list , list )
274278 if (sroute -> src_widget == src_widget && sroute -> sink_widget == sink_widget ) {
@@ -297,10 +301,34 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc
297301 return 0 ;
298302}
299303
304+ static bool sof_widget_in_same_direction (struct snd_sof_widget * swidget , int dir )
305+ {
306+ return swidget -> spipe -> direction == dir ;
307+ }
308+
309+ static int sof_set_up_same_dir_widget_routes (struct snd_sof_dev * sdev ,
310+ struct snd_soc_dapm_widget * wsource ,
311+ struct snd_soc_dapm_widget * wsink )
312+ {
313+ struct snd_sof_widget * src_widget = wsource -> dobj .private ;
314+ struct snd_sof_widget * sink_widget = wsink -> dobj .private ;
315+
316+ /*
317+ * skip setting up route if source and sink are in different directions (ex. playback and
318+ * echo ref) if the direction is set in topology. These will be set up later. It is enough
319+ * to check if the direction_valid is set for one of the widgets as all widgets will have
320+ * the direction set in topology if one is set.
321+ */
322+ if (sink_widget -> spipe && sink_widget -> spipe -> direction_valid &&
323+ !sof_widget_in_same_direction (sink_widget , src_widget -> spipe -> direction ))
324+ return 0 ;
325+
326+ return sof_route_setup (sdev , wsource , wsink );
327+ }
328+
300329static int sof_setup_pipeline_connections (struct snd_sof_dev * sdev ,
301330 struct snd_soc_dapm_widget_list * list , int dir )
302331{
303- const struct sof_ipc_tplg_ops * tplg_ops = sof_ipc_get_ops (sdev , tplg );
304332 struct snd_soc_dapm_widget * widget ;
305333 struct snd_sof_route * sroute ;
306334 struct snd_soc_dapm_path * p ;
@@ -323,7 +351,8 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
323351 continue ;
324352
325353 if (p -> sink -> dobj .private ) {
326- ret = sof_route_setup (sdev , widget , p -> sink );
354+ ret = sof_set_up_same_dir_widget_routes (sdev , widget ,
355+ p -> sink );
327356 if (ret < 0 )
328357 return ret ;
329358 }
@@ -339,7 +368,8 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
339368 continue ;
340369
341370 if (p -> source -> dobj .private ) {
342- ret = sof_route_setup (sdev , p -> source , widget );
371+ ret = sof_set_up_same_dir_widget_routes (sdev , p -> source ,
372+ widget );
343373 if (ret < 0 )
344374 return ret ;
345375 }
@@ -355,7 +385,6 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
355385 */
356386 list_for_each_entry (sroute , & sdev -> route_list , list ) {
357387 bool src_widget_in_dapm_list , sink_widget_in_dapm_list ;
358- struct snd_sof_widget * swidget ;
359388
360389 if (sroute -> setup )
361390 continue ;
@@ -364,40 +393,37 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
364393 sink_widget_in_dapm_list = widget_in_list (list , sroute -> sink_widget -> widget );
365394
366395 /*
367- * if both source and sink are in the DAPM list, the route must already have been
368- * set up above. And if neither are in the DAPM list, the route shouldn't be
369- * handled now.
396+ * no need to set up the route if both the source and sink widgets are not in the
397+ * DAPM list
370398 */
371- if (src_widget_in_dapm_list == sink_widget_in_dapm_list )
399+ if (! src_widget_in_dapm_list && ! sink_widget_in_dapm_list )
372400 continue ;
373401
374402 /*
375- * At this point either the source widget or the sink widget is in the DAPM list
376- * with a route that might need to be set up. Check the use_count of the widget
377- * that is not in the DAPM list to confirm if it is in use currently before setting
378- * up the route.
403+ * set up the route only if both the source and sink widgets are in the DAPM list
404+ * but are in different directions. The ones in the same direction would already
405+ * have been set up in the previous loop.
379406 */
380- if (src_widget_in_dapm_list )
381- swidget = sroute -> sink_widget ;
382- else
383- swidget = sroute -> src_widget ;
407+ if (src_widget_in_dapm_list && sink_widget_in_dapm_list ) {
408+ struct snd_sof_widget * src_widget , * sink_widget ;
384409
385- scoped_guard (mutex , & swidget -> setup_mutex ) {
386- if (!swidget -> use_count )
387- continue ;
410+ src_widget = sroute -> src_widget -> widget -> dobj .private ;
411+ sink_widget = sroute -> sink_widget -> widget -> dobj .private ;
388412
389- if (tplg_ops && tplg_ops -> route_setup ) {
390- /*
391- * this route will get freed when either the
392- * source widget or the sink widget is freed
393- * during hw_free
394- */
395- ret = tplg_ops -> route_setup (sdev , sroute );
396- if (!ret )
397- sroute -> setup = true;
398- }
413+ /*
414+ * it is enough to check if the direction_valid is set for one of the
415+ * widgets as all widgets will have the direction set in topology if one
416+ * is set.
417+ */
418+ if (src_widget && sink_widget &&
419+ src_widget -> spipe && src_widget -> spipe -> direction_valid &&
420+ sof_widget_in_same_direction (sink_widget , src_widget -> spipe -> direction ))
421+ continue ;
399422 }
400423
424+ ret = sof_route_setup (sdev , sroute -> src_widget -> widget ,
425+ sroute -> sink_widget -> widget );
426+
401427 if (ret < 0 )
402428 return ret ;
403429 }
@@ -407,7 +433,7 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
407433
408434static void
409435sof_unprepare_widgets_in_path (struct snd_sof_dev * sdev , struct snd_soc_dapm_widget * widget ,
410- struct snd_soc_dapm_widget_list * list )
436+ struct snd_soc_dapm_widget_list * list , int dir )
411437{
412438 const struct sof_ipc_tplg_ops * tplg_ops = sof_ipc_get_ops (sdev , tplg );
413439 struct snd_sof_widget * swidget = widget -> dobj .private ;
@@ -417,9 +443,15 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg
417443 if (is_virtual_widget (sdev , widget , __func__ ))
418444 return ;
419445
420- /* skip if the widget in use or already unprepared or is an aggregated DAI */
421- if (!swidget || !swidget -> prepared || swidget -> use_count > 0 ||
422- is_aggregated_dai (swidget ))
446+ if (!swidget )
447+ goto sink_unprepare ;
448+
449+ if (swidget -> spipe && swidget -> spipe -> direction_valid &&
450+ !sof_widget_in_same_direction (swidget , dir ))
451+ return ;
452+
453+ /* skip widgets in use, those already unprepared or aggregated DAIs */
454+ if (!swidget -> prepared || swidget -> use_count > 0 || is_aggregated_dai (swidget ))
423455 goto sink_unprepare ;
424456
425457 widget_ops = tplg_ops ? tplg_ops -> widget : NULL ;
@@ -434,9 +466,10 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg
434466 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
435467 if (!widget_in_list (list , p -> sink ))
436468 continue ;
469+
437470 if (!p -> walking && p -> sink -> dobj .private ) {
438471 p -> walking = true;
439- sof_unprepare_widgets_in_path (sdev , p -> sink , list );
472+ sof_unprepare_widgets_in_path (sdev , p -> sink , list , dir );
440473 p -> walking = false;
441474 }
442475 }
@@ -458,15 +491,20 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
458491 if (is_virtual_widget (sdev , widget , __func__ ))
459492 return 0 ;
460493
494+ if (!swidget )
495+ goto sink_prepare ;
496+
461497 widget_ops = tplg_ops ? tplg_ops -> widget : NULL ;
462498 if (!widget_ops )
463499 return 0 ;
464500
465- if (!swidget || !widget_ops [widget -> id ].ipc_prepare || swidget -> prepared )
466- goto sink_prepare ;
501+ if (swidget -> spipe && swidget -> spipe -> direction_valid &&
502+ !sof_widget_in_same_direction (swidget , dir ))
503+ return 0 ;
467504
468- /* skip aggregated DAIs */
469- if (is_aggregated_dai (swidget ))
505+ /* skip widgets already prepared or aggregated DAI widgets*/
506+ if (!widget_ops [widget -> id ].ipc_prepare || swidget -> prepared ||
507+ is_aggregated_dai (swidget ))
470508 goto sink_prepare ;
471509
472510 /* prepare the source widget */
@@ -484,6 +522,7 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
484522 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
485523 if (!widget_in_list (list , p -> sink ))
486524 continue ;
525+
487526 if (!p -> walking && p -> sink -> dobj .private ) {
488527 p -> walking = true;
489528 ret = sof_prepare_widgets_in_path (sdev , p -> sink , fe_params ,
@@ -513,23 +552,29 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap
513552 int dir , struct snd_sof_pcm * spcm )
514553{
515554 struct snd_soc_dapm_widget_list * list = spcm -> stream [dir ].list ;
516- struct snd_sof_widget * swidget ;
555+ struct snd_sof_widget * swidget = widget -> dobj . private ;
517556 struct snd_soc_dapm_path * p ;
518557 int err ;
519558 int ret = 0 ;
520559
521560 if (is_virtual_widget (sdev , widget , __func__ ))
522561 return 0 ;
523562
524- swidget = widget -> dobj .private ;
563+ if (!swidget )
564+ goto sink_free ;
525565
526- /* no need to free aggregated DAI widgets */
527- if (swidget && !is_aggregated_dai (swidget )) {
528- err = sof_widget_free (sdev , swidget );
529- if (err < 0 )
530- ret = err ;
531- }
566+ if (swidget -> spipe && swidget -> spipe -> direction_valid &&
567+ !sof_widget_in_same_direction (swidget , dir ))
568+ return 0 ;
532569
570+ /* skip aggregated DAIs */
571+ if (is_aggregated_dai (swidget ))
572+ goto sink_free ;
573+
574+ err = sof_widget_free (sdev , widget -> dobj .private );
575+ if (err < 0 )
576+ ret = err ;
577+ sink_free :
533578 /* free all widgets in the sink paths even in case of error to keep use counts balanced */
534579 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
535580 if (!p -> walking ) {
@@ -569,6 +614,11 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d
569614 if (swidget ) {
570615 int i ;
571616
617+ if (swidget -> spipe && swidget -> spipe -> direction_valid &&
618+ !sof_widget_in_same_direction (swidget , dir ))
619+ return 0 ;
620+
621+ /* skip aggregated DAIs */
572622 if (is_aggregated_dai (swidget ))
573623 goto sink_setup ;
574624
@@ -634,15 +684,13 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
634684 return 0 ;
635685
636686 for_each_dapm_widgets (list , i , widget ) {
637- if (is_virtual_widget (sdev , widget , __func__ ))
638- continue ;
639-
640- /* starting widget for playback is AIF type */
687+ /* starting widget for playback is of AIF type */
641688 if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget -> id != snd_soc_dapm_aif_in )
642689 continue ;
643690
644691 /* starting widget for capture is DAI type */
645- if (dir == SNDRV_PCM_STREAM_CAPTURE && widget -> id != snd_soc_dapm_dai_out )
692+ if (dir == SNDRV_PCM_STREAM_CAPTURE && widget -> id != snd_soc_dapm_dai_out &&
693+ widget -> id != snd_soc_dapm_output )
646694 continue ;
647695
648696 switch (op ) {
@@ -672,7 +720,7 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
672720 break ;
673721 }
674722 case SOF_WIDGET_UNPREPARE :
675- sof_unprepare_widgets_in_path (sdev , widget , list );
723+ sof_unprepare_widgets_in_path (sdev , widget , list , dir );
676724 break ;
677725 default :
678726 dev_err (sdev -> dev , "Invalid widget op %d\n" , op );
0 commit comments