diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-03-24 02:36:09 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-04-21 05:10:44 -0400 |
commit | b613291fb21a2d74eb8323d97fe9aa5d281b306c (patch) | |
tree | 142afbf9e2fa31b852c3fbfe1bb4dafd4977fb98 /sound/pci | |
parent | 92c7c8a7d6e03eb4c0a3c5888e35dbc45f24744c (diff) |
ALSA: hda - Retry codec-verbs at errors
The current error-recovery scheme for the codec communication errors
doesn't work always well. Especially falling back to the
single-command mode causes the fatal problem on many systems.
In this patch, the problematic verb is re-issued again after the error
(even with polling mode) instead of the single-cmd mode. The
single-cmd mode will be used only when specified via the command
option explicitly, mainly just for testing.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 17 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 19 |
3 files changed, 24 insertions, 13 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3d8bf39e6d98..1736ccbebc72 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -174,14 +174,23 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, | |||
174 | unsigned int verb, unsigned int parm) | 174 | unsigned int verb, unsigned int parm) |
175 | { | 175 | { |
176 | struct hda_bus *bus = codec->bus; | 176 | struct hda_bus *bus = codec->bus; |
177 | unsigned int res; | 177 | unsigned int cmd, res; |
178 | int repeated = 0; | ||
178 | 179 | ||
179 | res = make_codec_cmd(codec, nid, direct, verb, parm); | 180 | cmd = make_codec_cmd(codec, nid, direct, verb, parm); |
180 | snd_hda_power_up(codec); | 181 | snd_hda_power_up(codec); |
181 | mutex_lock(&bus->cmd_mutex); | 182 | mutex_lock(&bus->cmd_mutex); |
182 | if (!bus->ops.command(bus, res)) | 183 | again: |
184 | if (!bus->ops.command(bus, cmd)) { | ||
183 | res = bus->ops.get_response(bus); | 185 | res = bus->ops.get_response(bus); |
184 | else | 186 | if (res == -1 && bus->rirb_error) { |
187 | if (repeated++ < 1) { | ||
188 | snd_printd(KERN_WARNING "hda_codec: " | ||
189 | "Trying verb 0x%08x again\n", cmd); | ||
190 | goto again; | ||
191 | } | ||
192 | } | ||
193 | } else | ||
185 | res = (unsigned int)-1; | 194 | res = (unsigned int)-1; |
186 | mutex_unlock(&bus->cmd_mutex); | 195 | mutex_unlock(&bus->cmd_mutex); |
187 | snd_hda_power_down(codec); | 196 | snd_hda_power_down(codec); |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 2fdecf4b0eb6..cd8979c7670b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -623,6 +623,7 @@ struct hda_bus { | |||
623 | /* misc op flags */ | 623 | /* misc op flags */ |
624 | unsigned int needs_damn_long_delay :1; | 624 | unsigned int needs_damn_long_delay :1; |
625 | unsigned int shutdown :1; /* being unloaded */ | 625 | unsigned int shutdown :1; /* being unloaded */ |
626 | unsigned int rirb_error:1; /* error in codec communication */ | ||
626 | }; | 627 | }; |
627 | 628 | ||
628 | /* | 629 | /* |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 30829ee920c3..803b72098ed3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -604,6 +604,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
604 | } | 604 | } |
605 | if (!chip->rirb.cmds) { | 605 | if (!chip->rirb.cmds) { |
606 | smp_rmb(); | 606 | smp_rmb(); |
607 | bus->rirb_error = 0; | ||
607 | return chip->rirb.res; /* the last value */ | 608 | return chip->rirb.res; /* the last value */ |
608 | } | 609 | } |
609 | if (time_after(jiffies, timeout)) | 610 | if (time_after(jiffies, timeout)) |
@@ -623,8 +624,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
623 | chip->irq = -1; | 624 | chip->irq = -1; |
624 | pci_disable_msi(chip->pci); | 625 | pci_disable_msi(chip->pci); |
625 | chip->msi = 0; | 626 | chip->msi = 0; |
626 | if (azx_acquire_irq(chip, 1) < 0) | 627 | if (azx_acquire_irq(chip, 1) < 0) { |
628 | bus->rirb_error = 1; | ||
627 | return -1; | 629 | return -1; |
630 | } | ||
628 | goto again; | 631 | goto again; |
629 | } | 632 | } |
630 | 633 | ||
@@ -644,14 +647,12 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
644 | return -1; | 647 | return -1; |
645 | } | 648 | } |
646 | 649 | ||
647 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " | 650 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout (ERROR): " |
648 | "switching to single_cmd mode: last cmd=0x%08x\n", | 651 | "last cmd=0x%08x\n", chip->last_cmd); |
649 | chip->last_cmd); | 652 | spin_lock_irq(&chip->reg_lock); |
650 | chip->rirb.rp = azx_readb(chip, RIRBWP); | 653 | chip->rirb.cmds = 0; /* reset the index */ |
651 | chip->rirb.cmds = 0; | 654 | bus->rirb_error = 1; |
652 | /* switch to single_cmd mode */ | 655 | spin_unlock_irq(&chip->reg_lock); |
653 | chip->single_cmd = 1; | ||
654 | azx_free_cmd_io(chip); | ||
655 | return -1; | 656 | return -1; |
656 | } | 657 | } |
657 | 658 | ||