[alsa-devel] [PATCH 1/5] ASoC: dapm: Drop always true checks
list_first_entry() always returns non NULL and since the code previously checked that list is not empty it will also be a valid pointer. Furthermore a path has always a sink or a source widget. So both checks are redundant and can be removed.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/soc-dapm.c | 5 ----- 1 file changed, 5 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7f834a0..10f7c7c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3485,11 +3485,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path, list_source);
- if (WARN_ON(!source_p || !sink_p) || - WARN_ON(!sink_p->source || !source_p->sink) || - WARN_ON(!source_p->source || !sink_p->sink)) - return -EINVAL; - source = source_p->source->priv; sink = sink_p->sink->priv;
When running dapm_dai_get_connected_widgets() currently in is_connected_{input,output}_ep() for each widget that gets added the array is resized and the code also loops over all existing entries to avoid adding a widget multiple times.
The former can be avoided by collecting the widgets in a linked list and only once we have all widgets allocate the array.
The later can be avoided by changing when the widget is added. Currently it is added when walking the neighbor lists of a widget. Since a widget can be neighbors with multiple other widgets it could get added twice and hence the check is necessary. But the main body of is_connected_{input,output}_ep is guaranteed to be only executed at most once per widget. So adding the widget to the list at the beginning of the function automatically makes sure that each widget gets only added once. The only difference is that using this method the starting point itself will also end up on the list, but it can easily be skipped when creating the array.
Overall this reduces the code size and speeds things slightly up.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/soc-dapm.c | 101 ++++++++++++++++++--------------------------------- sound/soc/soc-pcm.c | 11 +----- 2 files changed, 38 insertions(+), 74 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 10f7c7c..7704bc8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1032,43 +1032,27 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) } }
-/* add widget to list if it's not already in the list */ -static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, - struct snd_soc_dapm_widget *w) +static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, + struct list_head *widgets) { - struct snd_soc_dapm_widget_list *wlist; - int wlistsize, wlistentries, i; - - if (*list == NULL) - return -EINVAL; - - wlist = *list; + struct snd_soc_dapm_widget *w; + struct list_head *it; + unsigned int size = 0; + unsigned int i = 0;
- /* is this widget already in the list */ - for (i = 0; i < wlist->num_widgets; i++) { - if (wlist->widgets[i] == w) - return 0; - } + list_for_each(it, widgets) + size++;
- /* allocate some new space */ - wlistentries = wlist->num_widgets + 1; - wlistsize = sizeof(struct snd_soc_dapm_widget_list) + - wlistentries * sizeof(struct snd_soc_dapm_widget *); - *list = krealloc(wlist, wlistsize, GFP_KERNEL); - if (*list == NULL) { - dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n", - w->name); + *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL); + if (*list == NULL) return -ENOMEM; - } - wlist = *list;
- /* insert the widget */ - dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n", - w->name, wlist->num_widgets); + list_for_each_entry(w, widgets, work_list) + (*list)->widgets[i++] = w;
- wlist->widgets[wlist->num_widgets] = w; - wlist->num_widgets++; - return 1; + (*list)->num_widgets = i; + + return 0; }
/* @@ -1076,7 +1060,7 @@ static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, * output widget. Returns number of complete paths. */ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_widget_list **list) + struct list_head *list) { struct snd_soc_dapm_path *path; int con = 0; @@ -1086,6 +1070,10 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
DAPM_UPDATE_STAT(widget, path_checks);
+ /* do we need to add this widget to the list ? */ + if (list) + list_add_tail(&widget->work_list, list); + if (widget->is_sink && widget->connected) { widget->outputs = snd_soc_dapm_suspend_check(widget); return widget->outputs; @@ -1104,22 +1092,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
if (path->connect) { path->walking = 1; - - /* do we need to add this widget to the list ? */ - if (list) { - int err; - err = dapm_list_add_widget(list, path->sink); - if (err < 0) { - dev_err(widget->dapm->dev, - "ASoC: could not add widget %s\n", - widget->name); - path->walking = 0; - return con; - } - } - con += is_connected_output_ep(path->sink, list); - path->walking = 0; } } @@ -1134,7 +1107,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, * input widget. Returns number of complete paths. */ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_widget_list **list) + struct list_head *list) { struct snd_soc_dapm_path *path; int con = 0; @@ -1144,6 +1117,10 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
DAPM_UPDATE_STAT(widget, path_checks);
+ /* do we need to add this widget to the list ? */ + if (list) + list_add_tail(&widget->work_list, list); + if (widget->is_source && widget->connected) { widget->inputs = snd_soc_dapm_suspend_check(widget); return widget->inputs; @@ -1162,22 +1139,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
if (path->connect) { path->walking = 1; - - /* do we need to add this widget to the list ? */ - if (list) { - int err; - err = dapm_list_add_widget(list, path->source); - if (err < 0) { - dev_err(widget->dapm->dev, - "ASoC: could not add widget %s\n", - widget->name); - path->walking = 0; - return con; - } - } - con += is_connected_input_ep(path->source, list); - path->walking = 0; } } @@ -1204,7 +1166,9 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, { struct snd_soc_card *card = dai->component->card; struct snd_soc_dapm_widget *w; + LIST_HEAD(widgets); int paths; + int ret;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
@@ -1218,9 +1182,16 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, }
if (stream == SNDRV_PCM_STREAM_PLAYBACK) - paths = is_connected_output_ep(dai->playback_widget, list); + paths = is_connected_output_ep(dai->playback_widget, &widgets); else - paths = is_connected_input_ep(dai->capture_widget, list); + paths = is_connected_input_ep(dai->capture_widget, &widgets); + + /* Drop starting point */ + list_del(widgets.next); + + ret = dapm_widget_list_create(list, &widgets); + if (ret) + return ret;
trace_snd_soc_dapm_connected(paths, stream); mutex_unlock(&card->dapm_mutex); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a6d3313..70e4b9d 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1231,24 +1231,17 @@ static int widget_in_list(struct snd_soc_dapm_widget_list *list, }
int dpcm_path_get(struct snd_soc_pcm_runtime *fe, - int stream, struct snd_soc_dapm_widget_list **list_) + int stream, struct snd_soc_dapm_widget_list **list) { struct snd_soc_dai *cpu_dai = fe->cpu_dai; - struct snd_soc_dapm_widget_list *list; int paths;
- list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) + - sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL); - if (list == NULL) - return -ENOMEM; - /* get number of valid DAI paths and their widgets */ - paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list); + paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list);
dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, stream ? "capture" : "playback");
- *list_ = list; return paths; }
The patch
ASoC: dapm: Simplify list creation in dapm_dai_get_connected_widgets()
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 1ce43acff0c078fd560ee0f2a4ae10b8da28e388 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen lars@metafoo.de Date: Sun, 26 Jul 2015 19:04:59 +0200 Subject: [PATCH] ASoC: dapm: Simplify list creation in dapm_dai_get_connected_widgets()
When running dapm_dai_get_connected_widgets() currently in is_connected_{input,output}_ep() for each widget that gets added the array is resized and the code also loops over all existing entries to avoid adding a widget multiple times.
The former can be avoided by collecting the widgets in a linked list and only once we have all widgets allocate the array.
The later can be avoided by changing when the widget is added. Currently it is added when walking the neighbor lists of a widget. Since a widget can be neighbors with multiple other widgets it could get added twice and hence the check is necessary. But the main body of is_connected_{input,output}_ep is guaranteed to be only executed at most once per widget. So adding the widget to the list at the beginning of the function automatically makes sure that each widget gets only added once. The only difference is that using this method the starting point itself will also end up on the list, but it can easily be skipped when creating the array.
Overall this reduces the code size and speeds things slightly up.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/soc-dapm.c | 101 ++++++++++++++++++--------------------------------- sound/soc/soc-pcm.c | 11 +----- 2 files changed, 38 insertions(+), 74 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index f80b7de..4586f95 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1032,43 +1032,27 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) } }
-/* add widget to list if it's not already in the list */ -static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, - struct snd_soc_dapm_widget *w) +static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, + struct list_head *widgets) { - struct snd_soc_dapm_widget_list *wlist; - int wlistsize, wlistentries, i; - - if (*list == NULL) - return -EINVAL; - - wlist = *list; + struct snd_soc_dapm_widget *w; + struct list_head *it; + unsigned int size = 0; + unsigned int i = 0;
- /* is this widget already in the list */ - for (i = 0; i < wlist->num_widgets; i++) { - if (wlist->widgets[i] == w) - return 0; - } + list_for_each(it, widgets) + size++;
- /* allocate some new space */ - wlistentries = wlist->num_widgets + 1; - wlistsize = sizeof(struct snd_soc_dapm_widget_list) + - wlistentries * sizeof(struct snd_soc_dapm_widget *); - *list = krealloc(wlist, wlistsize, GFP_KERNEL); - if (*list == NULL) { - dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n", - w->name); + *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL); + if (*list == NULL) return -ENOMEM; - } - wlist = *list;
- /* insert the widget */ - dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n", - w->name, wlist->num_widgets); + list_for_each_entry(w, widgets, work_list) + (*list)->widgets[i++] = w;
- wlist->widgets[wlist->num_widgets] = w; - wlist->num_widgets++; - return 1; + (*list)->num_widgets = i; + + return 0; }
/* @@ -1076,7 +1060,7 @@ static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list, * output widget. Returns number of complete paths. */ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_widget_list **list) + struct list_head *list) { struct snd_soc_dapm_path *path; int con = 0; @@ -1086,6 +1070,10 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
DAPM_UPDATE_STAT(widget, path_checks);
+ /* do we need to add this widget to the list ? */ + if (list) + list_add_tail(&widget->work_list, list); + if (widget->is_sink && widget->connected) { widget->outputs = snd_soc_dapm_suspend_check(widget); return widget->outputs; @@ -1104,22 +1092,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
if (path->connect) { path->walking = 1; - - /* do we need to add this widget to the list ? */ - if (list) { - int err; - err = dapm_list_add_widget(list, path->sink); - if (err < 0) { - dev_err(widget->dapm->dev, - "ASoC: could not add widget %s\n", - widget->name); - path->walking = 0; - return con; - } - } - con += is_connected_output_ep(path->sink, list); - path->walking = 0; } } @@ -1134,7 +1107,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, * input widget. Returns number of complete paths. */ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_widget_list **list) + struct list_head *list) { struct snd_soc_dapm_path *path; int con = 0; @@ -1144,6 +1117,10 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
DAPM_UPDATE_STAT(widget, path_checks);
+ /* do we need to add this widget to the list ? */ + if (list) + list_add_tail(&widget->work_list, list); + if (widget->is_source && widget->connected) { widget->inputs = snd_soc_dapm_suspend_check(widget); return widget->inputs; @@ -1162,22 +1139,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
if (path->connect) { path->walking = 1; - - /* do we need to add this widget to the list ? */ - if (list) { - int err; - err = dapm_list_add_widget(list, path->source); - if (err < 0) { - dev_err(widget->dapm->dev, - "ASoC: could not add widget %s\n", - widget->name); - path->walking = 0; - return con; - } - } - con += is_connected_input_ep(path->source, list); - path->walking = 0; } } @@ -1204,7 +1166,9 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, { struct snd_soc_card *card = dai->component->card; struct snd_soc_dapm_widget *w; + LIST_HEAD(widgets); int paths; + int ret;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
@@ -1218,9 +1182,16 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, }
if (stream == SNDRV_PCM_STREAM_PLAYBACK) - paths = is_connected_output_ep(dai->playback_widget, list); + paths = is_connected_output_ep(dai->playback_widget, &widgets); else - paths = is_connected_input_ep(dai->capture_widget, list); + paths = is_connected_input_ep(dai->capture_widget, &widgets); + + /* Drop starting point */ + list_del(widgets.next); + + ret = dapm_widget_list_create(list, &widgets); + if (ret) + return ret;
trace_snd_soc_dapm_connected(paths, stream); mutex_unlock(&card->dapm_mutex); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 256b9c9..7aed170 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1231,24 +1231,17 @@ static int widget_in_list(struct snd_soc_dapm_widget_list *list, }
int dpcm_path_get(struct snd_soc_pcm_runtime *fe, - int stream, struct snd_soc_dapm_widget_list **list_) + int stream, struct snd_soc_dapm_widget_list **list) { struct snd_soc_dai *cpu_dai = fe->cpu_dai; - struct snd_soc_dapm_widget_list *list; int paths;
- list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) + - sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL); - if (list == NULL) - return -ENOMEM; - /* get number of valid DAI paths and their widgets */ - paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list); + paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list);
dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, stream ? "capture" : "playback");
- *list_ = list; return paths; }
Add helper iterator macros for iterating over the source and sink paths of widget. This will make it easier to change the implementation later on.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc-dapm.h | 18 ++++++++++++++++++ sound/soc/intel/atom/sst-atom-controls.c | 4 ++-- sound/soc/soc-dapm.c | 30 +++++++++++++++--------------- 3 files changed, 35 insertions(+), 17 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index cadc7fc..4973083 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -673,4 +673,22 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( return dapm->bias_level; }
+/** + * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a + * widget + * @w: The widget + * @p: The path iterator variable + */ +#define snd_soc_dapm_widget_for_each_sink_path(w, p) \ + list_for_each_entry(p, &w->sinks, list_source) + +/** + * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to + * a widget + * @w: The widget + * @p: The path iterator variable + */ +#define snd_soc_dapm_widget_for_each_source_path(w, p) \ + list_for_each_entry(p, &w->sources, list_sink) + #endif diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index c95bc52..d55388e 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -1298,7 +1298,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dev_dbg(dai->dev, "Stream name=%s\n", dai->playback_widget->name); w = dai->playback_widget; - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue;
@@ -1317,7 +1317,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dev_dbg(dai->dev, "Stream name=%s\n", dai->capture_widget->name); w = dai->capture_widget; - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7704bc8..7482c5d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -193,7 +193,7 @@ static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) list_add_tail(&w->work_list, &list);
list_for_each_entry(w, &list, work_list) { - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->is_supply || p->weak || !p->connect) continue; sink = p->sink; @@ -232,7 +232,7 @@ static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w) list_add_tail(&w->work_list, &list);
list_for_each_entry(w, &list, work_list) { - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->is_supply || p->weak || !p->connect) continue; source = p->source; @@ -894,7 +894,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) /* add kcontrol */ for (i = 0; i < w->num_kcontrols; i++) { /* match name */ - list_for_each_entry(path, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, path) { /* mixer/mux paths name must match control name */ if (path->name != (char *)w->kcontrol_news[i].name) continue; @@ -958,12 +958,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) return ret;
if (w->id == snd_soc_dapm_mux) { - list_for_each_entry(path, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, path) { if (path->name) dapm_kcontrol_add_path(w->kcontrols[0], path); } } else { - list_for_each_entry(path, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, path) { if (path->name) dapm_kcontrol_add_path(w->kcontrols[0], path); } @@ -1079,7 +1079,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, return widget->outputs; }
- list_for_each_entry(path, &widget->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(widget, path) { DAPM_UPDATE_STAT(widget, neighbour_checks);
if (path->weak || path->is_supply) @@ -1126,7 +1126,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, return widget->inputs; }
- list_for_each_entry(path, &widget->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(widget, path) { DAPM_UPDATE_STAT(widget, neighbour_checks);
if (path->weak || path->is_supply) @@ -1292,7 +1292,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) DAPM_UPDATE_STAT(w, power_checks);
/* Check if one of our outputs is connected */ - list_for_each_entry(path, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, path) { DAPM_UPDATE_STAT(w, neighbour_checks);
if (path->weak) @@ -1716,12 +1716,12 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, /* If we changed our power state perhaps our neigbours changed * also. */ - list_for_each_entry(path, &w->sources, list_sink) + snd_soc_dapm_widget_for_each_source_path(w, path) dapm_widget_set_peer_power(path->source, power, path->connect);
/* Supplies can't affect their outputs, only their inputs */ if (!w->is_supply) { - list_for_each_entry(path, &w->sinks, list_source) + snd_soc_dapm_widget_for_each_sink_path(w, path) dapm_widget_set_peer_power(path->sink, power, path->connect); } @@ -1958,7 +1958,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, w->sname, w->active ? "active" : "inactive");
- list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connected && !p->connected(w, p->source)) continue;
@@ -1968,7 +1968,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, p->name ? p->name : "static", p->source->name); } - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue;
@@ -2429,7 +2429,7 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) if (w->dapm->card->fully_routed) break; w->is_source = 1; - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->source->id == snd_soc_dapm_micbias || p->source->id == snd_soc_dapm_mic || p->source->id == snd_soc_dapm_line || @@ -2444,7 +2444,7 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) if (w->dapm->card->fully_routed) break; w->is_sink = 1; - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->sink->id == snd_soc_dapm_spk || p->sink->id == snd_soc_dapm_hp || p->sink->id == snd_soc_dapm_line || @@ -2844,7 +2844,7 @@ static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n", route->source, route->sink);
- list_for_each_entry(path, &source->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(source, path) { if (path->sink == sink) { path->weak = 1; count++;
The patch
ASoC: dapm: Add widget path iterators
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From e63bfd45aba4269811662de0954785622a2ac928 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen lars@metafoo.de Date: Sun, 26 Jul 2015 19:05:00 +0200 Subject: [PATCH] ASoC: dapm: Add widget path iterators
Add helper iterator macros for iterating over the source and sink paths of widget. This will make it easier to change the implementation later on.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de Signed-off-by: Mark Brown broonie@kernel.org --- include/sound/soc-dapm.h | 18 ++++++++++++++++++ sound/soc/intel/atom/sst-atom-controls.c | 4 ++-- sound/soc/soc-dapm.c | 30 +++++++++++++++--------------- 3 files changed, 35 insertions(+), 17 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index cadc7fc..4973083 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -673,4 +673,22 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( return dapm->bias_level; }
+/** + * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a + * widget + * @w: The widget + * @p: The path iterator variable + */ +#define snd_soc_dapm_widget_for_each_sink_path(w, p) \ + list_for_each_entry(p, &w->sinks, list_source) + +/** + * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to + * a widget + * @w: The widget + * @p: The path iterator variable + */ +#define snd_soc_dapm_widget_for_each_source_path(w, p) \ + list_for_each_entry(p, &w->sources, list_sink) + #endif diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 31e9b9e..1399e34 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -1298,7 +1298,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dev_dbg(dai->dev, "Stream name=%s\n", dai->playback_widget->name); w = dai->playback_widget; - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue;
@@ -1317,7 +1317,7 @@ int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) dev_dbg(dai->dev, "Stream name=%s\n", dai->capture_widget->name); w = dai->capture_widget; - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 4586f95..ac506cf 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -193,7 +193,7 @@ static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) list_add_tail(&w->work_list, &list);
list_for_each_entry(w, &list, work_list) { - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->is_supply || p->weak || !p->connect) continue; sink = p->sink; @@ -232,7 +232,7 @@ static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w) list_add_tail(&w->work_list, &list);
list_for_each_entry(w, &list, work_list) { - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->is_supply || p->weak || !p->connect) continue; source = p->source; @@ -894,7 +894,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) /* add kcontrol */ for (i = 0; i < w->num_kcontrols; i++) { /* match name */ - list_for_each_entry(path, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, path) { /* mixer/mux paths name must match control name */ if (path->name != (char *)w->kcontrol_news[i].name) continue; @@ -958,12 +958,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) return ret;
if (w->id == snd_soc_dapm_mux) { - list_for_each_entry(path, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, path) { if (path->name) dapm_kcontrol_add_path(w->kcontrols[0], path); } } else { - list_for_each_entry(path, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, path) { if (path->name) dapm_kcontrol_add_path(w->kcontrols[0], path); } @@ -1079,7 +1079,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, return widget->outputs; }
- list_for_each_entry(path, &widget->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(widget, path) { DAPM_UPDATE_STAT(widget, neighbour_checks);
if (path->weak || path->is_supply) @@ -1126,7 +1126,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, return widget->inputs; }
- list_for_each_entry(path, &widget->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(widget, path) { DAPM_UPDATE_STAT(widget, neighbour_checks);
if (path->weak || path->is_supply) @@ -1292,7 +1292,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) DAPM_UPDATE_STAT(w, power_checks);
/* Check if one of our outputs is connected */ - list_for_each_entry(path, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, path) { DAPM_UPDATE_STAT(w, neighbour_checks);
if (path->weak) @@ -1716,12 +1716,12 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, /* If we changed our power state perhaps our neigbours changed * also. */ - list_for_each_entry(path, &w->sources, list_sink) + snd_soc_dapm_widget_for_each_source_path(w, path) dapm_widget_set_peer_power(path->source, power, path->connect);
/* Supplies can't affect their outputs, only their inputs */ if (!w->is_supply) { - list_for_each_entry(path, &w->sinks, list_source) + snd_soc_dapm_widget_for_each_sink_path(w, path) dapm_widget_set_peer_power(path->sink, power, path->connect); } @@ -1958,7 +1958,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, w->sname, w->active ? "active" : "inactive");
- list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connected && !p->connected(w, p->source)) continue;
@@ -1968,7 +1968,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, p->name ? p->name : "static", p->source->name); } - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connected && !p->connected(w, p->sink)) continue;
@@ -2426,7 +2426,7 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) if (w->dapm->card->fully_routed) break; w->is_source = 1; - list_for_each_entry(p, &w->sources, list_sink) { + snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->source->id == snd_soc_dapm_micbias || p->source->id == snd_soc_dapm_mic || p->source->id == snd_soc_dapm_line || @@ -2441,7 +2441,7 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) if (w->dapm->card->fully_routed) break; w->is_sink = 1; - list_for_each_entry(p, &w->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->sink->id == snd_soc_dapm_spk || p->sink->id == snd_soc_dapm_hp || p->sink->id == snd_soc_dapm_line || @@ -2841,7 +2841,7 @@ static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n", route->source, route->sink);
- list_for_each_entry(path, &source->sinks, list_source) { + snd_soc_dapm_widget_for_each_sink_path(source, path) { if (path->sink == sink) { path->weak = 1; count++;
After the recent cleanups and generalizations of the DAPM algorithm the handling of input and output paths is now fully symmetric. This means by making some slight changes to the data structure and using arrays with one entry for each direction, rather than separate fields, it is possible to create a generic implementation that is capable of handling both input and output paths.
Unfortunately this generalization significantly increases the code size on the hot path of is_connected_{input,output}_ep() and dapm_widget_invalidate_{input,output}_paths(), which has a negative impact on the overall performance. The inner loops of those functions are quite small and the generic implementation adds extra pointer arithmetic in a few places.
Testing on ARM shows that the combined code size of the specialized functions is about 50% larger than the generlized function in relative numbers. But in absolute numbers its less than 200 bytes, which is still quite small. On the other hand the generalized function increases the execution time of dapm_power_one_widget() by 30%. Given that this function is one of the most often called functions of the DAPM framework the tradeoff seems to be worth it.
To avoid this still keep two versions of these functions around, one for input and one for output. But have a generic implementation of the algorithm which gets inlined by those two versions and then let the compiler take care of optimizing it into specialized versions.
This still reduces the source code size as well as the makes making changes to the implementation more straight forward since the same change does no longer need to be done in two separate places. Also on the slow paths we can use a generic implementations that handle both input and output paths.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc-dapm.h | 54 ++++++-- sound/soc/soc-dapm.c | 353 +++++++++++++++++++++++------------------------ 2 files changed, 215 insertions(+), 192 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 4973083..535e9a3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -512,9 +512,18 @@ struct snd_soc_dapm_route { struct snd_soc_dapm_path { const char *name;
- /* source (input) and sink (output) widgets */ - struct snd_soc_dapm_widget *source; - struct snd_soc_dapm_widget *sink; + /* + * source (input) and sink (output) widgets + * The union is for convience, since it is a lot nicer to type + * p->source, rather than p->node[SND_SOC_DAPM_DIR_IN] + */ + union { + struct { + struct snd_soc_dapm_widget *source; + struct snd_soc_dapm_widget *sink; + }; + struct snd_soc_dapm_widget *node[2]; + };
/* status */ u32 connect:1; /* source and sink widgets are connected */ @@ -525,8 +534,7 @@ struct snd_soc_dapm_path { int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink);
- struct list_head list_source; - struct list_head list_sink; + struct list_head list_node[2]; struct list_head list_kcontrol; struct list_head list; }; @@ -560,8 +568,7 @@ struct snd_soc_dapm_widget { unsigned char new_power:1; /* power from this run */ unsigned char power_checked:1; /* power checked this run */ unsigned char is_supply:1; /* Widget is a supply type widget */ - unsigned char is_sink:1; /* Widget is a sink type widget */ - unsigned char is_source:1; /* Widget is a source type widget */ + unsigned char is_ep:2; /* Widget is a endpoint type widget */ int subseq; /* sort within widget type */
int (*power_check)(struct snd_soc_dapm_widget *w); @@ -576,16 +583,14 @@ struct snd_soc_dapm_widget { struct snd_kcontrol **kcontrols; struct snd_soc_dobj dobj;
- /* widget input and outputs */ - struct list_head sources; - struct list_head sinks; + /* widget input and output edges */ + struct list_head edges[2];
/* used during DAPM updates */ struct list_head work_list; struct list_head power_list; struct list_head dirty; - int inputs; - int outputs; + int endpoints[2];
struct clk *clk; }; @@ -673,6 +678,27 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( return dapm->bias_level; }
+enum snd_soc_dapm_direction { + SND_SOC_DAPM_DIR_IN, + SND_SOC_DAPM_DIR_OUT +}; + +#define SND_SOC_DAPM_DIR_TO_EP(x) BIT(x) + +#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN) +#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT) + +/** + * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the + * specified direction of a widget + * @w: The widget + * @dir: Whether to iterate over the paths where the specified widget is the + * incoming or outgoing widgets + * @p: The path iterator variable + */ +#define snd_soc_dapm_widget_for_each_path(w, dir, p) \ + list_for_each_entry(p, &w->edges[dir], list_node[dir]) + /** * snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths leaving a * widget @@ -680,7 +706,7 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( * @p: The path iterator variable */ #define snd_soc_dapm_widget_for_each_sink_path(w, p) \ - list_for_each_entry(p, &w->sinks, list_source) + snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_IN, p)
/** * snd_soc_dapm_widget_for_each_source_path - Iterates over all paths leading to @@ -689,6 +715,6 @@ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level( * @p: The path iterator variable */ #define snd_soc_dapm_widget_for_each_source_path(w, p) \ - list_for_each_entry(p, &w->sources, list_sink) + snd_soc_dapm_widget_for_each_path(w, SND_SOC_DAPM_DIR_OUT, p)
#endif diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7482c5d..12007be 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -47,6 +47,16 @@
#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
+#define dapm_widget_for_each_path_safe(w, dir, p, next_p) \ + list_for_each_entry_safe(p, next_p, &w->edges[dir], list_node[dir]) + +#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \ + SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN) + +#define dapm_for_each_direction(dir) \ + for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \ + (dir)++) + static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, const char *control, @@ -167,45 +177,59 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) }
/* - * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input - * paths - * @w: The widget for which to invalidate the cached number of input paths - * - * The function resets the cached number of inputs for the specified widget and - * all widgets that can be reached via outgoing paths from the widget. - * - * This function must be called if the number of input paths for a widget might - * have changed. E.g. if the source state of a widget changes or a path is added - * or activated with the widget as the sink. + * Common implementation for dapm_widget_invalidate_input_paths() and + * dapm_widget_invalidate_output_paths(). The function is inlined since the + * combined size of the two specialized functions is only marginally larger then + * the size of the generic function and at the same time the fast path of the + * specialized functions is significantly smaller than the generic function. */ -static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) +static __always_inline void dapm_widget_invalidate_paths( + struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir) { - struct snd_soc_dapm_widget *sink; + enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); + struct snd_soc_dapm_widget *node; struct snd_soc_dapm_path *p; LIST_HEAD(list);
dapm_assert_locked(w->dapm);
- if (w->inputs == -1) + if (w->endpoints[dir] == -1) return;
- w->inputs = -1; list_add_tail(&w->work_list, &list); + w->endpoints[dir] = -1;
list_for_each_entry(w, &list, work_list) { - snd_soc_dapm_widget_for_each_sink_path(w, p) { + snd_soc_dapm_widget_for_each_path(w, dir, p) { if (p->is_supply || p->weak || !p->connect) continue; - sink = p->sink; - if (sink->inputs != -1) { - sink->inputs = -1; - list_add_tail(&sink->work_list, &list); + node = p->node[rdir]; + if (node->endpoints[dir] != -1) { + node->endpoints[dir] = -1; + list_add_tail(&node->work_list, &list); } } } }
/* + * dapm_widget_invalidate_input_paths() - Invalidate the cached number of + * input paths + * @w: The widget for which to invalidate the cached number of input paths + * + * Resets the cached number of inputs for the specified widget and all widgets + * that can be reached via outcoming paths from the widget. + * + * This function must be called if the number of output paths for a widget might + * have changed. E.g. if the source state of a widget changes or a path is added + * or activated with the widget as the sink. + */ +static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) +{ + dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN); +} + +/* * dapm_widget_invalidate_output_paths() - Invalidate the cached number of * output paths * @w: The widget for which to invalidate the cached number of output paths @@ -219,29 +243,7 @@ static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) */ static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w) { - struct snd_soc_dapm_widget *source; - struct snd_soc_dapm_path *p; - LIST_HEAD(list); - - dapm_assert_locked(w->dapm); - - if (w->outputs == -1) - return; - - w->outputs = -1; - list_add_tail(&w->work_list, &list); - - list_for_each_entry(w, &list, work_list) { - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->is_supply || p->weak || !p->connect) - continue; - source = p->source; - if (source->outputs != -1) { - source->outputs = -1; - list_add_tail(&source->work_list, &list); - } - } - } + dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT); }
/* @@ -270,9 +272,9 @@ static void dapm_path_invalidate(struct snd_soc_dapm_path *p) * endpoints is either connected or disconnected that sum won't change, * so there is no need to re-check the path. */ - if (p->source->inputs != 0) + if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0) dapm_widget_invalidate_input_paths(p->sink); - if (p->sink->outputs != 0) + if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0) dapm_widget_invalidate_output_paths(p->source); }
@@ -283,11 +285,11 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card) mutex_lock(&card->dapm_mutex);
list_for_each_entry(w, &card->widgets, list) { - if (w->is_sink || w->is_source) { + if (w->is_ep) { dapm_mark_dirty(w, "Rechecking endpoints"); - if (w->is_sink) + if (w->is_ep & SND_SOC_DAPM_EP_SINK) dapm_widget_invalidate_output_paths(w); - if (w->is_source) + if (w->is_ep & SND_SOC_DAPM_EP_SOURCE) dapm_widget_invalidate_input_paths(w); } } @@ -923,18 +925,18 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) static int dapm_new_mux(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_context *dapm = w->dapm; + enum snd_soc_dapm_direction dir; struct snd_soc_dapm_path *path; - struct list_head *paths; const char *type; int ret;
switch (w->id) { case snd_soc_dapm_mux: - paths = &w->sources; + dir = SND_SOC_DAPM_DIR_OUT; type = "mux"; break; case snd_soc_dapm_demux: - paths = &w->sinks; + dir = SND_SOC_DAPM_DIR_IN; type = "demux"; break; default: @@ -948,7 +950,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) return -EINVAL; }
- if (list_empty(paths)) { + if (list_empty(&w->edges[dir])) { dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name); return -EINVAL; } @@ -957,16 +959,9 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) if (ret < 0) return ret;
- if (w->id == snd_soc_dapm_mux) { - snd_soc_dapm_widget_for_each_source_path(w, path) { - if (path->name) - dapm_kcontrol_add_path(w->kcontrols[0], path); - } - } else { - snd_soc_dapm_widget_for_each_sink_path(w, path) { - if (path->name) - dapm_kcontrol_add_path(w->kcontrols[0], path); - } + snd_soc_dapm_widget_for_each_path(w, dir, path) { + if (path->name) + dapm_kcontrol_add_path(w->kcontrols[0], path); }
return 0; @@ -1055,18 +1050,32 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, return 0; }
+static void trace_snd_soc_dapm_path(struct snd_soc_dapm_widget *w, + enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *p) +{ + if (dir == SND_SOC_DAPM_DIR_IN) + trace_snd_soc_dapm_input_path(w, p); + else + trace_snd_soc_dapm_output_path(w, p); +} + /* - * Recursively check for a completed path to an active or physically connected - * output widget. Returns number of complete paths. + * Common implementation for is_connected_output_ep() and + * is_connected_input_ep(). The function is inlined since the combined size of + * the two specialized functions is only marginally larger then the size of the + * generic function and at the same time the fast path of the specialized + * functions is significantly smaller than the generic function. */ -static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, - struct list_head *list) +static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, + struct list_head *list, enum snd_soc_dapm_direction dir, + int (*fn)(struct snd_soc_dapm_widget *, struct list_head *)) { + enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); struct snd_soc_dapm_path *path; int con = 0;
- if (widget->outputs >= 0) - return widget->outputs; + if (widget->endpoints[dir] >= 0) + return widget->endpoints[dir];
DAPM_UPDATE_STAT(widget, path_checks);
@@ -1074,12 +1083,12 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, if (list) list_add_tail(&widget->work_list, list);
- if (widget->is_sink && widget->connected) { - widget->outputs = snd_soc_dapm_suspend_check(widget); - return widget->outputs; + if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) { + widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget); + return widget->endpoints[dir]; }
- snd_soc_dapm_widget_for_each_sink_path(widget, path) { + snd_soc_dapm_widget_for_each_path(widget, rdir, path) { DAPM_UPDATE_STAT(widget, neighbour_checks);
if (path->weak || path->is_supply) @@ -1088,65 +1097,40 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, if (path->walking) return 1;
- trace_snd_soc_dapm_output_path(widget, path); + trace_snd_soc_dapm_path(widget, dir, path);
if (path->connect) { path->walking = 1; - con += is_connected_output_ep(path->sink, list); + con += fn(path->node[dir], list); path->walking = 0; } }
- widget->outputs = con; + widget->endpoints[dir] = con;
return con; }
/* * Recursively check for a completed path to an active or physically connected + * output widget. Returns number of complete paths. + */ +static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, + struct list_head *list) +{ + return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT, + is_connected_output_ep); +} + +/* + * Recursively check for a completed path to an active or physically connected * input widget. Returns number of complete paths. */ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, struct list_head *list) { - struct snd_soc_dapm_path *path; - int con = 0; - - if (widget->inputs >= 0) - return widget->inputs; - - DAPM_UPDATE_STAT(widget, path_checks); - - /* do we need to add this widget to the list ? */ - if (list) - list_add_tail(&widget->work_list, list); - - if (widget->is_source && widget->connected) { - widget->inputs = snd_soc_dapm_suspend_check(widget); - return widget->inputs; - } - - snd_soc_dapm_widget_for_each_source_path(widget, path) { - DAPM_UPDATE_STAT(widget, neighbour_checks); - - if (path->weak || path->is_supply) - continue; - - if (path->walking) - return 1; - - trace_snd_soc_dapm_input_path(widget, path); - - if (path->connect) { - path->walking = 1; - con += is_connected_input_ep(path->source, list); - path->walking = 0; - } - } - - widget->inputs = con; - - return con; + return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN, + is_connected_input_ep); }
/** @@ -1177,8 +1161,8 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, * to reset the cached number of inputs and outputs. */ list_for_each_entry(w, &card->widgets, list) { - w->inputs = -1; - w->outputs = -1; + w->endpoints[SND_SOC_DAPM_DIR_IN] = -1; + w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1; }
if (stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -1922,6 +1906,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, { struct snd_soc_dapm_widget *w = file->private_data; struct snd_soc_card *card = w->dapm->card; + enum snd_soc_dapm_direction dir, rdir; char *buf; int in, out; ssize_t ret; @@ -1958,25 +1943,21 @@ static ssize_t dapm_widget_power_read_file(struct file *file, w->sname, w->active ? "active" : "inactive");
- snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->connected && !p->connected(w, p->source)) - continue; + dapm_for_each_direction(dir) { + rdir = SND_SOC_DAPM_DIR_REVERSE(dir); + snd_soc_dapm_widget_for_each_path(w, dir, p) { + if (p->connected && !p->connected(w, p->node[rdir])) + continue;
- if (p->connect) - ret += snprintf(buf + ret, PAGE_SIZE - ret, - " in "%s" "%s"\n", - p->name ? p->name : "static", - p->source->name); - } - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (p->connected && !p->connected(w, p->sink)) - continue; + if (!p->connect) + continue;
- if (p->connect) ret += snprintf(buf + ret, PAGE_SIZE - ret, - " out "%s" "%s"\n", + " %s "%s" "%s"\n", + (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out", p->name ? p->name : "static", - p->sink->name); + p->node[rdir]->name); + } }
mutex_unlock(&card->dapm_mutex); @@ -2279,8 +2260,8 @@ struct attribute *soc_dapm_dev_attrs[] = {
static void dapm_free_path(struct snd_soc_dapm_path *path) { - list_del(&path->list_sink); - list_del(&path->list_source); + list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]); + list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]); list_del(&path->list_kcontrol); list_del(&path->list); kfree(path); @@ -2289,6 +2270,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_path *p, *next_p; + enum snd_soc_dapm_direction dir;
list_del(&w->list); /* @@ -2296,11 +2278,10 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) * While removing the path, remove reference to it from both * source and sink widgets so that path is removed only once. */ - list_for_each_entry_safe(p, next_p, &w->sources, list_sink) - dapm_free_path(p); - - list_for_each_entry_safe(p, next_p, &w->sinks, list_source) - dapm_free_path(p); + dapm_for_each_direction(dir) { + dapm_widget_for_each_path_safe(w, dir, p, next_p) + dapm_free_path(p); + }
kfree(w->kcontrols); kfree_const(w->name); @@ -2421,20 +2402,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); */ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) { + enum snd_soc_dapm_direction dir; struct snd_soc_dapm_path *p; + unsigned int ep;
switch (w->id) { case snd_soc_dapm_input: /* On a fully routed card a input is never a source */ if (w->dapm->card->fully_routed) - break; - w->is_source = 1; + return; + ep = SND_SOC_DAPM_EP_SOURCE; snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->source->id == snd_soc_dapm_micbias || p->source->id == snd_soc_dapm_mic || p->source->id == snd_soc_dapm_line || p->source->id == snd_soc_dapm_output) { - w->is_source = 0; + ep = 0; break; } } @@ -2442,25 +2425,30 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) case snd_soc_dapm_output: /* On a fully routed card a output is never a sink */ if (w->dapm->card->fully_routed) - break; - w->is_sink = 1; + return; + ep = SND_SOC_DAPM_EP_SINK; snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->sink->id == snd_soc_dapm_spk || p->sink->id == snd_soc_dapm_hp || p->sink->id == snd_soc_dapm_line || p->sink->id == snd_soc_dapm_input) { - w->is_sink = 0; + ep = 0; break; } } break; case snd_soc_dapm_line: - w->is_sink = !list_empty(&w->sources); - w->is_source = !list_empty(&w->sinks); + ep = 0; + dapm_for_each_direction(dir) { + if (!list_empty(&w->edges[dir])) + ep |= SND_SOC_DAPM_DIR_TO_EP(dir); + } break; default: - break; + return; } + + w->is_ep = ep; }
static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm, @@ -2513,6 +2501,8 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)) { + struct snd_soc_dapm_widget *widgets[2]; + enum snd_soc_dapm_direction dir; struct snd_soc_dapm_path *path; int ret;
@@ -2545,13 +2535,14 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, if (!path) return -ENOMEM;
- path->source = wsource; - path->sink = wsink; + path->node[SND_SOC_DAPM_DIR_IN] = wsource; + path->node[SND_SOC_DAPM_DIR_OUT] = wsink; + widgets[SND_SOC_DAPM_DIR_IN] = wsource; + widgets[SND_SOC_DAPM_DIR_OUT] = wsink; + path->connected = connected; INIT_LIST_HEAD(&path->list); INIT_LIST_HEAD(&path->list_kcontrol); - INIT_LIST_HEAD(&path->list_source); - INIT_LIST_HEAD(&path->list_sink);
if (wsource->is_supply || wsink->is_supply) path->is_supply = 1; @@ -2589,14 +2580,13 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, }
list_add(&path->list, &dapm->card->paths); - list_add(&path->list_sink, &wsink->sources); - list_add(&path->list_source, &wsource->sinks); + dapm_for_each_direction(dir) + list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
- dapm_update_widget_flags(wsource); - dapm_update_widget_flags(wsink); - - dapm_mark_dirty(wsource, "Route added"); - dapm_mark_dirty(wsink, "Route added"); + dapm_for_each_direction(dir) { + dapm_update_widget_flags(widgets[dir]); + dapm_mark_dirty(widgets[dir], "Route added"); + }
if (dapm->card->instantiated && path->connect) dapm_path_invalidate(path); @@ -3278,6 +3268,7 @@ struct snd_soc_dapm_widget * snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget) { + enum snd_soc_dapm_direction dir; struct snd_soc_dapm_widget *w; const char *prefix; int ret; @@ -3332,27 +3323,27 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
switch (w->id) { case snd_soc_dapm_mic: - w->is_source = 1; + w->is_ep = SND_SOC_DAPM_EP_SOURCE; w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_input: if (!dapm->card->fully_routed) - w->is_source = 1; + w->is_ep = SND_SOC_DAPM_EP_SOURCE; w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_spk: case snd_soc_dapm_hp: - w->is_sink = 1; + w->is_ep = SND_SOC_DAPM_EP_SINK; w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_output: if (!dapm->card->fully_routed) - w->is_sink = 1; + w->is_ep = SND_SOC_DAPM_EP_SINK; w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_vmid: case snd_soc_dapm_siggen: - w->is_source = 1; + w->is_ep = SND_SOC_DAPM_EP_SOURCE; w->power_check = dapm_always_on_check_power; break; case snd_soc_dapm_mux: @@ -3386,14 +3377,14 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, }
w->dapm = dapm; - INIT_LIST_HEAD(&w->sources); - INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list); INIT_LIST_HEAD(&w->dirty); list_add_tail(&w->list, &dapm->card->widgets);
- w->inputs = -1; - w->outputs = -1; + dapm_for_each_direction(dir) { + INIT_LIST_HEAD(&w->edges[dir]); + w->endpoints[dir] = -1; + }
/* machine layer set ups unconnected pins and insertions */ w->connected = 1; @@ -3447,14 +3438,17 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, int ret;
if (WARN_ON(!config) || - WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks))) + WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || + list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) return -EINVAL;
/* We only support a single source and sink, pick the first */ - source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path, - list_sink); - sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path, - list_source); + source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT], + struct snd_soc_dapm_path, + list_node[SND_SOC_DAPM_DIR_OUT]); + sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN], + struct snd_soc_dapm_path, + list_node[SND_SOC_DAPM_DIR_IN]);
source = source_p->source->priv; sink = sink_p->sink->priv; @@ -3826,6 +3820,7 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, int event) { struct snd_soc_dapm_widget *w; + unsigned int ep;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) w = dai->playback_widget; @@ -3835,12 +3830,22 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, if (w) { dapm_mark_dirty(w, "stream event");
+ if (w->id == snd_soc_dapm_dai_in) { + ep = SND_SOC_DAPM_EP_SOURCE; + dapm_widget_invalidate_input_paths(w); + } else { + ep = SND_SOC_DAPM_EP_SINK; + dapm_widget_invalidate_output_paths(w); + } + switch (event) { case SND_SOC_DAPM_STREAM_START: w->active = 1; + w->is_ep = ep; break; case SND_SOC_DAPM_STREAM_STOP: w->active = 0; + w->is_ep = 0; break; case SND_SOC_DAPM_STREAM_SUSPEND: case SND_SOC_DAPM_STREAM_RESUME: @@ -3848,14 +3853,6 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: break; } - - if (w->id == snd_soc_dapm_dai_in) { - w->is_source = w->active; - dapm_widget_invalidate_input_paths(w); - } else { - w->is_sink = w->active; - dapm_widget_invalidate_output_paths(w); - } } }
On Sun, Jul 26, 2015 at 07:05:01PM +0200, Lars-Peter Clausen wrote:
Testing on ARM shows that the combined code size of the specialized functions is about 50% larger than the generlized function in relative numbers. But in absolute numbers its less than 200 bytes, which is still quite small. On the other hand the generalized function increases the execution time of dapm_power_one_widget() by 30%. Given that this function is one of the most often called functions of the DAPM framework the tradeoff seems to be worth it.
This reads like you mean to say that it's worth it to combine things in spite of the 30% speed hit... you're not clear which tradeoff you mean.
To avoid this still keep two versions of these functions around, one for input and one for output. But have a generic implementation of the algorithm which gets inlined by those two versions and then let the compiler take care of optimizing it into specialized versions.
...which the compiler presumably actually manages to do.
--- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h
+/**
- snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the
- specified direction of a widget
- @w: The widget
- @dir: Whether to iterate over the paths where the specified widget is the
incoming or outgoing widgets
- @p: The path iterator variable
- */
+#define snd_soc_dapm_widget_for_each_path(w, dir, p) \
- list_for_each_entry(p, &w->edges[dir], list_node[dir])
This is a macro not a static inline? The other macros that use this are macros but that's more outdated code than anything I think, might be worth fixing that while we're at it.
#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
+#define dapm_widget_for_each_path_safe(w, dir, p, next_p) \
- list_for_each_entry_safe(p, next_p, &w->edges[dir], list_node[dir])
It's a bit odd not to have this in the header next to the unsafe version.
+#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
- SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
+#define dapm_for_each_direction(dir) \
- for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
(dir)++)
Eew.
list_for_each_entry(w, &card->widgets, list) {
w->inputs = -1;
w->outputs = -1;
w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
Loop over the endpoints array in some of the users like this perhaps?
- dapm_for_each_direction(dir) {
rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
snd_soc_dapm_widget_for_each_path(w, dir, p) {
if (p->connected && !p->connected(w, p->node[rdir]))
continue;
Looks like dapm_for_each_direction should be snd_soc_dapm_for_each_direction - the above looks wrong.
On 07/29/2015 03:14 PM, Mark Brown wrote: [...]
+/**
- snd_soc_dapm_widget_for_each_sink_path - Iterates over all paths in the
- specified direction of a widget
- @w: The widget
- @dir: Whether to iterate over the paths where the specified widget is the
incoming or outgoing widgets
- @p: The path iterator variable
- */
+#define snd_soc_dapm_widget_for_each_path(w, dir, p) \
- list_for_each_entry(p, &w->edges[dir], list_node[dir])
This is a macro not a static inline? The other macros that use this are macros but that's more outdated code than anything I think, might be worth fixing that while we're at it.
Sorry, I don't quite understand what you mean. snd_soc_dapm_widget_for_each_path() is a iterator so it can't be a function.
#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
+#define dapm_widget_for_each_path_safe(w, dir, p, next_p) \
- list_for_each_entry_safe(p, next_p, &w->edges[dir], list_node[dir])
It's a bit odd not to have this in the header next to the unsafe version.
You'd only need the unsafe variant if the paths are modified while being traversed. I'd rather not encourage drivers to do this by hand. So this macro is internal to the DAPM core.
+#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
- SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
+#define dapm_for_each_direction(dir) \
- for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
(dir)++)
Eew.
list_for_each_entry(w, &card->widgets, list) {
w->inputs = -1;
w->outputs = -1;
w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
Loop over the endpoints array in some of the users like this perhaps?
It's not really worth it if you only have a single line inside the loop. Doesn't make the code shorter nor more legible.
On Sun, Aug 02, 2015 at 12:18:26PM +0200, Lars-Peter Clausen wrote:
On 07/29/2015 03:14 PM, Mark Brown wrote:
#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
+#define dapm_widget_for_each_path_safe(w, dir, p, next_p) \
- list_for_each_entry_safe(p, next_p, &w->edges[dir], list_node[dir])
It's a bit odd not to have this in the header next to the unsafe version.
You'd only need the unsafe variant if the paths are modified while being traversed. I'd rather not encourage drivers to do this by hand. So this macro is internal to the DAPM core.
It's the unsafe version that's in the header though? I can tell why they're separate, I'd just rather keep them together even so - drivers shouldn't really be iterating over widgets at all.
list_for_each_entry(w, &card->widgets, list) {
w->inputs = -1;
w->outputs = -1;
w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
Loop over the endpoints array in some of the users like this perhaps?
It's not really worth it if you only have a single line inside the loop. Doesn't make the code shorter nor more legible.
It does save me wondering if we've missed any other array elements which was my first thought here.
The snd_soc_dapm_input_path and snd_soc_dapm_output_path trace events are identical except for the direction. Instead of having two events have a single one that has a field that contains the direction.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/trace/events/asoc.h | 53 +++++++++++++-------------------------------- sound/soc/soc-dapm.c | 9 -------- 2 files changed, 15 insertions(+), 47 deletions(-)
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index 88cf39d..317a1ed 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -8,6 +8,7 @@ #include <linux/tracepoint.h>
#define DAPM_DIRECT "(direct)" +#define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-")
struct snd_soc_jack; struct snd_soc_codec; @@ -152,62 +153,38 @@ TRACE_EVENT(snd_soc_dapm_walk_done, (int)__entry->path_checks, (int)__entry->neighbour_checks) );
-TRACE_EVENT(snd_soc_dapm_output_path, +TRACE_EVENT(snd_soc_dapm_path,
TP_PROTO(struct snd_soc_dapm_widget *widget, + enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *path),
- TP_ARGS(widget, path), + TP_ARGS(widget, dir, path),
TP_STRUCT__entry( __string( wname, widget->name ) __string( pname, path->name ? path->name : DAPM_DIRECT) - __string( psname, path->sink->name ) - __field( int, path_sink ) + __string( pnname, path->node[dir]->name ) + __field( int, path_node ) __field( int, path_connect ) + __field( int, path_dir ) ),
TP_fast_assign( __assign_str(wname, widget->name); __assign_str(pname, path->name ? path->name : DAPM_DIRECT); - __assign_str(psname, path->sink->name); + __assign_str(pnname, path->node[dir]->name); __entry->path_connect = path->connect; - __entry->path_sink = (long)path->sink; + __entry->path_node = (long)path->node[dir]; + __entry->path_dir = dir; ),
- TP_printk("%c%s -> %s -> %s", - (int) __entry->path_sink && + TP_printk("%c%s %s %s %s %s", + (int) __entry->path_node && (int) __entry->path_connect ? '*' : ' ', - __get_str(wname), __get_str(pname), __get_str(psname)) -); - -TRACE_EVENT(snd_soc_dapm_input_path, - - TP_PROTO(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_path *path), - - TP_ARGS(widget, path), - - TP_STRUCT__entry( - __string( wname, widget->name ) - __string( pname, path->name ? path->name : DAPM_DIRECT) - __string( psname, path->source->name ) - __field( int, path_source ) - __field( int, path_connect ) - ), - - TP_fast_assign( - __assign_str(wname, widget->name); - __assign_str(pname, path->name ? path->name : DAPM_DIRECT); - __assign_str(psname, path->source->name); - __entry->path_connect = path->connect; - __entry->path_source = (long)path->source; - ), - - TP_printk("%c%s <- %s <- %s", - (int) __entry->path_source && - (int) __entry->path_connect ? '*' : ' ', - __get_str(wname), __get_str(pname), __get_str(psname)) + __get_str(wname), DAPM_ARROW(__entry->path_dir), + __get_str(pname), DAPM_ARROW(__entry->path_dir), + __get_str(pnname)) );
TRACE_EVENT(snd_soc_dapm_connected, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 12007be..958c189 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1050,15 +1050,6 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, return 0; }
-static void trace_snd_soc_dapm_path(struct snd_soc_dapm_widget *w, - enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *p) -{ - if (dir == SND_SOC_DAPM_DIR_IN) - trace_snd_soc_dapm_input_path(w, p); - else - trace_snd_soc_dapm_output_path(w, p); -} - /* * Common implementation for is_connected_output_ep() and * is_connected_input_ep(). The function is inlined since the combined size of
The patch
ASoC: dapm: Consolidate path trace events
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 6e588a0d839b51bae49852b68740a25cacc91978 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen lars@metafoo.de Date: Tue, 11 Aug 2015 21:38:01 +0200 Subject: [PATCH] ASoC: dapm: Consolidate path trace events
The snd_soc_dapm_input_path and snd_soc_dapm_output_path trace events are identical except for the direction. Instead of having two events have a single one that has a field that contains the direction.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de Signed-off-by: Mark Brown broonie@kernel.org --- include/trace/events/asoc.h | 53 +++++++++++++-------------------------------- sound/soc/soc-dapm.c | 9 -------- 2 files changed, 15 insertions(+), 47 deletions(-)
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index 88cf39d..317a1ed 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h @@ -8,6 +8,7 @@ #include <linux/tracepoint.h>
#define DAPM_DIRECT "(direct)" +#define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-")
struct snd_soc_jack; struct snd_soc_codec; @@ -152,62 +153,38 @@ TRACE_EVENT(snd_soc_dapm_walk_done, (int)__entry->path_checks, (int)__entry->neighbour_checks) );
-TRACE_EVENT(snd_soc_dapm_output_path, +TRACE_EVENT(snd_soc_dapm_path,
TP_PROTO(struct snd_soc_dapm_widget *widget, + enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *path),
- TP_ARGS(widget, path), + TP_ARGS(widget, dir, path),
TP_STRUCT__entry( __string( wname, widget->name ) __string( pname, path->name ? path->name : DAPM_DIRECT) - __string( psname, path->sink->name ) - __field( int, path_sink ) + __string( pnname, path->node[dir]->name ) + __field( int, path_node ) __field( int, path_connect ) + __field( int, path_dir ) ),
TP_fast_assign( __assign_str(wname, widget->name); __assign_str(pname, path->name ? path->name : DAPM_DIRECT); - __assign_str(psname, path->sink->name); + __assign_str(pnname, path->node[dir]->name); __entry->path_connect = path->connect; - __entry->path_sink = (long)path->sink; + __entry->path_node = (long)path->node[dir]; + __entry->path_dir = dir; ),
- TP_printk("%c%s -> %s -> %s", - (int) __entry->path_sink && + TP_printk("%c%s %s %s %s %s", + (int) __entry->path_node && (int) __entry->path_connect ? '*' : ' ', - __get_str(wname), __get_str(pname), __get_str(psname)) -); - -TRACE_EVENT(snd_soc_dapm_input_path, - - TP_PROTO(struct snd_soc_dapm_widget *widget, - struct snd_soc_dapm_path *path), - - TP_ARGS(widget, path), - - TP_STRUCT__entry( - __string( wname, widget->name ) - __string( pname, path->name ? path->name : DAPM_DIRECT) - __string( psname, path->source->name ) - __field( int, path_source ) - __field( int, path_connect ) - ), - - TP_fast_assign( - __assign_str(wname, widget->name); - __assign_str(pname, path->name ? path->name : DAPM_DIRECT); - __assign_str(psname, path->source->name); - __entry->path_connect = path->connect; - __entry->path_source = (long)path->source; - ), - - TP_printk("%c%s <- %s <- %s", - (int) __entry->path_source && - (int) __entry->path_connect ? '*' : ' ', - __get_str(wname), __get_str(pname), __get_str(psname)) + __get_str(wname), DAPM_ARROW(__entry->path_dir), + __get_str(pname), DAPM_ARROW(__entry->path_dir), + __get_str(pnname)) );
TRACE_EVENT(snd_soc_dapm_connected, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 27b7fd9..cf2a069 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1047,15 +1047,6 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, return 0; }
-static void trace_snd_soc_dapm_path(struct snd_soc_dapm_widget *w, - enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *p) -{ - if (dir == SND_SOC_DAPM_DIR_IN) - trace_snd_soc_dapm_input_path(w, p); - else - trace_snd_soc_dapm_output_path(w, p); -} - /* * Common implementation for is_connected_output_ep() and * is_connected_input_ep(). The function is inlined since the combined size of
The patch
ASoC: dapm: Drop always true checks
has been applied to the asoc tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From 787126ebdb9821f1a19b1dfd1ab1bbb74b8c80b8 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen lars@metafoo.de Date: Sun, 26 Jul 2015 19:04:58 +0200 Subject: [PATCH] ASoC: dapm: Drop always true checks
list_first_entry() always returns non NULL and since the code previously checked that list is not empty it will also be a valid pointer. Furthermore a path has always a sink or a source widget. So both checks are redundant and can be removed.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/soc-dapm.c | 5 ----- 1 file changed, 5 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index cb4bc1c..f80b7de 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3482,11 +3482,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path, list_source);
- if (WARN_ON(!source_p || !sink_p) || - WARN_ON(!sink_p->source || !source_p->sink) || - WARN_ON(!source_p->source || !sink_p->sink)) - return -EINVAL; - source = source_p->source->priv; sink = sink_p->sink->priv;
participants (2)
-
Lars-Peter Clausen
-
Mark Brown