diff options
-rw-r--r-- | sound/pci/hda/hda_codec.c | 32 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 40 |
3 files changed, 55 insertions, 23 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d1d5fb9d7afb..aa0e1c18b606 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -165,28 +165,29 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, | |||
165 | unsigned int *res) | 165 | unsigned int *res) |
166 | { | 166 | { |
167 | struct hda_bus *bus = codec->bus; | 167 | struct hda_bus *bus = codec->bus; |
168 | int err, repeated = 0; | 168 | int err; |
169 | 169 | ||
170 | if (res) | 170 | if (res) |
171 | *res = -1; | 171 | *res = -1; |
172 | again: | ||
172 | snd_hda_power_up(codec); | 173 | snd_hda_power_up(codec); |
173 | mutex_lock(&bus->cmd_mutex); | 174 | mutex_lock(&bus->cmd_mutex); |
174 | again: | ||
175 | err = bus->ops.command(bus, cmd); | 175 | err = bus->ops.command(bus, cmd); |
176 | if (!err) { | 176 | if (!err && res) |
177 | if (res) { | 177 | *res = bus->ops.get_response(bus); |
178 | *res = bus->ops.get_response(bus); | ||
179 | if (*res == -1 && bus->rirb_error) { | ||
180 | if (repeated++ < 1) { | ||
181 | snd_printd(KERN_WARNING "hda_codec: " | ||
182 | "Trying verb 0x%08x again\n", cmd); | ||
183 | goto again; | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | mutex_unlock(&bus->cmd_mutex); | 178 | mutex_unlock(&bus->cmd_mutex); |
189 | snd_hda_power_down(codec); | 179 | snd_hda_power_down(codec); |
180 | if (res && *res == -1 && bus->rirb_error) { | ||
181 | if (bus->response_reset) { | ||
182 | snd_printd("hda_codec: resetting BUS due to " | ||
183 | "fatal communication error\n"); | ||
184 | bus->ops.bus_reset(bus); | ||
185 | } | ||
186 | goto again; | ||
187 | } | ||
188 | /* clear reset-flag when the communication gets recovered */ | ||
189 | if (!err) | ||
190 | bus->response_reset = 0; | ||
190 | return err; | 191 | return err; |
191 | } | 192 | } |
192 | 193 | ||
@@ -3894,11 +3895,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); | |||
3894 | /** | 3895 | /** |
3895 | * snd_hda_suspend - suspend the codecs | 3896 | * snd_hda_suspend - suspend the codecs |
3896 | * @bus: the HDA bus | 3897 | * @bus: the HDA bus |
3897 | * @state: suspsend state | ||
3898 | * | 3898 | * |
3899 | * Returns 0 if successful. | 3899 | * Returns 0 if successful. |
3900 | */ | 3900 | */ |
3901 | int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) | 3901 | int snd_hda_suspend(struct hda_bus *bus) |
3902 | { | 3902 | { |
3903 | struct hda_codec *codec; | 3903 | struct hda_codec *codec; |
3904 | 3904 | ||
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c5bd40f77bb9..f5fa5d1f223c 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -574,6 +574,8 @@ struct hda_bus_ops { | |||
574 | /* attach a PCM stream */ | 574 | /* attach a PCM stream */ |
575 | int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, | 575 | int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, |
576 | struct hda_pcm *pcm); | 576 | struct hda_pcm *pcm); |
577 | /* reset bus for retry verb */ | ||
578 | void (*bus_reset)(struct hda_bus *bus); | ||
577 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 579 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
578 | /* notify power-up/down from codec to controller */ | 580 | /* notify power-up/down from codec to controller */ |
579 | void (*pm_notify)(struct hda_bus *bus); | 581 | void (*pm_notify)(struct hda_bus *bus); |
@@ -624,6 +626,8 @@ struct hda_bus { | |||
624 | unsigned int needs_damn_long_delay :1; | 626 | unsigned int needs_damn_long_delay :1; |
625 | unsigned int shutdown :1; /* being unloaded */ | 627 | unsigned int shutdown :1; /* being unloaded */ |
626 | unsigned int rirb_error:1; /* error in codec communication */ | 628 | unsigned int rirb_error:1; /* error in codec communication */ |
629 | unsigned int response_reset:1; /* controller was reset */ | ||
630 | unsigned int in_reset:1; /* during reset operation */ | ||
627 | }; | 631 | }; |
628 | 632 | ||
629 | /* | 633 | /* |
@@ -907,7 +911,7 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); | |||
907 | * power management | 911 | * power management |
908 | */ | 912 | */ |
909 | #ifdef CONFIG_PM | 913 | #ifdef CONFIG_PM |
910 | int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); | 914 | int snd_hda_suspend(struct hda_bus *bus); |
911 | int snd_hda_resume(struct hda_bus *bus); | 915 | int snd_hda_resume(struct hda_bus *bus); |
912 | #endif | 916 | #endif |
913 | 917 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index b063d0e3d325..44f9a0aa20c5 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -661,14 +661,23 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
661 | return -1; | 661 | return -1; |
662 | } | 662 | } |
663 | 663 | ||
664 | snd_printk(KERN_ERR SFX "azx_get_response timeout (ERROR): " | 664 | /* a fatal communication error; need either to reset or to fallback |
665 | "last cmd=0x%08x\n", chip->last_cmd); | 665 | * to the single_cmd mode |
666 | /* re-initialize CORB/RIRB */ | 666 | */ |
667 | spin_lock_irq(&chip->reg_lock); | ||
668 | bus->rirb_error = 1; | 667 | bus->rirb_error = 1; |
668 | if (!bus->response_reset && !bus->in_reset) { | ||
669 | bus->response_reset = 1; | ||
670 | return -1; /* give a chance to retry */ | ||
671 | } | ||
672 | |||
673 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " | ||
674 | "switching to single_cmd mode: last cmd=0x%08x\n", | ||
675 | chip->last_cmd); | ||
676 | chip->single_cmd = 1; | ||
677 | bus->response_reset = 0; | ||
678 | /* re-initialize CORB/RIRB */ | ||
669 | azx_free_cmd_io(chip); | 679 | azx_free_cmd_io(chip); |
670 | azx_init_cmd_io(chip); | 680 | azx_init_cmd_io(chip); |
671 | spin_unlock_irq(&chip->reg_lock); | ||
672 | return -1; | 681 | return -1; |
673 | } | 682 | } |
674 | 683 | ||
@@ -709,6 +718,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) | |||
709 | struct azx *chip = bus->private_data; | 718 | struct azx *chip = bus->private_data; |
710 | int timeout = 50; | 719 | int timeout = 50; |
711 | 720 | ||
721 | bus->rirb_error = 0; | ||
712 | while (timeout--) { | 722 | while (timeout--) { |
713 | /* check ICB busy bit */ | 723 | /* check ICB busy bit */ |
714 | if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { | 724 | if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { |
@@ -1247,6 +1257,23 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, | |||
1247 | struct hda_pcm *cpcm); | 1257 | struct hda_pcm *cpcm); |
1248 | static void azx_stop_chip(struct azx *chip); | 1258 | static void azx_stop_chip(struct azx *chip); |
1249 | 1259 | ||
1260 | static void azx_bus_reset(struct hda_bus *bus) | ||
1261 | { | ||
1262 | struct azx *chip = bus->private_data; | ||
1263 | int i; | ||
1264 | |||
1265 | bus->in_reset = 1; | ||
1266 | azx_stop_chip(chip); | ||
1267 | azx_init_chip(chip); | ||
1268 | if (chip->initialized) { | ||
1269 | for (i = 0; i < AZX_MAX_PCMS; i++) | ||
1270 | snd_pcm_suspend_all(chip->pcm[i]); | ||
1271 | snd_hda_suspend(chip->bus); | ||
1272 | snd_hda_resume(chip->bus); | ||
1273 | } | ||
1274 | bus->in_reset = 0; | ||
1275 | } | ||
1276 | |||
1250 | /* | 1277 | /* |
1251 | * Codec initialization | 1278 | * Codec initialization |
1252 | */ | 1279 | */ |
@@ -1270,6 +1297,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, | |||
1270 | bus_temp.ops.command = azx_send_cmd; | 1297 | bus_temp.ops.command = azx_send_cmd; |
1271 | bus_temp.ops.get_response = azx_get_response; | 1298 | bus_temp.ops.get_response = azx_get_response; |
1272 | bus_temp.ops.attach_pcm = azx_attach_pcm_stream; | 1299 | bus_temp.ops.attach_pcm = azx_attach_pcm_stream; |
1300 | bus_temp.ops.bus_reset = azx_bus_reset; | ||
1273 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1301 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1274 | bus_temp.power_save = &power_save; | 1302 | bus_temp.power_save = &power_save; |
1275 | bus_temp.ops.pm_notify = azx_power_notify; | 1303 | bus_temp.ops.pm_notify = azx_power_notify; |
@@ -1997,7 +2025,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
1997 | for (i = 0; i < AZX_MAX_PCMS; i++) | 2025 | for (i = 0; i < AZX_MAX_PCMS; i++) |
1998 | snd_pcm_suspend_all(chip->pcm[i]); | 2026 | snd_pcm_suspend_all(chip->pcm[i]); |
1999 | if (chip->initialized) | 2027 | if (chip->initialized) |
2000 | snd_hda_suspend(chip->bus, state); | 2028 | snd_hda_suspend(chip->bus); |
2001 | azx_stop_chip(chip); | 2029 | azx_stop_chip(chip); |
2002 | if (chip->irq >= 0) { | 2030 | if (chip->irq >= 0) { |
2003 | free_irq(chip->irq, chip); | 2031 | free_irq(chip->irq, chip); |