[alsa-devel] [PATCH v2] ALSA: hda - add runtime PM support
Takashi Iwai
tiwai at suse.de
Tue Aug 21 07:34:00 CEST 2012
At Mon, 20 Aug 2012 17:30:55 +0800,
mengdong.lin at intel.com wrote:
>
> From: Mengdong Lin <mengdong.lin at intel.com>
>
> Runtime PM can bring more power saving:
> - When the controller is suspended, its parent device will also have a chance
> to suspend.
> - PCI subsystem can choose the lowest power state the controller can signal
> wake up from. This state can be D3cold on platforms with ACPI PM support.
> And runtime PM can provide a gernel sysfs interface for a system policy manager.
>
> Runtime PM support is based on current HDA power saving implementation. The user
> can enable runtime PM on platfroms that provide acceptable latency on transition
> from D3 to D0.
>
> Details:
> - When both power saving and runtime PM are enabled, and if all codecs are
> suspended (in D3), the HDA controller can also be suspended to a low power
> state by decreasing the power usage counter. And the user IO operation can
> resume the controller back to D0.
> - If runtime PM is disabled, power saving just works as before.
> - If power saving is disabled, the controller won't be suspended because the
> power usage counter can never be 0.
>
> TODO: Suspend the controller only if all codecs support CLKSTOP in D3, for
> pass-through operations and wakeup.
>
> Signed-off-by: Mengdong Lin <mengdong.lin at intel.com>
As I mentioned, I suspect calling snd_power_change_state() for runtime
PM is rather problematic. Could you point out the case where this
call is mandatory?
thanks,
Takashi
> ---
> sound/pci/hda/hda_intel.c | 55 ++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 52 insertions(+), 3 deletions(-)
>
> diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
> index b6a4ea7..cd02971 100644
> --- a/sound/pci/hda/hda_intel.c
> +++ b/sound/pci/hda/hda_intel.c
> @@ -46,6 +46,7 @@
> #include <linux/mutex.h>
> #include <linux/reboot.h>
> #include <linux/io.h>
> +#include <linux/pm_runtime.h>
> #ifdef CONFIG_X86
> /* for snoop control */
> #include <asm/pgtable.h>
> @@ -1278,6 +1279,9 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
> u8 sd_status;
> int i, ok;
>
> + if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
> + return IRQ_NONE;
> +
> spin_lock(&chip->reg_lock);
>
> if (chip->disabled) {
> @@ -2402,11 +2406,19 @@ static void azx_power_notify(struct hda_bus *bus)
> break;
> }
> }
> - if (power_on)
> + if (power_on) {
> + if (!chip->initialized)
> + pm_runtime_get_sync(&chip->pci->dev);
> azx_init_chip(chip, 1);
> + }
> else if (chip->running && power_save_controller &&
> - !bus->power_keep_link_on)
> + !bus->power_keep_link_on) {
> azx_stop_chip(chip);
> +
> + /* TODO: Suspend controller only if all codec support
> + stop-clock in D3, for wakeup consideration */
> + pm_runtime_put_sync(&chip->pci->dev);
> + }
> }
>
> static DEFINE_MUTEX(card_list_lock);
> @@ -2511,7 +2523,33 @@ static int azx_resume(struct device *dev)
> snd_power_change_state(card, SNDRV_CTL_POWER_D0);
> return 0;
> }
> -static SIMPLE_DEV_PM_OPS(azx_pm, azx_suspend, azx_resume);
> +
> +static int azx_runtime_suspend(struct device *dev)
> +{
> + struct snd_card *card = dev_get_drvdata(dev);
> + struct azx *chip = card->private_data;
> +
> + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
> + azx_clear_irq_pending(chip);
> + return 0;
> +}
> +
> +static int azx_runtime_resume(struct device *dev)
> +{
> + struct snd_card *card = dev_get_drvdata(dev);
> + struct azx *chip = card->private_data;
> +
> + azx_init_pci(chip);
> +
> + snd_power_change_state(card, SNDRV_CTL_POWER_D0);
> + return 0;
> +}
> +
> +static const struct dev_pm_ops azx_pm = {
> + SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
> + SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, NULL)
> +};
> +
> #define AZX_PM_OPS &azx_pm
> #else
> #define azx_suspend(dev)
> @@ -3238,6 +3276,9 @@ static int __devinit azx_probe(struct pci_dev *pci,
>
> pci_set_drvdata(pci, card);
>
> + if (pci_dev_run_wake(pci))
> + pm_runtime_put_noidle(&pci->dev);
> +
> dev++;
> return 0;
>
> @@ -3289,6 +3330,7 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)
> goto out_free;
>
> chip->running = 1;
> + pm_runtime_get_noresume(&chip->pci->dev); /* active by default */
> power_down_all_codecs(chip);
> azx_notifier_register(chip);
> azx_add_card_list(chip);
> @@ -3303,6 +3345,13 @@ out_free:
> static void __devexit azx_remove(struct pci_dev *pci)
> {
> struct snd_card *card = pci_get_drvdata(pci);
> +
> + /* undo 'get' in azx_probe_continue() */
> + pm_runtime_put_noidle(&pci->dev);
> +
> + if (pci_dev_run_wake(pci))
> + pm_runtime_get_noresume(&pci->dev);
> +
> if (card)
> snd_card_free(card);
> pci_set_drvdata(pci, NULL);
> --
> 1.7.9.5
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
More information about the Alsa-devel
mailing list