Re: snd-hda-intel prevents machine to power off

From: Takashi Iwai
Date: Wed Oct 29 2008 - 03:58:46 EST


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@xxxxxxx> 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@xxxxxxx> 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;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/