alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
From: mengdong.lin@intel.com
To: alsa-devel@alsa-project.org
Cc: tiwai@suse.de, Mengdong Lin <mengdong.lin@intel.com>
Subject: [RFC PATCH 1/1] ALSA: hda - add a timer to find and suspend idle codecs
Date: Tue, 14 Aug 2012 13:56:43 -0400	[thread overview]
Message-ID: <1344967003-5470-1-git-send-email-mengdong.lin@intel.com> (raw)

From: Mengdong Lin <mengdong.lin@intel.com>

(sorry, this patch is resent with title updated)


This patch sets up a timer to monitor changes of the parameter 'power_save'
and suspend any idle codecs if power save is re-enabled by the user.

A codec won't be suspended if it becomes idle when power save is disabled. And it
will remain unsuspended if power save is enabled later but no further user
operations comes. So a timer is used here to find and suspend such idle codecs
when power save is re-enabled.

Now the timer has a fixed interval of 1 second.

Signed-off-by: Mengdong Lin <mengdong.lin@intel.com>
---
 sound/pci/hda/hda_codec.c |  109 +++++++++++++++++++++++++++++++++++++++++++++
 sound/pci/hda/hda_codec.h |    9 ++++
 sound/pci/hda/hda_intel.c |    2 +-
 3 files changed, 119 insertions(+), 1 deletion(-)

diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 629131a..6bd8873 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -98,6 +98,8 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
 static void hda_power_work(struct work_struct *work);
 static void hda_keep_power_on(struct hda_codec *codec);
 #define hda_codec_is_power_on(codec)	((codec)->power_on)
+#define POWER_SAVE_MONITOR_INTERVAL 1000
+static void power_save_monitor_timeout(unsigned long data);
 #else
 static inline void hda_keep_power_on(struct hda_codec *codec) {}
 #define hda_codec_is_power_on(codec)	1
@@ -685,6 +687,9 @@ static int snd_hda_bus_free(struct hda_bus *bus)
 
 	if (!bus)
 		return 0;
+
+	snd_hda_power_save_monitor_stop(bus);
+
 	if (bus->workq)
 		flush_workqueue(bus->workq);
 	if (bus->unsol)
@@ -4558,6 +4563,106 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
 	return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power);
+
+#define BUS_POWER_SAVE(bus) \
+	((bus)->power_save && *(bus)->power_save ?  1 : 0)
+
+static void power_save_monitor_timeout(unsigned long data)
+{
+	int ret;
+	struct hda_bus *bus = (struct hda_bus *)data;
+	struct list_head *codec_list = &bus->codec_list;
+	struct hda_codec *codec, *next;
+
+	if (BUS_POWER_SAVE(bus) == bus->power_save_enabled)
+		goto out;
+
+	bus->power_save_enabled = BUS_POWER_SAVE(bus);
+	if (!bus->power_save_enabled) {
+		snd_printd("hda-bus: power save disabled\n");
+		goto out;
+	}
+
+	snd_printd("hda-bus: power save enabled\n");
+	list_for_each_entry_safe(codec, next, codec_list, list) {
+		spin_lock(&codec->power_lock);
+		if (codec->power_on
+			&& !codec->power_count
+			&& !codec->power_transition) {
+			snd_printd("hda codec %d idle\n", codec->addr);
+			codec->power_transition = -1; /* avoid reentrance */
+			queue_delayed_work(codec->bus->workq,
+				&codec->power_work,
+				msecs_to_jiffies(power_save(codec) * 1000));
+		}
+		spin_unlock(&codec->power_lock);
+	}
+
+out:
+	ret = mod_timer(&bus->power_save_timer,
+				jiffies + \
+				msecs_to_jiffies(POWER_SAVE_MONITOR_INTERVAL));
+	if (ret)
+		snd_printd("hda-bus: error in mod_timer\n");
+
+	return;
+}
+
+/**
+ * snd_hda_power_save_monitor_start - Setup a timer to monitor the changes of
+ *    power_save parameter.
+ * @bus: HD-audio bus
+ *
+ * Setup a timer to monitor whether parameter power_save is changed by the user.
+ * A codec won't be suspended if it becomes idle when power save is disabled,
+ * and can remain unsuspended after power save is enabled later.
+ * This monitor will find and suspened such idle codecs when power save is
+ * re-enabled.
+ */
+void  snd_hda_power_save_monitor_start(struct hda_bus *bus)
+{
+	int ret;
+
+	if (bus->power_save_timer_inited) {
+		snd_printd("hda-bus: power save timer already inited\n");
+		return;
+	}
+
+	setup_timer(&bus->power_save_timer,
+				power_save_monitor_timeout, (unsigned long)bus);
+	bus->power_save_timer_inited = 1;
+
+	snd_printd("hda-bus: start power save monitor\n");
+	ret = mod_timer(&bus->power_save_timer,
+			jiffies + \
+			msecs_to_jiffies(POWER_SAVE_MONITOR_INTERVAL));
+	if (ret)
+		snd_printd("hda-bus: error in mod_timer\n");
+
+	return;
+}
+EXPORT_SYMBOL_HDA(snd_hda_power_save_monitor_start);
+
+/**
+ * snd_hda_power_save_monitor_stop - Delete the timer to monitor the changes of
+ *    power_save parameter.
+ * @bus: HD-audio bus
+ */
+void snd_hda_power_save_monitor_stop(struct hda_bus *bus)
+{
+	int ret;
+
+	if (bus->power_save_timer_inited) {
+		snd_printd("hda-bus: stop power save monitor\n");
+		ret = del_timer_sync(&bus->power_save_timer);
+		if (ret < 0)
+			snd_printd("hda-bus: error in del_timer_sync\n");
+		bus->power_save_timer_inited = 0;
+	}
+
+	return;
+}
+EXPORT_SYMBOL_HDA(snd_hda_power_save_monitor_stop);
 #endif
 
 /*
@@ -5045,6 +5150,8 @@ int snd_hda_suspend(struct hda_bus *bus)
 {
 	struct hda_codec *codec;
 
+	snd_hda_power_save_monitor_stop(bus);
+
 	list_for_each_entry(codec, &bus->codec_list, list) {
 		if (hda_codec_is_power_on(codec))
 			hda_call_codec_suspend(codec);
@@ -5069,6 +5176,8 @@ int snd_hda_resume(struct hda_bus *bus)
 	list_for_each_entry(codec, &bus->codec_list, list) {
 		hda_call_codec_resume(codec);
 	}
+
+	snd_hda_power_save_monitor_start(bus);
 	return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_resume);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index c422d33..8b88ec5 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -653,6 +653,8 @@ struct hda_bus {
 	struct hda_bus_unsolicited *unsol;
 	char workq_name[16];
 	struct workqueue_struct *workq;	/* common workqueue for codecs */
