[Intel-gfx] [PATCH] ALSA: hda: Release display power reference during shutdown/reboot

Imre Deak imre.deak at intel.com
Tue Jun 22 19:58:13 UTC 2021


On Tue, Jun 22, 2021 at 04:18:14PM +0200, Takashi Iwai wrote:
> On Mon, 21 Jun 2021 19:44:15 +0200,
> Imre Deak wrote:
> > 
> > Make sure the HDA driver's display power reference is released during
> > shutdown/reboot.
> > 
> > During the shutdown/reboot sequence the pci device core calls the
> > pm_runtime_resume handler for all devices before calling the driver's
> > shutdown callback and so the HDA driver's runtime resume callback will
> > acquire a display power reference (on HSW/BDW). This triggers a power
> > reference held WARN on HSW/BDW in the i915 driver's subsequent shutdown
> > handler, which expects all display power references to be released by
> > that time.
> > 
> > Since the HDA controller is stopped in the shutdown handler in any case,
> > let's follow here the same sequence as the one during runtime suspend.
> > This will also reset the HDA link and drop the display power reference,
> > getting rid of the above WARN.
> 
> As kbuild bot suggested, __azx_runtime_suspend() is defined only with
> CONFIG_PM.  We need either moving the function out of ifdef CONFIG_PM
> block, or having CONFIG_PM conditional call there.

Thanks, missed that. I think we need to drop the power ref in the !CONFIG_PM
case as well (since AFAICS then the ref is held after the device is probed), so
I'd move __azx_runtime_suspend() out of the CONFIG_PM block (and perhaps rename
it to azx_shutdown_chip).

> I myself have no much preference,  but maybe the latter can be easier
> to be cherry-picked to stable kernels.

To my knowledge this only fixes the book-keeping in the i915 driver, so
not sure if it's a stable material.

Trying things now with !CONFIG_PM, I noticed that the HDA codec would still
keep a separate power reference (which was dropped for me with CONFIG_PM, as
the codec was runtime suspended). To fix that we'd need something like the
following (on top of the above changes in a separate patch), any
comments on it?:

diff --git a/include/sound/core.h b/include/sound/core.h
index c4ade121727df..5228dec658ad6 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -61,6 +61,7 @@ struct snd_device_ops {
 	int (*dev_free)(struct snd_device *dev);
 	int (*dev_register)(struct snd_device *dev);
 	int (*dev_disconnect)(struct snd_device *dev);
+	void (*dev_shutdown)(struct snd_device *dev);
 };
 
 struct snd_device {
@@ -314,6 +315,7 @@ void snd_device_disconnect(struct snd_card *card, void *device_data);
 void snd_device_disconnect_all(struct snd_card *card);
 void snd_device_free(struct snd_card *card, void *device_data);
 void snd_device_free_all(struct snd_card *card);
+void snd_device_shutdown_all(struct snd_card *card);
 int snd_device_get_state(struct snd_card *card, void *device_data);
 
 /* isadma.c */
diff --git a/sound/core/device.c b/sound/core/device.c
index bf0b04a7ee797..7c695f8a72f5b 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -238,6 +238,17 @@ void snd_device_free_all(struct snd_card *card)
 		__snd_device_free(dev);
 }
 
+void snd_device_shutdown_all(struct snd_card *card)
+{
+	struct snd_device *dev;
+
+	list_for_each_entry_reverse(dev, &card->devices, list) {
+		if (dev->ops->dev_shutdown)
+			dev->ops->dev_shutdown(dev);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_device_shutdown_all);
+
 /**
  * snd_device_get_state - Get the current state of the given device
  * @card: the card instance
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 5462f771c2f90..6da105bc57f58 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -866,6 +866,13 @@ static void snd_hda_codec_dev_release(struct device *dev)
 		kfree(codec);
 }
 
+static void snd_hda_codec_dev_shutdown(struct snd_device *device)
+{
+	struct hda_codec *codec = device->device_data;
+
+	codec_display_power(codec, false);
+}
+
 #define DEV_NAME_LEN 31
 
 static int snd_hda_codec_device_init(struct hda_bus *bus, struct snd_card *card,
@@ -930,6 +937,7 @@ int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
 	static const struct snd_device_ops dev_ops = {
 		.dev_register = snd_hda_codec_dev_register,
 		.dev_free = snd_hda_codec_dev_free,
+		.dev_shutdown = snd_hda_codec_dev_shutdown,
 	};
 
 	dev_dbg(card->dev, "%s: entry\n", __func__);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index f5ab0b682adcc..6ca05c6633fc6 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2382,8 +2382,10 @@ static void azx_shutdown(struct pci_dev *pci)
 	if (!card)
 		return;
 	chip = card->private_data;
-	if (chip && chip->running)
+	if (chip && chip->running) {
+		snd_device_shutdown_all(card);
 		azx_shutdown_chip(chip);
+	}
 }
 
 /* PCI IDs */

> thanks,
> 
> Takashi


More information about the Intel-gfx mailing list