Commit 1ee23fe0 authored by Takashi Iwai's avatar Takashi Iwai

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: default avatarBryan Quigley <gquigs@gmail.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 1c53e725
...@@ -651,7 +651,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) ...@@ -651,7 +651,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
int err = -ENODEV; int err = -ENODEV;
down_read(&chip->shutdown_rwsem); down_read(&chip->shutdown_rwsem);
if (chip->probing) if (chip->probing && chip->in_pm)
err = 0; err = 0;
else if (!chip->shutdown) else if (!chip->shutdown)
err = usb_autopm_get_interface(chip->pm_intf); err = usb_autopm_get_interface(chip->pm_intf);
...@@ -663,7 +663,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) ...@@ -663,7 +663,7 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
void snd_usb_autosuspend(struct snd_usb_audio *chip) void snd_usb_autosuspend(struct snd_usb_audio *chip)
{ {
down_read(&chip->shutdown_rwsem); down_read(&chip->shutdown_rwsem);
if (!chip->shutdown && !chip->probing) if (!chip->shutdown && !chip->probing && !chip->in_pm)
usb_autopm_put_interface(chip->pm_intf); usb_autopm_put_interface(chip->pm_intf);
up_read(&chip->shutdown_rwsem); up_read(&chip->shutdown_rwsem);
} }
...@@ -712,6 +712,8 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) ...@@ -712,6 +712,8 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
return 0; return 0;
if (--chip->num_suspended_intf) if (--chip->num_suspended_intf)
return 0; return 0;
chip->in_pm = 1;
/* /*
* ALSA leaves material resumption to user space * ALSA leaves material resumption to user space
* we just notify and restart the mixers * we just notify and restart the mixers
...@@ -727,6 +729,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) ...@@ -727,6 +729,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
chip->autosuspended = 0; chip->autosuspended = 0;
err_out: err_out:
chip->in_pm = 0;
return err; return err;
} }
......
...@@ -40,6 +40,7 @@ struct snd_usb_audio { ...@@ -40,6 +40,7 @@ struct snd_usb_audio {
struct rw_semaphore shutdown_rwsem; struct rw_semaphore shutdown_rwsem;
unsigned int shutdown:1; unsigned int shutdown:1;
unsigned int probing:1; unsigned int probing:1;
unsigned int in_pm:1;
unsigned int autosuspended:1; unsigned int autosuspended:1;
unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment