All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] ASoC: Factor write of widget power out into a separate function
@ 2011-10-03 20:32 Mark Brown
  2011-10-03 20:32 ` [PATCH 2/5] ASoC: Move bias level decision into main dapm_power_widgets() Mark Brown
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Mark Brown @ 2011-10-03 20:32 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

Split the decision about what the new power should be out from the
implementation of that decision.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 sound/soc/soc-dapm.c |   29 ++++++++++++++++++-----------
 1 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c277228..dcbd468 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1197,6 +1197,23 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
 	}
 }
 
+static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
+				  struct list_head *up_list,
+				  struct list_head *down_list)
+{
+	if (w->power == power)
+		return;
+
+	trace_snd_soc_dapm_widget_power(w, power);
+
+	if (power)
+		dapm_seq_insert(w, up_list, true);
+	else
+		dapm_seq_insert(w, down_list, false);
+
+	w->power = power;
+}
+
 static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
 				  struct list_head *up_list,
 				  struct list_head *down_list)
@@ -1241,17 +1258,7 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
 			}
 		}
 
-		if (w->power == power)
-			break;
-
-		trace_snd_soc_dapm_widget_power(w, power);
-
-		if (power)
-			dapm_seq_insert(w, up_list, true);
-		else
-			dapm_seq_insert(w, down_list, false);
-
-		w->power = power;
+		dapm_widget_set_power(w, power, up_list, down_list);
 		break;
 	}
 }
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] ASoC: Move bias level decision into main dapm_power_widgets()
  2011-10-03 20:32 [PATCH 1/5] ASoC: Factor write of widget power out into a separate function Mark Brown
@ 2011-10-03 20:32 ` Mark Brown
  2011-10-03 20:32 ` [PATCH 3/5] ASoC: Ensure all DAPM widgets have a power check callback Mark Brown
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2011-10-03 20:32 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

Future patches will try to reduce the number of widgets we check on each
DAPM run but we're still going to need to look and see if the devices is
on at all so we can manage the overall device bias. Move these checks out
into the main dapm_power_widgets() function so we don't have to think about
them for now.

Once we're doing more incremental updates it'll probably be worth using
refcounts for each bias level to avoid having to do the sweep over all
widgets but that's not going to be where the big performance wins are.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 sound/soc/soc-dapm.c |   44 +++++++++++++++++++++++---------------------
 1 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index dcbd468..12bd01a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1218,7 +1218,6 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
 				  struct list_head *up_list,
 				  struct list_head *down_list)
 {
-	struct snd_soc_dapm_context *d;
 	int power;
 
 	switch (w->id) {
@@ -1238,26 +1237,6 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
 		else
 			power = 1;
 
-		if (power) {
-			d = w->dapm;
-
-			/* Supplies and micbiases only bring the
-			 * context up to STANDBY as unless something
-			 * else is active and passing audio they
-			 * generally don't require full power.
-			 */
-			switch (w->id) {
-			case snd_soc_dapm_supply:
-			case snd_soc_dapm_micbias:
-				if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
-					d->target_bias_level = SND_SOC_BIAS_STANDBY;
-				break;
-			default:
-				d->target_bias_level = SND_SOC_BIAS_ON;
-				break;
-			}
-		}
-
 		dapm_widget_set_power(w, power, up_list, down_list);
 		break;
 	}
@@ -1302,6 +1281,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 		dapm_power_one_widget(w, &up_list, &down_list);
 	}
 
+	list_for_each_entry(w, &card->widgets, list) {
+		if (w->power) {
+			d = w->dapm;
+
+			/* Supplies and micbiases only bring the
+			 * context up to STANDBY as unless something
+			 * else is active and passing audio they
+			 * generally don't require full power.
+			 */
+			switch (w->id) {
+			case snd_soc_dapm_supply:
+			case snd_soc_dapm_micbias:
+				if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
+					d->target_bias_level = SND_SOC_BIAS_STANDBY;
+				break;
+			default:
+				d->target_bias_level = SND_SOC_BIAS_ON;
+				break;
+			}
+		}
+
+	}
+
 	/* If there are no DAPM widgets then try to figure out power from the
 	 * event type.
 	 */
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] ASoC: Ensure all DAPM widgets have a power check callback
  2011-10-03 20:32 [PATCH 1/5] ASoC: Factor write of widget power out into a separate function Mark Brown
  2011-10-03 20:32 ` [PATCH 2/5] ASoC: Move bias level decision into main dapm_power_widgets() Mark Brown
