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

ASoC: dapm: Fix handling of custom_stop_condition on DAPM graph walks

DPCM uses snd_soc_dapm_dai_get_connected_widgets to build a
list of the widgets connected to a specific front end DAI so it
can search through this list for available back end DAIs. The
custom_stop_condition was added to is_connected_ep to facilitate this
list not containing more widgets than is necessary. Doing so both
speeds up the DPCM handling as less widgets need to be searched and
avoids issues with CODEC to CODEC links as these would be confused
with back end DAIs if they appeared in the list of available widgets.

custom_stop_condition was implemented by aborting the graph walk
when the condition is triggered, however there is an issue with this
approach. Whilst walking the graph is_connected_ep should update the
endpoints cache on each widget, if the walk is aborted the number
of attached end points is unknown for that sub-graph. When the stop
condition triggered, the original patch ignored the triggering widget
and returned zero connected end points; a later patch updated this
to set the triggering widget's cache to 1 and return that. Both of
these approaches result in inaccurate values being stored in various
end point caches as the values propagate back through the graph,
which can result in later issues with widgets powering/not powering
unexpectedly.

As the original goal was to reduce the size of the widget list passed
to the DPCM code, the simplest solution is to limit the functionality
of the custom_stop_condition to the widget list. This means the rest
of the graph will still be processed resulting in correct end point
caches, but only widgets up to the stop condition will be added to the
returned widget list.

Fixes: 6742064aef7f ("ASoC: dapm: support user-defined stop condition in dai_get_connected_widgets")
Fixes: 5fdd022c2026 ("ASoC: dpcm: play nice with CODEC<->CODEC links")
Fixes: 09464974eaa8 ("ASoC: dapm: Fix to return correct path list in is_connected_ep.")
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20190718084333.15598-1-ckeepax@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Charles Keepax and committed by
Mark Brown
8dd26dff aa2ba991

+4 -4
+4 -4
sound/soc/soc-dapm.c
··· 1157 1157 list_add_tail(&widget->work_list, list); 1158 1158 1159 1159 if (custom_stop_condition && custom_stop_condition(widget, dir)) { 1160 - widget->endpoints[dir] = 1; 1161 - return widget->endpoints[dir]; 1160 + list = NULL; 1161 + custom_stop_condition = NULL; 1162 1162 } 1163 1163 1164 1164 if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) { ··· 1195 1195 * 1196 1196 * Optionally, can be supplied with a function acting as a stopping condition. 1197 1197 * This function takes the dapm widget currently being examined and the walk 1198 - * direction as an arguments, it should return true if the walk should be 1199 - * stopped and false otherwise. 1198 + * direction as an arguments, it should return true if widgets from that point 1199 + * in the graph onwards should not be added to the widget list. 1200 1200 */ 1201 1201 static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, 1202 1202 struct list_head *list,