Commit 63e51fd7 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Don't take unresponsive D3 transition too serious

When a codec is powered off, some systems don't respond properly after
D3 FG transition, while the driver still expects the response and
tries to fall back to different modes (polling and single-cmd).  When
the fallback happens, the driver stays in that mode, and falling back
to the single-cmd mode means it'll loose the unsol event handling,
too.

The unresponsiveness at D3 isn't too serious, thus this fallback is
mostly superfluous.  We can gracefully ignore the error there so that
the driver keeps the normal operation mode.

This patch adds a new bit flag for codec read/write, set in the power
transition stage, which is notified to the controller driver via a new
bus->no_response_fallback flag.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent e7ecc27e
...@@ -221,6 +221,8 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, ...@@ -221,6 +221,8 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
again: again:
snd_hda_power_up(codec); snd_hda_power_up(codec);
mutex_lock(&bus->cmd_mutex); mutex_lock(&bus->cmd_mutex);
if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
bus->no_response_fallback = 1;
for (;;) { for (;;) {
trace_hda_send_cmd(codec, cmd); trace_hda_send_cmd(codec, cmd);
err = bus->ops.command(bus, cmd); err = bus->ops.command(bus, cmd);
...@@ -233,6 +235,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, ...@@ -233,6 +235,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
*res = bus->ops.get_response(bus, codec->addr); *res = bus->ops.get_response(bus, codec->addr);
trace_hda_get_response(codec, *res); trace_hda_get_response(codec, *res);
} }
bus->no_response_fallback = 0;
mutex_unlock(&bus->cmd_mutex); mutex_unlock(&bus->cmd_mutex);
snd_hda_power_down(codec); snd_hda_power_down(codec);
if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) { if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) {
...@@ -3805,11 +3808,13 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, ...@@ -3805,11 +3808,13 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
hda_nid_t fg = codec->afg ? codec->afg : codec->mfg; hda_nid_t fg = codec->afg ? codec->afg : codec->mfg;
int count; int count;
unsigned int state; unsigned int state;
int flags = 0;
/* this delay seems necessary to avoid click noise at power-down */ /* this delay seems necessary to avoid click noise at power-down */
if (power_state == AC_PWRST_D3) { if (power_state == AC_PWRST_D3) {
/* transition time less than 10ms for power down */ /* transition time less than 10ms for power down */
msleep(codec->epss ? 10 : 100); msleep(codec->epss ? 10 : 100);
flags = HDA_RW_NO_RESPONSE_FALLBACK;
} }
/* repeat power states setting at most 10 times*/ /* repeat power states setting at most 10 times*/
...@@ -3818,7 +3823,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, ...@@ -3818,7 +3823,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
codec->patch_ops.set_power_state(codec, fg, codec->patch_ops.set_power_state(codec, fg,
power_state); power_state);
else { else {
snd_hda_codec_read(codec, fg, 0, snd_hda_codec_read(codec, fg, flags,
AC_VERB_SET_POWER_STATE, AC_VERB_SET_POWER_STATE,
power_state); power_state);
snd_hda_codec_set_power_to_all(codec, fg, power_state); snd_hda_codec_set_power_to_all(codec, fg, power_state);
......
...@@ -679,6 +679,7 @@ struct hda_bus { ...@@ -679,6 +679,7 @@ struct hda_bus {
unsigned int response_reset:1; /* controller was reset */ unsigned int response_reset:1; /* controller was reset */
unsigned int in_reset:1; /* during reset operation */ unsigned int in_reset:1; /* during reset operation */
unsigned int power_keep_link_on:1; /* don't power off HDA link */ unsigned int power_keep_link_on:1; /* don't power off HDA link */
unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
int primary_dig_out_type; /* primary digital out PCM type */ int primary_dig_out_type; /* primary digital out PCM type */
}; };
...@@ -930,6 +931,8 @@ enum { ...@@ -930,6 +931,8 @@ enum {
HDA_INPUT, HDA_OUTPUT HDA_INPUT, HDA_OUTPUT
}; };
/* snd_hda_codec_read/write optional flags */
#define HDA_RW_NO_RESPONSE_FALLBACK (1 << 0)
/* /*
* constructors * constructors
......
...@@ -942,6 +942,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, ...@@ -942,6 +942,9 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
} }
} }
if (!bus->no_response_fallback)
return -1;
if (!chip->polling_mode && chip->poll_count < 2) { if (!chip->polling_mode && chip->poll_count < 2) {
snd_printdd(SFX "%s: azx_get_response timeout, " snd_printdd(SFX "%s: azx_get_response timeout, "
"polling the codec once: last cmd=0x%08x\n", "polling the codec once: last cmd=0x%08x\n",
......
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