Commit 128960a9 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: hda - Fix registration race of VGA switcheroo



Delay the registration of VGA switcheroo client to the end of the
probing.  Otherwise a too quick switching may result in Oops during
probing.

Also add the check of the return value from snd_hda_lock_devices().

Reported-and-tested-by: default avatarDaniel J Blueman <daniel@quora.org>
Cc: <stable@vger.kernel.org> [v3.5+]
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent e73fa21b
Loading
Loading
Loading
Loading
+20 −11
Original line number Diff line number Diff line
@@ -501,6 +501,7 @@ struct azx {

	/* VGA-switcheroo setup */
	unsigned int use_vga_switcheroo:1;
	unsigned int vga_switcheroo_registered:1;
	unsigned int init_failed:1; /* delayed init failed */
	unsigned int disabled:1; /* disabled by VGA-switcher */

@@ -2640,7 +2641,9 @@ static void azx_vs_set_state(struct pci_dev *pci,
		if (disabled) {
			azx_suspend(&pci->dev);
			chip->disabled = true;
			snd_hda_lock_devices(chip->bus);
			if (snd_hda_lock_devices(chip->bus))
				snd_printk(KERN_WARNING SFX
					   "Cannot lock devices!\n");
		} else {
			snd_hda_unlock_devices(chip->bus);
			chip->disabled = false;
@@ -2683,14 +2686,20 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = {

static int __devinit register_vga_switcheroo(struct azx *chip)
{
	int err;

	if (!chip->use_vga_switcheroo)
		return 0;
	/* FIXME: currently only handling DIS controller
	 * is there any machine with two switchable HDMI audio controllers?
	 */
	return vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops,
	err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops,
						    VGA_SWITCHEROO_DIS,
						    chip->bus != NULL);
	if (err < 0)
		return err;
	chip->vga_switcheroo_registered = 1;
	return 0;
}
#else
#define init_vga_switcheroo(chip)		/* NOP */
@@ -2712,6 +2721,7 @@ static int azx_free(struct azx *chip)
	if (use_vga_switcheroo(chip)) {
		if (chip->disabled && chip->bus)
			snd_hda_unlock_devices(chip->bus);
		if (chip->vga_switcheroo_registered)
			vga_switcheroo_unregister_client(chip->pci);
	}

@@ -3060,14 +3070,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
	}

 ok:
	err = register_vga_switcheroo(chip);
	if (err < 0) {
		snd_printk(KERN_ERR SFX
			   "Error registering VGA-switcheroo client\n");
		azx_free(chip);
		return err;
	}

	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
	if (err < 0) {
		snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
@@ -3338,6 +3340,13 @@ static int __devinit azx_probe(struct pci_dev *pci,
	if (pci_dev_run_wake(pci))
		pm_runtime_put_noidle(&pci->dev);

	err = register_vga_switcheroo(chip);
	if (err < 0) {
		snd_printk(KERN_ERR SFX
			   "Error registering VGA-switcheroo client\n");
		goto out_free;
	}

	dev++;
	return 0;