aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-05-02 12:17:06 -0400
committerTakashi Iwai <tiwai@suse.de>2014-05-02 12:17:06 -0400
commit1ee23fe07ee83a38ecee927e701f762888ada942 (patch)
treef8af5087956bef2a461410b49584dc3bd2cd988c /sound
parent1c53e7253ed8769a00afa0f06777d731dbe1ba6f (diff)
ALSA: usb-audio: Fix deadlocks at resuming
The recent addition of the USB audio mixer suspend/resume may lead to deadlocks when the driver tries to call usb_autopm_get_interface() recursively, since the function tries to sync with the finish of the other calls. For avoiding it, introduce a flag indicating the resume operation and avoids the recursive usb_autopm_get_interface() calls during the resume. Reported-and-tested-by: Bryan Quigley <gquigs@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/card.c7
-rw-r--r--sound/usb/usbaudio.h1
2 files changed, 6 insertions, 2 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c
index e769d3977716..c3b5b7dca1c3 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -651,7 +651,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
651 int err = -ENODEV; 651 int err = -ENODEV;
652 652
653 down_read(&chip->shutdown_rwsem); 653 down_read(&chip->shutdown_rwsem);
654 if (chip->probing) 654 if (chip->probing && chip->in_pm)
655 err = 0; 655 err = 0;
656 else if (!chip->shutdown) 656 else if (!chip->shutdown)
657 err = usb_autopm_get_interface(chip->pm_intf); 657 err = usb_autopm_get_interface(chip->pm_intf);
@@ -663,7 +663,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
663void snd_usb_autosuspend(struct snd_usb_audio *chip) 663void snd_usb_autosuspend(struct snd_usb_audio *chip)
664{ 664{
665 down_read(&chip->shutdown_rwsem); 665 down_read(&chip->shutdown_rwsem);
666 if (!chip->shutdown && !chip->probing) 666 if (!chip->shutdown && !chip->probing && !chip->in_pm)
667 usb_autopm_put_interface(chip->pm_intf); 667 usb_autopm_put_interface(chip->pm_intf);
668 up_read(&chip->shutdown_rwsem); 668 up_read(&chip->shutdown_rwsem);
669} 669}
@@ -712,6 +712,8 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
712 return 0; 712 return 0;
713 if (--chip->num_suspended_intf) 713 if (--chip->num_suspended_intf)
714 return 0; 714 return 0;
715
716 chip->in_pm = 1;
715 /* 717 /*
716 * ALSA leaves material resumption to user space 718 * ALSA leaves material resumption to user space
717 * we just notify and restart the mixers 719 * we just notify and restart the mixers
@@ -727,6 +729,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
727 chip->autosuspended = 0; 729 chip->autosuspended = 0;
728 730
729err_out: 731err_out:
732 chip->in_pm = 0;
730 return err; 733 return err;
731} 734}
732 735
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 25c4c7e217de..91d0380431b4 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -40,6 +40,7 @@ struct snd_usb_audio {
40 struct rw_semaphore shutdown_rwsem; 40 struct rw_semaphore shutdown_rwsem;
41 unsigned int shutdown:1; 41 unsigned int shutdown:1;
42 unsigned int probing:1; 42 unsigned int probing:1;
43 unsigned int in_pm:1;
43 unsigned int autosuspended:1; 44 unsigned int autosuspended:1;
44 unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ 45 unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
45 46