+	/* timer to monitor changes of power_save parameter */
+	struct timer_list power_save_timer;
 
 	/* assigned PCMs */
 	DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
@@ -667,6 +669,9 @@ struct hda_bus {
 	unsigned int response_reset:1;	/* controller was reset */
 	unsigned int in_reset:1;	/* during reset operation */
 	unsigned int power_keep_link_on:1; /* don't power off HDA link */
+	/* power save flags */
+	unsigned int power_save_enabled:1;	/* enabled at last check */
+	unsigned int power_save_timer_inited:1;	/* timer is initialized */
 };
 
 /*
@@ -1062,10 +1067,14 @@ void snd_hda_power_up(struct hda_codec *codec);
 void snd_hda_power_up_d3wait(struct hda_codec *codec);
 void snd_hda_power_down(struct hda_codec *codec);
 void snd_hda_update_power_acct(struct hda_codec *codec);
+extern void snd_hda_power_save_monitor_start(struct hda_bus *bus);
+extern void snd_hda_power_save_monitor_stop(struct hda_bus *bus);
 #else
 static inline void snd_hda_power_up(struct hda_codec *codec) {}
 static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) {}
 static inline void snd_hda_power_down(struct hda_codec *codec) {}
+#define snd_hda_power_save_monitor_start(bus) {}
+#define snd_hda_power_save_monitor_stop(bus) {}
 #endif
 
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c8aced1..fe015d0 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -3236,7 +3236,7 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)
 	chip->running = 1;
 	power_down_all_codecs(chip);
 	azx_notifier_register(chip);
-
+	snd_hda_power_save_monitor_start(chip->bus);
 	return 0;
 
 out_free:
-- 
1.7.9.5

             reply	other threads:[~2012-08-14  9:29 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-14 17:56 mengdong.lin [this message]
2012-08-14 10:05 ` [RFC PATCH 1/1] ALSA: hda - add a timer to find and suspend idle codecs David Henningsson
2012-08-14 13:42   ` Lin, Mengdong
2012-08-14 10:08 ` Jaroslav Kysela
2012-08-14 13:55   ` Lin, Mengdong
2012-08-14 10:26 ` Takashi Iwai
2012-08-14 14:35   ` Lin, Mengdong
2012-08-14 14:42     ` Takashi Iwai
2012-08-14 15:19       ` Takashi Iwai
2012-08-14 15:20         ` [PATCH 1/2] ALSA: hda - Implement snd_hda_power_sync() helper function Takashi Iwai
2012-08-14 15:21         ` [PATCH 2/2] ALSA: hda - Check the power state when power_save option is changed Takashi Iwai
2012-08-15  4:19           ` Lin, Mengdong
2012-08-15  6:58             ` Takashi Iwai
  -- strict thread matches above, loose matches on Subject: below --
2012-08-14 17:44 [RFC PATCH 1/1] ALSA: hda - add a timer to find and suspend idle codecs mengdong.lin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1344967003-5470-1-git-send-email-mengdong.lin@intel.com \
    --to=mengdong.lin@intel.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).