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