aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-10-12 11:28:18 -0400
committerTakashi Iwai <tiwai@suse.de>2012-10-15 03:55:48 -0400
commit128960a9ad67e2d119738f5211956e0304517551 (patch)
tree1b81778fa4184861fe85cb168511153d8808cbc5
parente73fa21b4e6ce10934cc8016a9a512d7152a860b (diff)
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: Daniel J Blueman <daniel@quora.org> Cc: <stable@vger.kernel.org> [v3.5+] Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/hda_intel.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 69810b21f7f4..ecf277506ad1 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -501,6 +501,7 @@ struct azx {
501 501
502 /* VGA-switcheroo setup */ 502 /* VGA-switcheroo setup */
503 unsigned int use_vga_switcheroo:1; 503 unsigned int use_vga_switcheroo:1;
504 unsigned int vga_switcheroo_registered:1;
504 unsigned int init_failed:1; /* delayed init failed */ 505 unsigned int init_failed:1; /* delayed init failed */
505 unsigned int disabled:1; /* disabled by VGA-switcher */ 506 unsigned int disabled:1; /* disabled by VGA-switcher */
506 507
@@ -2640,7 +2641,9 @@ static void azx_vs_set_state(struct pci_dev *pci,
2640 if (disabled) { 2641 if (disabled) {
2641 azx_suspend(&pci->dev); 2642 azx_suspend(&pci->dev);
2642 chip->disabled = true; 2643 chip->disabled = true;
2643 snd_hda_lock_devices(chip->bus); 2644 if (snd_hda_lock_devices(chip->bus))
2645 snd_printk(KERN_WARNING SFX
2646 "Cannot lock devices!\n");
2644 } else { 2647 } else {
2645 snd_hda_unlock_devices(chip->bus); 2648 snd_hda_unlock_devices(chip->bus);
2646 chip->disabled = false; 2649 chip->disabled = false;
@@ -2683,14 +2686,20 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = {
2683 2686
2684static int __devinit register_vga_switcheroo(struct azx *chip) 2687static int __devinit register_vga_switcheroo(struct azx *chip)
2685{ 2688{
2689 int err;
2690
2686 if (!chip->use_vga_switcheroo) 2691 if (!chip->use_vga_switcheroo)
2687 return 0; 2692 return 0;
2688 /* FIXME: currently only handling DIS controller 2693 /* FIXME: currently only handling DIS controller
2689 * is there any machine with two switchable HDMI audio controllers? 2694 * is there any machine with two switchable HDMI audio controllers?
2690 */ 2695 */
2691 return vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, 2696 err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops,
2692 VGA_SWITCHEROO_DIS, 2697 VGA_SWITCHEROO_DIS,
2693 chip->bus != NULL); 2698 chip->bus != NULL);
2699 if (err < 0)
2700 return err;
2701 chip->vga_switcheroo_registered = 1;
2702 return 0;
2694} 2703}
2695#else 2704#else
2696#define init_vga_switcheroo(chip) /* NOP */ 2705#define init_vga_switcheroo(chip) /* NOP */
@@ -2712,7 +2721,8 @@ static int azx_free(struct azx *chip)
2712 if (use_vga_switcheroo(chip)) { 2721 if (use_vga_switcheroo(chip)) {
2713 if (chip->disabled && chip->bus) 2722 if (chip->disabled && chip->bus)
2714 snd_hda_unlock_devices(chip->bus); 2723 snd_hda_unlock_devices(chip->bus);
2715 vga_switcheroo_unregister_client(chip->pci); 2724 if (chip->vga_switcheroo_registered)
2725 vga_switcheroo_unregister_client(chip->pci);
2716 } 2726 }
2717 2727
2718 if (chip->initialized) { 2728 if (chip->initialized) {
@@ -3060,14 +3070,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
3060 } 3070 }
3061 3071
3062 ok: 3072 ok:
3063 err = register_vga_switcheroo(chip);
3064 if (err < 0) {
3065 snd_printk(KERN_ERR SFX
3066 "Error registering VGA-switcheroo client\n");
3067 azx_free(chip);
3068 return err;
3069 }
3070
3071 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); 3073 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
3072 if (err < 0) { 3074 if (err < 0) {
3073 snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); 3075 snd_printk(KERN_ERR SFX "Error creating device [card]!\n");
@@ -3338,6 +3340,13 @@ static int __devinit azx_probe(struct pci_dev *pci,
3338 if (pci_dev_run_wake(pci)) 3340 if (pci_dev_run_wake(pci))
3339 pm_runtime_put_noidle(&pci->dev); 3341 pm_runtime_put_noidle(&pci->dev);
3340 3342
3343 err = register_vga_switcheroo(chip);
3344 if (err < 0) {
3345 snd_printk(KERN_ERR SFX
3346 "Error registering VGA-switcheroo client\n");
3347 goto out_free;
3348 }
3349
3341 dev++; 3350 dev++;
3342 return 0; 3351 return 0;
3343 3352