diff options
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r-- | sound/pci/hda/hda_intel.c | 40 |
1 files changed, 34 insertions, 6 deletions
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); |