@ 2011-10-03 20:32 ` Mark Brown
  2011-10-03 20:32 ` [PATCH 4/5] ASoC: Factor out widget power check operation Mark Brown
  2011-10-03 20:32 ` [PATCH 5/5] ASoC: Do DAPM power checks only for widgets changed since last run Mark Brown
  3 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2011-10-03 20:32 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

Makes the code simpler.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 sound/soc/soc-dapm.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 12bd01a..8d76044 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -857,6 +857,11 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
 	return power;
 }
 
+static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
+{
+	return 1;
+}
+
 static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
 			    struct snd_soc_dapm_widget *b,
 			    bool power_up)
@@ -1229,9 +1234,6 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
 		break;
 
 	default:
-		if (!w->power_check)
-			break;
-
 		if (!w->force)
 			power = w->power_check(w);
 		else
@@ -2090,6 +2092,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 			break;
 		}
 
+		if (!w->power_check)
+			w->power_check = dapm_always_on_check_power;
+
 		/* Read the initial power state from the device */
 		if (w->reg >= 0) {
 			val = soc_widget_read(w, w->reg);
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] ASoC: Factor out widget power check operation
  2011-10-03 20:32 [PATCH 1/5] ASoC: Factor write of widget power out into a separate function Mark Brown
  2011-10-03 20:32 ` [PATCH 2/5] ASoC: Move bias level decision into main dapm_power_widgets() Mark Brown
  2011-10-03 20:32 ` [PATCH 3/5] ASoC: Ensure all DAPM widgets have a power check callback Mark Brown
@ 2011-10-03 20:32 ` Mark Brown
  2011-10-03 20:32 ` [PATCH 5/5] ASoC: Do DAPM power checks only for widgets changed since last run Mark Brown
  3 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2011-10-03 20:32 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

We've got the same code in two different places, let's have it in a single
place instead.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 sound/soc/soc-dapm.c |   21 ++++++++++-----------
 1 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8d76044..c1f3563 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -771,6 +771,14 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(dapm_reg_event);
 
+static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
+{
+	if (w->force)
+		return 1;
+	else
+		return w->power_check(w);
+}
+
 /* Generic check to see if a widget should be powered.
  */
 static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
@@ -840,13 +848,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
 		if (!path->sink)
 			continue;
 
-		if (path->sink->force) {
-			power = 1;
-			break;
-		}
-
-		if (path->sink->power_check &&
-		    path->sink->power_check(path->sink)) {
+		if (dapm_widget_power_check(path->sink)) {
 			power = 1;
 			break;
 		}
@@ -1234,10 +1236,7 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
 		break;
 
 	default:
-		if (!w->force)
-			power = w->power_check(w);
-		else
-			power = 1;
+		power = dapm_widget_power_check(w);
 
 		dapm_widget_set_power(w, power, up_list, down_list);
 		break;
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] ASoC: Do DAPM power checks only for widgets changed since last run
  2011-10-03 20:32 [PATCH 1/5] ASoC: Factor write of widget power out into a separate function Mark Brown
                   ` (2 preceding siblings ...)
  2011-10-03 20:32 ` [PATCH 4/5] ASoC: Factor out widget power check operation Mark Brown
@ 2011-10-03 20:32 ` Mark Brown
  2011-10-03 21:02   ` [PATCH] ASoC: Mark mixer and mux neighbours as dirty when changing them Mark Brown
  3 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2011-10-03 20:32 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

In order to reduce the number of DAPM power checks we run keep a list of
widgets which have been changed since the last DAPM run and iterate over
that rather than the full widget list. Whenever we change the power state
for a widget we add all the source and sink widgets it has to the dirty
list, ensuring that all widgets in the path are checked.

This covers more widgets than we need to as some of the neighbour widgets
won't be connected but it's simpler as a first step. On one system I tried
this gave:

           Power    Path   Neighbour
Before:    207      1939   2461
After:     114      1066   1327

which seems useful.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---

Still testing this one but it's looking robust enough right now.

 include/sound/soc-dapm.h |    1 +
 include/sound/soc.h      |    1 +
 sound/soc/soc-core.c     |    1 +
 sound/soc/soc-dapm.c     |   52 ++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index bb59532..c080635 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -492,6 +492,7 @@ struct snd_soc_dapm_widget {
 
 	/* used during DAPM updates */
 	struct list_head power_list;
+	struct list_head dirty;
 };
 
 struct snd_soc_dapm_update {
diff --git a/include/sound/soc.h b/include/sound/soc.h
index a4dc699..1224bc3 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -827,6 +827,7 @@ struct snd_soc_card {
 	struct list_head widgets;
 	struct list_head paths;
 	struct list_head dapm_list;
+	struct list_head dapm_dirty;
 
 	/* Generic DAPM context for the card */
 	struct snd_soc_dapm_context dapm;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 1ed8093..778c177 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2916,6 +2916,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
 		card->rtd[i].dai_link = &card->dai_link[i];
 
 	INIT_LIST_HEAD(&card->list);
+	INIT_LIST_HEAD(&card->dapm_dirty);
 	card->instantiated = 0;
 	mutex_init(&card->mutex);
 
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c1f3563..50517d8 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -119,6 +119,17 @@ static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
 	kfree(buf);
 }
 
+static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
+{
+	return !list_empty(&w->dirty);
+}
+
+static void dapm_mark_dirty(struct snd_soc_dapm_widget *w)
+{
+	if (!dapm_dirty_widget(w))
+		list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
+}
+
 /* create a new dapm widget */
 static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
 	const struct snd_soc_dapm_widget *_widget)
@@ -1208,11 +1219,30 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
 				  struct list_head *up_list,
 				  struct list_head *down_list)
 {
+	struct snd_soc_dapm_path *path;
+
 	if (w->power == power)
 		return;
 
 	trace_snd_soc_dapm_widget_power(w, power);
 
+	/* If we changed our power state perhaps our neigbours changed
+	 * also.  We're not yet smart enough to update relevant
+	 * neighbours when we change the state of a widget, this acts
+	 * as a proxy for that.  It will notify more neighbours than
+	 * is ideal.
+	 */
+	list_for_each_entry(path, &w->sources, list_sink) {
+		if (path->source) {
+			dapm_mark_dirty(path->source);
+		}
+	}
+	list_for_each_entry(path, &w->sinks, list_source) {
+		if (path->sink) {
+			dapm_mark_dirty(path->sink);
+		}
+	}
+
 	if (power)
 		dapm_seq_insert(w, up_list, true);
 	else
@@ -1276,13 +1306,18 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
 	memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
 
 	/* Check which widgets we need to power and store them in
-	 * lists indicating if they should be powered up or down.
+	 * lists indicating if they should be powered up or down.  We
+	 * only check widgets that have been flagged as dirty but note
+	 * that new widgets may be added to the dirty list while we
+	 * iterate.
 	 */
-	list_for_each_entry(w, &card->widgets, list) {
+	list_for_each_entry(w, &card->dapm_dirty, dirty) {
 		dapm_power_one_widget(w, &up_list, &down_list);
 	}
 
 	list_for_each_entry(w, &card->widgets, list) {
+		list_del_init(&w->dirty);
+
 		if (w->power) {
 			d = w->dapm;
 
@@ -1579,8 +1614,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
 			path->connect = 0; /* old connection must be powered down */
 	}
 
-	if (found)
+	if (found) {
+		dapm_mark_dirty(widget);
 		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
+	}
 
 	return 0;
 }
@@ -1607,8 +1644,10 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 		path->connect = connect;
 	}
 
-	if (found)
+	if (found) {
+		dapm_mark_dirty(widget);
 		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
+	}
 
 	return 0;
 }
@@ -1752,6 +1791,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
 	w->connected = status;
 	if (status == 0)
 		w->force = 0;
+	dapm_mark_dirty(w);
 
 	return 0;
 }
@@ -2107,6 +2147,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 
 		w->new = 1;
 
+		list_add(&w->dirty, &(w->dapm->card->dapm_dirty));
 		dapm_debugfs_add_widget(w);
 	}
 
@@ -2588,6 +2629,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 	INIT_LIST_HEAD(&w->sources);
 	INIT_LIST_HEAD(&w->sinks);
 	INIT_LIST_HEAD(&w->list);
+	INIT_LIST_HEAD(&w->dirty);
 	list_add(&w->list, &dapm->card->widgets);
 
 	/* machine layer set ups unconnected pins and insertions */
@@ -2638,6 +2680,7 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
 		dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
 			w->name, w->sname, stream, event);
 		if (strstr(w->sname, stream)) {
+			dapm_mark_dirty(w);
 			switch(event) {
 			case SND_SOC_DAPM_STREAM_START:
 				w->active = 1;
@@ -2727,6 +2770,7 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
 	dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
 	w->connected = 1;
 	w->force = 1;
+	dapm_mark_dirty(w);
 
 	return 0;
 }
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH] ASoC: Mark mixer and mux neighbours as dirty when changing them
  2011-10-03 20:32 ` [PATCH 5/5] ASoC: Do DAPM power checks only for widgets changed since last run Mark Brown
