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); |
