aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-11-19 08:14:58 -0500
committerTakashi Iwai <tiwai@suse.de>2012-11-19 08:14:58 -0500
commit989c3187156ad197ae473fa9d9d506eef9624f12 (patch)
tree2f18bbd11a8811729e039ab1cb72cdc21f74254f /sound/pci
parent0ced14fbda44bf9c4977f1b01ae1077b944b94ab (diff)
ALSA: hda - Fix recursive suspend/resume call
When the bus reset is performed during the suspend/resume (including the power-saving too), it calls snd_hda_suspend() and snd_hda_resume() again, and deadlocks eventually. For avoiding the recursive call, add a new flag indicating that the PM is being performed, and don't go to the bus reset mode when it's on. Reported-and-tested-by: Julian Wollrath <jwollrath@web.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_codec.c11
-rw-r--r--sound/pci/hda/hda_codec.h1
2 files changed, 10 insertions, 2 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 70d4848b5cd0..cebe2dfdd984 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -228,7 +228,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
228 } 228 }
229 mutex_unlock(&bus->cmd_mutex); 229 mutex_unlock(&bus->cmd_mutex);
230 snd_hda_power_down(codec); 230 snd_hda_power_down(codec);
231 if (res && *res == -1 && bus->rirb_error) { 231 if (!codec->in_pm && res && *res == -1 && bus->rirb_error) {
232 if (bus->response_reset) { 232 if (bus->response_reset) {
233 snd_printd("hda_codec: resetting BUS due to " 233 snd_printd("hda_codec: resetting BUS due to "
234 "fatal communication error\n"); 234 "fatal communication error\n");
@@ -238,7 +238,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
238 goto again; 238 goto again;
239 } 239 }
240 /* clear reset-flag when the communication gets recovered */ 240 /* clear reset-flag when the communication gets recovered */
241 if (!err) 241 if (!err || codec->in_pm)
242 bus->response_reset = 0; 242 bus->response_reset = 0;
243 return err; 243 return err;
244} 244}
@@ -3616,6 +3616,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
3616{ 3616{
3617 unsigned int state; 3617 unsigned int state;
3618 3618
3619 codec->in_pm = 1;
3620
3619 if (codec->patch_ops.suspend) 3621 if (codec->patch_ops.suspend)
3620 codec->patch_ops.suspend(codec); 3622 codec->patch_ops.suspend(codec);
3621 hda_cleanup_all_streams(codec); 3623 hda_cleanup_all_streams(codec);
@@ -3630,6 +3632,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
3630 codec->power_transition = 0; 3632 codec->power_transition = 0;
3631 codec->power_jiffies = jiffies; 3633 codec->power_jiffies = jiffies;
3632 spin_unlock(&codec->power_lock); 3634 spin_unlock(&codec->power_lock);
3635 codec->in_pm = 0;
3633 return state; 3636 return state;
3634} 3637}
3635 3638
@@ -3638,6 +3641,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
3638 */ 3641 */
3639static void hda_call_codec_resume(struct hda_codec *codec) 3642static void hda_call_codec_resume(struct hda_codec *codec)
3640{ 3643{
3644 codec->in_pm = 1;
3645
3641 /* set as if powered on for avoiding re-entering the resume 3646 /* set as if powered on for avoiding re-entering the resume
3642 * in the resume / power-save sequence 3647 * in the resume / power-save sequence
3643 */ 3648 */
@@ -3656,6 +3661,8 @@ static void hda_call_codec_resume(struct hda_codec *codec)
3656 snd_hda_codec_resume_cache(codec); 3661 snd_hda_codec_resume_cache(codec);
3657 } 3662 }
3658 snd_hda_jack_report_sync(codec); 3663 snd_hda_jack_report_sync(codec);
3664
3665 codec->in_pm = 0;
3659 snd_hda_power_down(codec); /* flag down before returning */ 3666 snd_hda_power_down(codec); /* flag down before returning */
3660} 3667}
3661#endif /* CONFIG_PM */ 3668#endif /* CONFIG_PM */
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 507fe8a917b6..4f4e545c0f4b 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -869,6 +869,7 @@ struct hda_codec {
869 unsigned int power_on :1; /* current (global) power-state */ 869 unsigned int power_on :1; /* current (global) power-state */
870 unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ 870 unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
871 unsigned int pm_down_notified:1; /* PM notified to controller */ 871 unsigned int pm_down_notified:1; /* PM notified to controller */
872 unsigned int in_pm:1; /* suspend/resume being performed */
872 int power_transition; /* power-state in transition */ 873 int power_transition; /* power-state in transition */
873 int power_count; /* current (global) power refcount */ 874 int power_count; /* current (global) power refcount */
874 struct delayed_work power_work; /* delayed task for powerdown */ 875 struct delayed_work power_work; /* delayed task for powerdown */