[alsa-devel] snd-hda-intel prevents machine to power off

Takashi Iwai tiwai at suse.de
Wed Oct 29 08:58:32 CET 2008


At Tue, 28 Oct 2008 20:12:09 +0100,
I wrote:
> 
> At Tue, 28 Oct 2008 16:44:33 -0200,
> Luiz Fernando N. Capitulino wrote:
> > 
> > Em Tue, 28 Oct 2008 17:51:30 +0100
> > Takashi Iwai <tiwai at suse.de> escreveu:
> > 
> > | At Tue, 28 Oct 2008 14:19:16 -0200,
> > | Luiz Fernando N. Capitulino wrote:
> > | > 
> > | > Em Tue, 28 Oct 2008 17:07:42 +0100
> > | > Takashi Iwai <tiwai at suse.de> escreveu:
> > | > 
> > | > | >  Hi Takashi,
> > | > | > 
> > | > | >  If I have some process with the sound device opened in my eeepc
> > | > | > (say KDE's kmix) and try to power off the machine, for example with:
> > | > | > 
> > | > | > # echo o > /proc/sysrq-trigger
> > | > | > 
> > | > | >  The machine will not power off.
> > | > | 
> > | > | At which point does it stop?
> > | > | What shows alt-sysrq-t (or w) output?
> > | > 
> > | >  I'm wondering how to get that kind of output because everything
> > | > is disabled at that point (display inclusive).
> > | 
> > | OK, then it's hard to see.
> > | A good news is that it goes at least fairly end point, thus likely no
> > | hanging task, etc.
> > | 
> > | 
> > | > | >  But it does work if I remove the snd-hda-intel module before issuing
> > | > | > the echo above.
> > | > | > 
> > | > | >  This problem seems to be pretty popular among distros, I could find
> > | > | > it reported for Mandriva, Ubuntu and Fedora.
> > | > | 
> > | > | Hmm, I haven't heard of unfixed issues.
> > | > 
> > | >  Well, these are the tickets I've found:
> > | > 
> > | > https://bugzilla.redhat.com/show_bug.cgi?id=444115
> > | > https://bugs.launchpad.net/ubuntu/+source/linux-source-2.6.22/+bug/126140
> > | > https://qa.mandriva.com/show_bug.cgi?id=44752
> > | 
> > | Looking through the comments that the power-saving helps, the problem
> > | may disappear even without disabling the pci device.  The power-saving
> > | doesn't involve with pci_disable_device() or changing the power-state
> > | of the controler.  So, at least, the problem is either in the codec
> > | or the controller setup.
> > | 
> > | Suppose you already use the power-saving and it solves the shutdown
> > | problem, could you set power_save_controller=0 option for
> > | snd-hda-intel, and check whether the shutdown still works or not?
> > | If the shutdown doesn't work with this option, it means that
> > | azx_stop_chip() is what would be needed.
> > 
> >  Yes, power_save_controller=0 doesn't work while the power-saving
> > one works.
> 
> OK, then could you check which call in azx_stop_chip() is critical?
> You can comment out each and check the difference.
> 
> >  Where should I put a call to azx_stop_ship()? I'm not an alsa
> > hacker. :)
> 
> This is the problem.  If it's a fast call like azx_int_clear() or
> azx_int_enable(), it can be relatively easily done at each time.
> But, it's like freeing memories, it shouldn't be done at each
> operation.

On the second thought, we may just use a reboot notifier as a
workaround for this kind of problem.
Below is a quick fix.  Could you give it a try?

Anyway, could you create a kernel bugzilla entry?  This will help
to keep records in a commit changelog greatly, why this ugly hack is
needed.
You can list the relevant URLs there as references, too.


thanks,

Takashi

---
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 5074ea6..042a518 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -45,6 +45,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/mutex.h>
+#include <linux/reboot.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include "hda_codec.h"
@@ -397,6 +398,9 @@ struct azx {
 
 	/* for pending irqs */
 	struct work_struct irq_pending_work;
+
+	/* reboot notifier (for mysterious hangup problem at power-down) */
+	struct notifier_block reboot_notifier;
 };
 
 /* driver types */
@@ -1903,12 +1907,36 @@ static int azx_resume(struct pci_dev *pci)
 
 
 /*
+ * reboot notifier for hang-up problem at power-down
+ */
+static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf)
+{
+	struct azx *chip = container_of(nb, struct azx, reboot_notifier);
+	azx_stop_chip(chip);
+	return NOTIFY_OK;
+}
+
+static void azx_notifier_register(struct azx *chip)
+{
+	chip->reboot_notifier.notifier_call = azx_halt;
+	register_reboot_notifier(&chip->reboot_notifier);
+}
+
+static void azx_notifier_unregister(struct azx *chip)
+{
+	if (chip->reboot_notifier.notifier_call)
+		unregister_reboot_notifier(&chip->reboot_notifier);
+}
+
+/*
  * destructor
  */
 static int azx_free(struct azx *chip)
 {
 	int i;
 
+	azx_notifier_unregister(chip);
+
 	if (chip->initialized) {
 		azx_clear_irq_pending(chip);
 		for (i = 0; i < chip->num_streams; i++)
@@ -2272,6 +2300,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
 	pci_set_drvdata(pci, card);
 	chip->running = 1;
 	power_down_all_codecs(chip);
+	azx_notifier_register(chip);
 
 	dev++;
 	return err;


More information about the Alsa-devel mailing list