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@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@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;