@ 2011-10-03 21:02   ` Mark Brown
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2011-10-03 21:02 UTC (permalink / raw)
  To: Liam Girdwood; +Cc: alsa-devel, patches, Mark Brown

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
 sound/soc/soc-dapm.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 50517d8..06d8cfa 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1608,10 +1608,14 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
 
 		found = 1;
 		/* we now need to match the string in the enum to the path */
-		if (!(strcmp(path->name, e->texts[mux])))
+		if (!(strcmp(path->name, e->texts[mux]))) {
 			path->connect = 1; /* new connection */
-		else
+			dapm_mark_dirty(path->source);
+		} else {
+			if (path->connect)
+				dapm_mark_dirty(path->source);
 			path->connect = 0; /* old connection must be powered down */
+		}
 	}
 
 	if (found) {
@@ -1642,6 +1646,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
 		/* found, now check type */
 		found = 1;
 		path->connect = connect;
+		dapm_mark_dirty(path->source);
 	}
 
 	if (found) {
-- 
1.7.6.3

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-10-03 21:02 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-03 20:32 [PATCH 1/5] ASoC: Factor write of widget power out into a separate function Mark Brown
2011-10-03 20:32 ` [PATCH 2/5] ASoC: Move bias level decision into main dapm_power_widgets() Mark Brown
2011-10-03 20:32 ` [PATCH 3/5] ASoC: Ensure all DAPM widgets have a power check callback Mark Brown
2011-10-03 20:32 ` [PATCH 4/5] ASoC: Factor out widget power check operation Mark Brown
2011-10-03 20:32 ` [PATCH 5/5] ASoC: Do DAPM power checks only for widgets changed since last run Mark Brown
2011-10-03 21:02   ` [PATCH] ASoC: Mark mixer and mux neighbours as dirty when changing them Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.