diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-05-02 12:17:06 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-02 12:17:06 -0400 |
commit | 1ee23fe07ee83a38ecee927e701f762888ada942 (patch) | |
tree | f8af5087956bef2a461410b49584dc3bd2cd988c /sound | |
parent | 1c53e7253ed8769a00afa0f06777d731dbe1ba6f (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.c | 7 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 1 |
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) | |||
663 | void snd_usb_autosuspend(struct snd_usb_audio *chip) | 663 | void 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 | ||
729 | err_out: | 731 | err_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 | ||